migrate from FUSE mounts to 9p client

- prompts/session-9p.md: all operations use `9p` commands
- LSP tools: sys.path from $OLLIE_TOOLS_PATH (no mount needed)
- 9p: removed auto-mount + OLLIE= env var from sessions

Agents now use the standalone 9p client binary for all 9P access.
Mounts remain available for human convenience but are not required.
This commit is contained in:
Levi Neely 2026-07-27 11:42:02 +02:00
parent 51ebb0768d
commit 01bf124ec0
9 changed files with 49 additions and 49 deletions

2
9p

@ -1 +1 @@
Subproject commit 666acceb0be10155efa10541b33a9f49178a8f28
Subproject commit cafe38292f16f6f3a77cb1eda27f4a6943730aef

View File

@ -1,8 +1,10 @@
# 9P Operational Model
Your world model is a 9P filesystem mounted at ${OLLIE}. Your session ID is `${OLLIE_SESSION_ID}`. Always prefer the 9P filesystem over D-Bus.
Your world model is a 9P filesystem served by olliesrv. Your session ID is `${OLLIE_SESSION_ID}`. Always prefer the 9P filesystem over D-Bus.
## Root Namespace (`${OLLIE}/`)
Access 9P files using the `9p` command (which auto-discovers the server and your identity via `$OLLIE_UNAME`).
## Root Namespace (`/`)
| File | Mode | Purpose |
|---|---|---|
@ -17,57 +19,55 @@ Your world model is a 9P filesystem mounted at ${OLLIE}. Your session ID is `${O
| `route` | r/w | Write: task description. Read: `backend=X model=Y` recommendation. |
| `tools` | r/w | Write: tool name. Read: tool's full prompt/documentation. |
`complete`, `generate`, `route`, and `tools` are request-response files. Open one r/w, write a query, then read the response from the same fd:
`complete`, `generate`, `route`, and `tools` are request-response files. Write a query, then read the response:
```bash
# Get a tool's documentation
exec 3<>$OLLIE/tools; echo 'file_edit' >&3; cat <&3; exec 3>&-
echo 'file_edit' | 9p rdwr tools
# → returns file_edit's usage, args, and examples
# Pick a backend+model for a task
exec 3<>$OLLIE/route; echo 'implement login page' >&3; cat <&3; exec 3>&-
echo 'implement login page' | 9p rdwr route
# → returns "backend=anthropic model=claude-sonnet-4-20250514"
# Generate text (one-shot, no session)
exec 3<>$OLLIE/generate; echo '{"prompt":"summarize X"}' >&3; cat <&3; exec 3>&-
echo '{"prompt":"summarize X"}' | 9p rdwr generate
# → returns the generated text
# Get a code completion
exec 3<>$OLLIE/complete; echo '{"file":"main.go","prefix":"func "}' >&3; cat <&3; exec 3>&-
echo '{"file":"main.go","prefix":"func "}' | 9p rdwr complete
# → returns completion candidates
```
Shorthand: `echo 'file_edit' | 9p rdwr ollie/tools`
## Peer Agent Discovery
Sessions sharing your `cwd` are your peer agents. Read `${OLLIE}/s/idx` to discover other sessions available for cooperation:
Sessions sharing your `cwd` are your peer agents. Read `s/idx` to discover other sessions available for cooperation:
```
{id}\t{state}\t{cwd}\t{backend}\t{model}
```
**Inter-Agent Communication**: To send a prompt to another session: `echo "your prompt" > ${OLLIE}/s/{id}/prompt`. Always provide a return path (e.g., [message from $OLLIE_SESSION_ID]).
**Inter-Agent Communication**: To send a prompt to another session: `echo "your prompt" | 9p write s/{id}/prompt`. Always provide a return path (e.g., [message from $OLLIE_SESSION_ID]).
## Session Management (`${OLLIE}/s/`)
## Session Management (`s/`)
Sessions live at `${OLLIE}/s/`. Each session is a directory; all operations are filesystem reads and writes.
Sessions live at `s/`. Each session is a directory; all operations are 9P reads and writes.
### Session Store Files
| File | Mode | Purpose |
|---|---|---|
| `${OLLIE}/s/new` | r/w | Read: key=value template. Write: create a new session. |
| `${OLLIE}/s/idx` | read | Session index (id\tstate\tcwd\tbackend\tmodel) |
| `${OLLIE}/s/ls` | exec | List sessions |
| `${OLLIE}/s/kill` | exec | Kill a session |
| `${OLLIE}/s/sh` | exec | Interactive shell |
| `${OLLIE}/s/b` | exec | Batch session |
| `${OLLIE}/s/bfg` | exec | Foreground query |
| `${OLLIE}/s/bbg` | exec | Background query |
| `${OLLIE}/s/cleanup` | exec | Kill idle sessions |
| `s/new` | r/w | Read: key=value template. Write: create a new session. |
| `s/idx` | read | Session index (id\tstate\tcwd\tbackend\tmodel) |
| `s/ls` | exec | List sessions |
| `s/kill` | exec | Kill a session |
| `s/sh` | exec | Interactive shell |
| `s/b` | exec | Batch session |
| `s/bfg` | exec | Foreground query |
| `s/bbg` | exec | Background query |
| `s/cleanup` | exec | Kill idle sessions |
### Session Directory (`${OLLIE}/s/{id}/`)
### Session Directory (`s/{id}/`)
| File | Mode | Purpose |
|---|---|---|
@ -82,7 +82,7 @@ Sessions live at `${OLLIE}/s/`. Each session is a directory; all operations are
| `fifo.out` | read | Pop queued prompt (FIFO output) |
| `models` | read | Available models for current backend |
| `offset` | read | Byte offset after last user prompt |
| `peer/` | dir | Peer links. `touch` to add, `rm` to remove (both sides updated). Write to send prompt to peer. |
| `peer/` | dir | Peer links. `create` to add, `remove` to remove (both sides updated). Write to send prompt to peer. |
| `plan` | r/w | Session-scoped markdown checklist; survives compaction; visible to peers |
| `proc/` | dir | Detached background processes |
| `prompt` | write | Submit a prompt to the agent |
@ -97,25 +97,25 @@ Sessions live at `${OLLIE}/s/`. Each session is a directory; all operations are
```bash
# Discover sessions
cat $OLLIE/s/idx
9p read s/idx
# Discover sessions in same cwd
grep "$PWD" $OLLIE/s/idx
9p read s/idx | grep "$PWD"
# Spawn a session (minimal, generated ID)
echo "cwd=$PWD" > $OLLIE/s/new
echo "cwd=$PWD" | 9p write s/new
# Spawn a session (named)
printf 'name=reviewer\ncwd=%s\n' "$PWD" > $OLLIE/s/new
printf 'name=reviewer\ncwd=%s\n' "$PWD" | 9p write s/new
# Kill a session
rm -r $OLLIE/s/{id}
9p remove s/{id}
# Rename a session
echo "rn newname" > $OLLIE/s/{id}/ctl
echo "rn newname" | 9p write s/{id}/ctl
# Send a prompt
echo "your prompt here" > $OLLIE/s/{id}/prompt
echo "your prompt here" | 9p write s/{id}/prompt
# Control commands via ctl:
# stop — interrupt the current agent turn
@ -126,30 +126,30 @@ echo "your prompt here" > $OLLIE/s/{id}/prompt
# cwd <path> — change the working directory
# model <name> — switch model
# backend <name> — switch backend
echo "model gpt-4o" > $OLLIE/s/{id}/ctl
echo "model gpt-4o" | 9p write s/{id}/ctl
# Read session config (backend, model, agent, cwd, params)
cat $OLLIE/s/{id}/cfg
9p read s/{id}/cfg
# Write config changes
echo "temperature=0.7" > $OLLIE/s/{id}/cfg
echo "temperature=0.7" | 9p write s/{id}/cfg
# Read most recent response
offset=$(cat $OLLIE/s/{id}/offset)
tail -c +$((offset + 1)) $OLLIE/s/{id}/chat
offset=$(9p read s/{id}/offset)
9p read s/{id}/chat | tail -c +$((offset + 1))
# Read current state
cat $OLLIE/s/{id}/state
9p read s/{id}/state
# Discover available models
cat $OLLIE/s/{id}/models
9p read s/{id}/models
# Add a peer link (bidirectional)
touch $OLLIE/s/{id}/peer/{peerid}
9p create s/{id}/peer/{peerid}
# Send a prompt to a peer
echo "your message" > $OLLIE/s/{id}/peer/{peerid}
echo "your message" | 9p write s/{id}/peer/{peerid}
# Remove a peer link (bidirectional)
rm $OLLIE/s/{id}/peer/{peerid}
9p remove s/{id}/peer/{peerid}
```

View File

@ -16,7 +16,7 @@
import os
import sys
sys.path.insert(0, os.path.join(os.environ['OLLIE'], 's', os.environ['OLLIE_SESSION_ID'], 't'))
sys.path.insert(0, os.environ.get('OLLIE_TOOLS_PATH', os.path.dirname(os.path.abspath(__file__))))
from _lib.lsp.client import request

View File

@ -16,7 +16,7 @@
import os
import sys
sys.path.insert(0, os.path.join(os.environ['OLLIE'], 's', os.environ['OLLIE_SESSION_ID'], 't'))
sys.path.insert(0, os.environ.get('OLLIE_TOOLS_PATH', os.path.dirname(os.path.abspath(__file__))))
from _lib.lsp.client import request

View File

@ -14,7 +14,7 @@
import os
import sys
sys.path.insert(0, os.path.join(os.environ['OLLIE'], 's', os.environ['OLLIE_SESSION_ID'], 't'))
sys.path.insert(0, os.environ.get('OLLIE_TOOLS_PATH', os.path.dirname(os.path.abspath(__file__))))
from _lib.lsp.client import request

View File

@ -14,7 +14,7 @@
import os
import sys
sys.path.insert(0, os.path.join(os.environ['OLLIE'], 's', os.environ['OLLIE_SESSION_ID'], 't'))
sys.path.insert(0, os.environ.get('OLLIE_TOOLS_PATH', os.path.dirname(os.path.abspath(__file__))))
from _lib.lsp.client import request

View File

@ -18,7 +18,7 @@
import os
import sys
sys.path.insert(0, os.path.join(os.environ['OLLIE'], 's', os.environ['OLLIE_SESSION_ID'], 't'))
sys.path.insert(0, os.environ.get('OLLIE_TOOLS_PATH', os.path.dirname(os.path.abspath(__file__))))
from _lib.lsp.client import request

View File

@ -15,7 +15,7 @@
import os
import sys
sys.path.insert(0, os.path.join(os.environ['OLLIE'], 's', os.environ['OLLIE_SESSION_ID'], 't'))
sys.path.insert(0, os.environ.get('OLLIE_TOOLS_PATH', os.path.dirname(os.path.abspath(__file__))))
from _lib.lsp.client import request

View File

@ -15,7 +15,7 @@
import os
import sys
sys.path.insert(0, os.path.join(os.environ['OLLIE'], 's', os.environ['OLLIE_SESSION_ID'], 't'))
sys.path.insert(0, os.environ.get('OLLIE_TOOLS_PATH', os.path.dirname(os.path.abspath(__file__))))
from _lib.lsp.client import request