Skip to content

wfa ​

wfa is the agent's command. An agent runs it in its own session, from its shell, to hand back its answer, call your tools and message its peers. You never type it, and your workflow never mentions it: every turn's prompt teaches the agent the commands that turn can use. Read this page to know what an agent can do in a run, and what it is told when something is refused. How it works shows where wfa fits.

The agent runs wfa by a full path, the launcher awf installs for that agent when it opens. The launcher holds the agent's connection to the run, so the connection, not anything the agent types, says which agent is calling. Run without the launcher, wfa exits 2. Prompts show the path, and this page shortens it to wfa.

text
usage: wfa result <call-id> --<name> '<value>' ...
       wfa result <call-id> <<'WF_JSON'
       <json>
       WF_JSON
       wfa tool <name> --<option> '<value>' ...
       wfa tool <name> <<'WF_JSON'
       <json>
       WF_JSON
       wfa waiting <call-id> --reason <text> [--timeout <duration>]
       wfa peers [--json]
       wfa send [--await-reply [--timeout <duration>]] <peer> <<'EOF'
       <message>
       EOF
       wfa reply [--await-reply [--timeout <duration>]] <peer> <<'EOF'
       <answer>
       EOF

Common to every command ​

  • Exit 2 is a usage error: an unknown command, a missing call id, peer or tool name, standard input over 1 MiB or not closed within 30 seconds, or, for waiting, peers, send and reply, a flag the command doesn't take. Nothing reached the run. The usage is printed to standard error. result and tool pass their flags to the run, which reads them by the schema: an unknown flag is refused invalid-result or invalid-input.
  • A duration is a positive decimal and s, m, h or d: 90s, 1.5m, 10m, as in a workflow.
  • wfa never sends a request twice. When the answer to a request is lost, it says so, and says whether the request may have taken effect.
  • While the agent owes a peer a reply or awaits one, an answer leads with a line saying so, such as wfa: you owe reviewer a reply (wfa reply reviewer)., so the agent gets it back after its harness compacts the conversation. wfa tool puts that line on standard error, keeping standard output for the result; wfa peers says it in its table instead.
  • Every command but wfa tool waits up to 30 seconds for the run's answer.

Any command can also be refused with one of these codes:

CodeMeaning
invalid-requestThe request was malformed: not one line of JSON, or a field of the wrong shape.
unsupported-versionThis wfa and the run's engine are different versions of awf, as when awf is installed anew while a run is live; the error names both wire versions, and nothing was done.
unsupported-commandThe command isn't available here, such as wfa waiting on a turn that doesn't offer it.
request-too-largeThe request is over the run's size limit, about 2 MiB.
internal-errorThe run couldn't record or answer the request, or had 64 connections open; try again later.

wfa result ​

Hands back the turn's answer. Every turn that asks for an answer uses it; the prompt names the call id and teaches the fields. Agents covers typed answers and when the fields are taught as flags.

sh
wfa result <call-id> --verdict 'approve' --notes 'Tests pass.'
wfa result <call-id> <<'WF_JSON'
{"verdict": "approve", "notes": "Tests pass."}
WF_JSON
wfa result <call-id>
  • As flags, when the answer's schema is an object of 1 to 6 fields, each a string, number, integer, boolean or enum, with a lowercase name. --name 'value' and --name=value both work; a number or boolean is converted by its type. A flag the schema doesn't name, a flag given twice, or a value outside the taught range is refused with the usage line.
  • As JSON on standard input, in a quoted heredoc, for any schema.
  • With nothing, for a turn that asks for no fields.

Standard input is read only when nothing follows the call id.

ExitMeaning
0Accepted. The turn ends answered.
1Refused, with a code and what to do next; or the request failed on the way.
2A usage error.
RefusalMeaning
invalid-resultThe answer didn't fit the schema. The turn stays open; the agent fixes it and runs wfa result again.
unknown-operationNo open call has that id. Usually a mistyped id; the agent checks it and tries again.
wrong-agentThe call id is another agent's.
expired-operationThe turn's deadline passed.
closed-operationThe turn already ended.
owes-replyA peer asked this agent a question; it replies first, then runs wfa result again.
no-resultThe call id is a turn a message started, which takes no result: the agent replies if asked and ends its turn.
tool-runningOne of the agent's tool calls is still running; it runs wfa result again once the call answers.

