Returns the fully rendered system prompt for the session, so
the 9P server can expose it via s/{id}/systemprompt.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
systemPrompt() now reads all *.md files from DefaultPromptsDir() in
lexical order (00_base.md, 01_foo.md, ...), applies template rendering
to each, and concatenates them with --- separators.
Removes hardcoded eager-loading of skills (reasoning, memory, task,
edit-text) and the skills package dependency. Those now live as numbered
prompt parts alongside the base prompt.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Skills are loaded into the system prompt from the first turn as an
alternative to encoding guidance in MCP schemas.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add TrustedToolsSetter interface and SetTrustedTools to execute.Server
- Add allowed(): trusted tools return true; untrusted with no Confirm
return false (deny by default). Confirm returns true=allow, consistent
with allowed() semantics throughout.
- BuildAgentEnv wires cfg.TrustedTools into the execute server
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
$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>
Reading from the 9P mount during session creation deadlocked the
server. Use skills.Read() to access the physical files directly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Read ollie/sk/reasoning.md and ollie/sk/memory.md from the 9P mount
and append them to the rendered system prompt. Removes dependency on
the model following a startup instruction.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove pkg/tools/file and pkg/tools/reasoning. Both are now implemented
as execute_tool scripts in ollie/t/ with feature parity:
- file_read, file_write, file_edit, file_grep, file_glob
- reasoning_think
isread guard delegated to /tmp/ollie/$OLLIE_SESSION_ID/<hash> markers.
SetSessionID renames the tmpdir on session rename.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Both idx files are now served as live synthetic files by the 9P server.
No physical files are written to disk.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace {{.Tools}} injection with ollie/t/idx (generated at session
start by rebuildToolsIdx); prompt now instructs grep-based discovery
- Replace {{.Skills}} injection with ollie/sk/idx (rebuildSkillsIdx);
same grep pattern
- Add {{.SessionID}} to system prompt identity line
- Expand filesystem section: full ollie/s/ layout, all session files,
ctl commands, s/idx cooperation pattern
- Fix execute_tool description: use ollie/t instead of physical ToolsPath()
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
toolsSummary() scans OLLIE_TOOLS_PATH for # description: and # Args:
headers and injects the result as {{.Tools}} in the system prompt —
same effect as MCP schema injection but for shell/python tools.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- pkg/tools/memory: memory_remember + memory_recall with FlatDirBackend
baked in (no more injectable MemoryBackend abstraction)
- pkg/tools/task: task_plan + task_complete with file-based plan
persistence baked in (no more injectable PlanBackend abstraction)
- pkg/tools/reasoning: stripped to reasoning_think only
- pkg/tools/tools: remove PlanStep/PlanBackend/MemoryBackend interfaces
- pkg/agent: remove dispatchMemoryBackend, dispatchPlanBackend,
WithFallbackPlanBackend; BuildAgentEnv takes no options
Fixes infinite recursion crash: previously dispatchMemoryBackend routed
memory_recall back to the reasoning server that owned it, causing
unbounded mutual recursion and a goroutine stack overflow.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add SetSessionID to Core interface and agentCore implementation
- Renames persisted .json and .compaction.jsonl files on disk
- Propagates OLLIE_SESSION_ID env var to execute server
- Add /kill and /rn to /help output
/backend, /agent, /compact, and /clear now return an error if
the agent loop is active. These commands replace pointers or
mutate session state that the running loop holds by copy or
reference, leading to silent failures or races.
Introduces memory_remember and memory_recall built-in tools on the
reasoning server. A MemoryBackend interface allows swapping backends:
dispatchMemoryBackend routes through a registered MCP server (e.g.
denote-mcp) when available; FlatDirBackend writes dated markdown files
to ~/.local/share/ollie/memory/ as a zero-config fallback.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Submit routes to Inject when a turn is already running, keeping the
routing decision in core rather than the frontend or 9p layer
- Inject no longer cancels the current action; the pending prompt is
stored and consumed at the next tool result boundary (success or
failure), matching goq interrupt semantics
- If an inject is already pending, fall back to the FIFO so nothing is
lost; /irw (interrupt-rewrite) explicitly overwrites the pending inject
- PopInject is now called after every tool result, not just the last one
- Injected prompts are echoed to the chat via the running turn's output
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The newline event is emitted via handler() directly, not through
loopcfg.Output, so the Output-based newline case never fired.
Commit replyBuf to s.reply alongside the state="idle" transition.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Frontends no longer need to shadow these in their own structs; they can
read authoritative values directly through the Core interface.
State and reply tracking moves into agentCore: state transitions on
call/tool events, reply resets and accumulates per-turn in Submit's
Output func. This also fixes a bug where reply accumulated across all
queue-drained turns instead of reflecting only the most recent one.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Submit now emits Event{Role:"user"} before each turn so queued prompts
appear in the chat log via the normal event path, not just direct
appendChat calls from the 9p prompt handler
- Strengthen system prompt rule against using execute_code/echo as a
communication mechanism
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove MaxSteps limit and associated stalled event emission.
The agent will now run indefinitely until completion or interruption,
eliminating the annoying 'agent stalled' messages.
- Add WorkDirSetter interface to pkg/tools so servers can receive workdir updates
- Add SetWorkDir on execute.Server with RWMutex-guarded workdir field
- Add WorkDir()/SetWorkDir() to the Core interface and agentCore
- Store agentPrompt in AgentEnv/agentCore so system prompt can be rebuilt on workdir change
- Add /cwd [path] slash command (no args shows current dir, arg changes it)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add reasoning_plan built-in tool: decomposes goals into ordered steps
with dependency edges; persists to task backend when available, falls
back to in-context plan otherwise.
- Add PlanBackend/PlanBackendSetter interfaces and PlanStep type to
pkg/tools; add GetServer to Dispatcher.
- Add dispatchPlanBackend in pkg/agent: routes task_create calls through
the dispatcher to any registered task MCP server.
- BuildAgentEnv auto-wires the task backend to the reasoning server after
connecting MCP servers; re-wires on every /agent switch.
- Add ListServers() to Core interface: groups all registered tools by
server, returns formatted text.
- Add /mcp command to handleCommand(); update /help.
- Add doc/PLANNING.md and update ARCHITECTURE.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Hooks now receive JSON on stdin, can block actions (exit 2), and inject
stdout into the conversation. Stop hooks can continue the agent loop
with stderr as the next prompt. 60s timeout, context-cancellable.
Config format unchanged — existing hooks still work.
- Inject(prompt) cancels the running tool and injects the message into
the conversation as <system-user-interruption>
- Queue/PopQueue FIFO for deferred prompt execution
- Submit() drains FIFO after each turn
- IsRunning() for frontends to choose Submit vs Inject
- TUI: typing during a turn calls Inject; /q queues
- 9P: prompt interrupts if busy; prompt.fifo is push/pop FIFO
Instead of discarding history on interruption, record what happened:
- Partial assistant content and tool calls are preserved
- Skipped tool calls get synthetic cancelled results
- Phase-specific notes (stream/tools/request) tell the model what occurred
- Side effects from already-executed tools are no longer hidden from history
- Add ContextLength(ctx) int to Backend interface; each backend fetches
from its API (OpenAI /v1/models, Ollama /api/show, CodeWhisperer
ListAvailableModels) with caching. Falls back to 128k default.
- Add Models(ctx) []string to Backend interface for model discovery.
- Add /models command to list available models.
- Auto-compact before each turn when estimated tokens >= 75% of context length.
- Structured compaction prompt asking for progress, decisions, next steps
- Flatten tool call/result sequences to plain text before compaction
- Preserve recent user messages (up to ~20k tokens) in compacted history
- Inject summary as handoff message for the resuming LLM
- Persist pre-compaction snapshots as append-only JSONL for long-term memory
Delete context.go and its entire eviction system (contextBuilder,
SoftLimit/HardLimit/TailMessages, buildBounded, sanitizeHistory).
Session now holds a plain []backend.Message with no silent dropping.
/compact still works via LLM-driven summarization. /context still
shows message count and token estimates.