Commit Graph

26 Commits

Author SHA1 Message Date
Levi Neely d65c06f27b implement namespace-bounded capability model
Per-agent file ownership with Unix permission enforcement:
- Agent directories owned by agent ID (UID), group 'agent' (GID)
- Private files (plan, ctl, fifo): mode 0600 - owner only
- Group-readable (chat, log): mode 0440 - owner + agent group
- World-readable (state, id): mode 0444 - observable by all
- Prompt: mode 0220 - CLI and owner can write

virtfs: fix UID/GID inheritance through nested paths
- Added findChildWithInheritance() to accumulate inherited UID/GID
- Stat now correctly shows agent ID as owner for nested files

server: admin bypass for server owner
- serverAdmin variable captures the Unix user running olliesrv
- Admin bypass includes empty uname, 'admin', or server owner

Documentation updates:
- fs/doc.go: 'The Namespace IS the Security Model'
- registry/doc.go: capability-based tool access
- peer.go: capability-based peer access
- lessons-learned.md: 'Model compliance is not a security boundary'
- architecture-9p.md: per-agent file ownership section

Security evaluation:
- Added experiments/security-eval/ with NERV attack corpus adaptation
- Test scripts for Landlock sandbox validation
- RESULTS.md documenting 0% ASR on hostile operations

This implements the NERV thesis: 'An agent can only access resources
explicitly bound into its namespace.' Enforcement is structural via
file permissions, not behavioral via model compliance.
2026-10-06 17:41:27 +02:00
Levi Neely c9c26d3a3d fix bypass+background hang: signal started immediately
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).
2026-10-06 11:00:23 +02:00
Ollie Agent 9395a0e07b config: rename agent autoLoad field to tools
The autoLoad name implied an automatic tool-loading path that no longer
exists; tools now come only from agent config plus the /tool_load ctl
command. Rename the AgentConfig.AutoLoad field (json autoLoad) to Tools
(json tools), rename LoadAutoLoadTools to LoadTools, and update all 14
agent JSON profiles and the tool-not-loaded error message.
2026-09-07 13:23:17 +02:00
Levi Neely 2b59409845 refactor: remove dead code across packages (-220 lines)
Dead code removal based on code review:

fs/spec.go:
- Remove unused Perm* constant aliases

fs/support.go:
- Remove unused agentCwd() function

session/registry.go:
- Remove unused CreateAgent() (callers use CreateAgentWithParams directly)

session/session.go:
- Remove unused sweepStaleTmpDirs() and sweepTmpOnce
- Remove unused Session.LoadTool() (callers use LoadToolOnConn directly)
- Simplify Resume() by removing dead else branch (Pause() always nils Keeper)

toolsrv/server/proc.go:
- Remove unused globalProcCounter
- Remove unused ListProcsWithState()

toolsrv/server/server.go:
- Remove unused Mode* constants

toolsrv/bypass/bypass.go:
- Remove unused PendingCount()

toolsrv/sandbox/config.go:
- Remove unused checkPath() and pathUnder()

backend/new.go:
- Remove unused newBackend() (callers use NewWithName)

agent/loop.go:
- Remove unused contextBudget()

agent/agent.go + turn.go + runtime.go:
- Remove unused startupMessages, StartupMsgs, Runtime.Messages

agent/agent_config.go:
- Remove unused Tools *bool field and ToolsEnabled() (tools always enabled)
2026-08-21 16:41:42 +02:00
Levi Neely 8960fb73fd feat: refresh autoLoad tools on agent profile switch
When the 'agent <profile>' ctl command switches profiles, the tool
registry now clears old tools and loads the new profile's autoLoad
list. Previously, switching profiles left the old tools loaded.

Changes:
- registry: add ClearAgent(agentID) to remove all tools for an agent
- server/proc: add ClearAgent wrapper and 'clear <agentID>' ctl command
- toolclient: add ClearTools() method to ToolsrvConn
- agent: SwitchProfile now returns *AgentConfig for tool reload
- fs/spec: agent ctl handler clears and reloads tools after switch
2026-08-21 10:57:59 +02:00
Levi Neely fef6cdc307 tool loading: require explicit autoLoad, clean package structure
Remove lazy tool loading (load-on-call). Tools must now be explicitly
listed in the agent's autoLoad config. Calling an unloaded tool fails
with a clear error message.

Package structure improvements:
- embedding/index.go: generic Index type for semantic matching
- skills/skills.go: uses embedding.Index internally, keeps Skill type
- agent/skill_match.go: matchSkills() for skill discovery
- agent/tool_match.go: matchTools() for tool hints (new file)

Tool hints now match only loaded tools, not all tools on disk.
This makes agent capabilities explicit and auditable.
2026-08-21 10:11:51 +02:00
Ollie Agent 4bf46ae85d Load hinted tools through the agent namespace 2026-08-20 18:29:10 +02:00
Levi Neely cd9da5ed27 quirks: reject shell calls to native tools
- Add quirks package for stupid model behavior workarounds
- ShellInvokesNativeTool blocks shell(cmd="tool_name") patterns
- Add client_9p tool: native wrapper for ollie-9p operations
- Block ollie-9p in shell — use client_9p instead
- Update all prompts to use client_9p, not shell+ollie-9p
- Clarify 9P namespace is complete (tools are NOT in 9P)
- Registry.All() lists all available tools for validation
2026-08-20 14:08:53 +02:00
Levi Neely 4750966048 toolsrv: auto-load tools on first use
When an agent calls a tool that exists but isn't loaded, toolsrv now
automatically loads it instead of returning an error. This eliminates
the round-trip of a separate load call.

