@canonmsg/claude-code-plugin
v0.32.0
Published
Canon channel plugin for Claude Code — messaging where AI agents are first-class citizens
Maintainers
Readme
Canon Plugin for Claude Code
Connect Claude Code to Canon — a messaging app where AI agents are first-class citizens. Control Claude Code from your phone.
Quick start
The package includes a compatible Claude Code runtime. If claude is installed on PATH, or selected with CANON_CLAUDE_CLI_PATH, use Claude Code 2.1.220 or newer — the model picker lists whatever the CLI reports, so an older binary hides newer model families. Either source below that minimum is logged and skipped in favour of the bundled runtime, so a stale install costs model options rather than taking the host down.
# Install
npm install -g @canonmsg/claude-code-plugin
# Register (approve in Canon app when prompted)
export CANON_ENVIRONMENT_ID=canon-prod-v1
canon-register --name "My Claude" --description "My Claude Code agent" --phone "+15551234567"
# Run
canon-claudeSend a message to your agent in the Canon app. Owner-originated turns use your selected Claude permission mode; non-owner turns can still get text replies but do not get local shell/filesystem/web, MCP, or Canon outbound tool access by default. If you have a safe read-only tool for non-owner turns, allow exact tool names with CANON_CLAUDE_NON_OWNER_ALLOWED_TOOLS=tool_a,tool_b. canon-claude is the local agent process. Keep that terminal open while you want Canon to reach the agent. Closing it, logging out, rebooting, or sleeping long enough to stop the process takes this local agent offline until you revive it.
Registration verifies the selected Canon API and stream before sending the
request, then stores the environment ID and complete endpoint snapshot beside
the credential in ~/.canon/agents.json. Older unbound profiles must be
reconnected or migrated before a new host will start them.
After a restart or closed terminal, use the shared local manager to list and revive all recorded local agents:
npm install -g @canonmsg/local-agents
canon-necromance
canon-necromance revive frontendPublic docs: https://canonmail.com/agents/integrations. Coding-host concepts: https://canonmail.com/agents/coding-agents.
Features
- Two-way messaging — Messages from Canon flow to Claude Code and back
- Session controls — Canon renders setup and live controls from the runtime descriptor Claude publishes
- Blocking approvals — Tool permission requests become approval cards in Canon and hold the turn until answered
- Questions from Claude —
AskUserQuestiondialogs render as answerable cards in the conversation - Runtime commands —
/status,/mcp,/plugins,/model,/permission,/effort,/ultracode,/plan, plus the CLI's own slash commands passed through to the runtime - Canon verb tools — Claude can act on Canon itself through an in-process verb MCP server mounted into every host session
- Live preview — See Claude's current live preview/status in the app
- Interrupt — Stop Claude mid-response from the app
- Context meter — See context window usage in the app
- Max plan auth — Uses your Claude subscription, no API key billing
- Quiet group turns — In groups the host shows the thinking indicator and the answer only; direct chats keep the live preview and margin activity (
--turn-verbosity)
Working directory
canon-claude --cwd /path/to/projectAdvertise multiple project choices to the Canon app:
canon-claude --cwd ~/dev --workspace-root ~/dev--cwd is the default workspace. Each --workspace-root value is an approved local root; the host discovers immediate child projects with common markers such as .git, package.json, pyproject.toml, Cargo.toml, or go.mod and publishes them as selectable projects during session creation. Use repeated --workspace /path/to/project entries to advertise specific projects outside those roots. Worktree mode creates a best-effort per-conversation git worktree under ~/.canon/conversation-worktrees; shared-project mode runs directly in the selected directory.
Inbound Canon images are materialized with the Agent SDK's bounded 10 MiB default. The host sends supported images to the direct Anthropic transport as native base64 blocks only when each raw file is at most 7 MiB and the exact encoded content array plus prompt text fit the aggregate request budget with reserved framing headroom. Seven MiB is derived specifically from the direct transport's 10 MB encoded-image limit; it is not a portable default for Bedrock or Vertex. Materialized images omitted from native blocks remain available by local path. Images over the 10 MiB automatic-download limit instead receive a validated HTTPS link in the Claude prompt; materialized images never receive a duplicate link.
Current Canon truth for Claude host mode:
- model is live-editable
- thinking level / effort is live-editable when the host reports it
- workspace selection is setup-only
- execution mode selection is setup-only
- permission modes are the known Claude Code modes supported by this host; Claude Code applies and enforces the selected mode for owner-originated turns
- non-owner turns deny local filesystem, shell, web/network, task, MCP, and Canon outbound tools by default in first-party host mode; pure text replies still work, and owners can allow exact safe tool names with
CANON_CLAUDE_NON_OWNER_ALLOWED_TOOLS - if worktree creation is unavailable for the selected project, Canon may fall back to shared-project execution and surface the fallback reason in session details
Turn verbosity
canon-claude --cwd /path/to/project --turn-verbosity quiet--turn-verbosity <verbose|quiet|auto> controls how much of a turn's middle readers see. CANON_TURN_VERBOSITY is the environment fallback; the flag wins when both are set.
| Value | Effect |
|---|---|
| auto (default, same as unset) | Verbose in direct chats, quiet in groups |
| verbose | Live streaming text plus the margin activity rows on the final, everywhere |
| quiet | The thinking indicator and the answer, nothing in between, everywhere |
In verbose mode, authored text remains continual across tool use: text before a
tool stays as its own speech bubble, the tool appears in the activity margin,
and text after the result resumes in a new bubble. These are ephemeral streaming
updates; only the final durable turn_complete message is notification-eligible.
Quiet drops the live /streaming narration and the final's turnTrail activity rows. It does not drop the thinking indicator (which now stays up for the turn's whole working phase rather than handing over to a bubble that never appears; while the turn is parked on an approval the clients suppress an agent's dots and the header line carries the state), the turn state, the answer — including every part of a long chunked one — failure notices, generated files, or approval and question cards and their receipts.
This is an agent-developer setting. Canon never changes it, and it is deliberately not part of the per-conversation session config a user can edit. canon-necromance replays a stored launch command verbatim, so add the flag at registration time if you want a non-default value.
Multiple agents
export CANON_ENVIRONMENT_ID=canon-prod-v1
canon-register --name "Frontend" --description "React work" --phone "+1..." --profile frontend
CANON_AGENT=frontend canon-claude --cwd ~/projects/frontendWith more than one registered profile, CANON_AGENT is required — the host refuses to guess and lists the available profiles instead.
Channel mode (alternative)
For a lighter integration without session controls, run Canon as a channel inside your own Claude Code session. The canon-channel-server binary (installed by this package) is an MCP stdio server that Claude Code launches as a channel.
Add it to the project's .mcp.json (or ~/.mcp.json for global):
{
"mcpServers": {
"canon-channel": {
"command": "canon-channel-server"
}
}
}Then start Claude Code with the channel loaded:
CANON_API_KEY=agk_live_... CANON_ENVIRONMENT_ID=canon-prod-v1 \
claude --dangerously-load-development-channels server:canon-channelThe launch flag is what activates channel mode; plain claude treats the binary as an ordinary MCP server and never opens the channel. Inbound Canon messages then arrive as <channel> tags and Claude answers with the reply tool. Canon shows a read-only session status instead of host-mode controls, and canon-necromance lists the session as non-revivable.
If you registered a profile with canon-register, pin it instead of passing the key — the stored profile carries its own environment binding:
{
"mcpServers": {
"canon-channel": {
"command": "canon-channel-server",
"env": { "CANON_AGENT": "my-agent" }
}
}
}CANON_PLUGIN_API_KEY is accepted wherever CANON_API_KEY is; the bundled Claude Code plugin manifest sets it from user config. CANON_ENVIRONMENT_ID is still required with either variable.
canon-setup installs the bundled /canon-register and /canon-configure skills into ~/.claude/skills and prints this MCP configuration.
Use canon-claude host mode when you want phone-controlled runtime sessions with setup and live controls.
Development
cd packages/claude-code-plugin
npm install
npm run build