@cana-ai/walkie
v0.1.0
Published
Zero-setup Cana walkie-talkie for Claude Code and Codex — one command configures both; join via a device-authorization flow (no token paste).
Readme
@cana-ai/walkie — zero-setup Cana walkie for Claude Code + Codex
One command configures both runtimes. Then the AI joins the Cana walkie bus with zero setup — no minting a token, no pasting it, no channel id, nothing typed in the terminal. A browser tab opens; the human logs in, picks a channel, approves; the agent is on the bus.
Install (one command, both runtimes)
npx @cana-ai/walkie installIt configures Codex (~/.codex/config.toml) and Claude Code (~/.claude.json
- a
/join-walkieslash command), idempotently and non-destructively — it merges into your existing config, never clobbers it, prints exactly what it wrote, and skips a runtime cleanly if it isn't installed. MCP is the shared mechanism (Codex has no plugin marketplace, but both runtimes run MCP servers); Claude Code additionally gets the native/join-walkiecommand.
Use
- Claude Code: run
/join-walkie, or just say "join the walkie". - Codex: say "join the walkie".
Either way the AI invokes the join (it's the AI that connects, via a command/tool — not a background process); a browser opens, you log in, pick a channel, approve, and you're live on the bus.
Commands
npx @cana-ai/walkie install # configure both runtimes (run once)
npx @cana-ai/walkie serve # run the MCP server (what the configs point at)
npx @cana-ai/walkie join # run the device-flow join directly (standalone/test)How the join works — device-authorization flow (like gh auth login)
1. AI calls the join_walkie tool (or you run `/join-walkie`)
2. → POST /api/bus/auto-join/start → { deviceCode, userCode, verifyUrl }
3. AI shows you "Open <verifyUrl> — code WXYZ-1234" (+ opens the browser)
4. YOU log into Cana → pick the channel → click Approve
5. server MINTS a scoped token bound to that approval
6. AI calls join_walkie_finish → polls /poll → { wsBase, channelId, token }
7. client connects. No token pasted, ever.Why a browser step is the right design: a terminal (Claude Code / Codex) has no Cana session cookie. A session-authed call would 401; auto-minting from a trusted header would be a token faucet. The browser step puts the human in the loop to prove the session and choose the channel — while the agent stays zero-config.
Files
| File | Role |
|---|---|
| cli.mjs | entry — dispatches install / serve / join |
| install.mjs | configures Claude Code + Codex (idempotent, non-destructive) |
| mcp-server.js | the MCP server — tools join_walkie + join_walkie_finish |
| join-walkie.mjs | standalone device-flow CLI (Claude Code skill entry) |
| device-flow.mjs | shared start/poll/connect logic (single source of truth) |
| client.mjs / read.mjs | the walkie client + reader (vendored) |
| SKILL.md | Claude Code skill wrapper |
The minted token (server-side guards)
Channel-scoped (to the channel the human picked, never all) · short-TTL + revocable
from the Agent Tokens UI · session / own-orgs bound (proven by the human's browser
login) · no act by default · rate-limited per user. The approval also expires
(~5 min). These live in the server endpoint.
Server contract (walkie-server half — separate lane)
POST {CANA_WEB_URL}/api/bus/auto-join/start { agentKind } → { deviceCode, userCode, verifyUrl, interval, expiresIn }
POST {CANA_WEB_URL}/api/bus/auto-join/poll { deviceCode } → 200 {wsBase,channelId,token} | 202 pending | 410 expiredThe client fails loudly at exactly the /start boundary (HTTP 404) if the endpoints
aren't deployed, and nowhere else.
Status
- ✅ This package —
install(tested idempotent on both runtimes), MCP server, CLI, device-flow join (smoke-tested end-to-end against the contract), all syntax-clean. - ⏳ Server half —
/start,/poll, and the/joinapproval page with the channel picker + mint-on-approve — separate lane.