A turn that awaits a peer's reply can still finish with wfa result; the wait is dropped.

wfa waiting ​

Says the agent is still on long work, such as a build, when it is nudged for its answer. It holds off the next nudge. It is offered only where the harness confirms what it was sent, a claude TUI agent today, and not a sandboxed one without a run-local home; elsewhere it is refused unsupported-command. In a claude TUI explains the nudge it answers.

sh
wfa waiting <call-id> --reason 'Running the full test suite' --timeout 10m
Flag
--reason <text>Required. Not blank, at most 2,048 bytes.
--timeout <duration>How long to hold off. Default 2 minutes, at least 30 seconds, and never past the turn's deadline.

A wait never moves the turn's deadline. The acknowledgement prints when the wait ends and the turn's deadline, if it has one, in Unix milliseconds.

While the agent awaits a peer's reply, wfa waiting changes nothing: it exits 0 and says the reply is already awaited, and a --timeout given with it is ignored.

Exits 0 when granted, 1 when refused or when the answer was lost (the wait may have been granted; nothing was retried), 2 on a usage error. It is refused with the same codes as wfa result, except invalid-result.

wfa tool ​

Calls one of the tools your workflow gave the agent, and prints what the handler returned. The prompt teaches each tool's name, description and input.

sh
wfa tool add_finding --file 'src/report.ts' --line '41' --problem 'formatDate is never called'
wfa tool label_item <<'WF_JSON'
{"id": "b2", "labels": ["ops", "cron"]}
WF_JSON
wfa tool list_findings

The input is given as wfa result's is: as flags for an input of up to 6 simple fields, as JSON on standard input for any other, or nothing for a tool without input.

The handler's result is the only thing on standard output: a string as it is, any other JSON value as JSON, nothing as nothing. Everything else goes to standard error.

ExitMeaning
0The handler returned; its result is on standard output.
1The call failed: the handler threw, or returned what isn't JSON or is over 64 KiB. The message is on standard error.
2A usage error.
3Refused, or never reached the workflow: the handler didn't run.
4The call timed out or was cancelled, or its answer was lost: it may have run, so check before calling again.
Refusal (exit 3)Meaning
no-operationThe agent isn't in a turn; a tool can be called only while it works on one.
result-acceptedThe turn's answer is accepted, so the turn is ending.
tool-busyAnother call of this agent's is running; it calls again once that one answers.
unknown-toolNo tool by that name; the refusal lists the agent's tools.
invalid-inputThe input didn't fit the schema. The refusal says what was wrong.

internal-error exits 4, since the call may have run. The other common refusals exit 3.

Time ​

wfa tool waits as long as the call takes. A handler has 30 seconds by default, or its own timeout, always within the turn's deadline; timeout: false leaves only the turn's deadline. When that passes, the handler's signal aborts; a handler that ignores it gets 5 more seconds, then the call ends timed-out and exits 4.

The harness may stop waiting on the shell command first. These are the harnesses' own limits, not awf's:

HarnessA long shell command
claudemoved to the background after 2 minutes
cursormoved to the background after 30 seconds
codexhanded back to the agent to poll after 10 seconds
pino limit unless the model sets one

An agent that then calls again with the same tool and input while the first call runs is given that call's answer, once. A call made after it ended runs the handler again.

Limits ​

Limit
Tools per agent16
A tool's namelowercase letters, digits and _, starting with a letter, at most 48 characters
A tool's descriptionnot empty, at most 1,024 bytes
A tool's input schemaan object, at most 8,192 bytes
One call's input, and its result as JSONat most 64 KiB each
Calls at onceone per agent
A handler's time30 seconds by default, then 5 seconds to settle after its signal aborts

The first four are checked when the agent opens.

wfa peers ​

Lists the agent's message routes.

sh
wfa peers
wfa peers --json

One row per route: the peer, what the agent can do on it, the peer's state, how many of this agent's messages the peer hasn't read yet, and the route's purpose. It ends with any reply the agent owes. --json prints the same as data:

