{
  "markdown": "# Uttero\n\n**Voice channel for Claude Code.** Receive phone calls while coding and let Claude answer in your voice. Uttero turns any Claude Code session into a live agent that can pick up a call, hear the caller, speak back via TTS, and keep working on your codebase between turns.\n\n> Status: public preview. Requires Claude Code v2.1.80+ with `--dangerously-load-development-channels` while under review for the official marketplace allowlist.\n\n## Demo\n\n![Uttero demo](./docs/demo-hd.gif)\n\n## Quick start\n\n```bash\n# Inside Claude Code — one-time setup\n/plugin marketplace add utterodev/uttero-plugins\n/plugin install uttero@uttero-plugins\n/uttero:configure        # paste the pair code from app.uttero.dev/settings/devices\n\n# Start Claude Code with the voice channel enabled\nclaude --dangerously-load-development-channels server:uttero\n```\n\nAfter approval to the official marketplace the last line simplifies to `claude --channels plugin:uttero@uttero-plugins`.\n\n## How it works\n\n```mermaid\nflowchart LR\n    caller[\"Caller<br/>(browser or mobile app)\"]\n    api[\"api.uttero.dev<br/>STT · TTS · call routing\"]\n    bridge[\"uttero bridge<br/>(MCP server)\"]\n    claude[\"Claude Code session\"]\n\n    caller <-- \"WebRTC audio\" --> api\n    api -- \"SSE (bearer auth)\" --> bridge\n    bridge -- \"authenticated HTTPS\" --> api\n    bridge <-- \"stdio / channel events\" --> claude\n\n    subgraph local[\"Your machine\"]\n        bridge\n        claude\n    end\n```\n\n1. A caller hits your public URL (`app.uttero.dev/call/<id>`) or initiates a call from the mobile client.\n2. Audio is streamed to `api.uttero.dev`, transcribed, and the transcription is pushed to your registered agent over an authenticated SSE stream.\n3. The local bridge (this plugin) receives the transcription and forwards it into Claude Code as a `<channel source=\"ottrvoice\" ...>` notification.\n4. Claude responds via the plugin's `reply` tool; the text is sent back to `api.uttero.dev`, synthesized, and streamed back to the caller.\n\nEverything between Claude and the caller traverses Uttero's hosted backend. The plugin itself is ~500 lines of TypeScript that speaks MCP stdio and authenticated HTTPS.\n\n## Pairing\n\n1. Sign in at <https://app.uttero.dev> (Google OAuth).\n2. Open **Settings → Devices** and generate a pair code (format `XXXX-XXXX`, expires in 5 minutes).\n3. In Claude Code, run `/uttero:configure` and paste the code when prompted. The command shells out to `bin/login.ts --code=<code>`.\n4. The bridge now has an OAuth-derived bearer token stored at `~/.uttero/credentials.json` (file mode 600, refreshed automatically).\n\nRevoke a device at any time from `app.uttero.dev/settings/devices`, or delete the local file with `rm ~/.uttero/credentials.json`.\n\n## Security\n\nSee [SECURITY.md](./SECURITY.md) for the full threat model and vulnerability disclosure policy.\n\nKey points for reviewers:\n\n- **Inbound sender gating is server-side.** The bridge authenticates to `api.uttero.dev` with a rotating bearer token and trusts the authenticated SSE streams it receives. The service enforces which accounts can reach you. Per-caller allowlist management on your device is planned but not yet enforced (see `plugin/commands/access.md`).\n- **No permission relay.** `capabilities.experimental['claude/channel/permission']` is deliberately omitted so voice callers cannot approve Bash/Write/Edit tool use.\n- **Transcription content is untrusted.** Claude Code automatically wraps channel content in a system reminder instructing the model to treat the payload as untrusted data, not instructions. The plugin does not add any path for a caller to override that framing.\n- **Credentials never leave the machine** except to `api.uttero.dev` for token refresh. The credentials file is mode 600.\n\n## Privacy\n\nSee [PRIVACY.md](./PRIVACY.md). In short: audio, transcriptions, and call metadata flow through Uttero's hosted backend; transcriptions enter your Claude Code session context. Full policy at <https://uttero.dev/privacy>.\n\n## Configuration\n\n| Env var           | Default                    | Purpose                                                                                |\n| :---------------- | :------------------------- | :------------------------------------------------------------------------------------- |\n| `UTTERO_API_URL`  | `https://api.uttero.dev`   | Backend base URL. Override only for development against a local Uttero server.         |\n| `UTTERO_APP_URL`  | `https://app.uttero.dev`   | Frontend base URL (used to build sharable call links).                                 |\n\nCredentials live in `~/.uttero/credentials.json`. The file stores the refresh token, the last-known server URL, and metadata about the paired device.\n\n## Tools exposed to Claude\n\n| Tool          | Purpose                                                              |\n| :------------ | :------------------------------------------------------------------- |\n| `reply`       | Speak back into an active call via TTS.                              |\n| `call_user`   | Place an outbound call to a registered user.                         |\n| `end_call`    | Hang up an active call.                                              |\n| `list_calls`  | List active calls on this agent.                                     |\n\n## Build & reproducibility\n\nThe published plugin ships a pre-built `dist/bridge.js` so the MCP runtime can launch the bridge with plain `node` (no Bun required on the user's machine). To rebuild from source and verify the shipped artifact:\n\n```bash\ncd plugin\nbun install\nbun run build\n# outputs dist/bridge.js from bin/bridge.ts\n```\n\nSource of truth is `plugin/bin/bridge.ts`. Auth and credential helpers live in `plugin/bin/lib/`. The build command is a single `bun build --target node` — no bundler config, no custom transforms.\n\n## Repository layout\n\n```\n.\n├── .claude-plugin/\n│   └── marketplace.json        # catalog for the marketplace\n├── plugin/                     # Claude Code plugin (source of truth)\n│   ├── .claude-plugin/\n│   │   └── plugin.json\n│   ├── bin/                    # bridge.ts, login.ts, setup-mcp.ts\n│   ├── commands/               # /uttero:configure, /uttero:setup, /uttero:access\n│   ├── dist/                   # built bridge.js\n│   └── package.json\n├── LICENSE                     # MIT\n├── PRIVACY.md\n├── README.md\n└── SECURITY.md\n```\n\n## Links\n\n- Website: <https://uttero.dev>\n- App: <https://app.uttero.dev>\n- Channels reference: <https://code.claude.com/docs/en/channels-reference>\n\n## License\n\nMIT — see [LICENSE](./LICENSE).\n",
  "bytes": 6536,
  "sha": "41682c435a5f0cc7fa8f0635e5b9a24ecd1ccbe20699dc73b69837dbc020e089",
  "repo_slug": "utterodev/uttero-plugins",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/plg_utterodev_uttero_plugins_uttero_21d8e297/readme"
}