# olliesrv `olliesrv` is a [9P](http://9p.cat-v.org) server that exposes the ollie agent runtime as a synthetic filesystem. Sessions are directories, conversation is a file, prompts are writes, tools are executables. It also embeds a D-Bus adapter (`org.ollie.SessionManager`) for KDE desktop clients. Mount it with `9pfuse` and interact with sessions using `echo`, `cat`, `tail`, and `rm`. The same interface works for interactive shells, editor plugins, scripts, web UIs, and multi-agent coordination. For usage examples, see [doc/USAGE.md](../doc/USAGE.md) in the monorepo. ## Filesystem layout ``` ollie/ agents read: list of available agent configs backends read: list of ollie-provided backends complete r/w: code completion (write JSON, read result; per-fid, like /net/dns) ctl write: root-level control commands generate r/w: one-shot generation (write JSON, read result; per-fid) help read: help file (backed by ~/.config/ollie/help.md) models read: all models from all backends (tab-separated: backend\tmodel) route r/w: model routing (write JSON, read "backend=X model=Y"; per-fid) tools r/w: tool prompt lookup (write tool name, read documentation; per-fid) s/ dir: sessions and session management scripts new r/w: read: KV template; write: create session idx read: index of all sessions (id, state, cwd, backend, model — one per line) sh exec: interactive chat shell ls exec: list active sessions kill exec: kill a session by ID b exec: one-shot query: create session, submit prompt, wait, print result, kill bfg exec: batch foreground: submit prompt, wait, print result bbg exec: batch background: submit prompt, print session path, return immediately cleanup exec: kill all idle sessions Session directories (multi-turn, idle<=>running): / rm -r to kill; mv to rename cfg r/w: KV snapshot of config and current state; write partial KV to mutate read fields: state, backend, model, agent, cwd, maxTokens, temperature, frequencyPenalty, presencePenalty writable fields: backend, model, agent, cwd, maxTokens, temperature, frequencyPenalty, presencePenalty (state is read-only; silently ignored on write) chat read: cumulative conversation history context read: full message history as JSONL (one message per line) cost read: cumulative cost in USD (if reported by backend) ctl write: stop | ctxsz read: estimated context size vs context window env read: session environment variables (OLLIE_SESSION_ID, OLLIE_*) fifo.in write: queue a prompt for later execution fifo.out read: pop the next queued prompt models read: available models from the backend offset read: byte offset in chat immediately after the last user prompt peer/ dir: peer links (touch to add, rm to remove — both sides; write to send prompt) plan r/w: scratch space for agent planning (persisted per session) proc/ dir: detached background processes prompt write: submit a prompt to the agent prompt.prev read: the last submitted prompt state read: current state (idle, thinking, calling: ) statewait read: blocks until state changes; returns new state systemprompt read: fully rendered system prompt for this session tail exec: exec tail -f chat usage read: token counts (input, output, requests; [estimated] if not reported by backend) ``` Agent configs, prompt templates, tools, skills, and scripts all live on disk at `~/.config/ollie/` and are read directly by the runtime — they are not served through 9P. Session IDs are Unix nanosecond timestamps with a random suffix (e.g. `1744276689123456789-2b986c`), so `ls s/` sorted lexicographically gives creation order. ## Building ```sh mk ``` Installs `olliesrv` and `ollie-9p` to `$HOME/bin`. ## ollie-9p `ollie-9p` is the 9P client used internally by agents and tool scripts to interact with the server. It auto-discovers the server via `$NAMESPACE` and identifies the caller via `$OLLIE_UNAME`. ``` ollie-9p [-a addr] ``` | Command | Description | |---|---| | `read path` | Read file contents to stdout | | `write path` | Write stdin to file | | `rdwr path` | Write stdin then read response (request-response files) | | `stat path` | Print file metadata | | `ls [-l] [-d] path` | List directory contents | | `create path` | Create a file | | `remove path` | Remove a file/directory | | `mkdir path` | Create a directory | Examples: ```sh # Submit a prompt echo "explain this code" | ollie-9p write s/ollie/prompt # Load a tool echo 'file_edit' | ollie-9p rdwr tools # Route a task to a model echo 'implement login page' | ollie-9p rdwr route # Create a session echo "cwd=$PWD" | ollie-9p write s/new # Read session state ollie-9p read s/ollie/state ``` Tool scripts use `ollie-9p` rather than the FUSE mount so they work in sandboxed environments where the mount may not be visible. ## Usage ```sh olliesrv # start the server (foreground) olliesrv mount [mnt] # mount a remote 9P server via 9pfuse olliesrv mount [mnt] # mount a remote 9P server via 9pfuse ``` The server listens on a Unix socket in the Plan 9 namespace (`$NAMESPACE/ollie`) and optionally mounts via `9pfuse` to `$HOME/mnt/ollie` (or `$OLLIE`). `olliesrv mount` is for remote instances: it calls `9pfuse ` and defaults the mountpoint to `$HOME/mnt/`. ### Flags | Flag | Effect | |------|--------| | `-strict` | Only promoted tools are allowed; inline `shell` commands are rejected. | | `-yolo` | Skip the landrun sandbox for all execution. | | `-tcp ` | Also listen on a TCP address (e.g. `:564`). | | `-mount ` | Override the FUSE mount path. | | `-nodbus` | Disable the embedded D-Bus adapter (implied by `-tcp`). | ```sh olliesrv -strict # tools only, sandboxed olliesrv -yolo # arbitrary code, no sandbox olliesrv -strict -yolo # tools only, no sandbox ``` ## Remote Access ### 9P mount `olliesrv` speaks 9P over TCP. A remote instance can be mounted into the local namespace using `9pfuse`: ```sh # On the remote host: olliesrv -tcp :9564 # Locally: olliesrv mount remotehost:9564 ~/mnt/remotehost ls ~/mnt/remotehost # s/, ... ``` Sessions created under `~/mnt/remotehost/s/` run on the remote host, so tool calls execute close to the remote filesystem rather than over the wire. ### HTTP gateway See [httpgw/](../httpgw/) for the HTTP REST gateway (`ollie-httpgw`). ### Container A `Containerfile` is included (at the monorepo root) for running a self-contained remote server: ```sh podman build --network=host -t olliesrv . podman run --network=host -e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY olliesrv ``` Then mount locally: ```sh olliesrv mount localhost:9564 ~/mnt/container-ollie ``` ## Sessions ### Create ```sh cat $OLLIE/s/new # show required/optional KV pairs echo "cwd=$PWD" > $OLLIE/s/new echo "cwd=$PWD backend=ollama model=qwen3:8b" > $OLLIE/s/new ``` Valid keys: `cwd` (required), `backend`, `model`, `agent`. ### Send a prompt ```sh echo "what files are in the current directory?" > $OLLIE/s//prompt ``` Writes dispatch asynchronously on close; the shell returns immediately. ### Read the conversation ```sh cat $OLLIE/s//chat # full history snapshot tail -f $OLLIE/s//chat # follow output as it arrives ``` ### Check state ```sh cat $OLLIE/s//state # idle | thinking | calling: ``` ### Control ```sh echo stop > $OLLIE/s//ctl # interrupt current turn echo compact > $OLLIE/s//ctl # summarize context echo clear > $OLLIE/s//ctl # clear history echo kill > $OLLIE/s//ctl # kill session echo "rn my-name" > $OLLIE/s//ctl echo "model qwen3:8b" > $OLLIE/s//ctl ``` `ctl` accepts only recognized commands: `stop`, `kill`, `rn `, `save`, `compact`, `clear`, `backend`, `model`, `models`, `agents`, `agent`, `sessions`, `cwd`, `skills`, `tools`, `context`, `usage`, `cost`, `history`, `irw`, `help`. The `/` prefix is added automatically. Unrecognized input is rejected with an error. ### Switch backend, model, or agent ```sh echo ollama > $OLLIE/s//backend echo qwen3:8b > $OLLIE/s//model echo myagent > $OLLIE/s//agent ``` Writes to `backend`, `model`, and `agent` are rejected when the agent is not idle. Check `state` to confirm the change took effect. ### Kill and rename ```sh rm -r $OLLIE/s/ # kill mv $OLLIE/s/ $OLLIE/s/my-friendly-name # rename ``` Rename is rejected if the agent is running or the target name already exists. All open file handles into the session are updated automatically. ## Stateless endpoints: generate, route, complete Three root-level files provide request/response access without session state. They follow the [Plan 9 /net/dns pattern](https://9fans.github.io/plan9port/man/man3/ndb.html): open the file, write a request, then read the response from the same file descriptor. The result is per-fid (per open file descriptor) and consumed on first read. Because the write and read must happen on the same fd, a simple `echo > file && cat file` won't work — that opens two separate fds. Use `exec` with a persistent fd, or `9p rdwr`. ### generate One-shot LLM generation with no session context. **Request** (JSON): `{"prompt": "...", "system": "...", "backend": "...", "model": "..."}` All fields except `prompt` are optional. If the write is not valid JSON, the entire string is used as the prompt. **Response**: the model's text output. ```sh # Using exec to keep the fd open: exec 3<> $OLLIE/generate echo '{"prompt": "what is 2+2?", "backend": "ollama", "model": "qwen3:8b"}' >&3 cat <&3 exec 3>&- # Plain text (uses default backend/model from env): exec 3<> $OLLIE/generate echo 'what is 2+2?' >&3 cat <&3 exec 3>&- ``` ### route Model selection: given a task description, picks the best backend+model from all available models. **Request** (JSON): `{"task": "...", "backend": "..."}` — `backend` is optional (restricts candidates). Plain text is treated as the task. **Response**: `backend= model=` The classifier uses `OLLIE_ROUTE_BACKEND` (default: `ollama`) and `OLLIE_ROUTE_MODEL` (default: `qwen3:8b`). ```sh exec 3<> $OLLIE/route echo 'write a bash script to parse JSON' >&3 cat <&3 exec 3>&- # → backend=openrouter model=anthropic/claude-sonnet-4-20250514 ``` ### complete Code completion: given file context (prefix/suffix around the cursor), returns a suggested insertion. **Request** (JSON): `{"cwd": "...", "file": "...", "prefix": "...", "suffix": "...", "context": "..."}` All fields except `prefix` are optional. Plain text is treated as the prefix. Uses `OLLIE_COMPLETE_BACKEND` and `OLLIE_COMPLETE_MODEL`. **Response**: the completion text. ```sh exec 3<> $OLLIE/complete echo '{"prefix": "func main() {\n\t", "suffix": "\n}", "file": "main.go"}' >&3 cat <&3 exec 3>&- ``` ## Example shell session ```sh $ echo "cwd=$PWD" > $OLLIE/s/new $ ls $OLLIE/s/ new 1744276689123456789-2b986c $ cd $OLLIE/s/1744276689123456789-2b986c $ tail -f chat & $ echo "list the go files in $PWD" > prompt user: list the go files in /home/lkn/src/ollie assistant: -> shell({"cmd":"find . -name '*.go'"}) = agent/core.go agent/loop.go ... assistant: The Go source files are: core.go, loop.go, ... $ cat state idle $ mv $OLLIE/s/1744276689123456789-2b986c $OLLIE/s/ollie-demo ```