CloudCLI tab plugin for task queue management on forge. Provides a browser UI inside the CloudCLI web interface to view, filter, and act on agent tasks without leaving the editor.
The plugin runs two components:
- UI (
dist/index.js) — Renders a tab panel inside CloudCLI. Shows a filterable task list and detail view with history timeline and context ref previews. - Backend server (
dist/server.js) — HTTP + WebSocket server launched by CloudCLI. Reads task YAML directly from~/.claude/task-queue/(list/detail) and watches it for file changes. Mutations (approve, cancel, status change, quarantine, restore) are proxied to thetask-queue-mcpHTTP control API (TASK_QUEUE_API, defaulthttp://127.0.0.1:8485), gated by a shared-secret header — so every write inherits the MCP core's transition validation andfcntllocking. The plugin no longer writes queue YAML directly.
The backend picks a free ephemeral port at startup and reports it to CloudCLI via JSON on stdout. The UI communicates with the backend via the CloudCLI plugin RPC API (api.rpc()), which proxies requests to the backend.
Live task updates arrive via WebSocket — the backend watches ~/.claude/task-queue/*.yml and pushes a tasks event to connected UI clients when files change. The UI debounces refreshes by 2s.
- Task list with filters by agent, status, and task type
- Detail view: full task data, history timeline, context ref file previews (confined to
~/.claude/comms/and~/.claude/task-queue/) - Session launch: review mode (plan permission, agent presents summary then waits) or auto mode (agent claims and executes)
- Lifecycle actions (all via the shared-secret control API, actor
operator):- Approve a submitted / pending task
- Cancel a non-terminal task — a graceful terminal record (recoverable as a record, never deleted) instead of mislabeling it
failed - Quarantine / restore — isolate a task to
quarantine/(drops from the list) and restore it later - Status change — advance a task an agent missed (audited operator override)
- Live connection indicator (WebSocket dot: green = live, grey = disconnected)
- Manual refresh button
Requires Node.js 20+ and CloudCLI running on localhost:3001.
cd ~/repos/personal/cloudcli-plugin-task-queue
npm install
./deploy.shdeploy.sh builds the TypeScript, copies the plugin to ~/.claude-code-ui/plugins/cloudcli-plugin-task-queue/, and toggles the plugin via the CloudCLI API to restart the backend server.
| Variable | Default | Purpose |
|---|---|---|
TASK_QUEUE_API |
http://127.0.0.1:8485 |
Base URL of the task-queue-mcp HTTP control API (mutations) |
TASK_QUEUE_API_SECRET |
— | Shared secret sent as X-Task-Queue-Secret on every mutation. Required — mutations fail closed if unset. Provisioned in ~/.secrets/forge.env, never in source. |
CLOUDCLI_ORIGIN |
— | Additional allowed WebSocket origin (added to localhost:3001) |
| Package | Purpose |
|---|---|
ws |
WebSocket server |
| Field | Value |
|---|---|
name |
task-queue |
displayName |
Task Queue |
slot |
tab |
entry |
dist/index.js (UI) |
server |
dist/server.js (backend) |
The backend server exposes a small HTTP API consumed by the UI via api.rpc().
| Method | Path | Description |
|---|---|---|
GET |
/health |
Liveness check; returns {status, uptime, version} |
GET |
/tasks |
List tasks; query params: agent, status, type |
GET |
/tasks/:id |
Task detail + context ref previews |
POST |
/tasks/:id/start |
Launch headless agent session; body {mode: "review"|"auto"} (client-side spawn, not a queue mutation) |
POST |
/tasks/:id/approve |
Approve — proxied to the control API |
POST |
/tasks/:id/cancel |
Cancel (terminal); body {note?} — proxied to the control API |
POST |
/tasks/:id/status |
Operator status change; body {status, note?, allow_override?} — proxied to the control API |
POST |
/tasks/:id/quarantine |
Isolate to quarantine/ — proxied to the control API |
POST |
/tasks/:id/restore |
Restore from quarantine/ — proxied to the control API |
Reads (/tasks, /tasks/:id) are served directly from the queue YAML. Mutations proxy to the task-queue-mcp control API with the X-Task-Queue-Secret header.
WebSocket upgrade is handled on the same port. Clients receive {type: "connected"} on connect and {type: "tasks", count, changed} when task files change.
| Mode | Permission mode | Agent prompt |
|---|---|---|
review |
plan |
Read task, present summary, wait for approval |
auto |
default |
Read task, claim it (in-progress), execute |
Agent project directories are resolved from the hardcoded map in server.js:
| Agent | Project dir |
|---|---|
sysadmin |
~/.claude/projects/sysadmin |
developer |
~/.claude/projects/developer |
research |
~/.claude/projects/research |
writer |
~/.claude/projects/writer |
security |
~/.claude/projects/security |
npm run build
# Compiles TypeScript + bundles server.js and index.js to dist/Build uses tsc for type checking and esbuild for bundling (ESM format).
After initial ./deploy.sh, subsequent deploys follow the same script: build → disable plugin → copy files → re-enable plugin → verify status.
The plugin lives at ~/.claude-code-ui/plugins/cloudcli-plugin-task-queue/. CloudCLI manages the backend process lifecycle.