Architecture
This page describes what the agent does on your machine: what runs, what it is allowed to touch, and what it writes down.
The turn loop
Everything the agent does is a turn. A turn is one round of: assemble the prompt, send it to your model endpoint, act on what comes back, repeat until the model stops asking for tools.
your input
↓
assemble prompt (instructions + tool schemas + memory + conversation history)
↓
model endpoint (streamed over SSE)
↓
tool calls → permission check → sandbox → results
↓
render to you, and append to history
↓
repeat until the model stops calling tools, or the iteration limit is reachedA single turn is capped at a configurable iteration count so a confused model cannot loop indefinitely. When the cap approaches, the agent is told how much budget remains and is pushed to finish rather than being cut off mid-thought.
The sandbox
Every file tool resolves its path with realpath before touching anything, then checks the result against the sandbox root. Resolving first is what stops a symlink from pointing out of the sandbox.
| Setting | Default | Change with |
|---|---|---|
| Sandbox root | The current working directory | --cwd <dir> or OASIS_CWD |
Paths outside the sandbox root, and anything under /etc, /dev, /proc, /sys and /root, always prompt, in every permission mode except dangerous. Changing permission mode does not widen where the agent may write. See Permission Model.
Risk tiers
Every tool declares a risk tier, and the tier decides whether you are asked before it runs.
| Tier | Behaviour | Examples |
|---|---|---|
| Safe | Read-only, no side effects. Never prompts. | Read, Glob, Grep, Check |
| Mutating | Changes local state. Prompts unless the mode waives it. | Write, Edit, Bash |
| Hard stop | Physical or irreversible effect. Always prompts, in every mode, including dangerous, and --skip-permissions does not waive it. | EtherCatWriteIo, EtherCatGoOperational, ModbusWrite |
The hard-stop tier is the interlock that makes an autonomy mode safe to enable on a machine that can move. A file write is not a hard stop; energising a physical output is.
The capability seam
Protocol support arrives as a capability pack, a self-contained set of tools the agent can call, enabled per project in configuration. The agent loop knows nothing about any individual pack: a pack declares its tools, their risk tiers and how their output should be treated, and the loop treats them exactly as it treats a built-in tool.
Two consequences that matter in practice:
- Turning a pack off costs nothing. It registers no tools and does not appear in the prompt.
- Turning a pack on changes the prompt prefix, which is part of the model server's cache key. See Capability Packs.
MCP servers arrive through the same seam, so a remote tool and a built-in tool are indistinguishable to the loop.
Prompt cache
The largest single cost in an agent turn is reprocessing the prompt prefix. Oasis CLI treats the prefix as something to be protected: the instructions, tool schemas and registration order are held stable so the model server can reuse its cached prefill across turns and across processes.
| Reuse | Cost of a turn boundary |
|---|---|
| 100% | 134 ms |
| 0% | 17.2 s |
The practical rule: the tool set is part of the cache key. An unchanged configuration reuses the cache. Enabling or disabling a pack, or adding an MCP server, lands on a cold slot and reprocesses the whole prompt once.
A resumed conversation assembles a byte-identical prefix to a fresh one, so resuming costs the cache nothing.
Compaction
Conversations outgrow the context window. Rather than truncating history and losing the thread, the agent evicts tool results, the bulkiest and least re-readable part of a transcript, once they age out of a keep window.
| Setting | Default | Purpose |
|---|---|---|
--context-window | Probed from the endpoint's /props, else 120 000 | Tokens the model can hold |
--response-reserve | 8 192 | Tokens held back for the reply |
--max-prompt-tokens | context-window − response-reserve | The compaction trigger |
Some tool output is pinned and never evicted: skill bodies and safety-interlock state, where losing the content mid-conversation would change what the agent believes about the machine.
What is written to disk
| Path | Contents | Disable with |
|---|---|---|
~/.oasis/config.json | User-level configuration | — |
./.oasis/config.json | Project-level configuration, overrides the above | — |
~/.oasis/sessions/ | Conversation history, written after every clean turn | --no-session |
~/.oasis/audit.jsonl | One actor-stamped line per write. See Audit Trail. | — |
~/.local/state/oasis-agent/memory/<project> | Persistent per-project notes | --no-memory |
~/.config/oasis-agent/mcp-tokens.json | Cached MCP OAuth tokens | — |
~/.oasis/versions/ | Installed versions and the active pointer | — |
History is persisted only after a clean turn. A failed turn leaves the last known-good file intact, so a poisoned context cannot be reloaded on the next run.
Running modes
| Mode | Process model | Session persistence |
|---|---|---|
| Interactive REPL | One process, one conversation, alive between turns | Saved after every clean turn |
One-shot (-p) | One process, one turn, then exits | Saved unless --no-session |
Background agent (--bg) | Detached process in its own process group | Saved; stops and holds state when it needs you |
Control protocol (serve) | One process, one session, connections come and go | Saved after every clean turn |
A session's lifetime is independent of any connection's. Nothing a client does to a connection can affect a running conversation. See Control Protocol.
Distribution
One static musl binary per architecture, no runtime dependencies. Full platform support in System Requirements.
| Architecture | Support |
|---|---|
| x86-64 | Full |
| ARMv8 / AArch64 | Full |
| ARMv7 | Best-effort |
There is one release line, with no promotion tier and no channel. The newest published version wins and latest is the only pointer.