Kanban board parity: what to implement
A focused target spec for bringing Nexus's task board up to the feature surface of Hermes's Kanban board. The broader Hermes gap analysis covers isolation, communication, and the learning loop — but not the board itself. This page fills that gap and lists the concrete work, grounded in the current code.
Hermes's board is a single-host local SQLite file (~/.hermes/kanban.db) with
an unauthenticated localhost dashboard. Nexus's board is MongoDB-authoritative,
projected to Taiga, served through an OIDC/Keycloak Admin UI, executed on
hardened K8s pods. In several dimensions (isolation, auth, distributed scale)
Nexus is already ahead. The job is enriching task metadata, board UX,
dispatcher self-healing, the command surface, and live updates — not adopting
Hermes's single-host design. See §7.
1. Already at parity ✅
So we don't rebuild it:
- 7 status columns (
planned, ready_for_agent, running, waiting_human, blocked, done, archivedinnexus-ui/.../board/page.tsx) ≈ Hermes's 7. - Drag-and-drop (custom HTML5 DnD), card chrome, task drawer with
description, dependency chips, comment thread (
BoardItemDrawer.tsx). - Dependency DAG (
depends_on), dependency-aware leasing, child auto-promotion. - Atomic leasing (
lease.run_id+expires_at) ≈ claim/reclaim; concurrency caps (NEXUS_MAX_ACTIVE_RUNS,NEXUS_AGENT_MAX_CONCURRENCY). - Run history (
agent_runs) ≈ Hermestask_runs; goal decomposition ≈decompose; comments mirrored to Taiga; multi-board via projects. - Agent-facing tools
board.comment,task.subtask,task.delegate,run.search.
2. The gaps to implement
A. Task / card fields (data model)
Task/BoardItem carry status, role, assignee, lease, depends_on — and little
else. Add:
| Field | Why | Notes |
|---|---|---|
priority: i32 | sortable badge; dispatch ordering | also unblocks goal-lifecycle prioritize |
acceptance_criteria: Vec<String> | drives goal-mode + close | see Goal lifecycle |
scheduled_at | deferred / cron work | pairs with scheduled automations |
idempotency_key | safe external task creation | dedup webhooks/API |
max_runtime / max_retries | circuit-breaker | today backoff_limit:1 = no retry |
pinned skills: Vec<String> | task-specific specialist skills | without editing the agent |
tenant | soft in-board isolation | filtered views |
workspace (scratch/dir:/worktree) | per-task workspace choice | repos are per-project today |
| attachments | files on a task (≤25 MB) | object store + drawer UI |
B. Board UX (the biggest visible gap)
| Feature | Today | Implement |
|---|---|---|
| Live updates | ❌ polling only (no WS/SSE) | SSE/WS endpoint in nexus-core tailing a task_events stream → subscribe in the board page. Highest-impact item. |
| Inline create per column | ⚠️ one global "new goal" form | + on each column header (title/assignee/priority/parent) |
| Multi-select + bulk actions | ❌ | shift/ctrl-select; batch status/archive/reassign → bulk PATCH /v1/tasks |
| Per-profile lanes in Running | ❌ | swimlane toggle by agent |
| Drawer: run-history tab | ⚠️ on /runs page | per-attempt outcome badges in the drawer |
| Drawer: event timeline | ❌ | last-N task_events on the card |
| Drawer: Decompose / Specify buttons | ❌ | trigger LLM decompose/spec from a card |
| Drawer: editable dependency add/unlink + upload | ⚠️ deps read-only | dependency editor + attachments |
| Toolbar: assignee / search / archived / "Nudge dispatcher" | ⚠️ board filter only | filters + manual POST /v1/dispatch |
| Orchestration settings panel | ⚠️ partly in /settings | board-level auto/manual + default assignee |
C. Triage column + auto-decompose
Hermes has a Triage lane where rough ideas land and get auto-decomposed (rate-capped), plus single-task Specify (acceptance criteria without fan-out). Nexus decomposes approved goals only — no triage lane, no Specify. Implement a triage column + Specify/Decompose card actions. (Overlaps the Goal lifecycle clarify/classify stages.)
D. Dispatcher robustness / self-healing
| Hermes guard | Today | Implement |
|---|---|---|
| Heartbeats (required hourly; stale → reclaim) | ⚠️ lease expires_at only | agent liveness signal → faster reclaim |
| Reclaim crashed workers | ⚠️ coarse lease expiry | active crash detection |
| Respawn guards (skip on quota/auth/429, recent success, active PR) | ❌ | prevent thrash on transient failure |
Auto-block after N spawn failures (failure_limit) | ❌ | per-task circuit breaker |
gave_up + retry/backoff | ❌ (backoff_limit:1) | bounded retries with backoff |
E. Event model / audit timeline
Hermes has a rich task_events table (created, promoted, claimed, completed, blocked, unblocked, assigned, edited, reprioritized, spawned, heartbeat, reclaimed, crashed, timed_out, gave_up) surfaced on the card and via tail/watch. Nexus
has a global events/logs collection but no per-task timeline in the UI.
Implement a task_events projection + drawer timeline + a tail/watch
equivalent (and feed the SSE stream from B).
F. Goal mode (iterative refinement)
Hermes --goal: an auxiliary judge checks each turn's output against the
task's acceptance criteria and loops in-session until it passes or the turn budget
is spent (then blocks, never silently exits). Nexus runs one-shot per lease.
Implement via the aux model lane + a goal-loop in the runner, gated on the new
acceptance_criteria field.
G. Slash-command / CLI surface
Hermes exposes every verb as /kanban <action> across many platforms plus a full
hermes kanban … CLI. Nexus has Telegram-only /goal /task /boards /status /summary. Implement: (1) a fuller board command grammar, (2) the multi-surface
gateway (Discord/Slack — roadmap item 9), (3) optionally a board CLI.
H. Swarm primitive
Hermes kanban swarm "title" --workers N --verifier --synthesizer builds a durable
fan-out+aggregate graph in one command. Nexus can express this via decomposition +
task.delegate but has no one-shot swarm verb/UI. Add it as a board action.
I. Notifications
Hermes auto-subscribes the originating chat to a task and pushes one message per
terminal event, auto-unsubscribing on done/archived. Nexus broadcasts
notify.events to all Telegram chats. Implement per-task subscribe/unsubscribe
- terminal-event delivery.
3. Prioritized roadmap
Ordered by value-per-effort for "a Hermes-like board." Timing TBD.
| Tier | Items | Why |
|---|---|---|
| P0 — board feel | B-live-updates (SSE), A-priority, B-drawer enrichment (runs + event timeline + decompose/specify), B-toolbar filters + nudge, B-inline create + bulk actions | Closes the biggest perceived gaps; mostly UI + small API. |
| P1 — model + self-healing | C-triage + Specify, A-(scheduled_at, pinned skills, idempotency, workspace, tenant), D-dispatcher robustness, A-attachments | Makes the board trustworthy under failure and richer per task. |
| P2 — orchestration | F-goal mode, H-swarm, scheduled automations (cron, roadmap 17) | Real autonomy; aligns with existing roadmap P1. |
| P3 — reach | G-board command grammar + multi-surface gateway, I-per-task notifications, board CLI | Broadens surfaces. |
4. Cross-cutting building blocks
Two items unlock several rows — build them first:
task_eventsprojection + SSE stream. A typed per-task event log (written byreconcile/dispatch) feeding anexus-coreSSE endpoint. Powers B-live-updates, E-timeline, I-notifications, and G-watchat once.Task.priority+acceptance_criteriaend-to-end. Small, but unblocks prioritize/sort (board), goal-mode (F), and close (goal lifecycle).
5. Mapping to existing roadmap
These board items reuse work already on the roadmap:
- SSE event stream is already listed as unshipped there → item B here is the board-facing consumer.
- Aux model lane (roadmap item 18) powers F (goal mode) and Specify (C).
- Scheduled automations (roadmap item 17) need A-
scheduled_at. - Multi-surface gateway (roadmap item 9) is G here.
- Agent-initiated delegation (roadmap item 6) underlies H (swarm).
6. Relationship to the goal lifecycle engine
The Goal lifecycle engine and this board spec are
complementary: the lifecycle engine produces and steers tasks (clarify →
decompose → replan → close); this spec makes those tasks visible, controllable,
and self-healing on the board. Triage (C) ≈ the lifecycle's clarify/classify;
goal mode (F) ≈ the lifecycle's acceptance_criteria + Close; the task_events
stream serves both.
7. Deliberately not copied
- Local SQLite board — keep Mongo-authoritative + Taiga projection.
- Unauthenticated localhost API — keep the OIDC/Keycloak proxy.
- Single-host PIDs / crash detection — use Job + lease semantics, not local PIDs.
- Cross-board-link prohibition — Nexus's
goal_id/project_id/depends_onalready model cross-cutting work; no need to inherit Hermes's limitation.