- spec9p.go: fsedsl-based namespace specification
- ToolsrvCtx with Server, Agent, Proc
- Handlers as package-level functions
- Follows fs/spec.go pattern
- server9p.go: simplified to state management only
- Agent registration with HMAC tokens
- BuildTree() creates fsedsl tree
- Removed redundant 9P protocol handling
The 9P protocol serving will use the same pattern as olliesrv
(cmd/olliesrv/server.go), which takes a *fsedsl.Tree and handles
all 9P message types generically.
New files:
- fs9p.go: FS9P struct with /proc-based execution model
- /proc/new (rdwr): blocking tool execution
- /proc/new.bg: background/detached execution
- /proc/<pid>/out, wait, stat, ctl: process management
- /tools, /ctl, /info: tool registry and host info
- Payload format: key=value lines, newline delimited
- exec9p.go: Decoupled tool execution
- ExecuteTool: standalone function for tool execution
- executeSandboxed: sandbox execution without Server deps
- executeBypassDirect: bypass broker without Server deps
- fs9p_test.go: Unit tests for FS9P
Design notes:
- Background execution is the internal model
- Foreground (/proc/new rdwr) blocks until completion
- No per-connection state (cwd/env passed per-call or at attach)
- Session ID scoping via registry, not env propagation
This is the foundation - actual 9P serving and integration pending.
The ctl tool_load command was loading tools into the registry but
not notifying the agent to refresh its preamble. Add RefreshTools()
method and call it after loading a tool via ctl.
Paths starting with / are treated as root-relative, ignoring
the current context prefix. This allows accessing root-level
files/directories even when in a session or agent context.
Example: o myproj/coding ls /bypass # list root bypass/ dir
Simplify context parsing:
- o <cmd> Root level
- o <session> <cmd> Session level
- o <session>/<agent> <cmd> Agent level
The slash disambiguates between session and agent context,
eliminating the need for 'session' and 'agent' keywords.
Examples:
o myproj ls # session level
o myproj/coding prompt # agent level
Refactor o CLI to use explicit context selectors:
- o <cmd> Root level
- o session <sname> <cmd> Session level
- o agent <sname> <aname> <cmd> Agent level
Environment variables $session and $agent can substitute for
positional args for backwards compatibility.
Update acme scripts to use new interface:
o agent $OLLIE_SESSION $OLLIE_AGENT prompt
Add acme-ollie-ensure helper that:
- Creates 'acme' session if it doesn't exist
- Creates agent named by cwd hash (like kate's approach)
- Updates agent cwd if it already exists
All acme commands now call acme-ollie-ensure before sending
prompts, so they work without manual session setup.
Add acme scripts for interacting with ollie:
- AskFile: describe the current file
- Explain: explain selected code
- Document: add documentation comments
- Fix: fix selected code
- Refactor: refactor selected code
- AddTests: write unit tests for selection
- SendVerbatim: send selection as-is
Scripts use the acme 9P filesystem to read selections and pipe
prompts to ollie via 'o prompt'.
Also update justfile to install/uninstall the acme scripts.
- backend: add CWD field to GenerationParams for environment state
- kiro: pass session CWD to kiroCurrentEnvState instead of hardcoded '/'
- agent/runtime: set GenParams.CWD from session cwd in BuildRuntime
- o new: create sessions and agents via 9P filesystem
- o prompt: support piped stdin for non-interactive use
- doc/boot-sequence.md: init chain from main → fs.NewRoot → session.Init
- Event protocol: comprehensive table on Event struct (all roles, semantics)
- RPC server moved from cmd/ollie-remote into toolsrv/rpcserver.go
(binary is now a 93-line thin wrapper)
- SetSessionEnv folded into NewAgent (no post-construction wiring needed)
- AgentCfg → AgentParams (distinguish from AgentConfig JSON schema)
- ToolResult/ToolResultContent shared types in toolsrv/rpcwire.go
- toolsrv/shell.go → toolsrv/exec.go (name matches purpose)
- Resume unified: single path, always through Keeper
- AGENTS.md: fix fs/builder.go → fsedsl/builder.go, handlers_*.go
- fsedsl/Tree: document dual-mode (EDSL lazy vs Manual Mount)
- Truncation stack documented at defaultToolResultMaxBytes
- Integration test rewritten to use srv.ServeRPC directly
The inFence state machine was dropping all lines between fence
delimiters, not just the delimiters themselves. Tool output, assistant
code blocks — everything inside fences was being eaten.
Fix: remove only [[[...]]] marker lines and bare fence delimiter lines
(``` / ```lang). Preserve all content between them.
When a streaming chunk contains only markers/fences, stripMarkers
returns empty bytes. The 9P server interprets a zero-length Rread as
EOF, closing the client's FD.
Fix: loop in streamAgentChatText, advancing the offset past
marker-only chunks until real content arrives.
README: mermaid diagram now shows o CLI as the foundation layer
between text frontends and 9P. KDE/Kate connect directly to 9P.
ellie.el (both versions): add ellie--9p-rdwr wrapper, use ctl rdwr
for systemprompt (no longer a standalone file).
Replace switch statement with rdwrHandler map. Each command is a
function value in agentCtlHandlers — easy to extend, test individually,
and introspect.
/tools — lists loaded tools
/tool_load X — loads a tool by name
System prompt updated to instruct the agent to use ctl for tool
management instead of writing to a tools file.
/models now lists available models for the agent's backend via ctl.
One fewer file in the agent namespace. The root-level models file
(all backends) remains unchanged.
The ctl file is now a Request handler: write a command, read the
response. Commands with no args return current state:
/model → prints current model
/agent → prints current profile
/cwd → prints working directory
/name → prints agent name
/model X → switches model, returns new model
/compact → compacts, returns 'ok'
o ctl now uses 'ollie-9p rdwr' to get the response.
This enables /model (no args) to show the current model from
any frontend.
The slash prefix in prompts now routes directly to the agent's ctl
file. No special-cased commands in the agent — the ctl handler is the
single command surface:
/stop, /compact, /clear, /model X, /inject X, /agent X, /cwd X
New ctl commands:
inject <text> — overwrites any pending inject (replaces /i and /irw)
agent <name> — switch agent profile (moved from commands.go)
Agent methods added: Compact(), Clear(), SwitchProfile() — called by
the ctl handler, testable independently.
HandleCommand is now a thin trampoline: strip /, run 'o ctl <rest>'.
commands.go reduced from 155 to 50 lines.
REPL: / → o ctl, !q/!quit → exit TUI.
The sandbox escape mechanism is a bypass, not privilege elevation.
The old name caused the agent to confuse it with sudo.
- elevate/ → bypass/ (package, types, tests)
- elevate_notify.go → bypass_notify.go
- Namespace: /elevate → /bypass, session/*/elevate → session/*/bypass
- Tool arg: "elevated" → "bypass"
- Env: OLLIE_ELEVATE_SOCKET → OLLIE_BYPASS_SOCKET
- File: elevate-policy.yaml → bypass-policy.yaml
- All docs, prompts, and scripts updated
- Merge readloop into read -l (loop mode)
- Remove chatstream command (TUI uses 'o read chat' directly)
- Rework ctl: o ctl <cmd> [session] [agent] — dispatches to
session ctl for kill/pause/resume, agent ctl for the rest
- Add trap EXIT to kill background statewait loop (fixes zombie)
- Remove -1 compatibility flag from generate
- Remove no-op bracketed paste bind from prompt REPL
- Fix /i help text: 'inject prompt (mid-turn or queued)'
- Update all help text to reflect current commands
- Delete agent/usage_log.go — wrote JSONL to disk but nothing read it
- Remove appendUsageLog call from turn.go
- Remove dead 'offset' from AGENT_FILES tab-completion list
- TUI: grep markers+fences from o log (single read, not streaming)
- fifo.in + fifo.out → single fifo (write enqueues, read dequeues)
- cost + usage + ctxsz → single stats (key=value lines)
- Remove connection (no consumers, heartbeat handles it)
- Remove dead prevPrompt field and write (prompt.prev gone from spec)
- Clean AGENT_FILES: remove state, context, tail (all already absent
from spec, were only in the tab-completion list)
chat — strips [[[...]]] markers and source fences at the byte level.
Partial lines pass through immediately for true streaming. Terminals
and text editors use this.
chat.raw — full block-structured stream with markers and fences.
GUIs that parse blocks (KDE, web) use this.
The TUI no longer pipes through grep (which was line-buffering and
killing char-by-char streaming since Aug 4).
The stripMarkers state machine processes each chunk from the server:
- Complete lines starting with [[[ and ending with ]]] → dropped
- Fence lines (```...) → dropped (open toggles in-fence state)
- Partial lines (no trailing \n) → always emitted immediately
- Everything else → passed through
session.New() had zero callers — all sessions are created via
NewEmpty() + buildAgent(). Remove it along with the Config struct
(20 fields) and the per-session sessionsDir field (always identical
to pkgSessionsDir).
-92 net lines
sync.Cond is the wrong primitive for Go — it requires holding a mutex
during Wait and needs context.AfterFunc hacks to integrate with ctx
cancellation.
Replace with a simple signal channel: notifyChange() closes it and
swaps in a fresh one; WaitChange() selects on the channel and
ctx.Done(). Simpler, idiomatic, no spurious wakeups.
Add JSON tags to backend.GenerationParams and embed it directly in
AgentConfig. The 14 duplicated sampling fields and the field-by-field
copy method disappear. Callers use cfg.GenerationParams directly.