How Agent Board works
Start here. This page gives you the mental model: what runs, where the data lives, and how one change travels from an agent to the browser. The other concept pages go deeper into each part.
The big picture
Agent Board is a single Rust executable, agboard. The same binary is the CLI that agents and people run, and the web server (agboard serve) that shows the board in a browser.
There is no database. Every project lives as plain files in the shared area, .agent-board/shared/ in the user's home directory (or under AGBOARD_HOME). Markdown holds what people and agents write: task bodies, acceptance conditions, history, and epic details. JSON holds the operational state: lanes, run states, and open questions. Because the files are the source of truth, agents may also edit TASK.md and EPIC.md directly, and the server notices.
Reading and writing data
The CLI and browser read and write the same local files. Task state is stored in task.json, bodies, acceptance conditions, and history in TASK.md, and epic details in EPIC.md.
Agents use commands such as agboard add, mv, and state; users work in the browser. Users run rm and init in the CLI for deletion and resets. TASK.md and EPIC.md can also be edited directly, and the server detects the changes. CLI saves use locks and temporary-file renames.
Change notifications
The CLI notifies the server through POST /api/notify; direct file edits are detected through OS change events. The server reloads the changed project, and when the data a screen shows has changed, it sends SSE: changed with the changed resources. Browsers then read the Summary again and only the open details that changed.
From a change to the screen
The server never sends the data itself in the notification. It sends the names of what changed. The browser then reads what it needs, and keeps the result in a cache.
- Summary. Every card and list row is drawn from the project's Summary. It holds no body text, so the board loads quickly, and a change to one task does not re-read the bodies of the other tasks.
- Detail. The body, acceptance text, and history are read only when a card or an epic is opened. The browser stores each section by its version.
- SSE. One
changedevent names the tasks, epics, and facets that changed, with aninstanceIdand aseq. A gap inseq, or a newinstanceId, tells the browser to drop its cache and read the Summary again. - Cache. The browser holds the Summary of the last four projects and a limited number of Details, least recently used first. A change never updates the cache from the notification alone: the browser reads the data again.
Mobile monitor
A phone browser reaches the read-mostly monitor through an ngrok tunnel that runs inside serve. You start it from Settings or with agboard serve --monitor ngrok; the exact public Host and a 4-digit passcode made for each start guard it. The tunnel forwards to a dedicated loopback entry. That entry uses the same FileStore, file watcher, and notifications as local access. See The mobile monitor.
Project docs
Each project also has a docs/ folder for the user's own documents. It sits inside the project's folder but is kept apart from the board: it is not part of the version, and a change in it sends the SSE docs event, never changed. The browser only reads these files, through routes of their own; the user edits them in their own editor. See Change notifications and Security model.
Design principles
Three ideas run through the whole design:
- Every operation names its project. Projects are identified by an immutable ProjectId, and commands never guess the target from the working folder or a selection. Folder bindings exist only to help the hook find the right project.
- A task is saved as a pair.
task.json(state) andTASK.md(body, conditions, history) are committed together under a lock, so nobody ever sees one without the other. See Storage and consistency. - The server is a cache, not an owner.
servekeeps an in-memory index for fast reads, but the files decide. If the server is stopped, the CLI still works; when it starts again, it reads the files.
Follow one change
An agent moves a task
When an agent runs agboard --project demo mv 12 doing --actor ai:
- The CLI resolves the project by name to its ProjectId.
- It takes the project's write lock (
.internal/write.lock), waiting up to 5 seconds. - Under the lock it re-reads the latest
task.jsonandTASK.md, checks the rules (for example, that an AI may not move this task to Done while conditions are unmet), and computes the new state and a history entry. - It saves both files as one pair through a journal, then releases the lock.
- If something actually changed, it reads
serve.jsonand sendsPOST /api/notifyto the running server. If no server runs, that is fine. - The server reloads the project, sees that the data changed, and sends SSE
changedwith the changed tasks and facets to every browser. Each browser reads the project's Summary again and re-fetches only the open details that changed.
A person answers a question in the browser
- The browser sends
POST /api/projects/{projectId}/tasks/{id}/answerwith the request ID and the chosen option, plus the write token embedded in the page. - The server checks Host, Origin,
Sec-Fetch-Site, and the token before it even looks up the task. - Under the write lock it confirms that the task still has the same open request, stores the answer in
requestAnswers, clears the request, appends history, and commits the pair. - The version changes, browsers update through SSE, and a default-waiting
state ... pending --request-jsoncommand wakes on the same SSE stream and reads the answer. The command saves the request, notifies the server, then waits; its wait settings are process-local.--no-waitreturns after saving and notifying.
An agent edits TASK.md directly
- The editor writes the file. No lock is involved; the last save wins.
- The server's file watcher receives an OS event and waits 200 ms for related events.
- It reloads the project, re-evaluates automatic Done for eligible tasks, and, if the data changed, notifies browsers and waiting agents.
Where to go next
- Follow your first change: trace one rule from the command to the file and its test.
- Tasks and states: what a task is and which states are valid.
- History and decisions: history, Pending, and automatic Done.
- Saving and recovery: locks, atomic saves, and failures.
- Change notifications: how a change reaches browsers and waiting agents.
- Server and web UI, Agent integration, The mobile monitor, and Security model.
- Code map when you need to find a file.

