Skip to contentSkip to Content
GuidesOperating a board

Operating a board

The contract for moving a board without breaking it: the session protocol, and every rule with the reason it holds. This is the page an agent reads before it touches board/.

folio-agents board init writes board/SKILL.md into the project that owns the board, giving agents an in-repo entry point even when they have not opened the published docs. Any agent follows the same steps, whether Claude Code, another framework, or a human with an editor; git is the only backend.

How an agent finds this

Nothing installs this protocol. An agent arrives at it by one of three paths, each of them an ordinary file.

  • board/SKILL.md, in the checkout. folio-agents board init writes it with a skill preamble: a name, and a description naming when it applies. The preamble is the shape skill-reading runtimes recognize, but those runtimes scan their own directories, not board/, so today an agent reaches this file because something points at it: a line in the repository’s agent instructions, or whoever opened the session. Folio registers the file with nothing: it calls no runtime and knows of none.
  • The published guide, when configured. The optional Folio Docs adapter can include these pages and the board in an agent-readable static site.

What init scaffolds is a starting point, not the contract: how to read the board, four commands, five rules, and a closing line sending the reader to these pages for the card schema and the validation rules. It is meant to grow with the project.

The checked-in skill remains canonical even when a site publishes a copy.

Session lifecycle

Start

Move your card into the working column before the feature work begins.

folio-agents board move my-card in-progress --commit

During the session

Ordinary code commits. The board stays untouched.

End of session

  • Append one trail line to every card you touched, with the commit sha or PR number as the ref.
  • Move cards whose state changed.
  • Commit work outputs (research, analysis, designs) into the card’s own directory, board/cards/<id>/. The files at its top level are the card’s artifacts, derived at build: Markdown compiles into site pages, other files publish verbatim, and each one opens on the served board. Attaching by hand is for labels and for what is not a file (pr:, url:, api:); a sibling’s target is its bare name. A doc: elsewhere opens only when a docs source publishes that page; anything else validated-but-unpublished is shown as its path.
  • Run folio-agents board check before committing. It is the standalone board gate; the optional Docs adapter consumes the same loader.
folio-agents board trail my-card --note "loader landed" --ref abc1234 --commit folio-agents board move my-card done --commit folio-agents board attach my-card --doc loader-analysis.md --label "Loader analysis" --commit folio-agents board check

What a session leaves behind

The card’s directory, board/cards/<id>/, is the session’s workspace, and because the build publishes it, what a session produced is readable from the board rather than only from a clone.

board/cards
loader.md
loader
├── brief.md
├── variant-a.html
├── variant-b.html
├── comparison.md
├── variant-a
│ └── styles.css
└── .verify
└── screenshot.png
  • One file per output. A brief is a file, a comparison is a file, each prototype is a file. One notes.md accumulating a whole session is not something a later reader opens twice.
  • The top level is the band on the card. Every file at the directory’s top level is an artifact, derived — so curation is placement. What a later reader would open sits at the top level; supporting material (a prototype’s stylesheet, its data) goes in a subdirectory, which still publishes but is not listed.
  • Scratch stays out. Screenshots from a verification run, throwaway scripts, downloaded fixtures: those go outside the board entirely, or into a dot-directory inside the card’s own (.verify/, .cache/), which the build leaves behind. A _-prefixed file stays in the bundle but off the band and out of compilation.

When a decision needs looking at rather than arguing about, keep a brief stating the problem and the rules, one file per variant, and a comparison that says what each variant is bad at. Those files publish from the card’s directory and open from the card’s page.

Compiled card documents are meant to be read inside the board, not as standalone documentation pages. A direct visit to a compiled artifact page (e.g. /docs/kanban/cards/<id>/review/) is automatically redirected into the board reader with the card and artifact already open. The page is also marked noindex so search engines index only the board itself, not the individual working papers.

The build enforces little here: a doc: or file: target that resolves to no file warns at build and check, naming the card and the path, and a directory whose card is missing is reported. Whether the card owns the path decides only whether the artifact opens. Everything above is convention. No build fails because a card directory is one long notes.md.

Two-stage artifact work

Artifact generation uses exactly two compact stages:

Review

Create standalone candidates in one owning card’s directory and present their links without changing product files.

Integrate

Start only after explicit owner confirmation, apply the selected direction to the product, and validate it.

Between stages, retain only the objective, confirmed decisions, open choice, canonical artifact links, and validation state. Generation transcripts, rejected detail, and repeated file contents are not durable project memory.

