Jacky integrates with OpenCode through three complementary mechanisms:
- Reaction plugin — A small JS plugin forwards OpenCode's lifecycle events to Jacky; Jacky reacts with emotions and speech automatically.
- MCP tool server — OpenCode can call Jacky tools (speak, notify, emote, run routines, and more) via the Model Context Protocol.
- Managed instructions — A marker block in a Jacky-managed file tells OpenCode about Jacky's capabilities.
All three are set up with a single command: jacky opencode install.
OpenCode has no settings.json-style hook system like Claude Code — reactions are delivered through a plugin file instead. See Claude Code Integration if you're connecting that agent too; both integrations run side by side with independent reaction settings.
Quick Start
# 1. Launch the Jacky desktop app
jacky
# 2. One-command setup
jacky opencode install
# 3. Restart Jacky to activate the WebSocket + MCP serversThat's it. OpenCode will now trigger Jacky reactions automatically, and can call Jacky tools via MCP.
Restart required: After running jacky opencode install, restart the Jacky desktop app so the WebSocket and MCP servers start with the new configuration.
Reaction Plugin
How It Works
OpenCode delivers most lifecycle events through a generic event hook (rather than one hook per event type), plus a few named hooks for chat messages and tool calls. Jacky's plugin listens to both and reacts in real time on your desktop:
| OpenCode Event | Jacky's Reaction | What It Means |
|---|---|---|
chat.message | 🤔 Thinking | You sent a message to OpenCode |
tool.execute.before / tool.execute.after | 🔧 Working | OpenCode is executing a tool |
permission.updated / permission.asked | ⚠️ Alerting | OpenCode needs your approval to run something |
question.asked | ⚠️ Alerting | OpenCode is waiting on you to pick an option |
session.idle | 😊 Happy | Session finished without errors |
session.error | 😢 Hurt | Something went wrong |
By default OpenCode auto-approves tool calls, so permission.updated rarely fires unless you configure approval prompts (e.g. "permission": {"bash": "ask"} in your opencode.json). The question.asked event — OpenCode's built-in "ask the user a question" tool — is treated the same way, since it's also a "waiting on you" moment.
Event Priority
OpenCode sometimes fires multiple events within milliseconds of each other — for example, session.error immediately followed by session.idle. Jacky resolves this with an event priority window: a lower-priority event won't overwrite a higher-priority reaction that just landed. From highest to lowest priority: task failed, permission/notification, task finished, working, prompt submitted.
Throttling
To avoid overwhelming you with reactions during rapid agent activity, Jacky applies the same smart cooldowns used for Claude Code:
| Cooldown Type | Duration | Description |
|---|---|---|
| Reaction | 10 seconds | Same reaction won't re-trigger within 10s |
| Speech | 20 seconds | Same speech category won't fire within 20s |
| Permission | 3 seconds | Permission/question events fire more frequently |
Claude Code and OpenCode use separate throttle state, so activity in one agent never suppresses reactions from the other.
MCP Tool Server
Jacky runs the same Model Context Protocol server used for Claude Code — a streamable HTTP transport bound to 127.0.0.1 (localhost only). Install adds it to OpenCode's config as a "remote" MCP entry.
Available MCP Tools
Once connected, OpenCode can call these Jacky tools:
| Tool | Description |
|---|---|
jacky_say | Speak text aloud with voice and show a speech bubble |
jacky_notify | Show a system tray notification (no voice) |
jacky_emote | Change Jacky's animation/emotion state |
jacky_react_to | Have Jacky react to text with an AI-generated response |
jacky_ask | Send text through Jacky's full agent pipeline |
jacky_run_routine | Run a Jacky routine by ID with optional variables |
jacky_set_timer | Create a countdown timer |
jacky_set_alarm | Create an alarm clock |
jacky_status | Get Jacky's current status (state, LLM, TTS, version) |
jacky_move_to | Walk Jacky to absolute screen coordinates (pixels) |
jacky_move | Walk Jacky a relative distance in pixels (left/right/up/down/top/bottom) |
Authentication
Jacky's MCP server requires a Bearer token — auto-generated once and stored securely in your OS keyring. jacky opencode install reads that token and writes it into the MCP entry's headers:
{
"mcp": {
"jacky": {
"type": "remote",
"url": "http://127.0.0.1:9877/mcp",
"enabled": true,
"headers": { "Authorization": "Bearer <token>" }
}
}
}If you regenerate the MCP token in Jacky's Settings → Integrations → MCP Server tab, the token written into opencode.json becomes stale and OpenCode will report that Jacky needs authentication. Re-run jacky opencode install to sync the new token.
Security
- The server is bound to localhost only (
127.0.0.1) — not accessible from other machines - Bearer token authentication (stored securely in your OS keyring)
- Allowed actions are configurable — you choose which tools external agents can use
- Error messages are sanitized before reaching the AI agent (no file paths, tokens, or tracebacks leaked)
Managed Instructions
When you run jacky opencode install, Jacky writes a managed instructions file (jacky.md) next to your OpenCode config and adds its path to the instructions array so OpenCode reads it automatically:
<!-- BEGIN JACKY:MANAGED -->
## Jacky Desktop Pet Integration
Jacky is a desktop pet that reacts to your coding activity in real time.
When you use OpenCode, Jacky will automatically emote and react to
lifecycle events (thinking, working, success, errors).
To control Jacky programmatically, use the `jacky` CLI:
- `jacky say "text"` — make Jacky say something
- `jacky emote happy` — set Jacky's emotion
- `jacky status` — check if Jacky is running
This integration is managed by `jacky opencode`. Do not edit the marker block.
Run `jacky opencode uninstall` to remove.
<!-- END JACKY:MANAGED -->If jacky.md already has content of your own, Jacky only touches the marker block — everything else in the file is left untouched, and uninstalling deletes the file only if the managed block was the only content.
Configuration Scope
By default, jacky opencode install configures OpenCode globally:
| Scope | Config directory | Notes |
|---|---|---|
| Global (default) | ~/.config/opencode/ | Same path on Windows, macOS, and Linux — OpenCode does not use %APPDATA% |
| Project | ./.opencode/ | Pass --project to target the current project instead |
# Project-level install (writes to ./.opencode/ in the current directory)
jacky opencode install --project
# Skip installing the reaction plugin (MCP tools only)
jacky opencode install --no-pluginThe config directory can be overridden with the OPENCODE_CONFIG_DIR or XDG_CONFIG_HOME environment variables, matching OpenCode's own resolution order.
CLI Commands
jacky opencode install [--project] [--no-plugin]
One-command setup. Performs all of the following automatically:
| Step | What it does |
|---|---|
| Enable servers | Activates the WebSocket and MCP servers in Jacky's configuration |
| Grant permissions | Enables the necessary permissions for external control |
| Write MCP entry | Adds a mcp.jacky remote entry (with auth headers) to OpenCode's config |
| Write instructions | Creates jacky.md with a managed block and references it in instructions |
| Install plugin | Copies the reaction plugin into OpenCode's plugins/ directory (skip with --no-plugin) |
jacky opencode uninstall [--project]
Removes everything: the mcp.jacky entry, the instructions reference and file (or just the managed block, if you added your own content), and the plugin file.
jacky opencode --doctor [--project]
Health check that verifies:
- OpenCode's config file exists and the
mcp.jackyentry is present and correct (including the auth header) - The managed instructions file exists and is referenced
- The reaction plugin file is installed
- Jacky desktop app is running
jackyCLI is on your PATH- Configuration has the necessary servers enabled and permissions granted
Full CLI Command Reference
Troubleshooting
Jacky doesn't react to OpenCode events
- Run
jacky opencode --doctor— check for any issues - Verify Jacky desktop app is running:
jacky status - Restart Jacky after running
jacky opencode install - Confirm the plugin file exists under your OpenCode config's
plugins/directory
OpenCode reports "jacky needs authentication"
The MCP token in opencode.json no longer matches the one Jacky's server expects — most likely because the token was regenerated in Settings. Run jacky opencode install again to sync it.
MCP tools not available in OpenCode
- Run
jacky opencode --doctor - Verify the
mcp.jackyentry is present in youropencode.jsonand has anAuthorizationheader - Restart Jacky after enabling the MCP server
- Verify the MCP server is running on the expected port (
http://127.0.0.1:9877/mcp)
Jacky seems quiet during rapid activity
This is likely throttling — Jacky intentionally limits reaction frequency to avoid spam. Throttle state is persisted locally (separately from Claude Code's) and resets automatically over time. You can delete OpenCode's throttle file to reset all cooldowns immediately.
Wrong config directory
OpenCode always uses ~/.config/opencode/ — never %APPDATA%, even on Windows. If you manually edited a config file elsewhere, OpenCode won't read it; run jacky opencode --doctor to confirm which file Jacky is managing.