ollie/doc/usage.md

10 KiB

Usage

Server

Start and stop

olliesrv                # start the server (foreground)
# Stop by sending SIGTERM or via the supervisor (e.g. rc-service ollie stop)

TCP listener

To also accept connections over TCP (e.g. for remote access):

olliesrv -tcp :9564

Debug logging

Log level is controlled by OLLIE_LOG (default: warn). Set to debug for verbose output:

OLLIE_LOG=debug olliesrv

Valid levels: debug, info, warn, error.


Security and sandboxing

toolsrv applies the configured policy directly through native Landlock in a short-lived child helper; it does not depend on an external sandbox executable. On Linux, the helper creates and restricts a Landlock ruleset before executing the tool. Use yolo=true only for explicit development cases where enforcement should be disabled.

o — Terminal CLI

o is a multi-call shell script that wraps the 9P namespace into a human-friendly interface. Installed to ~/.local/bin/o by make install-data.

Quick start

o myproj/default new                  # create session + agent
o myproj/default tui                  # launch the tmux TUI

Or without the TUI:

o myproject/default prompt        # interactive prompt REPL (one terminal)
o myproject/default read chat     # stream chat output (another terminal)
Screenshot of o tui: two tmux panes showing chat output and prompt input, with agent state in the status bar
o tui — tmux + shell commands
Screenshot of ollie running in the acme text editor: multiple windows showing session tree, chat, and prompts
acme — Plan 9 editor

Context model

Context is determined by the first argument — not by environment variables:

o <cmd>                     Root level (no context)
o <session> <cmd>           Session level
o <session>/<agent> <cmd>   Agent level

The slash in <session>/<agent> disambiguates session-only from session+agent. o ls lists the root of the ollie namespace; o with no arguments prints help.

Commands

Command Context Description
o ls root List sessions, models, backends
o generate <prompt> root One-shot generation (no session needed)
o <sess>/<agent> new [cwd] agent Create session (if needed) + agent
o <sess> ls session List session contents
o <sess> ctl <cmd> session Session control
o <sess>/<agent> prompt agent Interactive multi-line prompt REPL
o <sess>/<agent> tui agent Launch tmux TUI
o <sess>/<agent> ctl <cmd> agent Agent control (stop, compact, model, etc.)
o <sess>/<agent> log [-n N] agent Show last N lines of agent log
o read [-l] <path> any Read a file (-l: loop)
o write <path> [data] any Write to a file (args or stdin)
o env any Print export statements for current context
o help any Show help

Path resolution

When you supply a context, o sets a prefix:

  • Session: session/<sess>
  • Agent: session/<sess>/agent/<agent>

Paths given to read, write, and ls are resolved relative to this prefix. A leading / escapes the prefix and addresses the root namespace directly:

Invocation Resolves to
o myproj/coding read chat session/myproj/agent/coding/chat
o myproj/coding read cfg session/myproj/agent/coding/cfg
o myproj read env session/myproj/env
o myproj/coding read /models models (root)
o myproj/coding ls /bypass bypass (root)
o read models models (no context, no prefix)

The leading slash is necessary when you want to access root-level paths (like models, backends, bypass/) while in session or agent context. Without it, the path is concatenated with the context prefix.

Prompt REPL

o <session>/<agent> prompt is an interactive multi-line REPL:

$ o myproj/coding prompt
[myproj/coding]
Type . on a blank line to send, Ctrl+D to exit.
/ prefix runs ctl: /stop, /compact, /model X, /inject X
!q exits the TUI.

> write a fibonacci function in python
  and include a test case
  .

Type your prompt across multiple lines, then send with . on its own line. Any agent ctl command works as a slash command — the / prefix is stripped and the rest is sent to ctl:

Command Description
/stop Interrupt running agent
/compact Compact context window
/clear Clear history
/kill Kill the agent
/model [X] Show or switch model
/models List available models
/backend Show current backend
/agent [X] Show or switch agent profile
/name [X] Show or set agent display name
/cwd [X] Show or change working directory
/inject X Inject text into context (alias: /i)
/tools List loaded tools
/tool_load X Load a tool
/tool_unload X Unload a tool
/peeradd X Add a bidirectional peer link
/peerdel X Remove a bidirectional peer link
/peers List current peers
!q Kill the tmux TUI session and exit

