# AMC — Agent Mission Control A real-time dashboard for monitoring and interacting with Claude Code sessions. ## Overview AMC provides a unified view of all running Claude Code sessions across projects. It displays session status, conversation history, and pending questions — and allows you to respond directly from the dashboard without switching terminal tabs. ## Features - **Real-time monitoring** — Sessions are grouped by status (needs attention, active, starting, done) with 3-second polling - **Conversation history** — View the full chat history for any session, pulled from Claude Code's JSONL logs - **Response injection** — Send responses to agents directly via Zellij pane integration - **Question detection** — Detects both structured `AskUserQuestion` prompts and prose questions (messages ending with "?") - **Session lifecycle** — Automatically cleans up orphaned sessions and stale event logs ## Installation 1. Clone this repository 2. Symlink the launcher to your PATH: ```bash ln -s /path/to/amc/bin/amc ~/.local/bin/amc ``` 3. Configure Claude Code hooks (see [Hook Setup](#hook-setup)) ## Usage ```bash amc start # Start the server and open the dashboard amc stop # Stop the server amc status # Check if the server is running ``` The dashboard opens at `http://127.0.0.1:7400`. ## Hook Setup AMC requires Claude Code hooks to report session state. Add this to your `~/.claude/settings.json`: ```json { "hooks": { "SessionStart": [ { "command": "/path/to/amc/bin/amc-hook" } ], "UserPromptSubmit": [ { "command": "/path/to/amc/bin/amc-hook" } ], "Stop": [ { "command": "/path/to/amc/bin/amc-hook" } ], "SessionEnd": [ { "command": "/path/to/amc/bin/amc-hook" } ], "PreToolUse": [ { "matcher": "AskUserQuestion", "command": "/path/to/amc/bin/amc-hook" } ], "PostToolUse": [ { "matcher": "AskUserQuestion", "command": "/path/to/amc/bin/amc-hook" } ] } } ``` ## Architecture ``` ┌─────────────────────┐ ┌─────────────────────┐ │ Claude Code │────▶│ amc-hook │ │ (hooks) │ │ (writes state) │ └─────────────────────┘ └──────────┬──────────┘ │ ▼ ┌─────────────────────┐ │ ~/.local/share/ │ │ amc/sessions/ │ │ amc/events/ │ └──────────┬──────────┘ │ ▼ ┌─────────────────────┐ ┌─────────────────────┐ │ Dashboard │◀────│ amc-server │ │ (Preact UI) │ │ (Python HTTP) │ └─────────────────────┘ └─────────────────────┘ ``` ### Components | Component | Description | |-----------|-------------| | `bin/amc` | Launcher script — start/stop/status commands | | `bin/amc-server` | Python HTTP server serving the API and dashboard | | `bin/amc-hook` | Hook script called by Claude Code to write session state | | `dashboard/` | Modular Preact dashboard (index.html, components/, lib/, utils/) | ### Data Storage All runtime data lives in `~/.local/share/amc/`: | Path | Contents | |------|----------| | `sessions/*.json` | Current session state (one file per session) | | `events/*.jsonl` | Event log for each session (append-only) | | `server.pid` | PID file for the running server | | `server.log` | Server stdout/stderr | ## API Reference | Method | Endpoint | Description | |--------|----------|-------------| | GET | `/` | Dashboard HTML | | GET | `/api/state` | All sessions as JSON | | GET | `/api/events/{id}` | Event timeline for a session | | GET | `/api/conversation/{id}?project_dir=...` | Conversation history (from Claude Code logs) | | POST | `/api/dismiss/{id}` | Dismiss (delete) a completed session | | POST | `/api/respond/{id}` | Send a response to a session | ### Response Injection The `/api/respond/{id}` endpoint injects text into a session's Zellij pane. Request body: ```json { "text": "your response here", "freeform": true, "optionCount": 3 } ``` - `text` — The response to send - `freeform` — If true, treats as freeform text (selects "Other" option first) - `optionCount` — Number of options in the current question (used for freeform) Response injection works via: 1. **Zellij plugin** (`~/.config/zellij/plugins/zellij-send-keys.wasm`) — Required for pane-targeted sends and Enter submission 2. **Optional unsafe fallback** (`AMC_ALLOW_UNSAFE_WRITE_CHARS_FALLBACK=1`) — Uses focused-pane `write-chars` only when explicitly enabled AMC resolves the Zellij binary from PATH plus common Homebrew locations (`/opt/homebrew/bin/zellij`, `/usr/local/bin/zellij`) so response injection still works when started via `launchctl`. ## Session Statuses | Status | Meaning | |--------|---------| | `starting` | Session started, no prompt submitted yet | | `active` | Session is processing work | | `needs_attention` | Agent is waiting for user input (question or AskUserQuestion) | | `done` | Session stopped (can be dismissed) | ## Cleanup Behavior - **Orphan sessions**: Sessions with missing Zellij sessions in "starting" status are auto-deleted - **Stale "starting" sessions**: Sessions stuck in "starting" for >1 hour are removed - **Stale event logs**: Event logs without matching sessions are deleted after 24 hours - **SessionEnd**: Deletes the session file immediately ## Requirements - Python 3.8+ - Zellij (for response injection) - Claude Code with hooks support ## Testing Run the server test suite: ```bash python3 -m unittest discover -s tests -v ``` ## Zellij Plugin For pane-targeted response injection (including reliable Enter submission), install the `zellij-send-keys` plugin: ```bash # Build and install the plugin # (See zellij-send-keys repository for instructions) ``` Place the compiled WASM at `~/.config/zellij/plugins/zellij-send-keys.wasm`. ## License MIT