refactor: finish the AgentHub rename and drop the MCP server
Two leftovers from the rebrand, done together because they touch the same docs and manifests. **Data directory.** `agent-dashboard` could not simply be renamed in the source: it names a real directory holding the live SQLite database. Startup now moves it once, via `migrateLegacyDataDir()` in `server/lib/claude-home.js` — a same-filesystem rename, so it is instant even at multiple gigabytes and cannot leave two divergent copies. `getDataDir()` stays PURE and resolves to the legacy path until the move happens; the first version of this put the rename inside the getter, which meant `npm run test:server` relocated the developer's real database as a side effect. The call sits behind `require.main === module` and ahead of the router requires, because those pull in db.js, which opens SQLite at module load. A failed rename is silent and the old directory keeps being used: an unfashionable directory name beats a blank database beside an unreachable one. Same treatment for the port-discovery file (`.agent-dashboard.json` → `.agenthub.json`, old one dropped on write). Not renamed on purpose: the Sagi localStorage keys (renaming silently resets everyone's prefs) and the PWA manifest `id` (changing it orphans an installed app). **MCP server.** 4 tool calls in 46 days across 577,132 events, against 4,556 lines of TypeScript, a 2 MB committed build artifact, and a pre-commit guard that had already blocked commits twice. Deleted: `mcp/`, the maintainer skills and `mcp-reviewer` agent, the build check, `plugins/agenthub/.mcp.json`, `docs/MCP.md`, 12 npm scripts, 5 Makefile targets, and every doc section describing it. Kept, because they are unrelated things sharing the name: the Config Explorer's MCP tab and its API, per-lane Playwright MCP, the agenthub-config plugin's MCP audit, and the historical `mcp__plugin_agenthub_*` events that analytics must keep attributing. Verified: server 1432/1432, client 459/459, tsc clean, prettier clean. Both directions of the migration proven — a sandbox-HOME test run leaves the legacy directory untouched, and a real boot moves it with its contents intact.
This commit is contained in:
+2
-2
@@ -40,7 +40,7 @@ agenthub <command> [options]
|
||||
flowchart LR
|
||||
U["Terminal\nagenthub <command>"] --> CLI["bin/agenthub.js\n(zero dependencies)"]
|
||||
CLI -->|"env override"| ENV["CLAUDE_DASHBOARD_PORT /\nDASHBOARD_PORT"]
|
||||
CLI -->|"else discovery"| REG["~/.claude/.agent-dashboard.json\n(PID-liveness-checked)"]
|
||||
CLI -->|"else discovery"| REG["~/.claude/.agenthub.json\n(PID-liveness-checked)"]
|
||||
CLI -->|"else fallback"| DEF["http://127.0.0.1:4820"]
|
||||
ENV --> API["Dashboard REST API"]
|
||||
REG --> API
|
||||
@@ -76,7 +76,7 @@ The CLI finds your running dashboard the same way the Claude Code hook handler d
|
||||
| Priority | Source | Notes |
|
||||
| -------- | ------ | ----- |
|
||||
| 1 | `CLAUDE_DASHBOARD_PORT` / `DASHBOARD_PORT` env vars | Explicit override wins |
|
||||
| 2 | `~/.claude/.agent-dashboard.json` | Written by every running dashboard (`{port, pid, startedAt}` entries); stale entries are skipped via a PID liveness check |
|
||||
| 2 | `~/.claude/.agenthub.json` | Written by every running dashboard (`{port, pid, startedAt}` entries); stale entries are skipped via a PID liveness check |
|
||||
| 3 | `http://127.0.0.1:4820` | Default port fallback |
|
||||
|
||||
If no server answers, every API-backed command exits `1` with the `○ Dashboard server is NOT running` indicator and the ways to start one (see [Server Lifecycle](#server-lifecycle)).
|
||||
|
||||
+5
-4
@@ -64,9 +64,10 @@ graph TB
|
||||
```
|
||||
|
||||
**Database Location:**
|
||||
- **Canonical (default):** `~/.claude/agent-dashboard/dashboard.db` — shared by `npm start`, `npm run dev`, Docker (bind mount), and the desktop app when it uses the same data dir
|
||||
- **Canonical (default):** `~/.claude/agenthub/dashboard.db` — shared by `npm start`, `npm run dev`, Docker (bind mount), and the desktop app when it uses the same data dir
|
||||
- **Override:** set `DASHBOARD_DATA_DIR` (directory) or `DASHBOARD_DB_PATH` (file path) for tests or custom deployments
|
||||
- **Legacy:** repo-local `./data/dashboard.db` is migrated into the canonical location on first launch (see `server/db.js`)
|
||||
- **Pre-rebrand:** an install that predates AgentHub keeps its data in `~/.claude/agent-dashboard/`. Server startup renames that directory to `~/.claude/agenthub/` once, before anything opens the database (`migrateLegacyDataDir()` in `server/lib/claude-home.js`). It is a same-filesystem rename, so it is instant even at multiple gigabytes and never leaves two copies. If the rename fails, or `DASHBOARD_DATA_DIR` is set, nothing moves and the old directory keeps being used.
|
||||
|
||||
---
|
||||
|
||||
@@ -813,13 +814,13 @@ VACUUM INTO '/backups/dashboard_20240318.db';
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Stop application
|
||||
systemctl stop agent-dashboard
|
||||
systemctl stop agenthub
|
||||
|
||||
# Copy database file
|
||||
cp /var/lib/agent-dashboard/dashboard.db /backups/dashboard_$(date +%Y%m%d).db
|
||||
cp /var/lib/agenthub/dashboard.db /backups/dashboard_$(date +%Y%m%d).db
|
||||
|
||||
# Start application
|
||||
systemctl start agent-dashboard
|
||||
systemctl start agenthub
|
||||
```
|
||||
|
||||
### Backup Schedule
|
||||
|
||||
+43
-44
@@ -149,8 +149,8 @@ graph TB
|
||||
|
||||
```bash
|
||||
# Clone repository
|
||||
git clone https://github.com/your-org/agent-dashboard.git
|
||||
cd agent-dashboard
|
||||
git clone https://github.com/your-org/agenthub.git
|
||||
cd agenthub
|
||||
|
||||
# Install dependencies
|
||||
npm run setup
|
||||
@@ -190,7 +190,6 @@ npm run dev:server
|
||||
npm run dev:client
|
||||
|
||||
# Terminal 3: MCP server (optional)
|
||||
npm run mcp:dev
|
||||
```
|
||||
|
||||
---
|
||||
@@ -225,10 +224,10 @@ npm run build
|
||||
# 3. Set environment variables
|
||||
export NODE_ENV=production
|
||||
export PORT=4820
|
||||
export DASHBOARD_DB_PATH=/var/lib/agent-dashboard/dashboard.db
|
||||
export DASHBOARD_DB_PATH=/var/lib/agenthub/dashboard.db
|
||||
|
||||
# 4. Create data directory
|
||||
mkdir -p /var/lib/agent-dashboard
|
||||
mkdir -p /var/lib/agenthub
|
||||
|
||||
# 5. Start server
|
||||
node server/index.js
|
||||
@@ -250,7 +249,7 @@ DASHBOARD_TOKEN= # required on /api/* + WS when set; use
|
||||
DASHBOARD_ALLOWED_HOSTS= # extra Host names (comma-sep) for a LAN bind
|
||||
|
||||
# Database
|
||||
DASHBOARD_DB_PATH=/var/lib/agent-dashboard/dashboard.db
|
||||
DASHBOARD_DB_PATH=/var/lib/agenthub/dashboard.db
|
||||
|
||||
# Ingestion polls (0 disables either one)
|
||||
DASHBOARD_WORKFLOW_POLL_MS=12000 # Workflow-tool run journals
|
||||
@@ -278,7 +277,7 @@ LOG_LEVEL=info # debug | info | warn | error
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
agent-dashboard:
|
||||
agenthub:
|
||||
build: .
|
||||
ports:
|
||||
- "4820:4820"
|
||||
@@ -382,7 +381,7 @@ graph TB
|
||||
pip install awsebcli
|
||||
|
||||
# Initialize
|
||||
eb init -p node.js agent-dashboard
|
||||
eb init -p node.js agenthub
|
||||
|
||||
# Create environment
|
||||
eb create production
|
||||
@@ -401,20 +400,20 @@ eb open
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: agent-dashboard
|
||||
name: agenthub
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: agent-dashboard
|
||||
app: agenthub
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: agent-dashboard
|
||||
app: agenthub
|
||||
spec:
|
||||
containers:
|
||||
- name: agent-dashboard
|
||||
image: agent-dashboard:latest
|
||||
- name: agenthub
|
||||
image: agenthub:latest
|
||||
ports:
|
||||
- containerPort: 4820
|
||||
env:
|
||||
@@ -426,16 +425,16 @@ spec:
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: agent-dashboard-pvc
|
||||
claimName: agenthub-pvc
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: agent-dashboard
|
||||
name: agenthub
|
||||
spec:
|
||||
selector:
|
||||
app: agent-dashboard
|
||||
app: agenthub
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
@@ -453,9 +452,9 @@ graph TB
|
||||
end
|
||||
|
||||
subgraph "Pods"
|
||||
Pod1[agent-dashboard-1<br/>:4820]
|
||||
Pod2[agent-dashboard-2<br/>:4820]
|
||||
Pod3[agent-dashboard-3<br/>:4820]
|
||||
Pod1[agenthub-1<br/>:4820]
|
||||
Pod2[agenthub-2<br/>:4820]
|
||||
Pod3[agenthub-3<br/>:4820]
|
||||
end
|
||||
|
||||
subgraph "Storage"
|
||||
@@ -488,22 +487,22 @@ graph TB
|
||||
npm install -g pm2
|
||||
|
||||
# Start application
|
||||
pm2 start server/index.js --name agent-dashboard
|
||||
pm2 start server/index.js --name agenthub
|
||||
|
||||
# Start with environment
|
||||
pm2 start server/index.js --name agent-dashboard --env production
|
||||
pm2 start server/index.js --name agenthub --env production
|
||||
|
||||
# View logs
|
||||
pm2 logs agent-dashboard
|
||||
pm2 logs agenthub
|
||||
|
||||
# Monitor
|
||||
pm2 monit
|
||||
|
||||
# Restart
|
||||
pm2 restart agent-dashboard
|
||||
pm2 restart agenthub
|
||||
|
||||
# Stop
|
||||
pm2 stop agent-dashboard
|
||||
pm2 stop agenthub
|
||||
|
||||
# Auto-start on system boot
|
||||
pm2 startup
|
||||
@@ -516,7 +515,7 @@ pm2 save
|
||||
// ecosystem.config.js
|
||||
module.exports = {
|
||||
apps: [{
|
||||
name: 'agent-dashboard',
|
||||
name: 'agenthub',
|
||||
script: './server/index.js',
|
||||
instances: 2,
|
||||
exec_mode: 'cluster',
|
||||
@@ -527,11 +526,11 @@ module.exports = {
|
||||
env_production: {
|
||||
NODE_ENV: 'production',
|
||||
PORT: 4820,
|
||||
DASHBOARD_DB_PATH: '/var/lib/agent-dashboard/dashboard.db'
|
||||
DASHBOARD_DB_PATH: '/var/lib/agenthub/dashboard.db'
|
||||
},
|
||||
max_memory_restart: '500M',
|
||||
error_file: '/var/log/agent-dashboard/error.log',
|
||||
out_file: '/var/log/agent-dashboard/out.log',
|
||||
error_file: '/var/log/agenthub/error.log',
|
||||
out_file: '/var/log/agenthub/out.log',
|
||||
time: true
|
||||
}]
|
||||
};
|
||||
@@ -545,18 +544,18 @@ pm2 start ecosystem.config.js --env production
|
||||
### Systemd Service (Linux)
|
||||
|
||||
```ini
|
||||
# /etc/systemd/system/agent-dashboard.service
|
||||
# /etc/systemd/system/agenthub.service
|
||||
[Unit]
|
||||
Description=Agent Dashboard
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=agent-dashboard
|
||||
WorkingDirectory=/opt/agent-dashboard
|
||||
User=agenthub
|
||||
WorkingDirectory=/opt/agenthub
|
||||
Environment=NODE_ENV=production
|
||||
Environment=PORT=4820
|
||||
Environment=DASHBOARD_DB_PATH=/var/lib/agent-dashboard/dashboard.db
|
||||
Environment=DASHBOARD_DB_PATH=/var/lib/agenthub/dashboard.db
|
||||
ExecStart=/usr/bin/node server/index.js
|
||||
Restart=on-failure
|
||||
RestartSec=10
|
||||
@@ -569,14 +568,14 @@ WantedBy=multi-user.target
|
||||
|
||||
```bash
|
||||
# Enable and start service
|
||||
sudo systemctl enable agent-dashboard
|
||||
sudo systemctl start agent-dashboard
|
||||
sudo systemctl enable agenthub
|
||||
sudo systemctl start agenthub
|
||||
|
||||
# Check status
|
||||
sudo systemctl status agent-dashboard
|
||||
sudo systemctl status agenthub
|
||||
|
||||
# View logs
|
||||
sudo journalctl -u agent-dashboard -f
|
||||
sudo journalctl -u agenthub -f
|
||||
```
|
||||
|
||||
---
|
||||
@@ -680,8 +679,8 @@ graph TB
|
||||
#!/bin/bash
|
||||
# scripts/backup.sh
|
||||
|
||||
BACKUP_DIR="/var/backups/agent-dashboard"
|
||||
DB_PATH="/var/lib/agent-dashboard/dashboard.db"
|
||||
BACKUP_DIR="/var/backups/agenthub"
|
||||
DB_PATH="/var/lib/agenthub/dashboard.db"
|
||||
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
||||
BACKUP_FILE="$BACKUP_DIR/dashboard_$TIMESTAMP.db"
|
||||
|
||||
@@ -695,7 +694,7 @@ sqlite3 "$DB_PATH" "VACUUM INTO '$BACKUP_FILE'"
|
||||
gzip "$BACKUP_FILE"
|
||||
|
||||
# Upload to S3 (optional)
|
||||
aws s3 cp "$BACKUP_FILE.gz" s3://my-backups/agent-dashboard/
|
||||
aws s3 cp "$BACKUP_FILE.gz" s3://my-backups/agenthub/
|
||||
|
||||
# Delete old backups (keep last 7 days)
|
||||
find "$BACKUP_DIR" -name "dashboard_*.db.gz" -mtime +7 -delete
|
||||
@@ -710,7 +709,7 @@ echo "Backup completed: $BACKUP_FILE.gz"
|
||||
# scripts/restore.sh
|
||||
|
||||
BACKUP_FILE=$1
|
||||
DB_PATH="/var/lib/agent-dashboard/dashboard.db"
|
||||
DB_PATH="/var/lib/agenthub/dashboard.db"
|
||||
|
||||
if [ -z "$BACKUP_FILE" ]; then
|
||||
echo "Usage: ./restore.sh <backup_file.db.gz>"
|
||||
@@ -718,17 +717,17 @@ if [ -z "$BACKUP_FILE" ]; then
|
||||
fi
|
||||
|
||||
# Stop application
|
||||
systemctl stop agent-dashboard
|
||||
systemctl stop agenthub
|
||||
|
||||
# Decompress backup
|
||||
gunzip -c "$BACKUP_FILE" > /tmp/restore.db
|
||||
|
||||
# Restore database
|
||||
cp /tmp/restore.db "$DB_PATH"
|
||||
chown agent-dashboard:agent-dashboard "$DB_PATH"
|
||||
chown agenthub:agenthub "$DB_PATH"
|
||||
|
||||
# Start application
|
||||
systemctl start agent-dashboard
|
||||
systemctl start agenthub
|
||||
|
||||
echo "Restore completed from $BACKUP_FILE"
|
||||
```
|
||||
@@ -767,7 +766,7 @@ graph TB
|
||||
### TLS Configuration (Nginx Reverse Proxy)
|
||||
|
||||
```nginx
|
||||
# /etc/nginx/sites-available/agent-dashboard
|
||||
# /etc/nginx/sites-available/agenthub
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name dashboard.example.com;
|
||||
|
||||
+2
-2
@@ -573,13 +573,13 @@ function sendToServer(hookType, payload) {
|
||||
> 1. If `CLAUDE_DASHBOARD_PORT` is set in the environment, the handler treats
|
||||
> it as an explicit operator override and POSTs to that single port —
|
||||
> no discovery, no fan-out (useful for tests and container setups).
|
||||
> 2. Otherwise it reads `~/.claude/.agent-dashboard.json`, a JSON document
|
||||
> 2. Otherwise it reads `~/.claude/.agenthub.json`, a JSON document
|
||||
> that lists every dashboard server currently running on the machine.
|
||||
> Each server appends its `{port, pid, startedAt, dataDir}` entry on
|
||||
> startup and removes it on a clean shutdown. The handler **prunes any
|
||||
> entry whose PID is no longer alive** and POSTs the hook payload to one
|
||||
> port per **unique SQLite data directory** (lowest port wins when Docker
|
||||
> and `npm run dev` share `~/.claude/agent-dashboard`).
|
||||
> and `npm run dev` share `~/.claude/agenthub`).
|
||||
> 3. If neither yields a target, the handler falls back to `4820`.
|
||||
>
|
||||
> Dashboards with **different** databases (e.g. the packaged desktop app using
|
||||
|
||||
+1
-1
@@ -1370,7 +1370,7 @@ The lane card shows a lock badge when the lane **holds** a named lock (its `lane
|
||||
|
||||
The **ship-feature-lane** skill is the ported Shipyard driving skill for autonomous end-to-end feature pipelines in a single AgentHub lane. It coordinates the entire development flow: implementation (TDD) → independent unit tests → pre-push CI gates + dev preflight → e2e testing → code review → local QC → senior gate authorization → PR push and publication → CI watch → final report.
|
||||
|
||||
**Every stage whose job is to judge the work runs in a fresh-context subagent, never in the driving session.** The plan debate (Stage 0b), unit tests (Stage 1b), the e2e run and its triage (Stage 3), code review (Stage 4), browser QC (Stage 6), the senior gate (Stage 7), and a re-triage of CI that stayed red after a fix (Stage 10) are each dispatched with the Agent tool to a subagent that starts with an empty context and receives only artifacts it can verify itself — working directory, lane spec, diff range, commands, and the other agents' reports verbatim, never the driving session's paraphrase of why a finding was fine. The stages the driving session keeps are the ones that *do* rather than judge: intake, implementation, the mechanical gates, publishing, the CI/PR watch, and applying every fix the judges ask for. `subagent_type: fork` is explicitly forbidden for these: a fork inherits the implementing session's context, so it inherits the belief that the code is already correct. The driving session implements and applies fixes; it never grades its own work. Stages 1b/3 use the generic `general-purpose` type (nothing to install). Stage 4 uses the generic `Code Reviewer` type as its catch-all, plus — in parallel, routed by which of `server/`, `client/`, `mcp/` the diff touches — the plugin-qualified `agenthub:backend-reviewer` / `agenthub:frontend-reviewer` / `agenthub:mcp-reviewer` domain reviewers (nothing to install; `agenthub:` addressing works from any lane). Stages 6/7 use the lane-installed `qc-local`/`senior-gate-reviewer` agents.
|
||||
**Every stage whose job is to judge the work runs in a fresh-context subagent, never in the driving session.** The plan debate (Stage 0b), unit tests (Stage 1b), the e2e run and its triage (Stage 3), code review (Stage 4), browser QC (Stage 6), the senior gate (Stage 7), and a re-triage of CI that stayed red after a fix (Stage 10) are each dispatched with the Agent tool to a subagent that starts with an empty context and receives only artifacts it can verify itself — working directory, lane spec, diff range, commands, and the other agents' reports verbatim, never the driving session's paraphrase of why a finding was fine. The stages the driving session keeps are the ones that *do* rather than judge: intake, implementation, the mechanical gates, publishing, the CI/PR watch, and applying every fix the judges ask for. `subagent_type: fork` is explicitly forbidden for these: a fork inherits the implementing session's context, so it inherits the belief that the code is already correct. The driving session implements and applies fixes; it never grades its own work. Stages 1b/3 use the generic `general-purpose` type (nothing to install). Stage 4 uses the generic `Code Reviewer` type as its catch-all, plus — in parallel, routed by which of `server/`, `client/` the diff touches — the plugin-qualified `agenthub:backend-reviewer` / `agenthub:frontend-reviewer` domain reviewers (nothing to install; `agenthub:` addressing works from any lane). Stages 6/7 use the lane-installed `qc-local`/`senior-gate-reviewer` agents.
|
||||
|
||||
### Getting the skill (nothing to do, if you run the plugin)
|
||||
|
||||
|
||||
-855
@@ -1,855 +0,0 @@
|
||||
# MCP Integration Guide
|
||||
|
||||
Model Context Protocol (MCP) server integration for programmatic dashboard access.
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [MCP Architecture](#mcp-architecture)
|
||||
- [Setup & Installation](#setup--installation)
|
||||
- [Available Tools](#available-tools)
|
||||
- [Client Configuration](#client-configuration)
|
||||
- [Usage Examples](#usage-examples)
|
||||
- [Tool Reference](#tool-reference)
|
||||
- [Error Handling](#error-handling)
|
||||
- [Performance](#performance)
|
||||
- [Development](#development)
|
||||
- [Deployment](#deployment)
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
The Agent Dashboard MCP server exposes dashboard functionality as tools that can be used by Claude Desktop, Cline, and other MCP clients.
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "MCP Clients"
|
||||
Claude[Claude Desktop]
|
||||
Cline[Cline IDE]
|
||||
Custom[Custom MCP Client]
|
||||
end
|
||||
|
||||
subgraph "MCP Server"
|
||||
MCPServer[Agent Dashboard<br/>MCP Server]
|
||||
Tools[Tool Registry]
|
||||
end
|
||||
|
||||
subgraph "Dashboard API"
|
||||
API[Express API<br/>:4820]
|
||||
DB[(SQLite DB)]
|
||||
end
|
||||
|
||||
Claude -->|stdio| MCPServer
|
||||
Cline -->|stdio| MCPServer
|
||||
Custom -->|stdio| MCPServer
|
||||
|
||||
MCPServer --> Tools
|
||||
Tools -->|HTTP| API
|
||||
API --> DB
|
||||
|
||||
style MCPServer fill:#0f766e
|
||||
style API fill:#3B82F6
|
||||
style DB fill:#003B57,color:#fff
|
||||
```
|
||||
|
||||
**Key Benefits:**
|
||||
|
||||
- 🤖 **AI-Native** - Claude can query sessions, agents, and costs
|
||||
- 🔌 **Standardized** - Works with any MCP-compatible client
|
||||
- 🚀 **Easy Setup** - One-command installation
|
||||
- 🔒 **Local-First** - No cloud dependencies
|
||||
|
||||
---
|
||||
|
||||
## MCP Architecture
|
||||
|
||||
### MCP Protocol Flow
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as MCP Client<br/>(Claude Desktop)
|
||||
participant Server as MCP Server
|
||||
participant API as Dashboard API
|
||||
participant DB as SQLite
|
||||
|
||||
Client->>Server: Initialize connection
|
||||
Server-->>Client: Server info + capabilities
|
||||
|
||||
Client->>Server: List tools
|
||||
Server-->>Client: Tool definitions
|
||||
|
||||
Client->>Server: Call tool (get_sessions)
|
||||
Server->>API: GET /api/sessions
|
||||
API->>DB: Query sessions
|
||||
DB-->>API: Results
|
||||
API-->>Server: JSON response
|
||||
Server-->>Client: Tool result
|
||||
|
||||
Client->>Client: Process result
|
||||
```
|
||||
|
||||
### MCP Server Structure
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "MCP Server (mcp/)"
|
||||
Index[index.ts<br/>Entry point]
|
||||
Config[config/app-config.ts<br/>Configuration]
|
||||
Tools[tools/<br/>Tool implementations]
|
||||
Types[types.ts<br/>TypeScript types]
|
||||
end
|
||||
|
||||
subgraph "Tool Categories"
|
||||
Sessions[Session Tools<br/>get_sessions, get_session]
|
||||
Agents[Agent Tools<br/>get_agents, get_agent]
|
||||
Pricing[Pricing Tools<br/>get_pricing, create_rule]
|
||||
Stats[Stats Tools<br/>get_stats]
|
||||
end
|
||||
|
||||
Index --> Config
|
||||
Index --> Tools
|
||||
Tools --> Sessions
|
||||
Tools --> Agents
|
||||
Tools --> Pricing
|
||||
Tools --> Stats
|
||||
|
||||
style Index fill:#0f766e
|
||||
style Tools fill:#10B981
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Setup & Installation
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Node.js >= 18.0.0
|
||||
- Dashboard server running on `localhost:4820`
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
# Install MCP server dependencies
|
||||
npm run mcp:install
|
||||
|
||||
# Build MCP server (also stamps mcp/build/.srchash)
|
||||
npm run mcp:build
|
||||
|
||||
# Test MCP server
|
||||
npm run mcp:start
|
||||
```
|
||||
|
||||
Installing the `agenthub` plugin needs none of this: it ships the built server and
|
||||
wires it up itself (see [PLUGINS.md](PLUGINS.md)).
|
||||
|
||||
### Why `mcp/build/` is committed
|
||||
|
||||
Claude Code starts a plugin's MCP servers the moment a session opens and offers
|
||||
no "not ready yet, retry" state, so an async bootstrap cannot win that race. The
|
||||
build artifact is therefore committed, and `plugins/agenthub/.mcp.json` points at
|
||||
`${CLAUDE_PLUGIN_ROOT}/mcp/build/index.js`.
|
||||
|
||||
`npm run mcp:build` bundles `mcp/src` and its runtime dependencies
|
||||
(`esbuild --bundle`) into that single `build/index.js` file — the plugin cache
|
||||
never gets an `npm install` for `mcp/`, so a build that still had bare
|
||||
`node_modules` imports (plain `tsc` output) would throw `MODULE_NOT_FOUND` the
|
||||
instant Claude Code spawned it after any plugin install or update. `express`
|
||||
(only used by `--transport=http`, never by the stdio mode a real MCP host
|
||||
uses) is pulled in lazily via `await import(...)` in `src/index.ts` instead of
|
||||
a static import, so the stdio path never even evaluates it.
|
||||
|
||||
The cost is drift, so freshness is enforced by content hash — `mcp/src` plus the
|
||||
MCP manifests and tsconfig are hashed into `mcp/build/.srchash`:
|
||||
|
||||
```bash
|
||||
npm run mcp:check-build # fails when mcp/build is stale or unstamped
|
||||
```
|
||||
|
||||
`npm run mcp:build` re-stamps it, the pre-commit hook runs the check whenever
|
||||
`mcp/src` is part of the commit, and `/agenthub-doctor` reports it. Modification
|
||||
times are deliberately not used: a fresh clone stamps every file at checkout
|
||||
time in arbitrary order.
|
||||
|
||||
### Directory Structure
|
||||
|
||||
```
|
||||
mcp/
|
||||
├── src/
|
||||
│ ├── index.ts # MCP server entry point
|
||||
│ ├── config/
|
||||
│ │ └── app-config.ts # Configuration + validation
|
||||
│ ├── tools/
|
||||
│ │ ├── sessions.ts # Session-related tools
|
||||
│ │ ├── agents.ts # Agent-related tools
|
||||
│ │ ├── pricing.ts # Pricing management tools
|
||||
│ │ └── stats.ts # Statistics tools
|
||||
│ └── types.ts # TypeScript type definitions
|
||||
│
|
||||
├── build/ # Bundled, dependency-free output (COMMITTED — see above)
|
||||
│ ├── index.js # single esbuild bundle, no node_modules needed to run it
|
||||
│ └── .srchash # hash of mcp/src the build was produced from
|
||||
├── package.json
|
||||
├── tsconfig.json
|
||||
└── README.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Available Tools
|
||||
|
||||
### Tool Catalog
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "Session Management"
|
||||
GetSessions[get_sessions<br/>List all sessions]
|
||||
GetSession[get_session<br/>Get session details]
|
||||
end
|
||||
|
||||
subgraph "Agent Management"
|
||||
GetAgents[get_agents<br/>List session agents]
|
||||
GetAgent[get_agent<br/>Get agent details]
|
||||
GetTools[get_tools<br/>List agent tools]
|
||||
end
|
||||
|
||||
subgraph "Pricing"
|
||||
GetPricing[get_pricing<br/>List pricing rules]
|
||||
CreateRule[create_pricing_rule<br/>Add custom rule]
|
||||
DeleteRule[delete_pricing_rule<br/>Remove rule]
|
||||
end
|
||||
|
||||
subgraph "Statistics"
|
||||
GetStats[get_stats<br/>Dashboard statistics]
|
||||
end
|
||||
|
||||
style GetSessions fill:#3B82F6
|
||||
style GetAgents fill:#10B981
|
||||
style GetPricing fill:#F59E0B
|
||||
style GetStats fill:#8B5CF6
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Client Configuration
|
||||
|
||||
### Claude Desktop
|
||||
|
||||
Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS):
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"agent-dashboard": {
|
||||
"command": "node",
|
||||
"args": ["/path/to/agent-dashboard/mcp/dist/index.js"],
|
||||
"env": {
|
||||
"MCP_DASHBOARD_BASE_URL": "http://localhost:4820"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Linux:**
|
||||
```
|
||||
~/.config/Claude/claude_desktop_config.json
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
```
|
||||
%APPDATA%\Claude\claude_desktop_config.json
|
||||
```
|
||||
|
||||
### Cline (VS Code Extension)
|
||||
|
||||
Add to VS Code settings (`.vscode/settings.json`):
|
||||
|
||||
```json
|
||||
{
|
||||
"cline.mcpServers": {
|
||||
"agent-dashboard": {
|
||||
"command": "node",
|
||||
"args": ["/path/to/agent-dashboard/mcp/dist/index.js"],
|
||||
"env": {
|
||||
"MCP_DASHBOARD_BASE_URL": "http://localhost:4820"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `MCP_DASHBOARD_BASE_URL` | `http://localhost:4820` | Dashboard API base URL |
|
||||
|
||||
**URL Validation:**
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
URL[MCP_DASHBOARD_BASE_URL] --> Validate{Valid?}
|
||||
|
||||
Validate -->|Invalid Protocol| Error1[Throw: Only http/https allowed]
|
||||
Validate -->|Invalid Hostname| Error2[Throw: Only loopback allowed]
|
||||
Validate -->|Valid| Accept[Accept URL]
|
||||
|
||||
subgraph "Valid Hostnames"
|
||||
H1[127.0.0.1]
|
||||
H2[localhost]
|
||||
H3[::1]
|
||||
end
|
||||
|
||||
Accept --> H1 & H2 & H3
|
||||
|
||||
style Error1 fill:#EF4444
|
||||
style Error2 fill:#EF4444
|
||||
style Accept fill:#10B981
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Example 1: List Recent Sessions
|
||||
|
||||
**User Prompt:**
|
||||
> "Show me the 5 most recent Claude Code sessions"
|
||||
|
||||
**Tool Call:**
|
||||
```json
|
||||
{
|
||||
"name": "get_sessions",
|
||||
"arguments": {
|
||||
"limit": 5
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"sessions": [
|
||||
{
|
||||
"session_id": "sess_abc123",
|
||||
"model": "claude-sonnet-4",
|
||||
"status": "active",
|
||||
"total_cost": 1.23,
|
||||
"agent_count": 3,
|
||||
"tool_count": 12,
|
||||
"created_at": "2024-03-18T12:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Example 2: Analyze Session Cost
|
||||
|
||||
**User Prompt:**
|
||||
> "What was the cost breakdown for session sess_abc123?"
|
||||
|
||||
**Tool Sequence:**
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User
|
||||
participant Claude
|
||||
participant MCP as MCP Server
|
||||
participant API as Dashboard API
|
||||
|
||||
User->>Claude: Analyze session cost
|
||||
Claude->>MCP: get_session(sess_abc123)
|
||||
MCP->>API: GET /api/sessions/sess_abc123
|
||||
API-->>MCP: Session data
|
||||
MCP-->>Claude: Session result
|
||||
|
||||
Claude->>MCP: get_agents(sess_abc123)
|
||||
MCP->>API: GET /api/sessions/sess_abc123/agents
|
||||
API-->>MCP: Agents data
|
||||
MCP-->>Claude: Agents result
|
||||
|
||||
Claude->>User: Analysis:<br/>Total: $1.23<br/>3 agents:<br/>- Main: $0.85<br/>- Explore: $0.25<br/>- Task: $0.13
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Example 3: Create Custom Pricing Rule
|
||||
|
||||
**User Prompt:**
|
||||
> "Add a pricing rule for my-custom-model with input $5/1M and output $20/1M"
|
||||
|
||||
**Tool Call:**
|
||||
```json
|
||||
{
|
||||
"name": "create_pricing_rule",
|
||||
"arguments": {
|
||||
"pattern": "my-custom-model",
|
||||
"input_cost_per_1m": 5.0,
|
||||
"output_cost_per_1m": 20.0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"rule": {
|
||||
"id": 10,
|
||||
"pattern": "my-custom-model",
|
||||
"input_cost_per_1m": 5.0,
|
||||
"output_cost_per_1m": 20.0,
|
||||
"created_at": "2024-03-18T14:30:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Tool Reference
|
||||
|
||||
### get_sessions
|
||||
|
||||
List all sessions with optional filters.
|
||||
|
||||
**Input Schema:**
|
||||
```typescript
|
||||
{
|
||||
limit?: number; // Max sessions to return (1-1000)
|
||||
status?: 'active' | 'completed';
|
||||
}
|
||||
```
|
||||
|
||||
**Output Schema:**
|
||||
```typescript
|
||||
{
|
||||
sessions: Session[];
|
||||
total: number;
|
||||
}
|
||||
|
||||
interface Session {
|
||||
session_id: string;
|
||||
model: string;
|
||||
status: 'active' | 'completed';
|
||||
total_cost: number;
|
||||
agent_count: number;
|
||||
tool_count: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### get_session
|
||||
|
||||
Get single session details.
|
||||
|
||||
**Input Schema:**
|
||||
```typescript
|
||||
{
|
||||
session_id: string; // Required
|
||||
}
|
||||
```
|
||||
|
||||
**Output Schema:**
|
||||
```typescript
|
||||
{
|
||||
session: Session;
|
||||
}
|
||||
```
|
||||
|
||||
**Errors:**
|
||||
- `404` - Session not found
|
||||
|
||||
---
|
||||
|
||||
### get_agents
|
||||
|
||||
List agents for a session.
|
||||
|
||||
**Input Schema:**
|
||||
```typescript
|
||||
{
|
||||
session_id: string; // Required
|
||||
}
|
||||
```
|
||||
|
||||
**Output Schema:**
|
||||
```typescript
|
||||
{
|
||||
agents: Agent[];
|
||||
}
|
||||
|
||||
interface Agent {
|
||||
agent_id: string;
|
||||
session_id: string;
|
||||
agent_type: string;
|
||||
status: 'running' | 'completed' | 'failed';
|
||||
current_tool: string | null;
|
||||
input_tokens: number;
|
||||
output_tokens: number;
|
||||
cost: number;
|
||||
tool_count: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### get_agent
|
||||
|
||||
Get single agent details.
|
||||
|
||||
**Input Schema:**
|
||||
```typescript
|
||||
{
|
||||
agent_id: string; // Required
|
||||
}
|
||||
```
|
||||
|
||||
**Output Schema:**
|
||||
```typescript
|
||||
{
|
||||
agent: Agent;
|
||||
}
|
||||
```
|
||||
|
||||
**Errors:**
|
||||
- `404` - Agent not found
|
||||
|
||||
---
|
||||
|
||||
### get_tools
|
||||
|
||||
List tool executions for an agent.
|
||||
|
||||
**Input Schema:**
|
||||
```typescript
|
||||
{
|
||||
agent_id: string; // Required
|
||||
}
|
||||
```
|
||||
|
||||
**Output Schema:**
|
||||
```typescript
|
||||
{
|
||||
tools: ToolExecution[];
|
||||
}
|
||||
|
||||
interface ToolExecution {
|
||||
id: number;
|
||||
agent_id: string;
|
||||
tool_name: string;
|
||||
duration_ms: number;
|
||||
success: boolean;
|
||||
error_message: string | null;
|
||||
created_at: string;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### get_pricing
|
||||
|
||||
List pricing rules.
|
||||
|
||||
**Input Schema:**
|
||||
```typescript
|
||||
{} // No parameters
|
||||
```
|
||||
|
||||
**Output Schema:**
|
||||
```typescript
|
||||
{
|
||||
rules: PricingRule[];
|
||||
}
|
||||
|
||||
interface PricingRule {
|
||||
id: number;
|
||||
pattern: string;
|
||||
input_cost_per_1m: number;
|
||||
output_cost_per_1m: number;
|
||||
is_default: boolean;
|
||||
created_at: string;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### create_pricing_rule
|
||||
|
||||
Create custom pricing rule.
|
||||
|
||||
**Input Schema:**
|
||||
```typescript
|
||||
{
|
||||
pattern: string; // Model pattern
|
||||
input_cost_per_1m: number; // USD per 1M input tokens
|
||||
output_cost_per_1m: number; // USD per 1M output tokens
|
||||
}
|
||||
```
|
||||
|
||||
**Output Schema:**
|
||||
```typescript
|
||||
{
|
||||
rule: PricingRule;
|
||||
}
|
||||
```
|
||||
|
||||
**Errors:**
|
||||
- `400` - Invalid input
|
||||
- `409` - Pattern already exists
|
||||
|
||||
---
|
||||
|
||||
### delete_pricing_rule
|
||||
|
||||
Delete pricing rule.
|
||||
|
||||
**Input Schema:**
|
||||
```typescript
|
||||
{
|
||||
pattern: string; // Pattern to delete
|
||||
}
|
||||
```
|
||||
|
||||
**Output Schema:**
|
||||
```typescript
|
||||
{
|
||||
deleted: true;
|
||||
}
|
||||
```
|
||||
|
||||
**Errors:**
|
||||
- `404` - Pattern not found
|
||||
- `403` - Cannot delete default rule
|
||||
|
||||
---
|
||||
|
||||
### get_stats
|
||||
|
||||
Get dashboard statistics.
|
||||
|
||||
**Input Schema:**
|
||||
```typescript
|
||||
{} // No parameters
|
||||
```
|
||||
|
||||
**Output Schema:**
|
||||
```typescript
|
||||
{
|
||||
total_sessions: number;
|
||||
active_sessions: number;
|
||||
total_agents: number;
|
||||
total_tools: number;
|
||||
total_cost: number;
|
||||
avg_session_cost: number;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Error Response Format
|
||||
|
||||
```typescript
|
||||
interface MCPError {
|
||||
code: string;
|
||||
message: string;
|
||||
details?: any;
|
||||
}
|
||||
```
|
||||
|
||||
### Error Codes
|
||||
|
||||
| Code | Description | Resolution |
|
||||
|------|-------------|------------|
|
||||
| `INVALID_INPUT` | Invalid tool arguments | Check input schema |
|
||||
| `API_ERROR` | Dashboard API error | Check server is running |
|
||||
| `NOT_FOUND` | Resource not found | Verify ID exists |
|
||||
| `TIMEOUT` | Request timeout | Increase timeout, check network |
|
||||
| `CONFIG_ERROR` | Invalid configuration | Check `MCP_DASHBOARD_BASE_URL` |
|
||||
|
||||
### Error Handling Flow
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
Request[Tool Request] --> Validate{Input<br/>Valid?}
|
||||
|
||||
Validate -->|No| Error1[Return INVALID_INPUT]
|
||||
Validate -->|Yes| API[Call API]
|
||||
|
||||
API --> Success{HTTP 200?}
|
||||
|
||||
Success -->|No| HTTPCode{Status Code}
|
||||
HTTPCode -->|404| Error2[Return NOT_FOUND]
|
||||
HTTPCode -->|500| Error3[Return API_ERROR]
|
||||
HTTPCode -->|Timeout| Error4[Return TIMEOUT]
|
||||
|
||||
Success -->|Yes| Parse[Parse JSON]
|
||||
Parse --> Result[Return Result]
|
||||
|
||||
style Error1 fill:#EF4444
|
||||
style Error2 fill:#F59E0B
|
||||
style Error3 fill:#EF4444
|
||||
style Error4 fill:#EF4444
|
||||
style Result fill:#10B981
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Performance
|
||||
|
||||
### Tool Execution Time
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "Execution Breakdown"
|
||||
Validation[Input Validation<br/>~1ms]
|
||||
HTTP[HTTP Request<br/>~20ms]
|
||||
API[API Processing<br/>~5ms]
|
||||
DB[Database Query<br/>~5ms]
|
||||
Response[Response Serialization<br/>~5ms]
|
||||
end
|
||||
|
||||
Total[Total: ~36ms]
|
||||
|
||||
Validation --> HTTP
|
||||
HTTP --> API
|
||||
API --> DB
|
||||
DB --> Response
|
||||
Response --> Total
|
||||
|
||||
style Total fill:#10B981
|
||||
```
|
||||
|
||||
**Performance Benchmarks:**
|
||||
|
||||
| Tool | Avg Time | 95th Percentile |
|
||||
|------|----------|-----------------|
|
||||
| `get_sessions` | 25ms | 40ms |
|
||||
| `get_session` | 15ms | 25ms |
|
||||
| `get_agents` | 20ms | 35ms |
|
||||
| `get_tools` | 30ms | 50ms |
|
||||
| `get_pricing` | 10ms | 20ms |
|
||||
| `get_stats` | 40ms | 60ms |
|
||||
|
||||
---
|
||||
|
||||
## Development
|
||||
|
||||
### Building from Source
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
cd mcp && npm install
|
||||
|
||||
# Build TypeScript
|
||||
npm run build
|
||||
|
||||
# Watch mode (auto-rebuild)
|
||||
npm run dev
|
||||
|
||||
# Type checking
|
||||
npm run typecheck
|
||||
```
|
||||
|
||||
### Adding New Tools
|
||||
|
||||
```typescript
|
||||
// mcp/src/tools/my-tool.ts
|
||||
|
||||
import { z } from 'zod';
|
||||
import { fetchFromAPI } from '../utils';
|
||||
|
||||
export const myTool = {
|
||||
name: 'my_tool',
|
||||
description: 'Description of what this tool does',
|
||||
inputSchema: z.object({
|
||||
param1: z.string(),
|
||||
param2: z.number().optional()
|
||||
}),
|
||||
|
||||
async execute(args: { param1: string; param2?: number }) {
|
||||
const response = await fetchFromAPI(`/api/my-endpoint?param=${args.param1}`);
|
||||
return response.data;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Register in `index.ts`:
|
||||
|
||||
```typescript
|
||||
import { myTool } from './tools/my-tool';
|
||||
|
||||
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
switch (request.params.name) {
|
||||
case 'my_tool':
|
||||
return await myTool.execute(request.params.arguments);
|
||||
// ... other tools
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Deployment
|
||||
|
||||
### Docker Deployment
|
||||
|
||||
```dockerfile
|
||||
# mcp/Dockerfile
|
||||
FROM node:18-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install dependencies
|
||||
COPY package*.json ./
|
||||
RUN npm ci --production
|
||||
|
||||
# Copy built files
|
||||
COPY dist ./dist
|
||||
|
||||
CMD ["node", "dist/index.js"]
|
||||
```
|
||||
|
||||
```bash
|
||||
# Build Docker image
|
||||
npm run mcp:docker:build
|
||||
|
||||
# Run container
|
||||
docker run -e MCP_DASHBOARD_BASE_URL=http://localhost:4820 agent-dashboard-mcp:local
|
||||
```
|
||||
|
||||
### Podman Deployment
|
||||
|
||||
```bash
|
||||
# Build with Podman
|
||||
npm run mcp:podman:build
|
||||
|
||||
# Run with Podman
|
||||
podman run -e MCP_DASHBOARD_BASE_URL=http://localhost:4820 localhost/agent-dashboard-mcp:local
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
The MCP server provides:
|
||||
|
||||
- ✅ **AI-native interface** - Claude can query dashboard data naturally
|
||||
- ✅ **Complete tool coverage** - Sessions, agents, tools, pricing, stats
|
||||
- ✅ **Type-safe** - Full TypeScript types with Zod validation
|
||||
- ✅ **Standards-compliant** - Implements MCP protocol specification
|
||||
- ✅ **Easy setup** - One-command installation and configuration
|
||||
- ✅ **Local-first** - No cloud dependencies, runs entirely locally
|
||||
- ✅ **Docker-ready** - Containerized deployment support
|
||||
|
||||
For API details, see [docs/API.md](./API.md).
|
||||
+18
-20
@@ -74,7 +74,7 @@ Skills and commands are invoked as `/agenthub-<plugin>:<name>`. Agents are dispa
|
||||
## The `agenthub` plugin
|
||||
|
||||
The marketplace's root entry (`"source": "./"`) is the entire repository, so
|
||||
`server/`, `client/`, `mcp/`, `scripts/` and `bin/agenthub.js` all land under
|
||||
`server/`, `client/`, `scripts/` and `bin/agenthub.js` all land under
|
||||
`${CLAUDE_PLUGIN_ROOT}` when Claude Code caches it. That is what makes a
|
||||
checkout unnecessary.
|
||||
|
||||
@@ -85,12 +85,11 @@ checkout unnecessary.
|
||||
| The eight event hooks | inline `hooks` in `.claude-plugin/plugin.json`, each running `scripts/hook-handler.js` |
|
||||
| The dashboard server | started detached by the bootstrap, from the plugin cache |
|
||||
| The `agenthub` CLI | a launcher written to `~/.local/bin/agenthub` |
|
||||
| The MCP tools | `plugins/agenthub/.mcp.json`, pointing at the committed `mcp/build/index.js` |
|
||||
| The dashboard UI (`/run` and every other client route) | built into the runtime dir by the bootstrap, so it works the moment `claude` starts |
|
||||
| `/agenthub-doctor`, `/agenthub-update`, `/agenthub-open` | `plugins/agenthub/commands/` |
|
||||
| `/ship-full`, `/ship-quick` and one command per pipeline node (`/intake`, `/plan`, `/implement`, `/tests`, `/e2e`, `/review`, `/qc`, `/gate`, `/publishing`, `/pr-open`, `/done`, …) | `plugins/agenthub/commands/`, one file per name |
|
||||
| The skills (`ship-feature-lane`, `ship-feature`, `repo-onboarding`, `debug-live-issue`, `mcp-operations`, `update-project-docs`, `file-headers`) | `skills/` at the repo root — which IS the plugin root, so they are auto-discovered as plugin skills |
|
||||
| The agents (`qc-local`, `senior-gate-reviewer`, `backend-reviewer`, `frontend-reviewer`, `mcp-reviewer`) | `agents/` at the repo root, auto-discovered the same way — exposed as `agenthub:<name>` |
|
||||
| The skills (`ship-feature-lane`, `ship-feature`, `repo-onboarding`, `debug-live-issue`, `update-project-docs`, `file-headers`) | `skills/` at the repo root — which IS the plugin root, so they are auto-discovered as plugin skills |
|
||||
| The agents (`qc-local`, `senior-gate-reviewer`, `backend-reviewer`, `frontend-reviewer`) | `agents/` at the repo root, auto-discovered the same way — exposed as `agenthub:<name>` |
|
||||
|
||||
Plugin skills are namespaced: they are invoked as `/agenthub:<name>`, with the bare
|
||||
`/<name>` working as an alias unless another skill or command claims that name.
|
||||
@@ -100,8 +99,8 @@ useless for a lane working in a different repo. `agenthub skills install` surviv
|
||||
as the fallback for a plain checkout without the plugin.
|
||||
|
||||
**The agents ship the same way, from the same files.** `agents/` at the repo
|
||||
root holds all five (`qc-local`, `senior-gate-reviewer`, `backend-reviewer`,
|
||||
`frontend-reviewer`, `mcp-reviewer`), so the plugin exposes them as
|
||||
root holds all four (`qc-local`, `senior-gate-reviewer`, `backend-reviewer`,
|
||||
`frontend-reviewer`), so the plugin exposes them as
|
||||
`agenthub:<name>`. `agenthub lanes agents install` copies `qc-local` +
|
||||
`senior-gate-reviewer` from that same directory into a lane's own
|
||||
`.claude/agents/` — the highest-priority agent source — which is what makes the
|
||||
@@ -149,7 +148,7 @@ waits on an install:
|
||||
The first run takes a few minutes — most of it is the UI build, which is what
|
||||
makes client-only routes (`http://localhost:4820/run`, and every other page)
|
||||
work the moment `claude` starts, with no manual `/agenthub-open` step. Progress
|
||||
goes to `~/.claude/agent-dashboard/runtime/bootstrap.log`; `npm run build`'s own
|
||||
goes to `~/.claude/agenthub/runtime/bootstrap.log`; `npm run build`'s own
|
||||
output goes to `client-build.log` next to it; the server's own output goes to
|
||||
`server.log`.
|
||||
|
||||
@@ -164,7 +163,7 @@ cache directory rewrites and restarts the unit on the next session start, the
|
||||
same self-healing pattern the CLI launcher already uses. The bootstrap also
|
||||
tries `loginctl enable-linger` so the service starts on a cold boot before
|
||||
anyone logs in; when that needs elevated rights, it's skipped silently (check
|
||||
`~/.claude/agent-dashboard/runtime/bootstrap.log`, or run
|
||||
`~/.claude/agenthub/runtime/bootstrap.log`, or run
|
||||
`sudo loginctl enable-linger <user>` once by hand). A pre-existing
|
||||
`agenthub.service` unit not written by this bootstrap is left untouched, and the
|
||||
server falls back to the old per-session detached spawn instead.
|
||||
@@ -195,7 +194,7 @@ drive step by step (`brainstorming`, `writing-plans`,
|
||||
`verification-before-completion`, `finishing-a-development-branch`). Install it
|
||||
with `claude plugin install superpowers@claude-plugins-official`.
|
||||
|
||||
The row is a **WARN, never a FAIL**: the dashboard, hooks, CLI and MCP all work
|
||||
The row is a **WARN, never a FAIL**: the dashboard, hooks and CLI all work
|
||||
without it, and only those two pipeline skills stop partway. A plugin listed but
|
||||
explicitly disabled counts as missing — Claude Code will not resolve its skills.
|
||||
The skills present as plain user skills under `~/.claude/skills/` count as
|
||||
@@ -215,7 +214,7 @@ install clones from the network. It runs `claude plugin install
|
||||
superpowers@claude-plugins-official --scope user -y`; if that fails it registers
|
||||
the marketplace (`claude plugin marketplace add anthropics/claude-plugins-official`)
|
||||
and retries exactly once. Failure is logged with the manual command and nothing
|
||||
throws — the dashboard, hooks, CLI and MCP do not need these plugins.
|
||||
throws — the dashboard, hooks and CLI do not need these plugins.
|
||||
|
||||
The result is recorded as `skillPluginsSettled` in the bootstrap's `state.json`,
|
||||
which is also part of `fastPathOk()`: the check runs **once** per install, then
|
||||
@@ -240,9 +239,9 @@ without asking; it belongs in a review, not in a config file.
|
||||
|
||||
| Thing | Location | Survives a plugin update |
|
||||
|---|---|---|
|
||||
| SQLite DB, transcripts | `~/.claude/agent-dashboard/` | yes |
|
||||
| `node_modules`, `client-dist`, logs, lock, `state.json` | `~/.claude/agent-dashboard/runtime/` | yes (re-verified on every session start) |
|
||||
| Source, hooks, `mcp/build` | the plugin cache version directory | no — re-bootstrapped |
|
||||
| SQLite DB, transcripts | `~/.claude/agenthub/` | yes |
|
||||
| `node_modules`, `client-dist`, logs, lock, `state.json` | `~/.claude/agenthub/runtime/` | yes (re-verified on every session start) |
|
||||
| Source, hooks | the plugin cache version directory | no — re-bootstrapped |
|
||||
|
||||
The bootstrap deliberately does **not** set `DASHBOARD_DATA_DIR`: leaving the
|
||||
default keeps a plugin-run server and a developer's `npm run dev` server on one
|
||||
@@ -264,7 +263,7 @@ not assumed. It does **not**:
|
||||
`~/.claude/settings.json` (still pointing at that cache dir — they keep
|
||||
firing, and keep working, until the cache directory is eventually GC'd by
|
||||
Claude Code, at which point they silently start failing)
|
||||
- remove `~/.local/bin/agenthub` or `~/.claude/agent-dashboard/runtime/`
|
||||
- remove `~/.local/bin/agenthub` or `~/.claude/agenthub/runtime/`
|
||||
|
||||
For a clean machine, do all of this yourself:
|
||||
|
||||
@@ -274,10 +273,10 @@ For a clean machine, do all of this yourself:
|
||||
systemctl --user disable --now agenthub.service 2>/dev/null
|
||||
rm -f ~/.config/systemd/user/agenthub.service && systemctl --user daemon-reload 2>/dev/null
|
||||
# Fallback for a detached (non-systemd) server, or if the unit above was absent:
|
||||
kill "$(node -e 'console.log(JSON.parse(require("fs").readFileSync(require("os").homedir()+"/.claude/.agent-dashboard.json","utf8")).pid)')" 2>/dev/null
|
||||
kill "$(node -e 'console.log(JSON.parse(require("fs").readFileSync(require("os").homedir()+"/.claude/.agenthub.json","utf8")).pid)')" 2>/dev/null
|
||||
|
||||
# 2. Runtime state and the CLI launcher
|
||||
rm -rf ~/.claude/agent-dashboard/runtime # deps, UI bundle, logs, state
|
||||
rm -rf ~/.claude/agenthub/runtime # deps, UI bundle, logs, state
|
||||
rm -f ~/.local/bin/agenthub
|
||||
|
||||
# 3. The hook entries claude plugin install wrote (settings.json is not
|
||||
@@ -296,7 +295,7 @@ fs.writeFileSync(p, JSON.stringify(d, null, 2) + "\n");
|
||||
'
|
||||
```
|
||||
|
||||
`~/.claude/agent-dashboard/` still holds the SQLite database after all of the
|
||||
`~/.claude/agenthub/` still holds the SQLite database after all of the
|
||||
above — delete that directory too only if you want the recorded history gone.
|
||||
|
||||
## Available Plugins
|
||||
@@ -473,7 +472,7 @@ Audit your Claude Code configuration and curate the file-based memory store via
|
||||
|
||||
### 10. `agenthub-dashboard` — Dashboard Connector
|
||||
|
||||
Direct MCP integration, quick status, live watch, and endpoint probing.
|
||||
Quick status, live watch, and endpoint probing.
|
||||
|
||||
| Skill | Command | Purpose |
|
||||
|-------|---------|---------|
|
||||
@@ -484,7 +483,7 @@ Direct MCP integration, quick status, live watch, and endpoint probing.
|
||||
|
||||
**Commands:** `/agenthub-dashboard:status` · `/agenthub-dashboard:ping` · `/agenthub-dashboard:open-dashboard`
|
||||
|
||||
**Agent:** `dashboard-operator` — verifies the dashboard is up and guides start/restart/import. **MCP Server:** direct tool access to the Agent Monitor API. **Settings:** default agent model.
|
||||
**Agent:** `dashboard-operator` — verifies the dashboard is up and guides start/restart/import. **Access:** direct tool access to the Agent Monitor API. **Settings:** default agent model.
|
||||
|
||||
---
|
||||
|
||||
@@ -541,7 +540,6 @@ my-plugin/
|
||||
│ └── hooks.json # Event hooks (fail-safe, non-blocking)
|
||||
├── bin/
|
||||
│ └── my-cli-tool # CLI scripts (added to PATH)
|
||||
├── .mcp.json # MCP server configuration
|
||||
└── settings.json # Plugin settings
|
||||
```
|
||||
|
||||
|
||||
+2
-2
@@ -403,8 +403,8 @@ graph LR
|
||||
|
||||
### Getting Help
|
||||
|
||||
- **Issues:** [GitHub Issues](https://github.com/your-org/agent-dashboard/issues)
|
||||
- **Discussions:** [GitHub Discussions](https://github.com/your-org/agent-dashboard/discussions)
|
||||
- **Issues:** [GitHub Issues](https://github.com/your-org/agenthub/issues)
|
||||
- **Discussions:** [GitHub Discussions](https://github.com/your-org/agenthub/discussions)
|
||||
- **Documentation:** This folder
|
||||
|
||||
### Additional Resources
|
||||
|
||||
Reference in New Issue
Block a user