Backend:
- Add proc.start/proc.exit events for background process lifecycle
- Add proc idx ctl command for machine-readable process listing (TSV)
- Add event.pub file for external event publishing
- Add ListProcsIdx to toolclient and toolsrv
- Fix bypass commands to use Setpgid for process group isolation
GUI:
- Add configurable bypass approval shortcuts (Ctrl+Y/Ctrl+N default)
- Add Keyboard Shortcuts section to Settings dialog
- Store shortcuts in theme.conf
Kate:
- Fix 'Start Session Here' - use rdwr for session/new endpoint
Background procs with bypass were hanging because the caller blocked on
<-startedCh waiting for the process to start, but bypass.Submit blocks
until approval. Now we signal started immediately when entering bypass
path (with Process: nil), so the agent sees the proc ID right away.
Also handle term/kill when proc.proc is nil — cancel the context to stop
the operation (e.g., abort a pending bypass request).
executeBypassDirect was missing the streamOut parameter, so background
processes running via bypass never had their output written to the proc
buffer. Now both bypass and sandboxed paths receive the streaming writer.
GitSpawn class (Sep 2026): a repo's .git/config can set core.fsmonitor to
a command that executes on any git index refresh, silently and as the
user. Ollie never spawns git in its own plumbing (repo detection is
os.Stat), but model-run git inside a malicious repo would fire it.
- exec: force core.fsmonitor=false via GIT_CONFIG_* in sandboxed tool env
- turn: wrap repo AGENTS.md in <context> markers (untrusted data,
filtered by KDE chat rendering)
- AGENTS.md: document the no-git-in-plumbing invariant (lesson 16)
- ResolveTool now returns cmd field as-is instead of trying to resolve
it as a binary path. This allows meta-only tools to use full shell
command strings with env vars, pipes, and subshells.
- Prepend ~/.config/ollie/tools to PATH when executing tools so cmd
fields can reference other tools by name.
bypass.Submit now takes a context and returns early when cancelled.
This allows the stop command to properly cancel pending bypass requests
that haven't been approved or denied yet.
The full context chain is now:
1. stop command -> Interrupt -> cancel actCtx
2. actCtx cancellation -> closes CallTool fid
3. toolsrv proc/new sees closed fid -> propagates ctx cancellation
4. ExecuteTool -> executeBypassDirect -> bypass.Submit
5. bypass.Submit returns ctx.Err() when context is cancelled
The sudo credential broker was never functional and added complexity
without value. This removes:
- Sudo field from bypass Request structs (broker, client, toolsrv)
- Sudo parameter from EvaluateRequest interface and implementations
- Sudo/ResetsCounter fields from MetaFile and Variant structs
- sudo: true from system_logs.meta variants
- All sudo documentation from writing-tools.md, tool-registry.md,
core.md, evolution.md, and misc.md
Bypass remains fully functional for sandbox escapes. Tools that need
elevated privileges should handle that internally or be run manually.
This refactors the bypass (sandbox escape) mechanism to work with remote
toolsrv deployments. Previously, bypass used a Unix socket which only
works when toolsrv runs locally. Now:
1. toolsrv exposes bypass/{pending,resolve} 9P files
- pending: blocking read returns next bypass request as JSON
- resolve: write JSON {id, approved, error} to complete request
2. olliesrv reads bypass/pending in a loop per session
- Evaluates requests through the existing bypass broker
- Policy check, rate limiting, user notification all stay in olliesrv
- Writes approval/denial back to bypass/resolve
3. When approved, toolsrv executes the command directly (no sandbox)
- Execution happens on toolsrv's host (local or remote)
- Output streams back through the normal tool call path
This enables bypass to work when toolsrv is remote:
- User sees the approval notification locally
- Command executes on the remote host outside its sandbox
Architecture:
toolsrv (remote) olliesrv (local)
┌─────────────────┐ ┌──────────────────┐
│ sandboxed cmd │ │ bypass broker │
│ ↓ │ │ - policy │
│ bypass.Submit() │──────│ - notification │
│ ↓ │ 9P │ - rate limit │
│ wait for result │←─────│ - user approval │
│ ↓ │ └──────────────────┘
│ execute direct │
└─────────────────┘
The bypass broker requires a 'session' field in the JSON request
to identify which session is making the bypass request. The toolsrv
was sending requests without this field, causing 'denied (no session
identity)' errors.
Fix: Include OLLIE_SESSION_ID from environment in the bypass request.
Removed the named sandbox concept. One config file: sandbox.yaml
(installed to ~/.config/ollie/sandbox.yaml). Removed sandbox-remote.yaml,
moved restricted.yaml to doc/ as a sample. Removed the 'sandbox' arg
from tool dispatch.
- Background procs get timeout=0 (no deadline) set by toolsrv at
the execution layer — not injected as an arg from olliesrv.
Foreground default remains 30s. User can still override via args.
- Timeout logic simplified: caller sets default, ExecuteTool honors it.
- System prompt: clarify background has no timeout, uses 'stop' not 'kill'
- architecture.md: document lifecycle (connection-based ownership)
- evolution.md: update interrupt section with streaming, lifecycle, id= format
- README.md: add parallel execution to capabilities table
- KillAll(): sends SIGKILL to all running proc groups on clean shutdown
- Pdeathsig: SIGKILL ensures child procs die if toolsrv crashes
- Shell tool: use subshell + set +e for streaming without exit propagation
- Fix integration test to match new error format
This is the connection-based ownership model: toolsrv death = proc death.
The session owns the toolsrv process, so session death cascades to all procs.
- Timeout: timeout=0 means no deadline (was defaulting to 30s)
- Signal: send to process group (-pgid) not just process; SIGTERM no longer
cancels context (only SIGKILL does); cmd.Cancel sends SIGTERM with 5s WaitDelay
- Streaming: background procs stream output in real-time via procWriter;
shell tool no longer buffers all output into a bash variable
- Proc tree: olliesrv exposes proc/{id}/out, proc/{id}/ctl, proc/{id}/status
as proper 9P directory (was broken flat file)
- Connection: proc handlers dial fresh toolsrv conn per request via
Session.DialToolServer() to avoid deadlocking the agent's blocked conn
- Stat format: key=value (exited=true, exit_code=N, id=N) matching client parser
- GC: procs auto-removed 10min after LastRead (exited procs only)
- Rename: PID -> ID throughout (synthetic, not OS PID)
- Ctl commands: term (SIGTERM), kill (SIGKILL), signal <n>, dismiss
- System prompt: correct ollie-9p commands for proc management
- Move toolsrv logic into internal/{fs,exec,registry} packages to match
olliesrv's structure. server.go (9P protocol) stays at top level.
- Deduplicate parseKV/parsePayload: remove dead code from old spec9p.go,
single implementation in internal/fs/parse.go.
- Add structured logging via log/slog (replaces fmt.Fprintf to stderr).
- Standardize qid path hashing to fnv.New64a (matches olliesrv).
- Fix toolsrv process leaks:
- Add Pdeathsig to local spawn so toolsrv dies when olliesrv exits.
- Add idle timeout (30s with no connections after first client seen).
- ProcessKeeper.Dial() kills old process before respawning.