update docs: unify b/ into s/, introduce s/bfg and s/bbg

Batch and session namespaces are now a single s/ concept. s/bfg blocks
until the agent finishes and writes to stdout; s/bbg returns immediately
and prints the session path. s/b is the core one-shot runner. Remove all
b/ references from README, USAGE, ARCHITECTURE, and scripts/README.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Levi Neely 2026-04-25 08:31:15 +02:00
parent 7b8d665457
commit 2148c8c668
4 changed files with 105 additions and 113 deletions

View File

@ -1,6 +1,6 @@
# ollie
Ollie starts from a simple, slightly silly question: *What might an AI agent look like in [Plan 9](https://www.usenix.org/legacy/publications/compsystems/1995/sum_pike.pdf)?* From there follow two more: *What happens if agent primitives are exposed as an ordinary filesystem?* and *How much can we subtract from agent implementations while still being useful?* The result is not a conventional "agent framework" but a small Go runtime and 9P‑backed filesystem surface that defines what an agent is, then exposes its state and behaviors as regular files and I/O streams, so that the surrounding environment (shell scripts, TUIs, web apps, cron, containers, and other OS facilities) can handle orchestration, scheduling, workflows, and interfaces instead. Features like conductor agents, complex workflow engines, or fancy editors are optional layers you build yourself by composing ordinary file reads, writes, and processes: a tiny `s/sh` CLI, an `optimize | b/q` pipeline, or a Claude‑Code‑style UI talking to the same filesystem namespace.
Ollie starts from a simple, slightly silly question: *What might an AI agent look like in [Plan 9](https://www.usenix.org/legacy/publications/compsystems/1995/sum_pike.pdf)?* From there follow two more: *What happens if agent primitives are exposed as an ordinary filesystem?* and *How much can we subtract from agent implementations while still being useful?* The result is not a conventional "agent framework" but a small Go runtime and 9P‑backed filesystem surface that defines what an agent is, then exposes its state and behaviors as regular files and I/O streams, so that the surrounding environment (shell scripts, TUIs, web apps, cron, containers, and other OS facilities) can handle orchestration, scheduling, workflows, and interfaces instead. Features like conductor agents, complex workflow engines, or fancy editors are optional layers you build yourself by composing ordinary file reads, writes, and processes: a tiny `s/sh` CLI, an `optimize | s/bfg` pipeline, or a Claude‑Code‑style UI talking to the same filesystem namespace.
## Getting Started
@ -73,7 +73,7 @@ olliesrv start -tcp :9564
```sh
olliesrv mount remotehost:9564 ~/mnt/remotehost
ls ~/mnt/remotehost # s/, t/, b/, ...
ls ~/mnt/remotehost # s/, t/, ...
```
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.

View File

@ -92,11 +92,10 @@ User-facing scripts are organized by the 9P namespace they are hosted under and
| Namespace | Purpose | Scripts |
|---|---|---|
| `s/` | Session management | `sh`, `ls`, `kill` |
| `b/` | Batch job submission and execution | `job`, `q`, `sched` |
| `u/` | Utility scripts; compositions of `b/` primitives | `optimize` |
| `s/` | Session management and one-shot queries | `sh`, `ls`, `kill`, `cleanup`, `b`, `bfg`, `bbg` |
| `u/` | Utility scripts; compositions of `s/` primitives | `optimize` |
`b/job` is the core batch runner. `b/q` and `b/sched` are thin wrappers that add foreground-wait and background-submit semantics respectively. `u/` scripts have no special server backing — they are executable scripts that compose other namespaces via the filesystem.
`s/b` is the core one-shot runner. `s/bfg` and `s/bbg` are thin wrappers: `s/bfg` blocks until the agent finishes and writes the result to stdout; `s/bbg` returns immediately and prints the session path. `u/` scripts have no special server backing — they are executable scripts that compose other namespaces via the filesystem.
## Tool Scripts
@ -106,20 +105,20 @@ Examples from the default install: `file_read`, `file_write`, `file_edit`, `file
## Sub-agents
Sub-agents are implemented as a tool script (`subagent_spawn`) on top of the `b/` batch namespace. The script writes a job spec to `b/new`, blocks on `b/{id}/statewait` per job in background subshells, joins on all, and concatenates results. The `b/` namespace (backed by `BatchStore`) handles agent lifecycle, cancellation, and result storage.
Sub-agents are implemented as a tool script (`subagent_spawn`) on top of the `s/` namespace. The script writes a session spec to `s/new`, blocks on `s/{id}/statewait` per job in background subshells, joins on all, and concatenates results. The `s/` namespace handles agent lifecycle, cancellation, and result storage.
For heterogeneous parallel delegation (N agents, N different prompts), a `{parallel:[...]}` stage composes with `subagent_spawn` — each parallel step is one shell invocation with a distinct prompt:
```
execute_code {parallel} stage
├── subagent_spawn "prompt A" → b/{id-0}/result
├── subagent_spawn "prompt B" → b/{id-1}/result
└── subagent_spawn "prompt C" → b/{id-2}/result
├── subagent_spawn "prompt A" → s/{id-0}/chat
├── subagent_spawn "prompt B" → s/{id-1}/chat
└── subagent_spawn "prompt C" → s/{id-2}/chat
↓
concatenated in submission order
```
The architecture boundary is clean: `execute_code` is the only built-in tool in `core`; everything else is a tool script; `b/` is a 9P namespace. No layer knows about the others.
The architecture boundary is clean: `execute_code` is the only built-in tool in `core`; everything else is a tool script; `s/` is a 9P namespace. No layer knows about the others.
## Typical Consumer Setup

View File

@ -39,7 +39,7 @@ Valid levels: `debug`, `info`, `warn`, `error`. Per-subsystem overrides follow t
---
Examples below assume `$OLLIE` is set to the ollie mount point (default: `$HOME/mnt/ollie`).
Scripts under `s/`, `b/`, and `u/` are available directly via the mounted filesystem
Scripts under `s/` and `u/` are available directly via the mounted filesystem
after running `mk && mk scripts`.
## Interactive shell
@ -67,101 +67,95 @@ At the `> ` prompt:
`s/sh` tracks the last session per working directory in `~/.config/ollie/last-session`,
so switching directories and re-running `s/sh` resumes the right context automatically.
## Batch jobs
## One-shot queries
`b/` provides ephemeral one-shot agent runs — a single prompt, a single result, no
persistent session state.
`s/bfg` and `s/bbg` submit a single prompt to a new session. The difference is only in
how the caller is treated: `s/bfg` blocks until the agent finishes and writes the result
to stdout; `s/bbg` returns immediately and prints the path of the session.
### b/job
Both are thin wrappers around `s/b`, which is the core one-shot runner.
### s/bfg
Submit a prompt, wait for completion, print the result:
```sh
$OLLIE/b/job "Summarize this repo"
cat main.go | $OLLIE/b/job "explain this file"
$OLLIE/b/job -parallel 4 -keep "Write a haiku"
$OLLIE/b/job -backend ollama -model qwen3:8b "Explain this" < main.go
$OLLIE/s/bfg "Summarize this repo"
cat main.go | $OLLIE/s/bfg "explain this file"
$OLLIE/s/bfg -parallel 4 -keep "Write a haiku"
$OLLIE/s/bfg -backend ollama -model qwen3:8b "Explain this" < main.go
```
With `-parallel N`, N jobs run concurrently and results are separated by `=== {id} ===` headers.
With `-parallel N`, N jobs run concurrently and results are printed as they complete.
### b/q
### s/bbg
Foreground one-shot query; thin wrapper around `b/job`:
Submit a background job and return immediately; prints the `s/{id}` path:
```sh
$OLLIE/b/q "what is 2+2?"
echo "what is causing this?" | $OLLIE/b/q
```
### b/sched
Submit a background job and return immediately; prints the `b/{id}` path:
```sh
$OLLIE/b/sched "summarize the recent git log"
# /home/lkn/mnt/ollie/b/1744276689123456789-0
$OLLIE/s/bbg "summarize the recent git log"
# /home/lkn/mnt/ollie/s/1744276689123456789-0
```
Poll for completion:
```sh
path=$($OLLIE/b/sched "write a limerick about Go")
until [ "$(cat $path/state)" = "done" ]; do sleep 0.1; done
cat $path/result
path=$($OLLIE/s/bbg "write a limerick about Go")
until [ "$(cat $path/statewait)" = "idle" ]; do :; done
tail -c +$(($(cat $path/offset) + 1)) $path/chat
```
Fan out with `-parallel N` and collect results:
```sh
paths=$($OLLIE/b/sched -parallel 4 "draft a blog intro" < brief.txt)
paths=$($OLLIE/s/bbg -parallel 4 "draft a blog intro" < brief.txt)
for p in $paths; do
until [ "$(cat $p/state 2>/dev/null)" = "done" ]; do sleep 0.1; done
cat $p/result
until [ "$(cat $p/statewait 2>/dev/null)" = "idle" ]; do :; done
tail -c +$(($(cat $p/offset) + 1)) $p/chat
rm -r $p
done
```
### b/cleanup
### s/cleanup
Remove all completed jobs:
Remove all idle sessions:
```sh
$OLLIE/b/cleanup
$OLLIE/s/cleanup
```
Schedule regular cleanup with a cron job:
```
*/15 * * * * /path/to/mnt/ollie/b/cleanup
*/15 * * * * /path/to/mnt/ollie/s/cleanup
```
### Raw b/ access
### Raw s/ access
```sh
cat $OLLIE/b/new # show the spec template
printf 'cwd=%s\n---\nSummarize this.\n' "$PWD" > $OLLIE/b/new
cat $OLLIE/b/<job-id>/state # running | done | failed: <reason>
cat $OLLIE/b/<job-id>/result
rm -r $OLLIE/b/<job-id> # cancel and remove
cat $OLLIE/s/new # show the spec template
printf 'cwd=%s\n---\nSummarize this.\n' "$PWD" > $OLLIE/s/new
cat $OLLIE/s/<session-id>/state # running | idle | failed: <reason>
cat $OLLIE/s/<session-id>/chat
rm -r $OLLIE/s/<session-id> # cancel and remove
```
Valid spec keys: `name` (auto-generated if omitted), `cwd` (required), `agent`,
`backend`, `model`, `output`, `parallel`.
`backend`, `model`.
## AI pipelines
`b/q` and `b/job` write to stdout and compose naturally with Unix pipes. When both args
`s/bfg` writes to stdout and composes naturally with Unix pipes. When both args
and stdin are present, args are treated as the instruction and stdin as the content:
```sh
echo "write a haiku about filesystems" | $OLLIE/b/q | wc -w
cat error.log | $OLLIE/b/q "what is causing this?" | $OLLIE/b/q "suggest a fix"
$OLLIE/b/q "list 5 blog post ideas" | grep -v "^$" | head -3 | $OLLIE/b/q "expand the best one"
echo "write a haiku about filesystems" | $OLLIE/s/bfg | wc -w
cat error.log | $OLLIE/s/bfg "what is causing this?" | $OLLIE/s/bfg "suggest a fix"
$OLLIE/s/bfg "list 5 blog post ideas" | grep -v "^$" | head -3 | $OLLIE/s/bfg "expand the best one"
```
`u/optimize` is a worked example — it generates N candidate prompts in parallel via
`b/q -parallel N`, then judges them with a second `b/q` call to return the best:
`s/bfg -parallel N`, then judges them with a second `s/bfg` call to return the best:
```sh
$OLLIE/u/optimize -n 3 -cm qwen/qwen3-8b -jm anthropic/claude-opus-4-6 "explain recursion"
@ -171,7 +165,7 @@ Progress goes to stderr; pipe the optimized prompt with content into a subsequen
```sh
prompt=$($OLLIE/u/optimize "translate this to Spanish" 2>/dev/null)
cat document.txt | $OLLIE/b/q "$prompt"
cat document.txt | $OLLIE/s/bfg "$prompt"
```
## Alternative front-ends
@ -182,4 +176,3 @@ The 9P filesystem is the lowest level interface to ollie. All interfaces are sim
- **[ellie](https://github.com/lneely/ollie-el)** — `ellie.el` is the Emacs front-end, just wire it into your `init.el` and `M-x ellie`
See each repo's README for installation and usage.

View File

@ -10,17 +10,15 @@ so they are available without any `$PATH` changes:
exec $OLLIE/s/sh # start interactive shell
$OLLIE/s/ls # list sessions
$OLLIE/s/kill <id> # kill a session
$OLLIE/b/job "my prompt" # submit and wait for a batch job
$OLLIE/b/q "my prompt" # foreground one-shot query
$OLLIE/b/sched "my prompt" # submit a background job; prints b/ path
$OLLIE/b/cleanup # remove all completed jobs
$OLLIE/s/bfg "my prompt" # foreground one-shot query; blocks until done
$OLLIE/s/bbg "my prompt" # background one-shot query; prints session path
$OLLIE/s/cleanup # remove all idle sessions
$OLLIE/u/optimize "prompt" # generate and return best optimized prompt
```
Scripts are organized by the filesystem namespace they are hosted under:
- `s/` — session management scripts
- `b/` — batch job scripts
- `s/` — session management and one-shot query scripts
- `u/` — utility scripts; compositions of other ollie primitives
---
@ -89,87 +87,89 @@ s/kill <id>
---
## b/job
## s/bfg
Core batch job runner. Submits a prompt to `b/new`, waits for completion,
prints the result to stdout, then removes the job. Exit code is non-zero on
failure. `b/q` and `b/sched` are both wrappers around this script.
Foreground one-shot query. Submits a prompt to a new session, blocks until
the agent is done, writes the result to stdout, then removes the session.
Exit code is non-zero on failure. Thin wrapper around `s/b`.
```
b/job [flags] [prompt...]
echo "prompt" | b/job [flags]
s/bfg [flags] [prompt...]
echo "prompt" | s/bfg [flags]
```
**Flags**
| Flag | Description |
|---|---|
| `-name N` | Base job name; jobs are suffixed `-0`, `-1`, ... |
| `-cwd DIR` | Working directory (default: `pwd`) |
| `-agent A` | Agent config name |
| `-backend B` | Backend override |
| `-model M` | Model override |
| `-output json` | Append JSON-only instruction to prompt |
| `-parallel N` | Run the same prompt N times in parallel (default: 1) |
| `-keep` | Do not remove job(s) after printing result |
| `-bg` | Submit and exit immediately; prints job id(s); implies `-keep` |
Accepts the same flags as `s/b`.
**Examples**
```sh
b/job "Summarize this repo in one sentence"
cat error.log | b/job "What is causing this error?"
b/job -output json "List the top 3 risks as JSON"
b/job -parallel 4 -keep "Write a haiku about filesystems"
b/job -backend ollama -model qwen3:8b "Explain this function" < main.go
```
With `-parallel N` and N > 1, results are separated by `=== {id} ===` headers.
---
## b/q
Foreground one-shot query; thin wrapper around `b/job`. Accepts the same flags.
```
b/q [flags] [prompt...]
echo "prompt" | b/q [flags]
s/bfg "Summarize this repo in one sentence"
cat error.log | s/bfg "What is causing this error?"
s/bfg -output json "List the top 3 risks as JSON"
s/bfg -parallel 4 -keep "Write a haiku about filesystems"
s/bfg -backend ollama -model qwen3:8b "Explain this function" < main.go
```
---
## b/cleanup
## s/bbg
Remove all batch jobs with state `done`.
Background one-shot query. Submits a prompt to a new session and returns
immediately; prints the `s/{id}` path for each job. Thin wrapper around
`s/b -bg`.
```
b/cleanup
s/bbg [flags] [prompt...]
echo "prompt" | s/bbg [flags]
```
Accepts the same flags as `s/b`.
**Examples**
```sh
path=$(s/bbg "write a limerick about Go")
until [ "$(cat $path/statewait)" = "idle" ]; do :; done
tail -c +$(($(cat $path/offset) + 1)) $path/chat
```
---
## b/sched
## s/b
Submit a background job; prints the `b/` path for each job. Wrapper around
`b/job -bg`.
Core one-shot runner. Submits a prompt to a new session, optionally waits,
and handles parallel fan-out. `s/bfg` and `s/bbg` are both wrappers around
this script.
```
b/sched [flags] [prompt...]
echo "prompt" | b/sched [flags]
s/b [flags] [prompt...]
echo "prompt" | s/b [flags]
```
**Flags**
| Flag | Description |
|---|---|
| `-name N` | Base job name |
| `-name N` | Base session name; sessions are suffixed `-1`, `-2`, ... |
| `-cwd DIR` | Working directory (default: `pwd`) |
| `-agent A` | Agent config name |
| `-backend B` | Backend override |
| `-model M` | Model override |
| `-output FORMAT` | Output format hint (e.g. `json`) |
| `-parallel N` | Submit N parallel jobs (default: 1) |
| `-json` | Append JSON-only instruction to prompt |
| `-parallel N` | Run the same prompt N times in parallel (default: 1) |
| `-keep` | Do not remove session(s) after printing result |
| `-bg` | Submit and exit immediately; prints session path(s); implies `-keep` |
| `-failfast` | On first failure, cancel remaining parallel jobs and exit |
---
## s/cleanup
Remove all idle sessions.
```
s/cleanup
```
---
@ -198,7 +198,7 @@ echo "prompt" | u/optimize [flags]
```sh
u/optimize "Summarize this document"
u/optimize -n 5 -cm qwen/qwen3-8b -jm anthropic/claude-opus-4.6 "Write a haiku"
u/optimize "generate a hello world program. use c++." >[2]/dev/null | b/q
u/optimize "generate a hello world program. use c++." >[2]/dev/null | s/bfg
```
Outputs to stdout, making it composable with other pipeline stages.