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.
- Test all expandPath branches (HOME, XDG_*, OLLIE_CFG/DATA_PATH)
- Test checkPath symlink resolution and ROX read/write
- Test LoadSandbox reader error
- Test WrapCommand: landrun unavailable, ROX/RWX entries, sort tiebreaker, superpowerd wrapping
- Test isSuperpowerdRunning: all socket dir paths, successful connection
- Make isAvailableFn/isSuperpowerdRunningFn overridable for testing
- 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>
Add {OLLIE_TMP_PATH} to DefaultConfig filesystem RW list so landrun
permits writes to the tmp directory. Also mkdir the path at session
init so the pathExists check in WrapCommand doesn't skip it.
Add OLLIE_TMP_PATH to DefaultConfig env list and inject it via SetEnv
in NewAgentCore and SetSessionID, matching the pattern used for OLLIE
and OLLIE_SESSION_ID.
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.
$OLLIE is the ollie root (FUSE mount). Renaming makes it shorter and
cleaner for use in sandboxed code. SetSessionID now resolves and
injects OLLIE into the execute server env so it is always available
regardless of whether the parent process has it set.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
detectLanguage only checked filepath.Base(fields[0]), which returns
"env" for #!/usr/bin/env python3. Every such script was run as bash,
producing syntax errors. Now checks fields[1] when fields[0] is "env".
Also add OLLIE_MEMORY_PATH to default env passthrough.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Physical ollie paths need RWX so tools can read/write/execute
both through the 9P mount and directly to the backing store.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
OLLIE_MEMORY_PATH and OLLIE_PLAN_PATH are user-configured paths that
belong in sandbox yaml overlays, not hardcoded into the built-in
defaults. Remove them from DefaultConfig() and SystemDefaults() env
lists, and remove the hardcoded XDG_DATA_HOME/ollie/memory rw path.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add OLLIE_MEMORY_PATH to the env allowlist and both the env-var path and
the XDG default (~/.local/share/ollie/memory) to the RW filesystem list,
so file_* tools can read and write memory files.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
file_read, file_write, file_edit, file_grep, and file_glob now check
paths against the sandbox config before operating. Same policy that
landrun enforces on execute_code, applied at the application level.
- Add sandbox.LoadMerged: loads base config + named layer, graceful
fallback if layer missing. Replaces duplicated logic in execute.
- Add sandbox.CheckPath: resolves symlinks, expands templates, checks
path against allowed entries (RO/ROX for read, RW/RWX for write).
- file.Server.checkAccess wires the check into every file dispatch.
Vendor anvillm/pkg/sandbox into internal/sandbox, updating config
paths from ~/.config/anvillm to ~/.config/ollie. Remove anvillm
from go.mod.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Move internal/backend and internal/config to pkg/ so external consumers
can import them. Remove cmd/ollie and internal/tui — they now live in
the separate ollie-tui repo which imports ollie as a library.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
internal/mcp → pkg/mcp (MCP client, concrete)
internal/tools → pkg/tools (Executor interface + MCPExecutor)
internal/exec → pkg/tools/execute (builtin sandbox executor, split by tool)
Split exec.go into executor.go (sandbox runner), pipe.go (BuildPipeline/PipeStep),
tool.go (ReadTool), and code.go (execute_code is Executor.Execute with trusted=false).
All three packages are now importable by consumers outside this module.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each backend now owns its active model via Model()/SetModel(). ChatStream
no longer takes a model string — callers use SetModel to configure it.
AgentCoreConfig.ModelName sets the backend model at construction time via
SetModel, then the field can be dropped from the live agentCore struct.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Everything not part of the agent<->frontend contract is now unexported:
- contextConfig/Builder/Stats, loopConfig, toolExecutor, confirmFn,
run, state, toolResult — internal loop/session machinery
- buildFirstPrompt, systemPrompt, builtinTools — impl details
- agentCore struct (NewAgentCore returns Core)
- Session methods (saveTo, history, rollback, compact, etc.)
- AgentEnv internal fields (mcpExec, exec, confirm, tools, etc.)
App-level utilities moved from pkg/agent to cmd/ollie:
- resolveBackendName, defaultModelForBackend, newSessionID,
agentConfigPath
RestoreSession now takes int (ctxOverhead) directly, eliminating
the need for contextConfig to be public.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
AgentCore (the Core interface impl) belongs in internal/agent alongside
the loop, session, and state it orchestrates — not in a separate one-file
package.
To break the resulting import cycle (agent → pkg/core → agent), define
Event and EventHandler natively in pkg/core instead of aliasing from
internal/agent. The agent loop now imports pkg/core for these types.
Usage token tracking is internal to the loop and no longer emitted as
an event (no consumer used it).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Hooks are a generic lifecycle concept — not specific to any frontend.
core.Hooks, core.HookAgentSpawn/UserPromptSubmit/Stop constants, and
Hooks.Run() now live in pkg/core and are usable by any implementation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
WatchSignals and CtrlCExitWindow are generic — any frontend can use them.
Removing them from the TUI package keeps tui focused on terminal I/O only.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>