> Monitor and control the pi-dashboard server. List sessions, send prompts, abort runs, spawn new sessions, manage git branches, control flows, and configure the dashboard — all via REST API. Use when you need to interact with other pi sessions, check dashboard health, or orchestrate multi-session workflows.
npx skills add https://github.com/BlackBeltTechnology/pi-agent-dashboard --skill pi-dashboard
Interact with the pi-dashboard server from any pi session via its REST API.
Session/flow COMMAND verbs now ride the SAME WebSocket bus the web client uses,
via scripts/dashboard-bus.ts — a thin CLI wrapping
@blackbelt-technology/pi-dashboard-bus-client. It discovers the port itself
(config.json / DASHBOARD_PORT / 8000) and resolves an id-prefix to a full
session id from the live subscription snapshot, so command prose no longer needs
to teach BASE-URL derivation or GET /api/sessions id-resolution.
Canonical example:
npx tsx ./scripts/dashboard-bus.ts spawn /path/to/proj --prompt "/opsx-explore add-auth"
npx tsx ./scripts/dashboard-bus.ts until <id> idle
npx tsx ./scripts/dashboard-bus.ts prompt <id> "run the tests"
LLM authors can also write an ordinary type-checked .ts script importing
{ connect } from @blackbelt-technology/pi-dashboard-bus-client for multi-step
orchestration (spawn → prompt → until idle → read → plugin) using connect(),
spawn(), prompt(), until(), read.sessions(), and plugin("goal", …).
dashboard-bus.ts): abort, send_prompt, spawn,resume, flow_control, set_model, set_thinking_level, rename, hide/unhide,
attach/detach_proposal, plugin goal.
dashboard-api.sh): session / health /config reads, git ops, grep/browse, plugin_config_write, tunnel, peer scan,
openspec archive/toggle. REST remains a supported compatibility shell.
Read the port from config, defaulting to 8000:
PORT=$(cat ~/.pi/dashboard/config.json 2>/dev/null | grep '"port"' | grep -o '[0-9]*' || echo 8000)
BASE="http://localhost:$PORT"
Verify the server is running:
curl -s "$BASE/api/health" | jq .
# Expected: { "ok": true, "pid": ..., "uptime": ... }
By default, auth is disabled and all localhost requests work without tokens.
When auth is enabled (remote/tunnel access), include the JWT cookie:
# Check auth status
curl -s "$BASE/auth/status" | jq .
# If auth is enabled, include token in requests:
curl -s -b "pi_dash_token=YOUR_JWT" "$BASE/api/sessions" | jq .
| Action | Command |
|--------|---------|
| List sessions | curl -s "$BASE/api/sessions" \| jq . |
| Server health | curl -s "$BASE/api/health" \| jq . |
| Session file diff | curl -s "$BASE/api/session-diff?sessionId=ID" \| jq . |
| Read file | curl -s "$BASE/api/file?cwd=CWD&path=REL" \| jq . |
| List pinned dirs | curl -s "$BASE/api/pinned-dirs" \| jq . |
> The /dashboard:session-* and /dashboard:flow-* MUTATION commands now route
> through the bus CLI (scripts/dashboard-bus.ts). The REST rows below stay as a
> supported compatibility shell.
| Action | Command |
|--------|---------|
| Send prompt | curl -s -X POST "$BASE/api/session/ID/prompt" -H 'Content-Type: application/json' -d '{"text":"your message"}' |
| Abort | curl -s -X POST "$BASE/api/session/ID/abort" -H 'Content-Type: application/json' -d '{}' |
| Shutdown session | curl -s -X POST "$BASE/api/session/ID/shutdown" -H 'Content-Type: application/json' -d '{}' |
| Rename | curl -s -X POST "$BASE/api/session/ID/rename" -H 'Content-Type: application/json' -d '{"name":"my-name"}' |
| Hide | curl -s -X POST "$BASE/api/session/ID/hide" -H 'Content-Type: application/json' -d '{}' |
| Unhide | curl -s -X POST "$BASE/api/session/ID/unhide" -H 'Content-Type: application/json' -d '{}' |
| Spawn new | curl -s -X POST "$BASE/api/session/spawn" -H 'Content-Type: application/json' -d '{"cwd":"/path"}' |
| Resume/Fork | curl -s -X POST "$BASE/api/session/ID/resume" -H 'Content-Type: application/json' -d '{"mode":"continue"}' |
| Action | Command |
|--------|---------|
| Abort flow | curl -s -X POST "$BASE/api/session/ID/flow-control" -H 'Content-Type: application/json' -d '{"action":"abort"}' |
| Toggle autonomous | curl -s -X POST "$BASE/api/session/ID/flow-control" -H 'Content-Type: application/json' -d '{"action":"toggle_autonomous"}' |
| Action | Command |
|--------|---------|
| Set model | curl -s -X POST "$BASE/api/session/ID/model" -H 'Content-Type: application/json' -d '{"provider":"anthropic","modelId":"claude-sonnet-4-20250514"}' |
| Set thinking | curl -s -X POST "$BASE/api/session/ID/thinking-level" -H 'Content-Type: application/json' -d '{"level":"high"}' |
| Action | Command |
|--------|---------|
| List branches | curl -s "$BASE/api/git/branches?cwd=CWD" \| jq . |
| Checkout | curl -s -X POST "$BASE/api/git/checkout" -H 'Content-Type: application/json' -d '{"cwd":"CWD","branch":"main"}' |
| Init repo | curl -s -X POST "$BASE/api/git/init" -H 'Content-Type: application/json' -d '{"cwd":"CWD"}' |
| Stash pop | curl -s -X POST "$BASE/api/git/stash-pop" -H 'Content-Type: application/json' -d '{"cwd":"CWD"}' |
| Action | Command |
|--------|---------|
| Attach proposal | curl -s -X POST "$BASE/api/session/ID/attach-proposal" -H 'Content-Type: application/json' -d '{"changeName":"change-name"}' |
| Detach proposal | curl -s -X POST "$BASE/api/session/ID/detach-proposal" -H 'Content-Type: application/json' -d '{}' |
| Archive listing | curl -s "$BASE/api/openspec-archive?cwd=CWD" \| jq . |
| Action | Command |
|--------|---------|
| Read config | curl -s "$BASE/api/config" \| jq . |
| Update config | curl -s -X PUT "$BASE/api/config" -H 'Content-Type: application/json' -d '{"autoShutdown":false}' |
| Action | Command |
|--------|---------|
| Tunnel status | curl -s "$BASE/api/tunnel-status" \| jq . |
| Connect tunnel | curl -s -X POST "$BASE/api/tunnel-connect" |
| Disconnect tunnel | curl -s -X POST "$BASE/api/tunnel-disconnect" |
A convenience wrapper is available at scripts/dashboard-api.sh:
# Usage:
./scripts/dashboard-api.sh GET /api/sessions
./scripts/dashboard-api.sh POST /api/session/ID/prompt '{"text":"hello"}'
./scripts/dashboard-api.sh POST /api/session/spawn '{"cwd":"/path/to/project"}'
The /dashboard:* namespace wraps common operations as one-shot slash commands.
Files live in commands/ and are auto-discovered by the bridge's
prompt-expander (/dashboard:session-list resolves dashboard-session-list.md).
Two classes:
executable: bash frontmatter) — body runs as bash, outputrenders in chat, the LLM is never invoked (chat shows an "ℹ ran locally"
footer). Read-only / zero-blast-radius ops. Example:
/dashboard:session-list # table of every session, no token cost
/dashboard:session-info abc123 # all fields for a session by id-prefix
/dashboard:server-health # pid + uptime
executable frontmatter) — body expands into a usermessage the LLM interprets. Mutations needing judgment or free-form text.
Example:
/dashboard:session-tell abc123 please run the tests
/dashboard:session-abort-all # asks which sessions before aborting
LLM-free bodies get PI_DASHBOARD_PORT / PI_DASHBOARD_BASE injected, so they
curl the running dashboard without re-deriving the port. Full list:
references/slash-commands.md.
Convention + frontmatter: commands/README.md.
/dashboard:* command, args, LLM-free vs LLM-boundTake blackbelttechnology/pi-dashboard from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.
The instructions reference npx.
Without those the skill loads but fails at the first command.