When reading statewait with the same state value, the server now waits
500ms instead of 5 seconds before returning. This makes state polling
much more responsive.
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.
Two bugs:
1. GUI sends 'agent=<profile>' but server only recognized 'profile='
- Added 'agent' as alias for 'profile' in parseAgentNewRequest
2. Model dropdown showed cost columns appended to model names
- /models format: backend<tab>model[<tab>in<tab>out...]
- Parser took everything after first tab as model name
- Now stops at second tab to extract just the model name
CreateEmpty now returns (session, created, error): if a session with the
given name already exists it is returned untouched instead of erroring,
and only a freshly created session receives the provided cwd/workflow/
variant. The o script no longer suppresses errors from session/new, so
real failures surface while re-creating an existing session stays a
no-op success.
Landlock cannot add rules for sockets (S_IFSOCK) or FIFOs (S_IFIFO).
Previously, attempting to add a path like /run/user/1000/wayland-0
would fail with EINVAL.
Now these special file types are detected and skipped gracefully.
The field is rejected by models that don't support thinking/reasoning
configuration. Check model name before setting the field; 'auto' and
unknown models skip it to avoid ValidationException errors.
Make the namespace explain itself instead of requiring prior knowledge.
- ctl is self-describing: reading it (empty write) or writing 'help'
returns the valid verbs with one-line descriptions; an unknown verb
errors with the valid list. Refactor dispatch to an ordered []ctlCmd
carrying descriptions; drop the undocumented '.' alias and the
drift-prone hardcoded help verb. Keep 'i' (drop 'inject') for fast
injects. o's ctl usage now reads the live listing.
- Errors carry severity + remediation. backend.ClassifyError maps the
typed errors to transient/config/fatal with a one-line fix; the error
event renders [[[error:<severity>]]] and a 'remediation:' line so a
human knows whether to wait or intervene.
- Add a human status file: 'thinking · 12s', 'calling shell · 3s',
'idle' — distinct from the machine-facing raw state. Wire the TUI bar
to it.
- Bare 'o' shows an overview of running sessions/agents with status, so
you don't need to know any names to get oriented.
Tests: dispatch help/unknown/routing, ClassifyError severity table.
reasoningEffort (low|medium|high) is now the single human-facing control
for model deliberation. Backends that speak a discrete level (OpenAI,
OpenRouter, Copilot, Gemini, Kiro) send it verbatim; Anthropic, which
needs a numeric budget, translates via documented thresholds
(low=4096, medium=8192, high=16384). thinkingBudget remains an advanced
explicit override that wins when set.
- Add EffortLow/Medium/High, threshold consts, ValidReasoningEffort,
EffortThinkingBudget, and GenerationParams.ResolvedThinkingBudget.
- Anthropic: derive budget from effort, grow max_tokens above the budget
(Anthropic requires budget < max_tokens), and force temperature=1 when
thinking is enabled (both are Anthropic requirements).
- Validate reasoningEffort at config load so typos fail loudly instead
of silently no-opping.
- theo: drop explicit thinkingBudget/inflated maxTokens; reasoningEffort
high now implies the 16384 budget.
- Document thresholds and per-backend behavior in data/agents/README.md;
fix stale autoLoad/maxSteps references.
- Add unit tests for the mapping and Anthropic thinking behavior.
Reasoning effort is part of an agent's behavior definition, so set it
on all 14 profiles keyed to role (planning/review high, general medium,
lightweight assist low). Also rename the ThinkingBudget json tag from
the confusing bare "reasoning" to "thinkingBudget", distinct from the
reasoningEffort string knob. No config migration needed — no profile or
backends.conf used the old "reasoning" key.
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.
Regression guard for tool-free model compatibility: an agent with an
empty tool set must produce requests with no "tools"/"tool_choice"
field. Covers OpenAI, OpenRouter, Ollama, and Anthropic.
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)
Add per-model pricing to /models output. Format:
backend<tab>model[<tab>in<tab>out<tab>cache_read<tab>cache_write]
Pricing sources:
- Anthropic: hardcoded from official pricing, includes cache rates
- OpenRouter: parsed from API response pricing field
- Other backends: static lookup table fallback, marked with (e)
Changes:
- backend: Add ModelPricing/ModelInfo types, ModelLister interface,
static price table (Claude, GPT, Gemini, DeepSeek), LookupStaticPricing()
- openai: Parse pricing from API, implement ModelsInfo()
- anthropic: Implement ModelsInfo() with hardcoded cache rates
- fs/cache: Use ModelsInfo when available, fall back to static lookup,
format prices per 1M tokens with (e) suffix for estimates
- agent/cost: Use shared LookupStaticPricing instead of duplicate table
The old word-boundary check falsely triggered when tool names appeared
in arguments (e.g., git commit messages mentioning native tools).
New logic: split on shell separators and only flag when a tool is the
first token of a sub-command or a path ending with /toolname.
Allows user to background the current foreground tool process
by writing 'detach' to the agent ctl file. The agent can then
continue working without waiting for the tool to complete.
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
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.
Add semantic skill matching using all-MiniLM-L6-v2 sentence embeddings.
Skills are automatically injected into user turns based on relevance.
New packages:
- embedding: ONNX-based text embedding with MiniLM model
- skills: skill discovery, embedding cache, and semantic matching
Integration:
- InitSkillIndex called at startup in fs.NewRoot
- matchSkills called per-turn in executeTurn
- Matched skills injected in <context> block alongside user prompts
Makefile:
- install-models target downloads model and ONNX runtime
- Model files stored in ~/.local/share/ollie/models/
Config:
- Threshold: 0.2 cosine similarity
- Limit: 3 skills per turn
- Skill dirs: ~/.kiro/skills (user), ~/.config/ollie/skills (installed)
- 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
Add explicit guidance to Autonomous Operation section:
- New unacceptable behaviors: giving up before checking skill_list or trying to load tools
- New checklist: must check skills, try loading tools, attempt even uncertain options before reporting failure
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
chat.raw includes everything; chat strips:
- [[[...]]] markers
- fence delimiters
- <context>...</context> blocks (user prompts)
Text clients get clean output; GUI clients use chat.raw for full control.
Added explicit unacceptable behaviors:
- Mentioning a tool without calling it
- Acknowledging a tool exists but not using it
Added bold statement: 'Knowing a tool exists is not the same as using it.
Your response should contain tool calls, not descriptions of tools you
could call.'
Agents were using shell to invoke tools (cat, grep, ollie-9p) instead of
calling the actual tools. Added unmistakable WRONG/RIGHT code blocks
showing the correct pattern. Shell is ONLY for git, make, npm, etc.
Rewrote system prompt to enforce immediate tool use:
- New 'Autonomous Operation' section: act first, report results
- Explicit list of unacceptable behaviors (narrating intentions, asking
permission for routine ops, producing text when tools should be called)
- Tools section: 'Use them without hesitation', concrete examples
- Skills section: 'if the task needs it, load it' — no asking
- Stronger sub-agent prefix: 'Do NOT respond with a plan. Call tools.'
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
- Workflow() no longer defaults to 'conductor' when empty
- runWorkflow() returns immediately for '' or 'none'
- 'none' listed first in the workflows file output
- QML dropdowns default to 'none' instead of 'conductor'
- C++ fallback uses 'none' when server unreachable
- Add session-level cfg file (read: name/cwd/remote/workflow/variant/yolo;
write: workflow, variant, cwd)
- Add readSessionConfig() and updateSessionConfig() to C++ client
- NewSessionDialog supports editMode: pre-populates fields from session cfg,
title becomes 'Session Settings', button becomes 'Save'
- Name and Remote fields disabled in edit mode (non-reconfigurable)
- YOLO checkbox hidden in edit mode
- Only changed values are written back on save
- Add 'Settings...' to session context menu in SessionTree
- Wire sessionSettingsRequested signal through to dialog
- runWorkflow accepts a variant parameter; sources {workflow}-{variant}.conf
as env vars before exec'ing the script
- Session stores variant; persisted and restored
- session/new accepts variant= parameter
- 'run' ctl command accepts optional variant as second arg
- workflows file now lists variants: name<TAB>default,variant1,...
- review workflow reads AUTHOR_PROFILE/REVIEWER_PROFILE env vars
- Add review-code.conf and review-writing.conf example variants
Add peer/ directory to each agent's 9P namespace. Agents communicate
by writing to peer/{name}, which delivers to the target's prompt handler.
Only declared peers can be messaged — the directory is the ACL.
Implementation:
- Agent struct: peers map + AddPeer/RemovePeer/Peers methods
- fs/spec.go: peer/ Each node (write-only entries), peeradd/peerdel/peers ctl commands
- Bidirectional: peeradd A on B also adds B on A
- Peers constrained to same session
- Persisted with session state (PersistedAgent.Peers field)
- peeradd/peerdel trigger immediate session save
Docs updated: system_prompt.md, AGENTS.md, README.md, architecture-9p.md,
architecture-core.md, architecture.md, usage.md.
- Multicall pattern for tool families: one binary per family with
symlinks for each tool name. Reduces tools dir from 156MB to 31MB.
codeintel (6 tools), filetools (5 tools), lsptools (7 tools).
- Build with -ldflags="-s -w" to strip debug symbols.
- Fix Landlock EINVAL on regular files: filter directory-only access
rights (READ_DIR, MAKE_*, REMOVE_*) when adding rules for non-
directory paths.
- Fix toolsrv CWD initialization: pass --cwd flag value to server
state at startup so {CWD} in sandbox.yaml expands correctly.
- Add MEMO_TOOLS=1 env var to memo script; when set, all printed
instructions reference native tool names instead of memo paths
- Set MEMO_TOOLS=1 in all memory tool .meta wrappers
- Add memory_nap tool for compressions
- Add memory_zoom tool for tree navigation
- Add part/T pagination args to memory_wake
- Update system prompt to use memory_zoom tool call
- Fix inject ctl: submit as user message when agent is idle
- Add OptMem memory section to system_prompt.md with tool-based API
- Fix KRunner plugin icon: resolve via QStandardPaths instead of theme name
- Fix desktop file icon: use absolute path to bypass stale system icon