Piped input is also supported:

echo "explain this error" | o myproj/coding prompt
cat file.go | o myproj/coding write prompt

One-shot generation

No session or agent needed — o generate sends a prompt and returns a response:

o generate "explain monads in one sentence"
cat error.log | o generate   # pipe content as the prompt
echo "write a haiku about filesystems" | o generate | wc -w

o tui — tmux Terminal UI

o <session>/<agent> tui composes o read chat and o prompt into a single tmux layout — two shell commands in two panes, with agent state in the tmux status bar:

Screenshot of the o tui tmux layout: chat pane on top, prompt REPL on bottom, agent state in status bar

Usage

o myproj/coding tui
  1. Creates a tmux session named o-<session>.
  2. Two panes:
    • Pane 0 (top, 80%): streams chat output (log tail + live read chat).
    • Pane 1 (bottom, 20%): o prompt — multi-line REPL (/ prefix runs ctl commands).
  3. A background process subscribes to the agent's state events via echo "session.{s}.agent.{a}.state" | ollie-9p rdwrs event and updates the tmux status bar on each state transition.
  4. Focuses the prompt pane and attaches.

No polling. Each read blocks until data arrives. The status bar updates on every state transition via the event stream — zero CPU when idle.

tmux tips

  • Ctrl+b ; — toggle between last two panes (fast prompt ↔ tail switch)
  • Ctrl+b z — zoom any pane to full screen
  • Ctrl+b [ — scroll mode (arrow keys, q to exit)
  • Ctrl+b d — detach (session keeps running, reattach with tmux attach -t o-<session>)

o env — Context export

o env prints export statements for the current context. This is useful for other tools (raw ollie-9p commands, scripts) that need to know which session and agent are being addressed:

eval $(o myproj/coding env)
# exports OLLIE_SESSION=myproj OLLIE_AGENT=coding
ollie-9p read session/$OLLIE_SESSION/agent/$OLLIE_AGENT/stats

Note: o itself does not read these environment variables — it determines context purely from its positional arguments.


Pair programming — observer agents

An observer agent watches your coding session and makes real-time observations: bugs, missed error handling, security issues. It uses the feed file — a change-detecting input present on every agent. The same mechanism works whether a human or another agent is coding.

Setup

# Create the observer (use the observer profile for read-only tools):
o myproj/obs new /path/to/repo
o myproj/obs ctl agent observer

Wire a human coding session

Poll git diffs and pipe into the observer's feed. The feed file deduplicates — same diff written twice is ignored:

while :; do git diff HEAD --; sleep 5; done | o myproj/obs write feed

Read observations in another terminal:

o myproj/obs read chat

Wire an agent coding session

Use the event stream as the trigger — subscribe to state changes and pipe in the git diff when the coder's turn completes:

echo "session.myproj.agent.coder.state" | ollie-9p rdwrs event | while read -r topic state; do
    git diff HEAD --
done | o myproj/obs write feed

How it works

The feed file on each agent is a BlockOnce file:

  • Write: stores the data + signals change.
  • Read (blocking): blocks until the content changes from what it was when you opened. Returns new data once, then EOF.
  • Dedup: built into the read side. Same content written repeatedly never wakes the reader.

Internally, each agent has a ConsumeFeed goroutine that reads from its own feed file (via 9P) and submits new data as prompts. The observer processes each diff it receives, optionally reads surrounding code for context, and produces terse observations.

Multiple observers

Nothing stops you from running N observers on the same coder:

# Security-focused observer:
o myproj/security new /path/to/repo
o myproj/security ctl agent observer

# Performance-focused observer (custom prompt):
o myproj/perf new /path/to/repo
# ... configure with a different prompt

# Same feed wiring for both:
while :; do git diff HEAD --; sleep 5; done | tee >(o myproj/security write feed) | o myproj/perf write feed

Other front-ends

  • Session clients — shell, KDE, and other 9P clients
  • KDE — plasmoid, standalone GUI, Kate plugin, KRunner
  • acme — Plan 9 editor (scripts in data/scripts/acme/)

For technical details on the raw 9P filesystem, see doc/architecture-9p.md. For tool architecture and authoring, see architecture-tools.md.