Purpose: Documentation for the GSD Monitor system, a lightweight event-driven monitoring and alert system for the Claude Code GSD extension.
GSD Monitor enhances the Get Shit Done (GSD) Claude Code extension by providing:
- Real-time session status tracking across multiple concurrent sessions
- Web-based monitoring dashboard accessible from any device on your network
- Audio and browser alerts when Claude needs user input
- Two-step notification system - yellow warning at 60s idle, red alert when input required
- GSD project integration - shows current phase and plan progress
- Cross-platform support (Windows, macOS, Linux)
The system operates by injecting hooks into Claude Code's hook system, capturing events, updating a shared state file, and serving a web dashboard with real-time updates via WebSocket.
gsd-monitor/
├── injector.py # Installation & configuration manager
├── hooks/
│ ├── on_notification.py # Handles idle_prompt & permission_prompt events
│ ├── on_session_start.py # Handles session lifecycle events
│ ├── on_tool_use.py # Tracks tool execution in real-time
│ ├── on_stop.py # Handles completion events
│ └── state_utils.py # Shared state file utilities
├── gsd-monitor-web/
│ ├── run.py # CLI entry point with QR code display
│ ├── server.py # FastAPI server with WebSocket
│ ├── state_manager.py # Session CRUD and cleanup
│ ├── gsd_reader.py # GSD project state parser
│ ├── requirements.txt # Python dependencies
│ └── static/
│ ├── index.html # Web UI
│ ├── app.js # Frontend JavaScript
│ └── style.css # Mobile-first responsive CSS
├── requirements.txt
└── README.md
Installed Location: ~/.claude/gsd-monitor/
State File: ~/.claude/gsd-monitor/state.json
The installation manager responsible for:
- Deploying hook scripts to
~/.claude/gsd-monitor/hooks/ - Merging hooks into Claude Code's
settings.json - Creating backups before modifications
- Clean removal of injected hooks
Commands:
| Command | Description |
|---|---|
python injector.py inject |
Install hooks globally |
python injector.py inject --local |
Install to current project only |
python injector.py remove |
Remove all GSD Monitor hooks |
python injector.py status |
Check installation status |
Key Design Decisions:
- Uses
"_marker": "__gsd_monitor__"to identify injected hooks for safe removal - Appends hooks (never replaces existing hooks)
- Creates timestamped backups before any modification
- Auto-detects Python executable per platform
Triggers: idle_prompt, permission_prompt notifications
Actions:
- Determines notification urgency (NEEDS_INPUT vs NEEDS_PERMISSION)
- Updates state.json with current status (alerts handled by web UI)
Triggers: PreToolUse event (before each tool execution)
Actions:
- Generates human-readable activity descriptions
- Updates state with tool name and activity
Activity Description Examples:
- Task:
"Subagent: Fix authentication bug" - Bash:
"$ git status" - Write:
"Writing: src/index.ts" - Grep:
"Searching: TODO"
Triggers: SessionStart event
Actions:
- Records session initialization
- Distinguishes startup, resume, and context clear
- Sets
started_attimestamp
Triggers: Stop event
Actions:
- Marks Claude's response as complete
- Preserves
started_atfor duration tracking - Sets status to STOPPED
A real-time web dashboard providing:
- Session picker - view all active Claude Code sessions
- Live status updates via WebSocket
- Two-step notifications - yellow warning (STOPPED), red alert (NEEDS_INPUT)
- Browser notifications - native desktop alerts when input needed
- Audio alerts - two-tone doorbell sound via Web Audio API
- GSD integration - shows current phase and plan progress
- Mobile support - responsive design with QR code for phone access
- Auto-follow - tracks sessions across
/clearoperations
Usage:
cd gsd-monitor-web
pip install -r requirements.txt
python run.py # Start server on port 8765
python run.py --port 9000 # Custom port
python run.py --no-qr # Disable QR code display┌─────────────┐ Event ┌─────────────┐ Stdin JSON ┌─────────────┐
│ Claude Code │ ─────────────▶│ Hook System │ ─────────────────▶│ Hook Script │
└─────────────┘ └─────────────┘ └──────┬──────┘
│
│ Updates
▼
┌─────────────┐ Reads ┌─────────────┐
│ Web Monitor │ ◀────────────│ state.json │
│ (Browser) │ └─────────────┘
└─────────────┘
Complete Session Lifecycle:
- SessionStart → Status:
STARTED, recordsstarted_at - PreToolUse (repeated) → Status:
RUNNING, updates tool activity - Notification (if idle 60s) → Status:
NEEDS_INPUTorNEEDS_PERMISSION - Stop → Status:
STOPPED, preserves timestamps
Location: ~/.claude/gsd-monitor/state.json
{
"session-id-abc123": {
"status": "NEEDS_INPUT",
"message": "Claude is waiting for your input",
"updated_at": "2026-01-25T14:32:15.123456",
"started_at": "2026-01-25T14:30:00.000000",
"project": "my-project",
"cwd": "/home/user/projects/my-project",
"tool": "AskUserQuestion",
"transcript_path": "/path/to/transcript.json"
}
}Status Values:
| Status | Meaning | Web UI Color |
|---|---|---|
STARTED |
Session just initialized | Blue |
RUNNING |
Claude actively executing tools | Green |
STOPPED |
Waiting for next prompt | Yellow (warning) |
NEEDS_INPUT |
Claude waiting for user input | Red (alert) |
NEEDS_PERMISSION |
Permission required | Red (alert) |
NOTIFICATION |
Generic notification | White |
Hooks are injected into Claude Code's settings.json:
{
"hooks": {
"Notification": [
{
"matcher": "idle_prompt|permission_prompt",
"hooks": [{ "type": "command", "command": "python ~/.claude/gsd-monitor/hooks/on_notification.py" }],
"_marker": "__gsd_monitor__"
}
],
"PreToolUse": [
{
"hooks": [{ "type": "command", "command": "python ~/.claude/gsd-monitor/hooks/on_tool_use.py" }],
"_marker": "__gsd_monitor__"
}
],
"Stop": [
{
"hooks": [{ "type": "command", "command": "python ~/.claude/gsd-monitor/hooks/on_stop.py" }],
"_marker": "__gsd_monitor__"
}
],
"SessionStart": [
{
"hooks": [{ "type": "command", "command": "python ~/.claude/gsd-monitor/hooks/on_session_start.py" }],
"_marker": "__gsd_monitor__"
}
]
}
}Hook scripts (standard library only):
json,pathlib,datetime,sys
Web monitor (pip install):
fastapi- Web frameworkuvicorn- ASGI serverwatchfiles- File change detectionqrcode- QR code generation for mobile access
- All hooks catch exceptions silently to avoid breaking Claude Code
- JSON parse errors result in graceful exit
- State file I/O wrapped in try/except
| Setting | Location | How to Modify |
|---|---|---|
| Web server port | gsd-monitor-web/run.py |
Use --port argument |
| Disable QR code | gsd-monitor-web/run.py |
Use --no-qr argument |
| State file location | hooks/state_utils.py |
Edit STATE_FILE constant |
-
60-second alert delay - Relies on Claude Code's
idle_promptnotification which fires after 60s idle. The web UI mitigates this with a yellow warning state when STOPPED. -
Single state file - All sessions share one file; potential for race conditions with many concurrent sessions (mitigated by atomic writes in state_utils.py).
- Non-invasive: Hooks append, never replace existing hooks
- Clean removal: Marker-based identification enables complete uninstall
- No privilege escalation: Runs entirely in user context
- Trusted input: Only processes JSON from Claude Code via stdin
- No eval(): Uses
json.loads()for safe parsing
# Install hooks
cd gsd-monitor
python injector.py inject
# Start web monitor
cd gsd-monitor-web
pip install -r requirements.txt
python run.py
# Uninstall hooks
python injector.py removeLast Updated: 2026-01-25