|
|
||
|---|---|---|
| cmd/ollie-9p | ||
| fs | ||
| mount | ||
| prompts | ||
| server | ||
| session | ||
| .gitignore | ||
| 9p | ||
| LICENSE | ||
| README.md | ||
| dbus.go | ||
| elevate_notify.go | ||
| go.mod | ||
| go.sum | ||
| main.go | ||
| main_test.go | ||
| ollie-9p | ||
README.md
olliesrv
olliesrv is a 9P 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 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):
<session-id>/ 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 | <command>
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: <tool>)
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
mk
Installs olliesrv to $HOME/bin.
Usage
olliesrv # start the server (foreground)
olliesrv mount <addr> [mnt] # mount a remote 9P server via 9pfuse
olliesrv mount <addr> [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 <addr> <mnt> and defaults the mountpoint to $HOME/mnt/<addr>.
Flags
| Flag | Effect |
|---|---|
-strict |
Only {tool} steps are allowed in execute_code; inline {code} steps are rejected. |
-yolo |
Skip the landrun sandbox for all execute_code execution. |
-tcp <addr> |
Also listen on a TCP address (e.g. :564). |
-mount <path> |
Override the FUSE mount path. |
-nodbus |
Disable the embedded D-Bus adapter (implied by -tcp). |
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:
# 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/ for the HTTP REST gateway (ollie-httpgw).
Container
A Containerfile is included (at the monorepo root) for running a self-contained remote server:
podman build --network=host -t olliesrv .
podman run --network=host -e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY olliesrv
Then mount locally:
olliesrv mount localhost:9564 ~/mnt/container-ollie
Sessions
Create
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
echo "what files are in the current directory?" > $OLLIE/s/<session-id>/prompt
Writes dispatch asynchronously on close; the shell returns immediately.
Read the conversation
cat $OLLIE/s/<session-id>/chat # full history snapshot
tail -f $OLLIE/s/<session-id>/chat # follow output as it arrives
Check state
cat $OLLIE/s/<session-id>/state
# idle | thinking | calling: <toolname>
Control
echo stop > $OLLIE/s/<session-id>/ctl # interrupt current turn
echo compact > $OLLIE/s/<session-id>/ctl # summarize context
echo clear > $OLLIE/s/<session-id>/ctl # clear history
echo kill > $OLLIE/s/<session-id>/ctl # kill session
echo "rn my-name" > $OLLIE/s/<session-id>/ctl
echo "model qwen3:8b" > $OLLIE/s/<session-id>/ctl
ctl accepts only recognized commands: stop, kill, rn <name>, 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
echo ollama > $OLLIE/s/<session-id>/backend
echo qwen3:8b > $OLLIE/s/<session-id>/model
echo myagent > $OLLIE/s/<session-id>/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
rm -r $OLLIE/s/<session-id> # kill
mv $OLLIE/s/<session-id> $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: 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.
# 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=<name> model=<name>
The classifier uses OLLIE_ROUTE_BACKEND (default: ollama) and OLLIE_ROUTE_MODEL (default: qwen3:8b).
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.
exec 3<> $OLLIE/complete
echo '{"prefix": "func main() {\n\t", "suffix": "\n}", "file": "main.go"}' >&3
cat <&3
exec 3>&-
Example shell session
$ 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: -> execute_code({"code":"find . -name '*.go'","language":"bash"})
= pkg/agent/core.go
pkg/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