Headless runs
harmony run: one Harmony Agent turn from a script or CI, its options, its output schema, and its exit codes.
harmony run runs one Harmony Agent model turn without a UI and exits when
the turn is over. It is the command to reach for in scripts, CI and scheduled
jobs. The turn goes through the same pipeline as the TUI: it
registers a session for the working directory, sends the prompt once, reads the
turn's events back, and closes the session when it is done.
harmony run "fix the failing tests"
echo "refactor utils" | harmony run --output jsonl
harmony run "summarize the diff" --output json --timeout 120
harmony run "audit the config" --cwd ./service --non-interactive-approval fail
Before the first run, set up a model once: run harmony tui, then /login
and /model. Without that, harmony run stops before any turn starts and
exits 3 with that instruction.
Options
The prompt is the first argument. When there is none, harmony run reads it
from stdin. These are the only options it accepts; anything else is a usage
error (exit 2).
| Option | Default | Meaning |
|---|---|---|
--cwd <dir> | current directory | The directory the agent's workspace is bound to |
--timeout <seconds> | 600 | Turn deadline, up to 86400. When it passes, the turn is cancelled and the run exits 7 |
--output text|json|jsonl | text | Output format, described below |
--output-file <path> | none | Write the output to a file inside the current directory instead of stdout |
--non-interactive-approval deny|fail | deny | What happens when the agent asks for a permission: deny refuses it and lets the turn continue; fail ends the turn |
--no-color | off | Suppress the launch banner in text output |
--detach | Refused (exit 2). The runtime acknowledges a turn only once it has finished, so there is no "accepted, still running" receipt to hand back, and no command can read a detached turn's result later |
Nothing is ever approved. There is no approval policy that grants a permission on your behalf; a headless run cannot give consent you did not give. There is also no hidden fallback: no other API key, subscription or model is tried when the configured one is unavailable.
The provider, model and profile come from the setup you made in the TUI. The run does not take them as flags.
Ctrl+C cancels the turn. The run reports cancelled only when the runtime
confirms the cancel; if it cannot confirm, the run says the turn may still be
running rather than claiming it stopped.
Output
The output schema is version 2. Every event and the final result carry
"schemaVersion": 2.
text: the assistant's reply, then a short summary: classification, exit code, session, turn, model, event count and duration.json: one object,{ "result": …, "events": [ … ] }, printed when the turn is over.jsonl: one line per event as it arrives, then a final line with"type": "final"holding the result.
The final result names what ran:
| Field | Meaning |
|---|---|
ok, exitCode | The verdict; exitCode matches the process exit status |
classification | success, failed, cancelled, timeout, setup-required or refused |
stage | The step that produced the classification, such as runtime start or model turn |
sessionId, launchIntentId, workspaceId, taskId | The runtime session this run registered and the records it is bound to |
turn | The turn's ids, from the runtime's prompt receipt |
text | The assistant's reply |
eventCount, streamSettlement | How many events were read, and whether the event stream itself carried the turn's end |
deniedPermissionRequests | Permission requests this run refused |
cancel | Whether a cancel was requested, and whether the runtime confirmed it |
runtimeClosed | Whether the session was closed at the end |
error | The NALA_* code, the message, and a remediation when there is one concrete next step |
Provider-specific data is kept under provider, and any payload key that
looks like a secret is replaced with [REDACTED].
With the global --json flag, the result comes back inside the standard
JSON envelope instead.
Exit codes
harmony run classifies its own outcome, so a script can branch on the code.
| Code | Meaning |
|---|---|
0 | The turn finished |
2 | Usage: no prompt, an unknown option, or --detach |
3 | No model is set up, or the provider or daemon is unavailable |
4 | Refused: a permission was denied under --non-interactive-approval fail, or the billing route lock refused the turn |
5 | The turn failed |
6 | Cancelled, confirmed by the runtime |
7 | Timed out; the turn was cancelled at the --timeout deadline |
8 | Version or capability mismatch between the CLI and the daemon |
9 | Conflict: the write raced another writer |
10 | Anything else the run could not classify |
These codes are specific to harmony run and harmony "<prompt>". Other
commands follow the shared table.
harmony "<prompt>"
A prompt with no command runs the same single turn and prints a plain
transcript as the events arrive. It is not the TUI: for a conversation, run
harmony or harmony tui. It takes one option, --cwd, and has no deadline;
Ctrl+C cancels the turn the same way.
harmony ask and harmony plan refuse
Both commands refuse today and exit 8 with NALA_CAPABILITY_UNSUPPORTED.
Nothing is submitted. ask promises a read-only turn and
plan a planning-only one, and the Harmony Agent runtime cannot enforce either
yet. Rather than run a turn that could change files, they do nothing. Use
harmony run for a supervised turn in the meantime.