- probe configured server URL (~1s) before remote commands; on failure
re-discover via LAN discovery, persist and use the resolved URL
- poll tryClaim/trySurfaceMessages every ~4s during the SSE wait in CLI
work and MCP waitForTask — a lost SSE frame costs seconds, never sleep
- work/MCP no longer auto-mark messages read: surfacing sets delivered,
explicit ack/read required; loops still wake only on unread (no spin)
- parseSSEBuffer accepts CRLF frame separators and joins multi data: lines
- bump version to 0.10.1 (package.json, CLI --version, MCP server)
- core/index.ts: the FTS5 'search' table has no UNIQUE on id, so INSERT OR
REPLACE appended a new row every update and the search JOIN returned an id
N times. Now delete-then-insert by id -> exactly one FTS row per entity.
- taskService.claimTask: race-guarded — only an OPEN task can be claimed;
same-agent re-claim is an idempotent no-op; a task claimed by another agent or
past open is refused. getTask+updateTask are sync, so within the single-thread
event loop the read-check-write is effectively atomic (first claim wins).
- routes.ts (spec 'nicht brechen'): PATCH in_progress surfaces a lost/non-open
claim as a clean 400 instead of 500, so the board drag reverts gracefully and
a second agent can't clobber the first's claim.
- tests: +coreCorrectness.test.ts (no FTS dup after updates; concurrent claims
-> one wins; idempotent re-claim; refuse non-open) + server.test.ts route guard
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- work.ts: the CLI work loop now wakes on architect follow-up MESSAGES, not just
tasks. drainAgentMessages() surfaces + marks-read the agent's inbox; wired into
waitAndClaim (SSE message events) and as an upfront check in workAgent. reopen +
next-assign already wake via task events; a plain message no longer leaves the
re-armed loop dormant.
- mcp/server.ts: implementer agenthub_work LOOP reminder now explicitly instructs
re-arming after agenthub_task_review so the architect's approval/reopen/message
wakes it (waitForTask already wakes on task+message).
- tests: work.test.ts +message-wake +reopen-wake
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- routes PATCH /tasks/🆔 uniformly appendTaskLog + publishLog for every status
transition (claim/review/done/cancel/reopen) and on assign; best-effort, never
fails the mutation. No double-emission (log rides the 'log' channel; fsWatch
only watches .md so the .log append is not re-emitted).
- MCP agenthub_task_log tool + remoteClient.appendTaskLog + CLI 'task log <id>
--text [--agent][--level]'
- agenthub_work LOOP reminder: 'Report meaningful progress with agenthub_task_log'
- taskDetail: Live Console panel — historic lines via readTaskLog + live tail via
the named task-log SSE event filtered to this task id
- tests: +taskLog-live.test.ts (PATCH->one log event, no double change, historic
render, POST /log, remoteClient)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The green pulse now visualises real task flow instead of looping randomly:
- delegation (task → in_progress/reassigned) fires a green pulse architect→agent
and the agent card turns 'active' (green ring + badge);
- review submission (→ review) fires an amber pulse agent→architect and the
card enters the 'reviewing' state.
Pulses are one-shot, created per transition (SSE-driven, deduped against a
baseline snapshot) and removed on arrival, which lights the destination node.
At rest only the connectors breathe faintly. Active state recoloured green to
match the pulse. Verified: delegation→down+active, review→up+reviewing.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Board (/board):
- Drag an AGENT chip onto a task card to (re)assign it (realtime-notified).
- Drag a task card to a column to change status; open→in_progress auto-assigns
from the title's "<agent>:" prefix — no manual agent picking.
- "+ New task" composer (agent dropdown removed; agent comes from the title).
- Live Cost & Budget panel.
Team (/team): live SSE sync of busy state + always-on ambient animation
(connector shimmer, idle glow) that brightens to a busy pulse when an agent
works. Org-chart hierarchy stays.
Token accounting: new budgetService/rosterService + GET /budget and /agents.
Real doneTokens + time-on-task estimate capped at 45 min/task (avoids the
wall-clock overcount that produced multi-million-token totals), blended
per-model EUR cost + optional budget bars. All estimates flagged "~".
Autostart: `agent setup` writes deterministic SessionStart hooks for Codex
(~/.codex/config.toml) and Kimi (~/.kimi-code/config.toml), not just Claude
Code. Verified: both auto-enter the agenthub_work loop.
Realtime architect review: agenthub_work is role-aware — architect/reviewer
blocks on SSE and wakes when a task hits review (no manual watcher re-arm).
mDNS: server advertises agenthub.local (bonjour-service) so the hub is
reachable in a browser on the LAN without an IP.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
codex reworked the board per the user's "keep it simple": /board now shows only
the compact KPI cards + the kanban (half-donut removed), with realtime SSE folded
in (TSK-0030). Recent Activity + Done Archive moved to a new /activity page; nav is
Board · Team · Activity · Decisions. team.ts / ui-shared.ts touched for nav + a
tier data-role hook. Tests green (133). The /team + /activity 500s seen on review
were a local better-sqlite3 ABI mismatch (native module rebuilt for Node 24), not a
code bug — all pages 200 after rebuild.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Closes the addressing gap that left a waiting `agenthub work` blocked: the
remaining Win tasks were titled "Win L2: …" / unassigned, so they matched
no agent and the daemon waited forever.
`agenthub task assign <id> --agent <name>` sets assignedTo WITHOUT claiming
(status stays open) and fires task/updated — so an agent's blocked `work`
re-checks, matches via assignedTo, and auto-claims it. The architect can now
route a specific open task to a specific agent and have its daemon pick it up.
- taskService.assignTask; PATCH /tasks/:id handles assignedTo-without-status;
remoteClient.assignTask; CLI `task assign`.
- test: assign keeps status open + sets assignedTo; start/work then claims it
via the assignedTo match. 122/122 green.
Bump 0.5.0 -> 0.6.0.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Closes the architect-side gap: the auto-claim daemon wakes implementers on
new tasks, but the architect had no signal when an implementer submitted.
`agenthub watch --await-review` exits (after printing) the moment a task
enters `review` — including any task already in review on connect (initial
check) — so the architect can run it in the background and be re-invoked by
the harness the instant a submission needs a verdict.
- watch.ts: awaitReview option, initial fetchReviewTasks() check + SSE exit
on task→review.
- index.ts: --await-review flag.
- tests: returns immediately on already-pending review; exits on a review
transition while watching. 121/121 green.
Bump 0.4.0 -> 0.5.0.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The missing autonomy step: an implementer no longer needs a human prompt
per task. `agenthub work --agent <name> --role <role>` announces, then:
- claims an already-open task addressed to the agent immediately, or
- blocks on the SSE stream until one appears (newly delegated OR
reopened after review), then claims + prints it.
Loop: work → implement → `task review` → work. New/reopened tasks are
picked up automatically; run it in the background so the wait doesn't tie
up the turn.
- src/cli/commands/start.ts: extracted announceAgent / findAddressedOpenTask
/ claimAndPrintTask (shared by start + work); addressed-match now also
covers assignedTo (reopened tasks coming back for rework).
- src/cli/commands/work.ts: wait-and-claim via /events, with a gap-close
re-check after subscribing and an optional --timeout.
- index.ts: `agenthub work` command.
- templates: implementer guides lead with `work` (the autonomous loop),
keep `start` as the one-shot.
- tests: immediate claim (local) + wait-then-claim (server SSE). 119/119.
Bump 0.3.1 -> 0.4.0.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The status snapshot (.agenthub/status/latest.md) was only refreshed on an
explicit `status --update`, so it drifted stale and misled agents that
follow golden rule #2 ("read status/latest.md") — e.g. an implementer
seeing an old task list and picking the wrong task.
- src/server/statusRefresh.ts: subscribe to the event bus and regenerate
the snapshot on every task/handoff/decision/memory change (REST and
filesystem-watch paths), debounced 300 ms. Presence ('agent') events
are skipped; the snapshot lives outside the watched dirs so it can't
feed back into the watcher.
- wired into startServer lifecycle (start + stop on close).
- test: status/latest.md reflects a new task shortly after POST /tasks.
117/117 green.
Bump 0.3.0 -> 0.3.1.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
An agent runs ONE command and is working: it announces presence, claims
the open task addressed to it, and prints the task + its handoff + the
next step. Removes the per-agent kickoff copy-paste.
- src/cli/commands/start.ts: `agenthub start --agent <name> --role <role>`.
"Addressed to <agent>" = task title starts with "<agent>:" OR a handoff
has toAgent=<agent>. Claims it, prints task body + handoff + the review
gate reminder. No addressed task → lists open role tasks to pick.
Works on local + --server paths.
- templates: implementer guides (AGENTS/CODEX/KIMI.md) now lead with
"On your first turn, RUN `agenthub start …` — do not just summarize",
so a fresh session self-onboards from one trigger word.
- tests: start auto-claims the addressed task, ignores others, no-ops on
empty queue; templates test updated for the new commands. 116/116 green.
Bump 0.2.2 -> 0.3.0.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Implements the architect-controlled workflow: implementers submit work
for review, only the architect closes tasks.
- CLI: `agenthub task review <id>` (implementer submits → status review)
and `agenthub task reopen <id>` (architect re-triggers → status open).
Server already supported both statuses; now exposed on local + --server
paths, with remoteClient.reviewTask/reopenTask.
- templates: AGENTS.md + role guides rewritten so agents self-drive the
CLI on open (hello → claim → implement → task review → wait), with the
hard rule that ONLY the architect runs `task done`. Implementer guides
(codex/kimi) never call done; architect guide documents done/reopen.
- tests: review/reopen SSE events + formatEvent "Task review"/"Task
reopened" lines. 113/113 green.
Bump 0.2.0 -> 0.2.1.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Agents now connect to the hub with no manual env/flag, and announce
themselves on join — restoring the agreed onboarding flow.
Auto-connect (resolveContext):
- An initialized project WITHOUT a configured serverUrl now falls
through to LAN auto-discovery (previously it went straight to local
mode, so agents in an initialized repo never found the server). The
discovered URL is persisted to the project config, so the next
command is instant.
- IP-change self-heal: when a configured server is unreachable,
runRemote re-discovers the live server and updates the config so the
next command reconnects automatically.
Presence (join-announce):
- POST /announce broadcasts an ephemeral 'agent/joined' event (not
written to disk). New `agenthub hello --agent <name> --role <role>`
posts it; watchers print "AgentHub: <agent> joined (<role>)".
- AgentHubEvent extended with type 'agent' + actions 'joined'/'left';
formatEvent renders presence lines; remoteClient.announce() added.
Tests: formatEvent agent lines + /announce SSE e2e. 109/109 green.
Bump 0.1.2 -> 0.2.0 (CLI --version too).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Every user-facing line — the watch stream and each command's success
line, on both the local and --server (remote) paths — now carries an
"AgentHub:" prefix so it's recognizable in any agent's console
(Claude / Codex / Kimi), independent of the board.
- watch: formatEvent rewritten to verb-based, branded lines
("AgentHub: Task received <id> <title> [status]",
"AgentHub: Task done <id> by <agent>", "AgentHub: Handoff …"),
plus an "AgentHub: connected" line on stream start.
- task/handoff/decision/memory/delegate/init + server-listening lines
branded on the local command path.
- cli/index.ts: same branding on the --server remote path (the path
agents actually hit), so CLI line and SSE stream now match.
- tests: formatEvent assertions updated to the branded format
(regex-tolerant of column padding). 106/106 green.
codex + kimi stay implementers by convention (role=implementer +
assignedTo) — no schema change. Bump 0.1.1 -> 0.1.2.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Closes the documented /events limitation: mutations made through the
local CLI (direct file + SQLite writes, no --server) bypassed the
in-process event bus and were invisible to SSE subscribers. A watcher
(e.g. a Windows client) was therefore NOT triggered when another agent
created a task via plain `agenthub task create`.
- src/server/fsWatch.ts: watch the entity dirs (tasks/handoffs/
decisions/memory); on any .md change, parse the entity and emit the
matching AgentHubEvent. Debounced per-file; self-creates dirs so it
attaches even before the first write.
- src/server/events.ts: shared dedup cache (signature = type🆔stamp)
+ emitChange() so the REST path and the watcher deliver each change
exactly once (no echo when REST writes the file the watcher sees).
- src/server/routes.ts: route emits go through emitChange(); update the
stale limitation comment.
- src/server/index.ts: start/stop the watcher with the server lifecycle.
- tests/sse.test.ts: CLI-write -> SSE, CLI-update -> SSE, and REST
dedup (exactly-once). 102/102 green.
Effect: a watcher is auto-triggered the instant any agent creates a
task, with or without --server. Bump 0.1.0 -> 0.1.1.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Local-mode branch of 'memory add' omitted category when calling memoryAdd, so it always fell through to an interactive select() prompt — which throws in non-TTY agent contexts and breaks the reporting loop. Forward category; add tests for the non-interactive flag path.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
GET /tasks/:id/activity returns a time-sorted ActivityItem[] assembled from existing data (task created, handoffs by taskId, memory by relatedTasks, current status). memory add + task done gain optional tokens/duration/by metadata surfaced in the timeline. Board cards expand inline to show the timeline. Index gains taskId + relatedTasks columns with migrations. 74 -> 97 tests.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- src/server/events.ts: in-process EventEmitter bus (AgentHubEventBus);
singleton per server process, unlimited listeners for SSE fan-out.
- src/server/routes.ts: GET /events SSE endpoint — keepalive every 25 s,
optional ?role= server-side filter, reply.hijack() for clean streaming;
eventBus.publish() called on every successful mutating route (POST tasks/
handoffs/decisions/memory, PATCH tasks/:id).
- src/cli/commands/watch.ts: SSE client using Node fetch + ReadableStream
reader; exports parseSSEBuffer + formatEvent for testability; --once flag
exits 0 after first event (turn-based agent use case); --role for client-
side filtering (additive to server-side filter).
- src/cli/index.ts: register agenthub watch command via resolveContext.
- tests/sse.test.ts: 18 new tests (74 total, all green) — unit tests for
parseSSEBuffer + formatEvent, integration tests for eventBus on each
mutation type, E2E SSE stream + role-filter tests over real HTTP.
Limitation (documented): only REST mutations through the server emit events.
Local-CLI writes (direct file+SQLite) are invisible to subscribers — a
filesystem-watch increment is deferred to a later phase.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
GAP A: extend PATCH /tasks/:id to support all five TaskStatus values
(open, in_progress, review, done, cancelled). Add reviewTask, cancelTask,
reopenTask helpers in taskService. Claim semantics preserved: in_progress
requires assignedTo. Board columns for review and cancelled now reachable
via the API.
GAP B: index fromRole/toRole/fromAgent/toAgent on handoff upsert. SQLite
migration guard adds columns to pre-existing DBs without data loss. Board
renderHandoffs shows "fromRole[@agent] → toRole[@agent]" via → arrow.
GET /handoffs now carries the routing fields in every index entry.
Tests: +14 (56 total, 21 files, all green). Covers every new status
transition, index field presence, board markup assertions, and a guard for
the claim-without-assignedTo 400.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Serves a single self-contained HTML page (inline CSS+JS, no build step,
no framework, no npm deps) that polls /tasks, /handoffs and /decisions on
the same origin and renders a column board by task status
(open/in_progress/review/done/cancelled). Each card shows id, title, role
and assignedTo; small handoffs + decisions panels below; auto-refresh
every 4s with a connection indicator. Purely additive and read-only — the
CLI core path is untouched.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
agenthub update: fetch + reset install to origin/<branch> + reinstall + rebuild, so users never touch git or pnpm. Robust to a dirty working tree (the 'commit before pull' wall) by resetting to remote; guards unpushed local commits and refuses to discard them. Adds a daily, non-blocking update hint on startup (detached background fetch + instant local comparison, like gh/npm/brew) that never auto-applies. Tests for the non-git-install path.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Make the network MVP simple to operate: server start refuses a second instance on a port already serving AgentHub (single source of truth, prevents discovery split-brain); commands auto-discover a LAN server when run outside any project so the CLI works from any directory with zero config; walk up to the nearest .agenthub project (cwd-robust) and serve the project root; replace raw stack traces with actionable messages; add tests for findProjectRoot and the single-instance guard.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>