- Remove Registry.Exists() (superseded by auto-load logic)
- Fire OnToolsChanged callback after auto-load so olliesrv can update
  tool definitions for subsequent turns
2026-08-20 12:16:01 +02:00
Levi Neely 4ff37741e2 subagent: fix timeout and premature response issues
Timeout fix:
- Add Timeout field to ToolInfo (protocol) and MetaFile (metadata)
- proc.go respects tool-declared timeout before falling back to 30s default
- subagent_spawn.meta declares timeout=0 (no timeout) so the tool is
  never killed prematurely while waiting for the sub-agent to finish
- Tool schema declares timeout with 'do not set' guidance to prevent
  the LLM from adding a short timeout

Premature response fix:
- Inject behavioral prefix into sub-agent prompt: complete all work
  before responding, report results not intentions
- Sub-agent's final text is returned to parent; this instruction ensures
  it contains accomplished work, not a plan
2026-08-20 10:59:23 +02:00
Ollie Agent 6ef1fe52e0 Make process GC startup idempotent 2026-08-18 07:08:38 +02:00
Ollie Agent 6a4f83b5b2 Bound completed toolsrv process retention 2026-08-18 06:51:43 +02:00
Ollie Agent b6009f0f7a Reserve toolsrv process slots atomically 2026-08-18 06:50:02 +02:00
Ollie Agent 93e7f510b7 Prevent dismissing running processes 2026-08-18 06:45:23 +02:00
Ollie Agent 3ad431957c Fix background tool startup signaling 2026-08-17 17:48:23 +02:00
Ollie Agent 59c4ed23ac merge paths utilities into util 2026-08-16 18:37:03 +02:00
Ollie Agent 81933e5281 refactor toolsrv into client protocol and metadata packages 2026-08-16 17:22:59 +02:00
Levi Neely 250ad4b233 agent/new: sub-agent support via rdwr with prompt=
Writing to session/{s}/agent/new with a prompt= key now blocks
until the agent completes its task, then returns the reply and
destroys the transient agent. Without prompt=, behaves as before
(creates agent, returns ID).

Also:
- Move ParsePayload/UnescapeValue to shared ollie/toolsrv package
- Remove duplicate implementations from cmd/toolsrv/internal/server
- Add session.CreateAgentWithParams for direct AgentParams usage
- Eliminate flattenParams/unescapeValue redundancy in fs package
2026-08-14 14:48:12 +02:00
Levi Neely 5dcde264e6 toolsrv: add path-based lock table for cross-agent serialization
All foreground tool calls now acquire a lock based on the tool's
declared scope and file path before execution:

  - scope "read":  no lock (reads never conflict)
  - scope "write": exclusive lock on the file path
  - scope "global": exclusive global lock (serializes with everything)

This ensures writes to the same path serialize regardless of which
agent initiated the call, enabling safe parallel sub-agents within
a session without explicit coordination.

Cross-session serialization (shared toolsrv per host) is left as
future work.
2026-08-14 14:27:21 +02:00
Levi Neely dc26871bdc proc/list: use fixed-width columns instead of tabs 2026-08-13 22:28:33 +02:00
Levi Neely 0fed1aa124 proc/list: include command in output 2026-08-13 22:24:50 +02:00
Levi Neely de33f954e2 toolsrv: proc/list now rdwr with agent filtering
Write agent ID to filter, or empty for all. Returns pid\tstate\ttool.
Added ListProcsForAgent to State.
2026-08-13 22:08:15 +02:00
Levi Neely bc7f51a9dc refactor: push proc completion from toolsrv to agent prompt
- toolsrv pushes <system-proc-complete> to agent prompt when bg proc exits
- Remove bgTracker and CollectInterrupts from olliesrv
- Add Cmd, AgentID, SessionID fields to Proc
- Add OnProcExit callback to State
- Add command field to Proc.Stat() output
2026-08-12 16:39:43 +02:00
Levi Neely 1d5e9c4f8d fix: background proc output capture and status display
- Detach background proc context from request context so processes survive
  after the 9P request returns (fixes premature SIGTERM)
- Add /proc/list file to toolsrv showing all procs with state
- Show status (running/exited (N)) in agent proc list
- Keep exited procs in tracker until explicitly dismissed
- Skip 'list' entry in ListDetachedRaw
2026-08-12 14:10:08 +02:00
Levi Neely d59f49ee54 feat: context cancellation for tool calls
Wire context cancellation through the toolsrv 9P server so that
canceling a CallTool context properly terminates the running tool.

Changes:
- virtfs: Add Close() to File interface with CloseFn for Request handlers
- toolsrv/p9.go: Handle requests concurrently to allow Tclunk during
  blocking Twrite; call entry.Close() in handleClunk
- toolsrv/internal/server/proc.go: Check ctx.Done() while waiting for
  tool completion in NewProc
- Integration tests for context cancellation chain

The cancellation chain: client cancels ctx → fid.Close() → Tclunk →
handleClunk calls entry.Close() → closeFn cancels reqCtx → NewProc
sees ctx.Done() and returns ctx.Err()
2026-08-12 10:00:44 +02:00
Ollie Agent 62fe1dab83 toolsrv: rename internal/fs → internal/server
The package defines the Server type and its namespace — 'fs' was a
leftover name from when it only held the filesystem spec. Now it's
the server definition. File renamed spec.go → server.go to match.
2026-08-11 21:15:03 +02:00