From e8e79c7b4cba24f48877e711b91b24eaf2045db1 Mon Sep 17 00:00:00 2001 From: Christopher Mayor Date: Sat, 7 Mar 2026 12:39:11 -0800 Subject: [PATCH] [taskboard] document control plane status and roadmap --- README.md | 15 +++++++++++ docs/IMPLEMENTATION_STATUS.md | 47 +++++++++++++++++++++++++++++++++++ docs/ROADMAP.md | 45 +++++++++++++++++++++++++++++++++ lib/dispatch.ts | 14 +++++++++-- lib/fleet-config.ts | 2 ++ 5 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 docs/IMPLEMENTATION_STATUS.md create mode 100644 docs/ROADMAP.md diff --git a/README.md b/README.md index cea838a..b6c3576 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,16 @@ It tracks and visualizes: - `/wiki` - markdown-backed runbooks and generated docs - `/usage` - usage aggregates from the local tracking table +## Control Plane Features + +- typed fleet config and task template config +- dispatch lifecycle states and SQLite audit history +- OpenClaw swarm dispatch into `~/.clawdbot/active-tasks.json` +- ZeroClaw webhook dispatch for `grizzley` and `ice` +- failure queue and dispatch history views +- family-specific runtime views for OpenClaw and ZeroClaw +- architecture documentation rendered directly from tracked config + ## Fleet Model ### OpenClaw @@ -99,3 +109,8 @@ npm start - The UI intentionally treats OpenClaw and ZeroClaw as separate families with different runtime and channel models. - `ice` ZeroClaw remains tied to host-local secret/encryption state; the dashboard reads that runtime but does not attempt to rewrite it. + +## Status Docs + +- [Implementation status](./docs/IMPLEMENTATION_STATUS.md) +- [Roadmap](./docs/ROADMAP.md) diff --git a/docs/IMPLEMENTATION_STATUS.md b/docs/IMPLEMENTATION_STATUS.md new file mode 100644 index 0000000..1dc92d3 --- /dev/null +++ b/docs/IMPLEMENTATION_STATUS.md @@ -0,0 +1,47 @@ +# Taskboard Implementation Status + +## Implemented + +- Next.js App Router migration with React 19, Tailwind CSS, and shadcn-style UI primitives +- Typed fleet model loaded from `config/fleet.json` +- Typed task templates loaded from `config/task-templates.json` +- Unified task intake for OpenClaw and ZeroClaw +- Dispatch lifecycle states: + - `planned` + - `assigned` + - `dispatched` + - `acknowledged` + - `completed` + - `failed` +- SQLite-backed audit log in `task_events` +- Dispatch history API and UI +- Failure queue UI +- Family-specific pages: + - `/openclaw` + - `/zeroclaw` +- Architecture page rendered from tracked fleet config +- Agent cards with: + - heartbeat age + - workload + - last dispatch event + - failure counts +- OpenClaw swarm dispatch: + - repo map lookup + - safe-directory git handling for mounted repos + - worktree creation + - queue insertion into `~/.clawdbot/active-tasks.json` +- ZeroClaw webhook dispatch: + - bearer-token support for paired gateways + - direct gateway mode for testing + +## Verified Live + +- `grizzley` ZeroClaw webhook dispatch from taskboard +- `ice` ZeroClaw webhook dispatch from taskboard +- OpenClaw swarm queue creation and host worktree creation on `ubuntu` + +## Current Limits + +- Taskboard can dispatch OpenClaw swarm tasks, but it does not yet monitor tmux session progress automatically. +- ZeroClaw acknowledgements and completions are still operator-driven; remote runtimes do not push completion state back yet. +- The board records remote webhook responses, but not structured per-step execution output from the agents. diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md new file mode 100644 index 0000000..f14d4ec --- /dev/null +++ b/docs/ROADMAP.md @@ -0,0 +1,45 @@ +# Taskboard Roadmap + +## Next + +1. Add execution-state sync for OpenClaw swarm tasks. + - Read `~/.clawdbot/active-tasks.json` + - Detect `queued`, `running`, and `completed` + - Reflect those states back into taskboard tasks automatically + +2. Add remote completion callbacks for ZeroClaw. + - Accept structured webhook acknowledgements + - Persist remote execution summaries + - Auto-transition tasks to `acknowledged` or `completed` + +3. Add per-host direct taskboard targets beyond the current fleet. + - `pve` + - `truenas` + - `panda` + +4. Add operator controls for swarm execution. + - launch queued task + - stop task + - nudge task + - open session/log link + +5. Add richer audit detail. + - store structured request payload + - store response excerpt separately from summary + - attach host/service verification artifacts + +6. Add dashboard summaries. + - task counts by family + - stale heartbeat warnings + - failure trends + - dispatch latency + +7. Add completion workflows. + - generate wiki summary automatically + - link completed task to artifacts, PRs, or logs + +## Longer Term + +- Introduce a fleet capability registry so the taskboard can validate whether a task is legal for a given host before dispatch. +- Add authentication and RBAC for multi-operator use. +- Add generated runbooks and service maps directly from live host inventory. diff --git a/lib/dispatch.ts b/lib/dispatch.ts index 6760f02..a62b8c7 100644 --- a/lib/dispatch.ts +++ b/lib/dispatch.ts @@ -5,6 +5,7 @@ import { execFile } from "node:child_process"; import { REPO_ACCESS_ROOTS, + SWARM_HOST_WORKTREES_DIR, SWARM_REPO_MAP_FILE, SWARM_TASKS_FILE, SWARM_WORKTREES_DIR, @@ -78,6 +79,7 @@ async function dispatchOpenClawTask(taskId: number) { const taskKey = `taskboard-${task.id}`; const repoName = path.basename(repoPath); const worktree = path.join(SWARM_WORKTREES_DIR, repoName, taskKey); + const hostWorktree = path.join(SWARM_HOST_WORKTREES_DIR, repoName, taskKey); const branch = `feat/taskboard-${task.id}`; const baseBranch = task.base_branch || "main"; @@ -102,7 +104,7 @@ async function dispatchOpenClawTask(taskId: number) { repo: repoName, repoPath, repoSlug: task.repo_slug, - worktree, + worktree: hostWorktree, branch, baseBranch, tmuxSession: `${agentName}-${taskKey}`, @@ -124,6 +126,14 @@ async function dispatchOpenClawTask(taskId: number) { reviewPassed: false, }, }); + } else { + existing.repoPath = repoPath; + existing.repoSlug = task.repo_slug; + existing.worktree = hostWorktree; + existing.branch = branch; + existing.baseBranch = baseBranch; + existing.agent = agentName; + existing.tmuxSession = `${agentName}-${taskKey}`; } fs.writeFileSync(SWARM_TASKS_FILE, JSON.stringify({ tasks }, null, 2)); @@ -131,7 +141,7 @@ async function dispatchOpenClawTask(taskId: number) { return { state: "dispatched" as const, summary: `Queued in OpenClaw swarm for ${agentName}`, - detail: `${task.repo_slug} -> ${worktree}`, + detail: `${task.repo_slug} -> ${hostWorktree}`, }; } diff --git a/lib/fleet-config.ts b/lib/fleet-config.ts index 31961b9..6ff244b 100644 --- a/lib/fleet-config.ts +++ b/lib/fleet-config.ts @@ -9,6 +9,8 @@ export const OPENCLAW_CONFIG_PATH = process.env.OPENCLAW_CONFIG || "/home/bear/. export const SWARM_TASKS_FILE = process.env.SWARM_TASKS_FILE || "/app/swarm/active-tasks.json"; export const SWARM_REPO_MAP_FILE = process.env.SWARM_REPO_MAP_FILE || "/app/swarm/repo-map.json"; export const SWARM_WORKTREES_DIR = process.env.SWARM_WORKTREES_DIR || "/app/swarm/worktrees"; +export const SWARM_HOST_WORKTREES_DIR = + process.env.SWARM_HOST_WORKTREES_DIR || SWARM_WORKTREES_DIR; export const REPO_ACCESS_ROOTS = (process.env.REPO_ACCESS_ROOTS || "/srv/apps,/home/bear") .split(",") .map((entry) => entry.trim())