{
  "markdown": "# URC — Universal Remote Control\n\nControl Codex and Gemini from the Claude App on your phone.\n\n![URC Demo — orchestrating Codex and Gemini from the Claude App](docs/demo.gif)\n\nYou know `/remote-control` — the Claude Code feature that lets you control a session from the Claude App on your phone. URC makes it **universal**. One command, and your phone controls Codex. Another command, and it controls Gemini. Same app, same conversation, same interface. No extra API keys. No extra apps.\n\n```bash\n/urc codex    # Your phone now controls Codex\n/urc gemini   # Your phone now controls Gemini\n```\n\nBehind the scenes, URC spawns a lightweight Haiku relay that acts as a pure passthrough — your messages go through unchanged, output comes back verbatim. The relay is self-managing: it auto-clears, auto-reconnects on target death, and runs indefinitely without intervention.\n\n## Features\n\n**Phone control for every CLI**\n- Bridge any Codex or Gemini pane from your phone in one command\n- Spawn new panes or bridge existing ones (`/urc 875`)\n- Initiate bridges from the other side too (Codex skill or Gemini `/rc` command)\n\n**Self-managing relay**\n- Auto-clears at 25 sends — respawns itself, restores phone connection, resets counter\n- Auto-reconnects on target death — spawns replacement, retries your message (3 attempts)\n- Type **\"status\"** to check capacity, target health, and respawn count\n- No manual maintenance, no `/clear`, no restarts\n\n**Real-time visibility**\n- Push attribution shows who dispatched each message and what was asked\n- Instant \"message received\" confirmation when target gets your message\n- Responses stream back to your phone as turns complete\n\n**$0 relay mode**\n- Type `>codex: message` or `>gemini: message` for hook-based passthrough\n- Zero model invocation, zero cost — a `UserPromptSubmit` hook handles dispatch\n- Setup: `bash urc/core/relay-ctl.sh add codex %NNN && bash urc/core/relay-ctl.sh on`\n\n**Cross-CLI coordination**\n- 11-tool MCP server for pane-level communication (dispatch, read, register, heartbeat, messaging)\n- Agents across Claude Code, Codex, and Gemini can send messages, share work, and coordinate\n- 5-layer inbox notification stack ensures no message is missed\n\n**Tested and validated**\n- 160 assertions across 10 test suites\n- 23-check plugin validation\n- Post-Enter stuck-input detection for TUI reliability\n\n## Quick Start\n\n### Prerequisites\n\n- **tmux**: `brew install tmux` (macOS) or `sudo apt install tmux` (Linux)\n- **Python 3.10+**, **jq**\n- **Claude Code CLI**: `curl -fsSL https://claude.ai/install.sh | bash`\n- **Claude Max plan** (for phone control — see [claude.com/pricing](https://claude.com/pricing))\n- **Codex CLI** and/or **Gemini CLI** (optional — install whichever you want to bridge)\n  - Codex: `npm install -g @openai/codex`\n  - Gemini: see [github.com/google-gemini/gemini-cli](https://github.com/google-gemini/gemini-cli)\n\n### Install\n\n```bash\ntmux new -s urc                # Start a tmux session (required)\ngit clone https://github.com/siddharthkandan/universal-remote-control\ncd universal-remote-control\n./setup.sh                     # Detects your CLIs, generates configs\n```\n\nOr install as a Claude Code plugin:\n\n```\n/plugin marketplace add siddharthkandan/universal-remote-control\n/plugin install urc\n```\n\n### Use It\n\nFrom Claude Code (inside tmux):\n\n```bash\n/urc codex                    # Spawn Codex pane + bridge it to your phone\n/urc gemini                   # Spawn Gemini pane + bridge it to your phone\n/urc 875                      # Bridge an existing pane by ID\n/urc                          # List unbridged panes\n```\n\nOpen the **Claude App on your phone** — the relay automatically activates Remote Control. Type a message and it goes straight to Codex or Gemini. Responses stream back as they complete.\n\nAliases: `/rc-bridge`, `/rc-any`, `/rc-relay` all work.\n\nYou can also bridge from the other side:\n- **From Codex:** activate the `rc-bridge` skill\n- **From Gemini:** type `/rc`\n\nYour Claude plan covers the Haiku relay — no separate API key needed.\n\n### Gemini Setup Note\n\nGemini CLI requires additional configuration beyond what `setup.sh` generates:\n\n- `setup.sh` creates the project config and policy rules automatically\n- If `~/.gemini/settings.json` has a `tools.allowed` whitelist, remove the `\"tools\"` block\n- Verify: `gemini mcp list` (outside session) or `/mcp list` (in session)\n- Note: Gemini's `/tools` command intentionally hides MCP tools — don't use it to check\n\n## How It Works\n\n```\nPhone (Claude App)\n    |  Remote Control\n    v\nHaiku Relay (rc-bridge agent)        ← self-managing, auto-clears at 25 sends\n    |  send.sh              push files\n    |  (dispatch) ←———————— (response)\n    v                           |\nTarget pane (tmux)              |\n    |  hook.sh fires ———————————┘    ← captures response, writes push file\n```\n\n**The relay is a stateless passthrough.** State lives in tmux pane options (`@bridge_target`, `@bridge_cli`, `@bridge_relays`). Dispatch and response reading are handled through a `UserPromptSubmit` hook (`bridge-push-hook.sh`) — the relay's phone message triggers the hook, which dispatches via `send.sh` and reads any pending push files, all without consuming a model turn. When the target completes its turn, `hook.sh` captures the response and writes a push file. The relay picks it up on its next wake and displays it on your phone.\n\n**The MCP server** (`urc-coordination`, 11 tools) provides the cross-pane infrastructure: dispatch messages, read pane output, register agents, track heartbeats, and send/receive async messages via SQLite. Any agent in any CLI can use these tools to coordinate with others.\n\n> A second MCP server (`urc-teams`, 17 tools) provides structured team creation, typed messages, and task dependencies. Currently dormant — the coordination server handles all active messaging.\n\n## Project Structure\n\n> The root directory includes CLI-specific files (`CLAUDE.md`, `AGENTS.md`, `GEMINI.md`, symlinks) because each AI CLI has its own conventions for discovering instructions. All actual code lives in `urc/`.\n\n### Core (`urc/`)\n\n```\nurc/\n├── core/\n│   ├── server.py                 Coordination MCP server (11 tools)\n│   ├── db.py                     SQLite foundation\n│   ├── teams_protocol.py         Teams data layer (dormant)\n│   ├── teams_server.py           Teams MCP server (dormant)\n│   ├── send.sh                   Pane dispatch (bracketed paste + post-Enter verify)\n│   ├── hook.sh                   Turn completion + push attribution + respawn\n│   ├── wait.sh                   Blocking wait with self-wake\n│   ├── dispatch-and-wait.sh      Atomic dispatch + wait + read\n│   ├── cli-adapter.sh            CLI detection + paste behavior\n│   ├── urc-spawn.sh              Fire-and-forget relay+target spawner\n│   ├── urc-dispatch.sh           ! mode CLI dispatcher\n│   ├── urc-status.sh             Fleet status display\n│   ├── inbox-watcher.sh          Background inbox notification\n│   ├── circuit.sh                Circuit breaker for dispatch failures\n│   ├── relay-ctl.sh              $0 relay configuration\n│   └── test-*.sh                 8 test suites (94 assertions)\n├── lib/\n│   └── state-write.sh            Atomic JSON write helper\n└── schemas/\n    └── response.md               Response file schema\n```\n\n### CLI Integration\n\n| File/Dir | Required by | Purpose |\n|----------|-------------|---------|\n| `CLAUDE.md` | Claude Code | Agent instructions |\n| `AGENTS.md` | Codex | Agent instructions |\n| `GEMINI.md` | Gemini | Agent instructions |\n| `.claude/agents/` | Claude Code | RC Bridge agent definition |\n| `.claude/skills/` | Claude Code | `/urc` command |\n| `.claude/hooks/` | Claude Code | Session init + inbox hooks |\n| `.agents/skills/` | Codex | Codex bridge skill |\n\n### Plugin System\n\n```\n.claude-plugin/plugin.json           Plugin manifest\nhooks/hooks.json                     Plugin hooks (Stop + SessionStart)\nhooks/scripts/bridge-push-hook.sh    Hook-based dispatch + push reading (UserPromptSubmit)\nhooks/scripts/plugin-setup.sh        Auto-setup on first session\n```\n\n## Documentation\n\n- [Getting Started](docs/getting-started.md) — Install, first bridge, tmux basics\n- [Architecture Overview](docs/architecture-overview.md) — System design and message flows\n- [Turn Completion System](docs/turn-completion-system.md) — Hook signal ordering and response capture\n- [Design Decisions](docs/design-decisions.md) — Why things are built this way\n- [Teams Protocol](docs/teams-protocol.md) — Structured cross-CLI messaging (dormant)\n\n## Glossary\n\n| Term | What it means |\n|------|---------------|\n| **Remote Control** | A Claude Code feature that lets you control a session from the Claude App on your phone |\n| **MCP** | Model Context Protocol — how AI agents talk to external tools and services |\n| **Haiku** | Claude's fastest model — used for the relay since it just passes messages through |\n| **tmux** | Terminal multiplexer — runs multiple sessions in panes within one window |\n| **Pane** | A terminal session inside tmux, identified by an ID like `%875` |\n| **Push** | Response delivery from the target pane back to the relay when a turn completes |\n\n## Troubleshooting\n\n**MCP tools not showing in Gemini?**\nRun `gemini mcp list`. If empty, verify `~/.gemini/policies/urc-mcp.toml` exists (created by `setup.sh`). Remove any `tools.allowed` whitelist from `~/.gemini/settings.json`.\n\n**Relay shows \"pane does not exist\"?**\nThe target died. Type \"status\" to confirm, then \"reconnect %NNN\" with a new pane ID, or let auto-reconnect handle it.\n\n**Text stuck in a pane's input field?**\nA TUI timing edge case. `send.sh` retries automatically in most cases. If still stuck, press Enter manually.\n\n**`setup.sh` fails on venv creation?**\nNeeds Python 3.10+. On some systems: `sudo apt install python3.12-venv`.\n\n**Plugin validation fails?**\nRun `bash scripts/validate-plugin.sh` for diagnostics. Most common fix: re-run `setup.sh`.\n\n## Known Issues\n\n### RC session idle timeout (~20 minutes) — [#32982](https://github.com/anthropics/claude-code/issues/32982)\n\nRemote Control sessions are deregistered server-side after ~20 minutes of idle time, even when the local CLI process is alive. This affects ALL `/remote-control` sessions (not just URC relays) and is caused by a keepalive bug in Claude Code:\n\n1. `CLAUDE_CODE_REMOTE` (set internally for all RC sessions) disables the 5-minute WebSocket keepalive\n2. `CLAUDE_CODE_REMOTE_SEND_KEEPALIVES` (the replacement) is refcount-gated — only sends keepalives during active model processing, not during idle\n3. Result: idle RC sessions have zero keepalive mechanism and the server deregisters them\n\n**Impact on URC:** Relay sessions lose their phone connection after ~20 minutes of inactivity. The relay process stays alive but the phone shows \"Disconnected\" / \"unknown network error.\"\n\n**Status:** Bug report filed with full source analysis. Waiting for Anthropic's response before implementing workarounds. A watchdog (periodic activity to reset the server-side timer) is the known workaround but is deferred pending upstream clarity.\n\n## Known Limitations\n\n- **Gemini auto-reconnect race:** `send.sh` can report `delivered` for a dying pane. The next message triggers reconnect.\n- **Prompt injection surface:** The relay passes phone messages in bash variables via `send.sh`. Low risk (phone user is machine owner), but content is not sanitized.\n- **No automated tests for prompt-based features:** Push attribution, auto-reconnect, and the health dashboard are behavioral instructions in the agent prompt, not executable code.\n\n## License\n\n[MIT](LICENSE)\n",
  "bytes": 11613,
  "sha": "45c5831d45a4207ac21e2acd9ed573e7c8c7b15a7277cf3d55582a2dfda5fef9",
  "repo_slug": "siddharthkandan/universal-remote-control",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/plg_siddharthkandan_universal_remote_control_9d0640d2/readme"
}