Add _is_system_injected() filter to conversation.py that drops user
messages starting with known system-injected prefixes. These messages
(hook outputs, system reminders, teammate notifications) appear in
JSONL session logs as type: "user" with string content but are not
human-typed input.
Filtered prefixes:
- <system-reminder> — Claude Code system context injection
- <local-command-caveat> — local command hook output
- <available-deferred-tools> — deferred tool discovery messages
- <teammate-message — team agent message delivery (no closing >
because tag has attributes)
This brings Claude parsing to parity with the Codex parser, which
already filters system-injected content via SKIP_PREFIXES (line 222).
The filter uses str.startswith(tuple) with lstrip() to handle leading
whitespace. Applied at line 75 in the existing content-type guard chain.
Affects both chat display and input history navigation — system noise
is removed at the source so all consumers benefit.
tests/test_conversation.py:
- TestIsSystemInjected: 10 unit tests for the filter function covering
each prefix, leading whitespace, normal messages, mid-string tags,
empty strings, slash commands, and multiline content
- TestClaudeSystemInjectedFiltering: 5 integration tests through the
full parser verifying exclusion, sequential ID preservation after
filtering, and all-system-message edge case
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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
AskUserQuestionprompts and prose questions (messages ending with "?") - Session lifecycle — Automatically cleans up orphaned sessions and stale event logs
Installation
- Clone this repository
- Symlink the launcher to your PATH:
ln -s /path/to/amc/bin/amc ~/.local/bin/amc
- Configure Claude Code hooks (see Hook Setup)
Usage
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:
{
"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:
{
"text": "your response here",
"freeform": true,
"optionCount": 3
}
text— The response to sendfreeform— 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:
- Zellij plugin (
~/.config/zellij/plugins/zellij-send-keys.wasm) — Required for pane-targeted sends and Enter submission - Optional unsafe fallback (
AMC_ALLOW_UNSAFE_WRITE_CHARS_FALLBACK=1) — Uses focused-panewrite-charsonly 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:
python3 -m unittest discover -s tests -v
Zellij Plugin
For pane-targeted response injection (including reliable Enter submission), install the zellij-send-keys plugin:
# 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