From 2148c8c668a8255d44864fa7ddd392e7de706516 Mon Sep 17 00:00:00 2001 From: Levi Neely Date: Sat, 25 Apr 2026 08:31:15 +0200 Subject: [PATCH] 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 --- README.md | 4 +- doc/ARCHITECTURE.md | 17 ++++--- doc/USAGE.md | 87 ++++++++++++++++------------------- scripts/README.md | 110 ++++++++++++++++++++++---------------------- 4 files changed, 105 insertions(+), 113 deletions(-) diff --git a/README.md b/README.md index f4f2d83..3e53fad 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/doc/ARCHITECTURE.md b/doc/ARCHITECTURE.md index 05e2a74..1d04987 100644 --- a/doc/ARCHITECTURE.md +++ b/doc/ARCHITECTURE.md @@ -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 diff --git a/doc/USAGE.md b/doc/USAGE.md index 53ad85d..d1b4ed5 100644 --- a/doc/USAGE.md +++ b/doc/USAGE.md @@ -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//state # running | done | failed: -cat $OLLIE/b//result -rm -r $OLLIE/b/ # 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//state # running | idle | failed: +cat $OLLIE/s//chat +rm -r $OLLIE/s/ # 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. - diff --git a/scripts/README.md b/scripts/README.md index 61153ed..dc29a46 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -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 # 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 --- -## 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.