Appearance
Runner API
wfm run now starts a local attach API for the lifetime of the running process.
The attach API lets a UI or local client inspect run status, per-step progress, loaded adapter config, and live agent output chunks without waiting for the final JSON result.
CLI behavior
wfm run ./workflow.json --port 43121binds the attach API to127.0.0.1:43121wfm run ./workflow.jsonbinds to127.0.0.1on an OS-assigned free portwfm run ./workflow.json --verbosekeeps the default live progress UI and also streams per-step agent output to stderr- interactive human approvals now show an inline terminal prompt with a review summary; non-interactive or external waits can still be resolved through the attach API
- the CLI prints the attach base URL and ephemeral bearer token to stderr before step execution starts
wfm run --jsonincludes a top-levelsessionobject with the same attach metadata
Example:
bash
wfm run ./example-workflow.json --auto-confirm-all
# Attach API: http://127.0.0.1:43121 (token 3b8c...)Authentication
- bind address is always
127.0.0.1 - every endpoint except
/healthrequiresAuthorization: Bearer <token> - the token is generated per run and is never persisted
Endpoints
GET /health
Returns process-level liveness.
json
{ "ok": true }GET /session
Returns attach session metadata.
json
{
"sessionId": "f7d8...",
"pid": 12345,
"host": "127.0.0.1",
"port": 43121,
"baseUrl": "http://127.0.0.1:43121",
"startedAt": "2026-05-02T19:00:00.000Z",
"run": {
"runId": "run_123",
"workflowKey": "example",
"workflowTitle": "Example Workflow",
"status": "running"
}
}GET /runs/:runId
Returns the latest run snapshot.
Fields include:
- run status
- current step key
- workflow objective and objectives
- waiting-for-approval reason when applicable
- per-step status, attempt count, timestamps, and adapter
GET /runs/:runId/steps/:stepKey
Returns one step detail record, including config summary.
Config fields include:
modelskillsmcpssystemPromptscontextSummary
GET /runs/:runId/logs
Returns buffered stdout/stderr chunks.
Query params:
stepKeyoptionallimitoptional, defaults to200cursoroptional numeric offset
GET /runs/:runId/events
Server-sent events stream with historical replay followed by live events.
Query params:
sinceSequenceoptionalincludeLogs=true|falseoptional, defaults totrue
GET /runs/:runId/events/list
One-shot JSON poll over the same event history, designed for tool-calling agents that cannot hold an SSE stream open.
Query params:
sinceSequenceoptional; only events with a higher sequence are returnedincludeLogs=true|falseoptional, defaults totrue;falsefiltersagent.stdoutandagent.stderr
Response:
json
{
"items": [
{ "id": "...", "sequence": 4, "type": "step.execution_started", "runId": "run_123", "stepKey": "plan", "occurredAt": "...", "data": { "attempt": 1 } }
],
"nextSequence": 4
}nextSequence is the highest sequence in items, or the passed sinceSequence when no new events exist; pass it back as sinceSequence on the next poll.
POST /runs/:runId/approve
Approves the currently waiting step and lets execution continue.
Optional body:
json
{ "stepKey": "review" }Optional metadata fields:
actornotesource
POST /runs/:runId/resume
Alias of approve for clients that treat approval and external resume as the same action.
POST /runs/:runId/cancel
Cancels the waiting run.
Optional body:
json
{ "stepKey": "review" }CLI control commands
The CLI can call the attach API directly:
bash
wfm approve --url http://127.0.0.1:43121 --token <token> --step review --actor alice --note "LGTM"
wfm resume --url http://127.0.0.1:43121 --token <token> --step review --actor alice
wfm cancel --url http://127.0.0.1:43121 --token <token> --step review --actor alice --note "stop this run"Notes:
--run-idis optional; if omitted, the CLI reads it fromGET /session--urlcan also be provided viaWFM_RUNNER_URL--tokencan also be provided viaWFM_RUNNER_TOKEN- connection details resolve in priority order:
--url/--tokenflags, then--session-file, then the environment variables
Attach clients
wfm run --session-file <path> writes attach connection details to a JSON file (mode 0600, parent directories created) as soon as the attach API is listening:
json
{
"baseUrl": "http://127.0.0.1:43121",
"attachToken": "3b8c...",
"runId": "run_123",
"pid": 12345,
"startedAt": "2026-05-02T19:00:00.000Z"
}When the run finishes, the same file is rewritten with endedAt and the final status; it is never deleted. This lets a host agent start wfm run in the background and observe or control the run afterwards with plain CLI calls:
bash
wfm run ./workflow.json --session-file ./run-session.json &
wfm status --session-file ./run-session.json
wfm status --session-file ./run-session.json --step review
wfm logs --session-file ./run-session.json --step review --limit 50
wfm events --session-file ./run-session.json --since 4
wfm approve --session-file ./run-session.json --step reviewwfm statusprints the run snapshot (or one step detail with--step) as compact JSON on stdoutwfm logsproxiesGET /runs/:runId/logsand prints{ "items": [...], "nextCursor": ... }wfm eventspollsGET /runs/:runId/events/listonce and prints{ "items": [...], "nextSequence": ... }; log events are excluded unless--include-logsis passed- the read commands exit
0whenever the API answered — a failed run status is data, not an error — and1only for connection or validation errors - all attach commands accept
--url/--token,--session-file, or theWFM_RUNNER_URL/WFM_RUNNER_TOKENenvironment variables
Event stream
The current implementation emits the existing workflow events plus agent output events:
run.createdrun.startedrun.waiting_for_approvalrun.completedrun.failedstep.runnablestep.claimedstep.execution_startedstep.execution_finishedstep.waiting_for_approvalstep.confirmedstep.retriedagent.startedagent.stdoutagent.stderragent.finished
Example SSE frame:
text
event: step.execution_started
id: 4
data: {"id":"...","sequence":4,"type":"step.execution_started","runId":"run_123","stepKey":"plan","occurredAt":"2026-05-02T19:00:01.000Z","data":{"attempt":1}}Notes
- the API is in-memory and ephemeral; it disappears when the
wfm runprocess exits mocksteps do not emit stdout/stderr chunksclaude-codeand realopencodesteps can emit live log chunks throughagent.stdoutandagent.stderr- approval and cancel actions only work while the run is in
waiting_for_approval - approval audit events include optional actor, note, and source metadata when provided
- secrets are not persisted by the attach API, and step context is summarized instead of exposing raw context objects by default