Follow your first change
This tutorial traces one existing rule through the code, from the command to the file to its test, so that you learn where things are before you change something. The rule: an AI agent cannot move a task to Done while an acceptance condition is unmet.
You need a working build. If you have not built Agent Board yet, start with Set up and run.
1. See the rule in action
Use a temporary board so that your own board is untouched:
export AGBOARD_HOME="$(mktemp -d)"
cargo run -- project create demo
cat > /tmp/demo-task.md <<'EOF'
---
acceptance:
- id: AC-1
text: The list is returned as JSON.
done: false
history: []
---
Return the list as JSON.
EOF
cargo run -- --project demo add "List as JSON" --assignee ai --actor ai --desc-file /tmp/demo-task.md
cargo run -- --project demo mv 1 doing --actor ai
cargo run -- --project demo mv 1 done --actor aiThe last command fails with acceptance_unmet and names the unmet condition. Run it again with --actor human and it succeeds: the rule restrains agents, not people.
2. Find the command
Every command lives in src/cli/commands/. Open mv.rs. It resolves the project, builds a ChangeContext (the actor and the reason), and calls files.move_work_task(...). It does no checking of its own. The rules live below the CLI so that the web server and the CLI share them.
3. Find the rule
move_work_task is in src/file_store/ops/agent.rs. Read the function in order:
- It takes the project write lock (
lock_project), because everything after this point must see the latest files. - It reads the task strictly (
read_task_strict); a task with a defective file is refused here. - It refuses archived tasks and Done tasks for AI actors.
- This is the rule: when the actor is
Ai, the target isDone, and the task is not Done yet, it callsensure_acceptance_met. That function returnsAcceptanceUnmetwith the unmet conditions. - Only then does it build the history entry, update the fields, and call
save_task, which commitstask.jsonandTASK.mdas one pair (see Saving and recovery).
Notice what is not here: no printing and no JSON. The error carries a code (acceptance_unmet), and src/error.rs turns it into the message, the exit code, and the HTTP status. See Error codes.
4. Find the test
The CLI behavior is tested in tests/acceptance_cli.rs. Find an_agent_cannot_move_a_task_to_done_while_a_condition_is_unmet. Tests run the real binary against a temporary AGBOARD_HOME, which is why they never touch your board.
Run just that file:
TZ=UTC cargo test --test acceptance_cli5. Change the rule, test first
Suppose a person also had to confirm Done when conditions are unmet. A real change would follow this order:
- Write a failing test in
tests/acceptance_cli.rs(copy the test for a person moving a task and change its expectation). - Change the condition in
move_work_task. Because the web server calls the same function, one change covers both entry points. - Run
TZ=UTC cargo test --test acceptance_cli, then the whole suite. - Update the page that describes the rule. This one is in History and decisions, and its Japanese translation in
docs/ja/dev/.
You do not need to make this change; the point is the path: command → shared rule in file_store → error code → test → documentation. Almost every change in Agent Board follows it.
Where to go next
- Tasks and states for the model behind the rule.
- Verify and open a pull request for the checks to run before you finish.

