Moved all 9P FUSE mount code from core to 9p module using lifecycle hooks.
Changes:
- Removed 9P-specific fields (mountProc, mountPath, mountEnabled) from execute.Server
- Removed WithMount(), MountPath(), startMount(), remountIfStale() functions
- Added lifecycle hooks: OnPreDispatch, OnClose, OnEnvSet with corresponding options
- Updated SetEnv(), Close(), and Dispatch() to call hooks instead of hardcoded mount logic
- Fixed tool descriptions to use $OLLIE_TOOLS_PATH instead of 9P-specific $OLLIE/s/$SID/t paths
- Removed unused execute import from agent/commands.go
The core execute server is now harness-agnostic.
- Add ListHandlers map to AgentCoreConfig/agent struct; /skills and /tools
dispatch through it instead of reading local paths directly
- Add ReadPlanStep to AgentCoreConfig; wired by 9p/ directly from sess.plan
- Export NextUncheckedStep([]byte) as pure helper
- Fix prependOlliePath to use OLLIE_CFG_PATH/scripts/x/ instead of $OLLIE/x/
- Add OLLIE_CFG_PATH to EnsureDefaults and managed env var list
Session identity is now a numeric UID (starting at 10000) assigned at
creation and never changed. Session names can be renamed freely without
affecting the 9P identity.
- AgentCoreConfig.Uname carries the principal
- pushSessionEnv sets OLLIE_UNAME on the execute server
- startMount gated by WithMount() option (not env var)
- Close() uses context timeout to avoid hanging on fusermount
The execute server now starts ollie-9p-mount when OLLIE_SESSION_ID is
set, giving each agent session its own FUSE proxy that attaches to
olliesrv with Uname=session_id. Tools see the full namespace through
$OLLIE but all 9P operations carry the session's identity.
Close() tears down the mount on session destroy.
- Wire PlanFile from $OLLIE/s/{id}/plan into agentConfig so plan
re-injection is no longer dead code
- Add missing failureWindow/maxFailures/blockDuration constants
- Replace hand-rolled contains() with strings.Contains
- Fix rm -rf .. regex to match end-of-string and whitespace
- Add TestPlanReinjection covering periodic plan re-surfacing
- Add loop_maxsteps_helpers_test.go with mockResponse/newState/sequentialStream
- steps: independent, run in parallel when annotated safe, outputs
concatenated. No stdout chaining.
- pipe: explicit pipeline, sequential, stdout of each stage feeds
stdin of the next.
steps and pipe are mutually exclusive in a single execute_code call.
steps is always a pipe (sequential, stdout chains to next stdin).
Concurrent fan-out requires explicit use of the parallel field.
The ollie:parallel annotation still drives agent-level tool call
parallelism via IsParallelRead, but no longer hijacks pipe semantics.
WrapCommand now returns an error instead of silently falling back to
unsandboxed execution when landrun is not in PATH. execute_code
propagates this as a hard failure.
Add {PLAN9} to test sandbox rwx list so plan9 binaries (cat, sleep,
grep, bc, sed) are accessible. Drop -q from bc invocation since
plan9 bc does not support it; -l alone works on both GNU and plan9.
Entries in the prompt array that contain a newline are now treated as
literal text instead of shell commands. This enables JIT agent configs
to embed identity text directly without escaping.
Also clarify that execute_code timeout is a top-level parameter, not
per-step, to prevent models from placing it in the wrong location.
Tools annotated with "# ollie:parallel read" now run concurrently when
the LLM issues multiple such calls in a single round, without needing
an execute_code pipeline.
- tools.ParallelClassifier interface; execute.Server implements it via
IsParallelRead, which reads the tool script and checks the annotation
- BuildAgentEnv wires IsParallelRead → AgentEnv.classifyTool →
agentConfig.ClassifyTool (nil when execute server absent)
- loop.go: consecutive parallel-safe calls are fanned out with a
WaitGroup; results are collected in submission order; cancellation
fills remaining calls with interrupted results; serial tools and
batches of one skip the goroutine overhead
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Covers detectParallelClass, sanitizeLockName, acquireFlock, classifyStep,
SetLockDir, and runReadBatch — bringing pkg/tools/execute from 70.9% to 92.4%.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add paths.ExpandHome() helper for tilde expansion
- Apply in NewAgentCore, SetCWD (agent + execute server), and hook runner
- Fixes 'chdir ~/path: no such file or directory' errors
- Add contract tests for tools.Server and tools.Dispatcher interfaces
(tools_test.go), covering all exported behavior including error paths.
pkg/tools coverage: 0% -> 100%.
- Add contract test for execute.Server (ListTools, CallTool), Decl
factory test, and executeElevated early-exit test. execute coverage:
68% -> 71%.
- Remove Close() from Server and Dispatcher interfaces and all
implementations/callers. These existed for MCP server cleanup which
has been removed.
- sandbox: remove dead code (DefaultConfig, Load/Save, LayeredConfig, Merge,
Version, SystemDefaults, validateName, ConfigPath, OpenSandbox); unexport
internal symbols; LoadSandbox now takes io.Reader; loadSandboxConfig owns
file opening; 83% package coverage via new sandbox_test.go
- backend: add BaseURL field to AnthropicBackend for testability; new
backend_test.go runs checkContract against all five implementations
(Ollama, OpenAI, Copilot, Anthropic, CodeWhisperer) via httptest servers
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Allows wrapper scripts in ~/.config/ollie/scripts/x/ to shadow system
binaries transparently without modifying the user's shell environment.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove the elevation package and Elevator interface entirely. The
execute server now invokes x/elevate directly, with detection reduced
to a stat check. Decl() loses the elevator parameter.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove session-scoped env injection from frontend (s/{id}/env, -e/-env flags) — superseded
by per-invocation superpowers run-session in the elevator. Keep agentCore env map and
OLLIE_SESSION_ID propagation via pushSessionEnv.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New pkg/env package owns EnsureDefaults, Set, Get, All, Format
- BuildAgentEnv reverted to 3-arg signature (no initialEnv)
- agentCore.setEnv removed; pushSessionEnv handles OLLIE_SESSION_ID only
- execute.Server.SetEnv no longer calls os.Setenv (session-scoped only)
- !cmd handler sets OLLIE_SESSION_ID explicitly in subprocess env
- mcp/transport: seed cmd.Env from os.Environ() so MCP servers inherit PATH etc.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace all hard-coded ~/.config/ollie and ~/.local/share/ollie paths
with a new paths package that reads OLLIE_CFG_PATH and OLLIE_DATA_PATH,
falling back to the previous defaults when unset.
- execute_code now takes steps:[{code,language}|{tool,args}] instead of
a single code/language pair. Single-step calls return raw output;
multi-step calls run in parallel and return results under === step N ===
headers in submission order.
- execute_pipe stages may now include {parallel:[...]} to fan out
concurrently within a pipeline. Parallel outputs are concatenated in
submission order and fed as stdin to the next stage.
- Stage execution is now Go-level (stdin chaining) rather than a single
bash pipeline string, enabling parallel stages and tool/code mixing.
- CodeStep and resolveCodeStep are the shared primitives for both
execute_code and execute_pipe parallel stages.
- executeWithStdin added to Server for stdin chaining between stages.
- Tool steps use shebang detection; language field applies only to
inline code steps (default: bash).
- ListTools schemas and descriptions updated throughout.
ToolsPath() fell back to ~/.config/ollie/tools when OLLIE_TOOLS_PATH
was unset, ignoring the 9P mount entirely. Add /home/lkn/mnt/ollie/t as the
preferred fallback so execute_tool finds tools on the mounted
filesystem regardless of cwd.
- extractMCPResult: parse isError from MCP response so tool failures
are returned as Go errors and marked isErr=true in the loop
- CallTool: emit isError:true content block instead of bare {"error":...}
so the model sees tool failures as error results, not success
- SetEnv: call os.Setenv so OLLIE_SESSION_ID/OLLIE are in the process
env and inherited by sandboxed subprocesses
- NewAgentCore: inject session env into execute server at creation time,
not only on rename, so tools have OLLIE_SESSION_ID from the first call
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>