Node.js server + realtime web dashboard for Claude Code project statuses.
npm startOpen:
POST:
Content-Type:
application/json
Body:
{
"status": "green",
"project": "my-project"
}Allowed status values:
- red
- yellow
- green
A new project automatically gets a new traffic-light card.
The dashboard updates immediately using Server-Sent Events (SSE). No manual refresh is required.
Invoke-RestMethod `
-Uri "http://127.0.0.1:8765/status" `
-Method POST `
-ContentType "application/json" `
-Body '{"status":"green","project":"my-project"}'Try:
Invoke-RestMethod -Uri "http://127.0.0.1:8765/status" -Method POST -ContentType "application/json" -Body '{"status":"yellow","project":"my-project"}'
Invoke-RestMethod -Uri "http://127.0.0.1:8765/status" -Method POST -ContentType "application/json" -Body '{"status":"red","project":"another-project"}'Then open the dashboard in a browser. The cards change instantly.
GET /— dashboardPOST /status— update a projectPOST /claude-event— current state as JSONGET /events— realtime SSE streamGET /health— health check
State is currently held in memory and is lost when the server restarts.
Add similar structure to <PROJECT>/.claude/settings.json:
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "http",
"url": "http://127.0.0.1:8765/claude-event"
}
]
}
],
"PreToolUse": [
{
"matcher": "*",
"hooks": [
{
"type": "http",
"url": "http://127.0.0.1:8765/claude-event"
}
]
}
],
"PermissionRequest": [
{
"matcher": "*",
"hooks": [
{
"type": "http",
"url": "http://127.0.0.1:8765/claude-event"
}
]
}
],
"PostToolUse": [
{
"matcher": "*",
"hooks": [
{
"type": "http",
"url": "http://127.0.0.1:8765/claude-event"
}
]
}
],
"PostToolUseFailure": [
{
"matcher": "*",
"hooks": [
{
"type": "http",
"url": "http://127.0.0.1:8765/claude-event"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "http",
"url": "http://127.0.0.1:8765/claude-event"
}
]
}
],
"StopFailure": [
{
"matcher": "*",
"hooks": [
{
"type": "http",
"url": "http://127.0.0.1:8765/claude-event"
}
]
}
]
}
}