Condense artifact context

An agent using the board skill recognizes this maintenance directive:

condense artifacts <card-id>

It is not a shell command or Folio CLI surface. It replaces verbose artifact-related working context with one compact checkpoint containing the five fields above. The scope is exactly one permanent card id: the agent may read only cards/<id>.md and cards/<id>/. It must reject all, ., paths, globs, multiple ids, a missing card, or any attempt to widen the operation.

Condensing context never edits, moves, or deletes files. A durable change found during maintenance is a separate operation and still requires explicit owner confirmation.

Say where it lives

Every operation ends with a report the human can click. Never announce an outcome without linking what it produced.

Before the handoff, open or request every rendered artifact URL and verify it responds successfully. A repository path or local filesystem path alone is not an artifact notification.

  • The card file. board/cards/<id>.md is the permanent home of the plan; link it every time you create or change a card.
  • The served board. The card is on /kanban/, and /kanban/?q=<filter> narrows it to what you are reporting on: /kanban/?q=status:in-review tag:spec is a link to exactly the cards you just described. The filter is one expression, and ?milestone=<v> still works on its own.
  • Every artifact you attached from the card’s directory. Markdown opens at <docs route>/kanban/cards/<id>/<stem>/; raw files open at /_folio/kanban/<id>/<file>. Link the rendered page, not the repository path.

The report contract

“Card created” is an incomplete report. The contract is: “Card created: board/cards/<id>.md — on the board at /kanban/.”

Readable artifacts

The first screen answers what changed, what it means, and what is next. Headings are claims with the number in them. Tables keep three columns or fewer in the card reader. One component per idea; never a chart followed by a table of the same rows. Raw data is linked, never inlined. An artifact stays under about 150 lines or splits by purpose (status, measurements, architecture, next steps, history). Finished work is written in the past tense, proposed work in the present. The card status is the only place that says whether the task is in progress.

One logical operation, one commit

Every board commit touches only board/ and carries a conventional message. The CLI’s --commit flag produces these automatically, scoped to the board directory — unrelated staged changes are never swept in. The message for each operation is listed under --commit.

Editing by hand (no CLI required)

The format is plain files; any editor works, under the same rules the CLI enforces:

  • Move a card: change the status line to another column id.

    - status: backlog + status: in-progress

    That is the whole move: a one-line diff.

  • Add a trail line: append it as the last line of the ## Trail section, never at the top (create the section at the end of the file if missing).

    - 2026-08-24 @claude (abc1234): loader landed; moved to in-progress
  • Create a card: copy cards/_TEMPLATE.md to cards/<slug>.md. The filename must be a lowercase slug and is permanent — it is the card id.

  • Lists are hand edits by design: tags, blocked_by, and removing an artifact or trail line are one-line edits in the file; the CLI does not do them.

Rules, and why they hold

RuleWhy it holds
Never edit agents.yaml during a sessionIt is the board’s control plane; only init writes it, and write commands read it only to resolve board.source
board.yaml is human-ownedColumn changes are topology; a human asked for them or they don’t happen
Never rewrite other cards’ files in your commitOne card, one file is what makes conflicts structurally impossible
Omit order unless placement was requestedOrdering is computed; ranks are the exception, never bulk-renumbered
Appends go at the section endTail appends make concurrent-session conflicts mechanically resolvable

How the CLI edits files without destroying your formatting is covered in the CLI reference; why prose warns and topology fails, in Board formats.

A static board never writes card files; it captures intent. A drag stays in the browser until you export it as a list of folio-agents board move commands, which run through the validating CLI. A live board writes through folio-board-server, which checks the whole board and makes one commit per save; see Edit the board in the browser. Either way every change is an ordinary git commit on the board branch.

Merge conflicts

Conflicts are rare by construction: one card is one file and there is no shared index, so two sessions editing different cards can never conflict. Only two shapes exist, both with mechanical resolutions.

Both sides moved the same card:

<<<<<<< HEAD status: in-progress ======= status: done >>>>>>> feature/loader

Resolution: read both sessions’ trail lines and keep the column that reflects reality after both, done here if the other session’s trail line records the work landing. Keep both trail lines.

The second shape is both sides appending a trail line to the same card. Keep both lines, ordered by date.

Never use a union merge driver

A silent both-sides merge of a status edit corrupts the frontmatter.