json
{
  "peers": [
    { "peer": "architect", "can": "send", "kind": "agent", "state": "idle", "queued": 0, "purpose": "Design questions about the retry change" },
    { "peer": "coordinator", "can": "both", "kind": "participant", "queued": 0, "purpose": "Ask before merging" }
  ],
  "owes": []
}
FieldValues
cansend on a route from this agent, reply on one only to it, both either way
kindagent, an agent of the run, or participant, a participant outside the run, which has no state
statean agent's: not-started, working, idle, awaiting-reply (with awaits, whose reply), or stopped (with reason)
queuedthis agent's messages the peer hasn't read; always 0 for a participant
owesthe peers this agent owes a reply
awaitsthe peer whose reply this agent awaits, and until, when the wait ends, if it does

wfa peers takes no other flag. It exits 0, 1 when refused or failed, and 2 on a usage error.

wfa send ​

Sends a peer a message, or with --await-reply asks it a question. Messaging covers routes and when a message arrives.

sh
wfa send architect <<'EOF'
Retries are in; the client's timeout is now per attempt.
EOF
wfa send --await-reply --timeout 10m architect <<'EOF'
Should retries live in the client or the queue?
EOF
wfa send architect 'Retries are in.'

The message comes from a quoted heredoc, standard input, or one final argument; given an argument, standard input isn't read. Flags go before the message, before or right after the peer. A message that starts with -- goes in a heredoc. A heredoc's final newline is dropped.

Flag
--await-replyAsk a question: the peer owes a reply.
--timeout <duration>Only with --await-reply. Shortens the wait for the reply; it can't lengthen it.

wfa send returns once the message is recorded. The acknowledgement says when the peer reads it: when its current turn ends, now in a turn of its own if it is idle or hasn't run, or with the reply it awaits.

--await-reply doesn't block. The agent goes on with work that doesn't need the answer, then ends its turn; the reply starts its next turn. The wait lasts until the turn's deadline, if it has one, or the --timeout, whichever is sooner. An agent that finds the answer itself can finish with wfa result, and the wait is dropped.

Where --await-reply works:

HarnessHeadlessTUI
claudeyesyes, where the pane confirms delivery; not a sandboxed claude TUI agent without a run-local home
codexyesno
piyesno
cursornono

Elsewhere it is refused unsupported, and the agent sends without waiting and says where the answer should go, such as a file.

Exits 0 when sent, 1 when refused or when the answer was lost, 2 on a usage error. A message the run couldn't confirm may have been queued, and wfa says not to send it again; one that never reached the run says to try again.

RefusalMeaning
no-operationThe agent isn't in a turn.
no-routeNo route to that peer, or only one it can reply on.
peer-stoppedThe peer has stopped.
closedThe route closed when its stage ended, or the stage or workflow is finishing.
too-largeThe message is over 16 KB; the agent writes a file and sends its path.
already-awaitingThe agent already awaits a reply.
unsupportedIt can't await a reply where it runs.
cycleThe peer already waits, directly or through others, on this agent.
limitThe route has used its messages; or it has room for one more but not a question and its reply.
inbox-fullThe peer has 16 unread messages; try after its turn ends.

wfa reply ​

Answers a question a peer asked. Takes the same message forms and flags as wfa send; with --await-reply it asks something back.

sh
wfa reply implementer <<'EOF'
In the queue: the client is shared with the batch path.
EOF

An agent that was asked can't hand back its own answer until it replies: wfa result and wfa waiting are refused owes-reply. A turn a message started needs no wfa result: the agent replies and ends its turn. If it ends the turn still owing, it is reminded once; if it still doesn't reply, the asker is told there is no answer.

Exits as wfa send does.

RefusalMeaning
no-operationThe agent isn't in a turn.
none-owedThat peer asked nothing open, or was answered already; to message it, wfa send.
expiredThe peer stopped waiting, or stopped.
closedThe route closed, or with --await-reply, the stage or workflow is finishing.
too-largeThe reply is over 16 KB.
already-awaiting, unsupported, cycleAs for wfa send, only with --await-reply.
limitWith --await-reply, the route has room for the reply but not a question back.

Message limits ​

Limit
A message16 KB
Messages on a route, replies included40; a route's maxMessages can only lower it. A question counts its reply too.
A peer's unread messages16
A route's purposeone line, at most 200 characters
A turn a message starts15 minutes of its own, or less where a stage's deadline ends sooner; an asker waiting on its reply can lengthen it

See also ​