Harness Mode
Harness mode is how another program embeds Oasis CLI. Instead of rendering a turn to a terminal, the agent reads control input from stdin, writes its event stream to a file as newline-delimited JSON, and takes permission verdicts back through a named pipe.
This is the integration surface. A program that wants to show a turn as it happens tails the log file and renders from it.
Harness mode or the control protocol?
Both let another program drive the agent. Use harness mode to embed a single conversation in a program you control, with the simplest possible transport: a file and a pipe. Use serve when you want a request/response protocol, several sessions, or a broker between the client and the agent.
Entering harness mode
Harness mode is selected by passing both of its transport flags. Neither works alone.
oasis-agent --log-file ./run.jsonl --response-fifo ./verdicts.fifo| Flag | Purpose |
|---|---|
--log-file <path> | Write this run's event stream to <path> as newline-delimited JSON, one event per line. Requires --response-fifo |
--response-fifo <path> | Named pipe the agent reads permission verdicts from. Requires --log-file |
--persistent | Serve every turn of the conversation from one process. Requires both flags above |
--history-file <path> | Conversation history to resume from, as an OpenAI-format JSON array |
The agent refuses combinations that cannot mean anything, rather than picking one:
| Command | Result |
|---|---|
--log-file without --response-fifo | --log-file requires --response-fifo (harness mode needs both) |
--response-fifo without --log-file | --response-fifo requires --log-file (harness mode needs both) |
--persistent without both | --persistent requires harness mode (--log-file + --response-fifo) |
-p together with the harness pair | Refused. One reads the prompt as an argument and renders to the terminal, the other reads from stdin and writes JSONL |
Permissions
When a tool needs approval the agent emits a permission request on the event stream and blocks. The embedding program writes one JSON line to the response FIFO to allow or deny, and the turn continues.
This is the whole permission loop. The agent never prompts a terminal in harness mode, so a program that does not answer the FIFO will stall the turn rather than proceeding unapproved.
Hard-stop tools still cannot be waived
Answering a request on the FIFO is the same act as approving it at a prompt. It does not lift the hard-stop tier, and neither does --skip-permissions.
Persistent mode
By default a harness run is one process per turn. With --persistent, one process stays alive and serves every turn of the conversation, reading user messages and control events from stdin.
This saves a process start and a history rebuild on every turn, which is most of the cost of a turn boundary.
| Mode | Cost of a turn boundary |
|---|---|
| One process per turn, prompt cache warm | 134 ms |
| One process per turn, no cache reuse | 17.2 s |
| Persistent | ~0.35 s |
For why the difference is this large, see Architecture.
Resuming a conversation
An embedding program passes --history-file on every turn after the first. In persistent mode the file is also written back after each clean turn, so the harness does not have to reconstruct the history itself.
The file is an OpenAI-format JSON array, which is the same shape the model endpoint receives.
Relationship to the other modes
| Mode | Selected by | Output |
|---|---|---|
| Interactive REPL | Default when stdin is a terminal, or --repl | Rendered to the terminal |
| One-shot | -p, --print | Rendered to the terminal |
| Background agent | --bg | Detached; tracked by oasis-agent agents |
| Harness | --log-file + --response-fifo | JSONL event stream to a file |
| Control protocol | serve | OCP on stdio or a unix socket |