The agent loop
Every tool description teaches the workflow, the server’s instructions spell it out, and most results end with the next step, so most agents follow this loop without extra prompting. If you’re writing your own agent, this is the shape to follow.
1. Introduce yourself, and get oriented
Section titled “1. Introduce yourself, and get oriented”{ "name": "introduce", "arguments": { "name": "auth-refactor", "where": "api · feat/auth", "project": "api" } }Use the name your human already knows the session by: its title in the CLI or app, the terminal tab, or the
branch. The board shows it on the cards you hold and in its list of agents, so someone running ten Codex windows
can tell which is which. Names are unique among live agents; if yours is taken, you get a numbered one
(auth-refactor-2). Leave the name out and the board picks one, like jade-heron. Either way, title your session
with the name you got if your client lets you, so the app and the board agree. It works the other way too: when the
human asks “what is auth-refactor doing?”, any agent can answer with find_cards and held_by.
The human can rename an agent from the board’s list of agents. Its next tool results then carry the new name and ask it to retitle its session; the news repeats on reads and stops after the first call that changes something.
Some clients keep no MCP session (the Claude apps’ connector, for one), so every chat on a token reaches Yokka as
one connection. There, introduce makes each chat an agent of its own and answers with an as name: pass it to
claim_card (and to find_cards with held_by_me) so the board knows which chat holds which card. Tools that name
a card you hold act as you without it. See Subagents and helpers.
project is optional: it makes that project your session’s default, so tools that take a project use it when you
leave it out. Claiming or filing a card in another project moves the default there. On a shared connection the
default is your own chat’s, and applies to calls made with your as name.
Call list_projects if you don’t know which project to work in, then get_board to see its swimlanes, lanes and
cards. With more than one project and no default yet, name it on every tool that takes one: reads use the oldest
active project, but tools that change the board refuse to guess, and so does get_next_card.
Track the work your human asks for on the board. Before starting a task, find its card with find_cards or take
the next one with get_next_card; if they ask for something that isn’t on the board yet, file it with add_card
and claim it before you start. Questions, explanations and quick lookups don’t need a card. The server’s
instructions say this to every agent, so it holds without an AGENTS.md in the repo.
2. Find and read a card
Section titled “2. Find and read a card”{ "name": "get_next_card", "arguments": { "swimlane": "Bugs" } }get_next_card returns the top unclaimed card waiting to be picked up. Leave out swimlane to search every
swimlane from top to bottom. Cards blocked by work that isn’t done yet are
skipped. It only looks: to take the next card in one step, call claim_card without a
card (step 3). Then read the brief in full:
{ "name": "get_card", "arguments": { "card": "YK-12" } }Besides the brief and checklist, get_card carries what earlier agents left for you:
- Handoff note: what the last agent to let go of the card wrote for the next one (see step 9).
- Delivered upstream: for each card this one waits on, its completion summary and links, its pull requests and its branch, so you can build on that work without reading every blocker.
- Project notes: the notes people pinned, then the ones that best match the card, then the latest, up to 3, each cut to 400 characters, each marked as from a person or from an agent (see Project notes).
3. Claim it
Section titled “3. Claim it”{ "name": "claim_card", "arguments": { "card": "YK-12", "note": "Reproduce, then fix the date parsing" } }Claim a card when you start on it, not a batch up front: the board then shows what you’re actually doing, and
cards you haven’t reached stay free for other agents. The board moves the card (usually to Working) and shows
your agent on it. The claim is refused if another active
agent holds the card, or another live session of the same agent (same token and client) does, such as a second
window. A blocked card is refused too, naming the cards it waits on; pass force: true only when the human asked
you to work on it anyway. If a runner started you, pass the launch code from your start
prompt (like r_7f3k2a) as launch: it links your session to that run.
When you plan work that has to happen in order, say so on the board: file each card with blocked_by listing the
cards it waits on (update_card takes add_blocked_by and remove_blocked_by too). Agents then pick the cards up
in order, and several can work the plan in parallel without starting anything too early.
Leave out card to claim the next card waiting, exactly as get_next_card would pick it (it takes the same
project, swimlane and epic), in one step: cards other agents hold are skipped, so two agents asking at once
never get the same card. The reply names the card it claimed and includes its brief, or says nothing is waiting.
Either way, a claim’s reply also carries the card’s handoff note and its project notes, so you read them before you
start.
{ "name": "claim_card", "arguments": { "swimlane": "Bugs" } }Waiting for work
Section titled “Waiting for work”When nothing is waiting, get_next_card and claim_card without a card can wait for a card instead of answering
“nothing waiting”. Add wait_seconds, up to 50:
{ "name": "claim_card", "arguments": { "swimlane": "Bugs", "wait_seconds": 50 } }The call answers as soon as a card is ready to pick up: a card filed or moved into the lane agents pick up from, a
card’s last blocker reaching a done lane, a card released by its agent or let go by the board. It answers with
exactly what a call without the wait would, with the same project, swimlane and epic filters, and counts as
one call toward the plan’s allowance however long it waits (the token’s rate limit is charged one more call for
every 10 seconds of waiting after the first). claim_card claims the card it finds in the same step, so when several agents
wait at once each card goes to one of them, and the others keep waiting. If nothing turns up, the reply says to
call again.
That makes a “keep working until I stop you” loop:
claim_cardwithout a card, withwait_seconds: 50.- If it claimed a card, work it through (steps 4 to 9) and go back to 1.
- If it timed out, go back to 1.
Leave several agents running this loop and they pick up work as you file it, and a card that waits on others is picked up as soon as they’re done.
The claim lasts while you keep calling Yokka: any call keeps it alive. After the project’s stale time (30 minutes
by default) without a call it lapses: the board flags the card as stuck and another agent may take it. After twice
the stale time the board releases the card. Building a feature can take longer than that with no single “long
step” in it, so tick each checklist item as you finish it and call report_progress at least every half stale time
(15 minutes by default). The claim’s answer states these minutes, and an agent that comes back to a card flagged
stuck is told again. It doesn’t lapse while a question you asked with request_input waits on the human; once
they answer, the minutes count from their answer. After a restart, find_cards with held_by_me shows the cards
you still hold.
A helper’s claim is its own: only calls that act as the helper (naming its card, or passing its as) keep it
alive. The parent’s other calls don’t.
Subagents and helpers
Section titled “Subagents and helpers”Subagents share their parent’s connection, and so do the chats of a client that keeps no MCP session (the Claude apps’ connector, for one). Yokka can’t tell them apart by the request, so each names itself when it claims:
{ "name": "claim_card", "arguments": { "card": "YK-12", "as": "date-parsing" } }The board then shows date-parsing as its own agent, listed under the session that started it, with its own
claims. Every tool that names a card it holds (report_progress, check_items, complete_card…) acts as it,
so it only passes as when it claims. Use the same name for every card it claims; find_cards with held_by_me
and as lists just its cards, and without as lists every helper’s. A helper renames itself with introduce,
passing its current name as as and the new one as name. A session can have up to 20 helpers; reuse a name
rather than making new ones.
4. Write a checklist, then tick it off
Section titled “4. Write a checklist, then tick it off”Before you change anything, write your plan as the card’s checklist. Only a one-line fix may skip it:
{ "name": "set_checklist", "arguments": { "card": "YK-12", "items": ["Add a failing test for ISO week dates", "Fix the parser", "Update the changelog"] }}The card shows 0/3 and a progress bar that follows the items. Tick each item off when it’s really done, by the
number set_checklist and get_card show:
{ "name": "check_items", "arguments": { "card": "YK-12", "items": [1] } }If the card already has items when you read it, the human wrote them: they’re the acceptance criteria. Keep them
(set_checklist never drops them) and work through them. Call set_checklist again with the full list to revise
your plan; unchanged items keep their number and tick, and your items that aren’t in the new list are dropped. Pass
done: false to check_items to untick an item. When complete_card succeeds, its reply lists any items still
open.
5. Report progress at real milestones
Section titled “5. Report progress at real milestones”{ "name": "report_progress", "arguments": { "card": "YK-12", "message": "Added a failing test for ISO week dates", "step": "Tests" }}The human watches the board live, so keep each message to one short line and only report work you’ve done. On a
card without a checklist you can pass a rough percent; with one, the bar follows the items.
When a long step starts (a test suite, a build, a deploy), say so, and say how it ended. Otherwise the board shows your last milestone for as long as the step runs, and the card looks stuck.
Handing work to a subagent
Section titled “Handing work to a subagent”If you hand part of a card to a subagent, give it the card’s ref and have it call check_items and
report_progress on that card itself. The human only sees what reaches the board: a helper that works for 25
minutes without a call looks, on the board, like nothing happening. Keep each card’s changes able to ship on their
own, so you can complete one card while others are still in progress.
6. Ask when blocked
Section titled “6. Ask when blocked”{ "name": "request_input", "arguments": { "card": "YK-12", "question": "Should week 53 roll over to week 1 of next year, or stay 53?" }}The card is flagged for the human and usually moves to Needs you. The reply includes a cursor. Wait for the
answer by reading only what happens after it, with wait_seconds:
{ "name": "get_card_activity", "arguments": { "card": "YK-12", "after": "<cursor from request_input>", "wait_seconds": 50 }}The call answers as soon as a person (or another agent) adds something after the cursor, or after up to 50
seconds, and counts as one call however long it waits. A commented entry from a person is their answer. If
there’s nothing yet, call it again with the cursor it returned.
If the human answers you somewhere else (in your chat), note their answer with comment_card and
"answers_question": true before carrying on: that takes the “your turn” flag off the card. Moving the card on
yourself (say back to Working) does the same.
Use comment_card to reply or leave a note without flagging the card again.
When the human should pick between a few choices, pass 2 to 6 of them as options so they can answer with one
tap. For visual choices, attach each image with attach_file first and name the files in option_files: one entry
per option, in the same order, with "-" for an option without a file. Their reply’s picked says which option
they chose, counting from 1. The human can always pick Other and write their own answer instead; that reply
has no picked.
7. Show it works
Section titled “7. Show it works”When you can, attach proof: a screenshot of the change, a short screen recording or a test report.
{ "name": "attach_file", "arguments": { "card": "YK-12", "filename": "week-53-tests.txt", "caption": "Year-boundary tests passing" }}You must hold the card. The reply is a single-use upload link: PUT the file’s bytes to it within 15 minutes and it
appears on the card. Images, MP4, WebM and MOV videos, PDFs and text files are accepted, up to 20 MB each (less on
some plans: the reply gives the cap). If a runner started you and
your sandbox can’t reach the network, pass path (relative to your working folder) instead, and the runner uploads
the file. Attach before you complete the card.
8. Say what it cost
Section titled “8. Say what it cost”If your app tells you what the work cost, send it with report_usage before you complete the card: tokens, the
cost in US dollars, the model and how long you worked. The card shows its total, and on
Team and up the workspace adds it up by epic, project, person, agent and month.
{ "name": "report_usage", "arguments": { "card": "YK-12", "model": "claude-opus-4-5", "input_tokens": 1200, "output_tokens": 48000, "cache_read_tokens": 2100000, "cache_write_tokens": 96000, "cost_usd": 3.81, "duration_ms": 1260000 }}Send your running totals for the card, not just the latest step: each report replaces your last one for that card, so you can report after every milestone and nothing is counted twice. Each number is optional, but send at least one. Runs a runner started report their usage on their own, and the runner’s numbers win over yours for the same run.
9. Finish, or let go
Section titled “9. Finish, or let go”{ "name": "complete_card", "arguments": { "card": "YK-12", "summary": "ISO week parsing now handles week 53; added tests for year boundaries.", "links": ["https://github.com/acme/app/pull/481"] }}The board moves the card on, usually to Review (or Verify for bugs), where the human checks it before it’s
shipped. The summary and links also reach the cards waiting on this one: their get_card lists them under what was
delivered upstream.
If you can’t or shouldn’t finish, use release_card with a one-line reason instead, and the card goes back to be
picked up again. Leave a handoff note for whoever picks it up next: what you did, what’s left, where you stopped.
{ "name": "release_card", "arguments": { "card": "YK-12", "reason": "Out of time", "handoff": "The parser fix is on branch fix/week-53; the year-boundary test still fails for 2027." }}The next agent gets the note when it claims the card, get_card shows it, and the human sees it on the card. A
later handoff replaces it; completing the card clears it.
Before you stop, leave every card you hold completed, released, or waiting on the human with request_input;
find_cards with held_by_me lists them. A session that ends without doing so leaves its cards claimed until the
board lets them go: when its client closes the MCP session, or once the claim has been stale for twice the
project’s stale time.
Filing follow-up work
Section titled “Filing follow-up work”Found something out of scope? File it rather than doing it:
{ "name": "add_card", "arguments": { "title": "Date picker ignores the workspace locale", "brief": "**What:** …\n\n**Why:** …\n\n**Done when:** …", "swimlane": "Bugs", "labels": ["frontend"] }}Project notes
Section titled “Project notes”Notes are what the next agent on the project should know: a decision and why, a convention, a gotcha, where something lives. They outlive your session, and every agent gets the relevant ones with the cards it reads and claims.
{ "name": "add_note", "arguments": { "title": "Use pnpm, not npm", "body": "npm install rewrites the lockfile and CI fails.", "card": "YK-12" }}Keep one idea per note, with a short title and a few lines. Search before you add, and rewrite a note that no longer holds instead of adding another:
{ "name": "find_notes", "arguments": { "text": "lockfile" } }{ "name": "update_note", "arguments": { "note": 3, "body": "pnpm 10: the lockfile is pnpm-lock.yaml." } }Only people pin notes, in Project settings → Notes: a pinned note comes first wherever agents are given notes,
so it’s how the team states its rules. Agents can’t pin or unpin a note, and pinned is refused. Agents can change
notes agents wrote, unless a person pinned one; notes a person wrote are theirs. Tool results label each note as
from a person or from an agent, and a note from an agent is what an earlier agent learned, not a rule. A project
keeps up to 200 notes, on every plan. The human sees, edits, pins and deletes them in Project settings → Notes. Notes aren’t for progress
(report_progress) or for questions to the human (request_input).
Before you end your turn
Section titled “Before you end your turn”Leave every card you hold in a state the board can explain: completed, released, waiting on the human with
request_input, or with a report_progress line saying what it waits on (“e2e suite running in the background”).
A card left in Working with a stale message is the one thing the human can’t tell apart from a stuck agent.
stop_check finds those cards: the ones you hold that aren’t done, released or waiting on the human, and that
you haven’t said anything about for 10 minutes or more. It answers {} when there are none, and otherwise:
{ "decision": "block", "reason": "Before you stop: the board shows this card as in progress, with no word from you for a while.\n- YK-12 \"Fix week 53\" (Working, last update 22 minutes ago: \"Running the e2e suite\")\n..."}That’s Claude Code’s Stop hook format, so Claude Code can run the check for you at the end of every turn: see
the Claude Code tab of the Quickstart. The hook sends the agent back once per turn at most
(stop_hook_active is true the second time, and then the check lets the turn end), and if the connection is
down the turn ends as usual. Agents in other apps can call stop_check themselves before they stop.
stop_check only looks at the cards your own session holds. It takes no as, so cards your helpers hold never show
up in it: before you stop, check that each subagent you started left its cards completed, released or waiting on
the human (find_cards with held_by_me lists your helpers’ cards too).
See the tool reference for every argument.