Agent integration
Agents use Agent Board through three pieces: the skill that tells them how to work, the hook that hands them the progress table, and wait that lets them block until a person answers. This page explains each piece and what agboard setup prepares. The user-facing workflow is in Working with agents; the JSON they receive is in Hook, progress, and wait output.
How the pieces fit together
| Piece | Lives in | Job |
|---|---|---|
Skill agent-board | .agents/skills/agent-board/SKILL.md | Judgment: how to choose work, report progress, ask decisions, and respect drafts and Done tasks. |
| Hook | agboard hook (src/agent/hook.rs) | Fetching and formatting: after tool calls, attach the current progress table to the agent's context. |
| Progress table | src/progress.rs | The list of workable tasks, shared by agboard progress and the hook. |
wait | src/agent/wait.rs | Block until the project changes or a decision is answered. |
The skill is named agent-board; the executable is agboard. A typical loop: the hook shows the progress table → the agent reads only the EPIC.md and TASK.md it needs → it clarifies an unclear title through agboard edit --title, preserving the original request → it moves the task to Doing and Running → it records progress with history add → it asks a decision and waits by default when blocked → it checks conditions off, and automatic Done finishes the task. Title refinement is a skill instruction shared by the ordinary loop and listener, not a server-side summarization feature.
Agents append progress at the start, meaningful progress, decisions, verification, interruptions, and resumptions, without per-entry approval, and never duplicate entries that operations already appended. The body keeps the plan and concise verification results. Images can be attached when visual proof is useful.
The skill gives BUG and ENHANCEMENT a fixed-body exception: they are ongoing classification epics, not per-feature plans. Their canonical bodies live in assets/BUG-EPIC.md and assets/ENHANCEMENT-EPIC.md beside the skill. After one-time initialization in the board’s language, normal work and listener runs record plans and outcomes only on tasks. An explicit user request is required to replace existing non-empty content, with useful old content retained in relevant task bodies. Priority frontmatter remains editable. This is not a server-side edit restriction.
The progress table and the hook
The progress table lists non-Pending Todo and Doing tasks, grouped by epic in priority order, with each task's ID, title, owner, status, acceptance counts, and the paths of its EPIC.md and TASK.md. It never includes bodies or history. A Pending task higher in the order does not block lower tasks, and an answered task that is still unfinished returns to the table.
src/progress.rs builds the optional pending and done sections from Include, which agboard progress and agboard hook fill from --include-pending and --include-done. The default Include adds nothing, so the default table is unchanged. See Epics and progress for the options.
The hook identifies the project from the nearest bound ancestor of the input cwd (or the process cwd), never from a session ID, and never selects all projects when the folder is unbound. It returns the table as AGBOARD_PROGRESS JSON in hookSpecificOutput.additionalContext, or an AGBOARD_ERROR such as folder_unbound.
- Claude Code. The template in
integrations/claude-code/registersagboard hookon PostToolUse, and on PostToolUseFailure after failures, without a fixed project name. Generic skill frontmatter hooks are not used. The skill reads a snapshot when first loaded; the table is fetched again after compaction (SessionStartcompact) or on the next tool completion. - Codex. The template in
integrations/codex/registersagboard hook --agent codexon PostToolUse and also fetches at first use and after compaction. Existing settings are never written automatically; users review and trust the template. - Limits. Input is limited to 64 KiB of UTF-8, the table to 256 KiB, and a run to 10 seconds. Codex's
additionalContextLimitis set to 0 so the hook enforces its own limit. Exceeding it reportscontext_too_large; output is never truncated and reported as success. When the table cannot be produced or the full input did not arrive, the hook says so and keeps the original tool result. - Safety. Commands are fixed; nothing is built from task text or
tool_input. The hook never calls agent tools, never triggers itself, and never changes files. Paths appear only in local CLI and hook output, never in remote JSON.
Agents make no board-dependent changes until the table can be read, and they read a fresh table after context compaction.
The skill requires all task-related questions to use board decision requests with choices. pending --request-json waits indefinitely by default, even when wait is omitted; wait: {} remains compatible. The skill uses --no-wait only when the user explicitly asks to register a question and return immediately. It forbids substituting chat or native agent question tools, including when the board is unavailable.
Waiting for changes
agboard wait --after <cursor> blocks until the project changes:
- Read
pidandportfromserve.jsonin the same data area and connect toGET /api/events. - Match the project name against the cursor and fix the ProjectId. A cursor for another project, or in an old format, is
cursor_invalid. - After
ready, compare the project's current version with the cursor. If they differ, return at once; this catches changes made between fetching and subscribing. - Otherwise wait for
changed. If a re-read shows the same version (another project changed), keep waiting.
changed,ready, and keep-alive comments are distinguished. Renames return the same project's snapshot; deletion returnsproject_not_foundand never moves to a re-created project.- The connection limit is 3 seconds, and the wait itself is unlimited by default. With an optional
--timeout, it checks the version once more at the end and returnswait_timeoutif nothing changed. A disconnect returnsboard_unavailable. There are no automatic short retries and no periodic polling. - Disconnects, timeouts, and Ctrl+C never change tasks or history, never count as "no change", and never restart a finished agent.
- Because CLI notifications are best effort, a missed one is caught on the next connection, a real
changed, or the final read at a timeout.
Decision requests are saved before the CLI notifies serve and waits on the existing SSE event stream. The default wait needs a running serve; a preflight check runs before the save, so an unavailable server does not create the question. Omitting wait and using wait: {} both wait indefinitely; an integer timeoutSeconds from 1 to 86,400 limits only that CLI process. wait: null and timeoutSeconds: null mean no timeout. The wait settings are not saved with the task.
On success, the waiting command returns {task, answer}; --no-wait returns {task} after saving and notifying and does not need serve. It can be combined with wait: {}, but not an integer timeout. A timeout, interruption, or lost connection leaves the question Pending; request_changed means it was withdrawn. After a browser answer the task becomes Idle; the agent reads the answer and history, then explicitly resumes Running with a reason. See Decision requests for the user workflow.
Waiting for the next task
agboard --project <name> wait --until task --idle-timeout <seconds> --json uses the same event-driven wait engine. It reads eligible tasks immediately before subscribing, checks again after the SSE ready, and checks after each changed event. A single monotonic deadline starts when the initial snapshot has no eligible task; unrelated project changes and keep-alives do not extend it. At the deadline it reads once more, returning a task if one arrived at the boundary, otherwise idle_timeout with exit code 0.
The selector uses ordered_tasks, the same ordering as the progress table: epics sorted by ID, each epic's saved task priority and then task ID, followed by ungrouped tasks by ID. It returns one AI-owned Todo or Doing task whose run state is Idle, provided it is not a draft or archived. The initial read means tasks created before listening are eligible. The result contains the snapshot cursor, the task, its local TASK.md path, and its EPIC.md path when it has an epic. Selection is read-only and does not claim a task; callers must re-read its state before acting. The listener procedure checks the complete snapshot first and resolves any existing AI work in running or pending; an idle task in Doing is eligible to resume. A timeout is a normal idle result, while a read defect, unavailable server, or deleted project remains an error.
For one-session orchestration, the agent-board listener procedure describes task enrichment, approval checks, Pending answers, sequential work, and interruption recovery. A Pending task blocks that session until its existing request is answered; listener mode does not skip it or treat its time as idle.
Automatic Done
The rule is defined in Data model. Evaluation works like this:
- It re-reads the latest
TASK.mdand task fields under the FileStore project lock and applies one shared eligibility check. serveevaluates existing tasks at startup, before publishing the first snapshot. During operation it evaluates after FileStore saves and after atomic file updates seen by the watcher. It never re-triggers from its own notification, and re-evaluating the same task never duplicates history.- A CLI edit that also changes the epic is evaluated after all changes apply. AI-facing CLI and FileStore entry points apply the Done guard.
- Pending tasks are skipped and re-evaluated after the answer. Done tasks never reopen automatically.
- Agents record verification in history, put concise results in the body, and only then set the last condition to
done: true. - Starting a new version of
servecompletes existing eligible tasks. Before adopting it for normal use, list those tasks and take a backup.
This restrains cooperative agents; it does not authenticate against direct file edits or a spoofed actor.
Sample cards of the first-run guide
The first-run guide creates two sample cards. Each carries an onboardingSample identity, which holds the run ID and the ordinal (1 or 2). The progress table, the hook, and wait --until task leave out every card with this identity, whatever its lane or run state, so an agent never picks one up.
Only the guide writes the identity. Create and edit requests have no field for it, and moves, history updates, archiving, and restoring keep it. The board still shows the cards. For what the user sees, see Before you start.
Preparing access with setup
agboard setup adds the Agent Board data area to the agents' allowed folders so they can edit shared files. It is a one-time step the user runs; it never creates projects or registers hooks.
How it is built:
- It branches before normal store handling and resolves the data area once through the shared path resolution.
- Environment and path resolution, the change plan, Codex TOML editing (
toml_edit, preserving comments, other keys, and arrays), Claude Code JSON editing (preserving unknown keys), and backup and apply are separate steps. The change plan holds each file's original and updated content; dry runs use the same validation. - It never switches permission modes or managed settings. It checks whether the change is possible under the current scheme, validates every target before writing, and confirms originals did not change meanwhile. Writing a file is reported separately from an agent loading it.
When something fails:
- Invalid JSON or TOML, an unsupported permission scheme, or a concurrent change stops setup before anything is written, with the target, reason, and next step.
- Each file to change is backed up to a unique file in the same folder, then replaced from a temporary file. Unchanged files are neither backed up nor written.
- If a run fails partway, only what that run wrote is restored, without overwriting external changes. If restoring is impossible, the run is not reported as complete; it states what changed and where the backups are.
- Symbolic links are resolved and the real file is edited. Unresolvable paths stop setup instead of guessing.
- A dry run creates no folders, settings files, or backups. Setup never changes old data or a running server's notification target.
What it may and may not grant is part of the Security model.

