Non-interactive mode is the point where the agent stops being an interlocutor and becomes a link in a pipeline. A run with the print flag performs the task without an interface and exits. The key detail to absorb before the first script: without the force flag changes are proposed but not applied. Mutating the working tree in an automatic run requires an explicit permission and a suitable policy - that is an operational gate rather than a side effect of the mode.
The distinction deserves emphasis, because different places in the documentation phrase it differently while behavior decides everything. A run without forcing is safe in effect: it reads, reasons and returns a result. A run with forcing changes files. The first is fine for review and analysis in continuous integration, the second only where you have deliberately built isolation and rights.
There are three output formats, and they are chosen by who reads the result. Text returns only the final message - that is for a human and for a simple script. A single JSON object arrives as one reply and contains the result together with service fields such as duration and identifiers - that is for automation that needs machine parsing. The streaming format emits events line by line and ends with a terminal event - that is for interfaces showing progress and for auditing tool calls.
It helps to see all three calls together once. Below are explaining the changes without edits, listing risks as a single object, and fixing a test with streaming output and permission to change files. Note that the force flag appears only in the third command: the first two do not need it and therefore do not have it.
The service fields of machine output deserve attention of their own. The run and session identifiers are what tie the result to the build log, to the issue in a tracker and to the ability to continue the work later; the duration is what makes it noticeable that a task now costs three times more than it did a week ago. A script that takes only the text out of the reply throws away exactly the part that makes an automatic run observable.
| Format | What comes out | When to use it |
|---|
| text | Only the final message | A human-readable script |
|---|---|---|
| json | A single result object on success | You need the result, duration and identifiers |
| stream-json | Events line by line and a terminal event | Progress, call auditing, cancellation |
| stream-json with partials | Character deltas and repeated events | A real-time interface; filter by documented fields |
A consumer of streaming output must be written with room for the future. Unknown fields are ignored, the terminal event is awaited, and its absence is not treated as success. That is not over-caution: the product evolves, and new event types appear before your parsing is updated. Rigid parsing built exactly for today's set breaks on the first update, and it breaks silently.
There is a separate rule about error handling that saves a lot of time. On a failure the result object may not arrive at all: the error will be in the error stream and the exit code will be non-zero. So automation checks both the exit code and the structure of the output rather than relying on one of the two. A script that reads only standard output will one day take a failure for success and pass it further down the pipeline.
There is also a limit of applicability that is easy to forget in the enthusiasm for automation. An automatic run is worth trusting only with work that has a machine-verifiable sign of success: a test, a linter, a build, a comparison against a reference. A task whose result is judged by eye turns, in non-interactive mode, into text that nobody reads. Framing an assignment for a script, you are at the same time framing how its result will be proved.
The engineering conclusion is simple: non-interactive mode is strong through predictability, and that has to be maintained by explicit decisions. The output format is chosen for the consumer, rights are set in advance, changing files is allowed deliberately, errors are handled by two signals. Then the agent really becomes a pipeline tool rather than a source of surprises in it.
The typical failures are predictable. Expecting file changes without explicitly allowing mutation. Parsing text output where a machine format is needed. Treating the absence of a terminal event as successful completion. And checking only the exit code without looking at the structure of the result.
# Safe in effect: get an answer
agent -p --output-format text "Explain the current diff"
# A single final object for machine parsing
agent -p --output-format json "List the risks in the tests"
# An event stream; changing files is allowed explicitly
agent -p --force --output-format stream-json --stream-partial-output \
"Fix the focused test and attach a verification report"