On this page
Run a prompt from a script or CI
haarness run sends one prompt, waits for the agent to finish, and prints its reply. It does the
same work as the terminal UI, so you can use it in shell scripts, Git hooks and CI jobs.
You need: a model connected.
haarness run "List the TODO comments in src/"The reply is printed when the turn finishes. The command exits with status 0 when the turn
completes and non-zero when it fails. On a terminal, a Working · 12s · Ctrl-C to stop line
shows on stderr while you wait.
Choose the model
Without -m, a new chat uses your default model: the model in your
configuration, or else the model the terminal UI
would pick from a provider you connected. A continued chat keeps its own model. If nothing is
connected, the run says how to connect a provider and starts no chat.
To choose, pass -m provider/model:
haarness run -m anthropic/claude-sonnet-5-5 "…"
haarness run --provider openai --model gpt-5.6 "…" # the same idea, as two flags
haarness models # what you can use--agent reviewer runs the turn with another agent profile.
--variant picks a reasoning variant for this turn.
Pipe in context
When you pipe text in, it is added after the prompt:
git diff | haarness run "Review this change"With no prompt argument, the piped text is the whole prompt.
With a prompt argument, Haarness reads piped text only if it is already waiting when the run starts, so a pipe that never closes cannot hold the run. Output from a slow command may not be there yet; save it to a file first and redirect it in:
cargo test > test-output.txt 2>&1
haarness run "Why do these tests fail?" < test-output.txtAttach files
Use -f once per file. PDFs, images, audio and short video work when the model supports them.
haarness run -m gemini/gemini-3.8-flash -f ./brief.pdf -f ./clip.mp4 "Compare these"Get output a script can parse
haarness run --format json "List the crates" \
| jq -r 'select(.type=="assistant") | .text'--format json prints one JSON object per line. Each has type (assistant or reasoning),
text, threadID and turnID. Use threadID to continue the chat later.
When a run fails, the last line is an error record, and the command exits non-zero:
{"type":"error","threadID":"…","message":"Stopped: the agent asked to …"}Other records you may see: refused (a request that --auto refused, with its reason),
workflow (a workflow run's result), and background or background_subagent (work still
running on the server when the command returns, with its count).
In plain-text output, the model's reasoning is printed too, under a thinking: line before the
reply (dimmed on a terminal). Add --no-thinking to print only the reply.
Continue a chat
Each run starts a new chat unless you say otherwise:
haarness run --continue "now add tests" # the last chat in this folder
haarness run --thread <id> "…" # a specific chat
haarness run --continue --fork "try another way" # a copy, leaving the original alone
haarness run --title "Nightly audit" "…" # name a new chatChats belong to the folder you run in. See Find and resume a chat.
Stop a run
Press Ctrl-C. Haarness stops the chat's turn on the server, with any helpers and workflows it started, and the command exits with status 130. A second Ctrl-C exits at once. A cancelled CI job that sends SIGTERM stops the run the same way, with status 143. Closing the terminal window a run is attached to stops it too, with status 129.
Files keep whatever the agent had already written. Open the chat in the terminal UI and run
/undo to roll them back.
Handle permission prompts in CI
Inside the project, the agent edits files and runs commands without asking. When it needs a permission beyond that, for example to read a file outside the project:
At a terminal, the run asks you there, even when you piped text in. Type
yto allow it once; anything else refuses it. If you answer the same request in the terminal UI or Desktop first, the run carries on.The agent asks to reach outside the project (/etc/hosts). Allow it once? [y/N]With no terminal, as in CI, the request is refused and the run stops with an error that says what was asked:
Error: Stopped: the agent asked to reach outside the project (/etc/hosts), and nobody can approve that in this run. Allow it by adding {"permission":{"external_directory":{"/etc/*":"allow"}}} to haarness.json in the project or ~/.config/haarness/haarness.json, or run again with --yolo to approve every request.The rule it names is the one an "always" answer would save, so you can copy it into your configuration.
To let an unattended run do what it needs, choose one:
- Allow it with permission rules in the project's configuration. This is the safer choice.
- Pass
--autoto put the chat in Auto: a reviewer model approves routine requests once. With no terminal, each request it leaves to a person is refused, the agent is told why, and the run carries on; five refusals in a row stop it. A run that finished but refused something exits with status 3. The chat stays in Auto afterwards, in every app, until someone switches it back. - Pass
--yoloto approve every request in this run. Rules set todenystill block, and Haarness Cloud actions that spend money or delete something still ask: with no terminal, the run stops at one of those and says it "always needs an answer".
A website in your Chrome always needs a person: none of these approve it, and a run with no terminal stops and names the site. All of them are permissions inside Haarness only; none changes what the operating system allows.
If the agent asks you a question, the run declines it and carries on.
What --yolo leaves running
Nothing that approves. haarness run uses the Haarness server for the folder and starts one if
none is running; that server keeps running after the command ends, but --yolo stays with the
run. It approves the run's requests once each, including its agents and workflows, and saves no
rule. The terminal UI, Desktop and your other runs in this folder keep asking.
Only haarness serve --yolo starts a server that approves for every chat; see
Approve everything.
Run a saved command or workflow
haarness run --command audit "the billing crate"
haarness run --workflow audit --workflow-arg scope=server--command runs one of your slash commands with the text as
its arguments. --workflow runs a workflow instead of a normal turn.
Keep going until a goal is met
haarness run --goal "Migrate the tests to the new API and make them pass"--goal treats the prompt as a goal and keeps working across turns. The
command exits with status 0 only if the goal is achieved; paused or blocked goals exit with an
error.
Wait for background work
The agent can start helpers that run in the background. By default the command returns when the main turn ends and says how many helpers are still running on the workspace server.
haarness run --wait-background "…"
haarness run --background-timeout-ms 600000 "…" # wait at most 10 minutesUse the strongest reasoning
haarness run --ultracode "Audit every API boundary"--ultracode uses the strongest reasoning the model offers for this run and lets the agent split
the work into parallel tasks. Keep it for hard problems. See
Reasoning and ultracode.
Run on another server
haarness run --attach http://build-box:4096 --password "$PASSWORD" "…"For a server that uses a token, pass --token or set HAARNESS_SERVER_TOKEN. See
Start a Haarness server.
The short form
haarness "prompt" is the same as haarness run "prompt". It only works when the prompt does not
contain /, does not start with -, and is not the name of a command or file. In scripts, write
haarness run.
Keep CI out of the usage statistics
Runs report to the daily usage statistics
like any other chat. Set HAARNESS_TELEMETRY=0 in a CI job to leave it out.
Reference
| Flag | Does |
|---|---|
-m, --model |
provider/model, or a model ID with --provider |
--agent, --variant |
Agent profile and reasoning variant |
-f, --file |
Attach a file (repeatable) |
--format json |
One JSON object per line, and an error record on failure |
--no-thinking |
Leave reasoning out of the output |
-c, --continue / -s, --thread |
Continue the last or a given chat |
--fork |
Copy that chat first |
--title |
Name the new chat |
--auto |
Put the chat in Auto; see Handle permission prompts in CI |
--yolo |
Approve every permission request; see what it leaves running |
--command, --workflow |
Run a slash command or workflow |
--workflow-arg KEY=VALUE |
A workflow argument (repeatable) |
--goal |
Pursue the prompt as a goal |
--ultracode |
Strongest reasoning for this run |
--wait-background |
Wait for background helpers |
--background-timeout-ms |
Wait at most this long |
--attach (or --connect), --token, --username, --password |
Use another server |
| Exit status | Means |
|---|---|
| 0 | The turn completed |
| 1 | It failed, or stopped on a permission nobody could answer |
| 3 | It finished, but --auto refused at least one request |
| 129 | The terminal it ran in was closed |
| 130 | You pressed Ctrl-C |
| 143 | It received SIGTERM |