Add self-documenting filesystem:
- Doc() option on FsNodeDecl for human-readable descriptions
- /help now generated from spec at runtime, not loaded from file
- Every file/directory in spec.go has documentation
Also fix file-template Each nodes:
- Each without children but with Read/Write creates files, not dirs
- Update validator, listDir, statDir to recognize file templates
- Fix elevate/{reqid} and proc/{pid} to use file-template pattern
Add Doc() EDSL option and Desc field to FsNodeDecl for self-documenting
filesystem specification. Every file and directory now has a human-readable
description explaining its purpose, format, and usage.
Documentation covers:
- Root-level files (backends, models, agents, tools, ctl, etc.)
- Elevate broker (policy, pending requests)
- Session management (new, idx, per-session files)
- Agent management (prompt, chat, state, config, tools, proc)
This makes spec.go the single source of truth for both structure and
documentation. The Desc field can be used to generate help text or
API documentation programmatically.
Each says exactly what it does: for each item in a collection,
create this directory structure.
DirNode, FileNode, Each - the EDSL is now clear and declarative.
- Leaf → FileNode (file node)
- Dir → DirNode (directory node)
- Blueprint → Dynamic (state-dependent directory)
The names now clearly indicate what they create:
- FileNode: a file
- DirNode: a directory
- Dynamic: a directory whose children depend on runtime state
New EDSL construct: Blueprint(name, instancesFn, ...children)
- Declares static structure in treeSpec
- InstanceFn returns identity info (name, aliases, UID/GID, data binding)
- Handlers access instance data via ctx.Session/Agent/AgentLog
- No more closure captures for session/agent data
Changes:
- Add Instance type and InstanceFn to fsnode.go
- Add Blueprint() constructor
- Update builder.go to handle blueprint node expansion
- Convert session/{id} to Blueprint with sessionInstances
- Convert agent/{aid} to Blueprint with agentInstances
- Convert all handlers to use ctx fields instead of closures
Benefits:
- Full namespace structure visible in treeSpec at top of spec.go
- Handlers are stateless functions (easier to test/reason about)
- Less memory (no closure allocations per instance)
- Cleaner separation: structure vs data binding vs handlers
Single source of truth for the 9P namespace:
- Move rootfiles.go handlers into spec.go
- Move sessionfiles.go (listSessions) into spec.go
- Move agentfiles.go (listAgents) into spec.go
- Move procfiles.go (listProcesses) into spec.go
- Move elevatefiles.go handlers into spec.go
The full namespace structure is now visible in one file with
structure comments documenting the layout of dynamic subtrees.
No functional changes - just reorganization.
Go shared library (c-shared buildmode) that wraps 9fans.net/go/plan9/client.
Provides C API for persistent 9P connections, eliminating process spawn
overhead for GUI operations.
Exports: ollie9p_connect, ollie9p_read, ollie9p_write, ollie9p_rdwr,
ollie9p_ls, ollie9p_stat, ollie9p_remove, ollie9p_create, ollie9p_mkdir,
ollie9p_rename, ollie9p_close, ollie9p_last_error, ollie9p_free
Build: go build -buildmode=c-shared -o libollie9p.so
Install: just lib9p (installs to ~/.local/lib and ~/.local/include)
The 9P logger was hardcoded to LevelDebug, causing all 9P operations
to print timing info to stdout. This blocked the server on terminal
output, hurting GUI responsiveness.
Now uses NewLogger('9p') which:
- Defaults to the sink's level (warn)
- Can be overridden with OLLIE_9P_LOG=debug
Also updates kde submodule with incremental session tree updates.
Event topics now follow session hierarchy:
session.{sid}.new/kill/pause/resume/rename
session.{sid}.agent.{aid}.new/kill/state
Wildcard routing publishes to all ancestors:
session.{sid}.agent.{aid}.state publishes to:
session.{sid}.agent.{aid}.*
session.{sid}.agent.*
session.{sid}.*
session.*
*
GUI can subscribe to session.{sid}.* to get all events
for one session including its agents.
Also:
- ollie-9p -a flag now supports TCP (host:port or tcp!host:port)
- Add Session.ID() accessor method
- Use github.com/simonfxr/pubsub for topic-based event routing
- Topic format: session.{id}.{action}, agent.{id}.{action}
- Wildcard subscriptions: *, session.*, agent.*
- PublishEvent routes to exact topic + wildcards
- WaitEvent maintains backwards compatibility for eventwait
- Add agent.SetOnStateChange callback for state change events
- Extend session/idx format with paused, connected, agent list
Events now published:
- session.{id}.new/kill/pause/resume/rename
- agent.{id}.new/kill/state
This enables efficient selective subscriptions - GUI can subscribe
to specific sessions/agents instead of receiving all events.
Adds session/{id}/connected file that pings the RPC connection to
determine if the tool server is responsive. Used by GUI to show:
- Green: connected and not paused
- Gray: paused (intentional)
- Red: disconnected/crashed (not paused but connection broken)
- Yellow: zombie (paused but still connected - shouldn't happen)
Adds pause and resume commands to session/ctl:
- pause: stops the tool server process, closes connections
- resume: respawns the process and re-establishes connection
When paused, tool calls return 'connection closed' errors which
propagate to the chat log. Useful for reducing resource usage when
many sessions exist but aren't actively being used.
Also adds session/{id}/paused file to check pause status.
The 9P protocol returns write handler errors via Rclunk, not Rwrite.
cmdWrite and cmdRdwr were using defer fid.Close() which discarded the
error. Now they check fid.Close() return value and exit non-zero on
failure, allowing the GUI to detect rename errors.
The OutputFormat function was set once at runtime build time and stored
in ag.runtime.OutputFormat. When tools were dynamically loaded via
tool_load, the tool definitions were refreshed but the OutputFormat
lookup still used the stale runtime version that didn't know about
newly loaded tools.
Build the outputFormats map from the fresh tool list on each turn,
just like we already do for the tool definitions. This ensures
outputFormat (e.g., 'diff' for file_edit) is available immediately
after loading a tool.
Bedrock rejects requests containing toolUse/toolResult content blocks
without a corresponding toolConfig. When agents have zero tools loaded
(e.g., autoload disabled/failed), conversation history containing tool
interactions would cause 'toolConfig field must be defined' errors.
Add kiroStripToolBlocks() to remove tool-related content from messages
when len(tools) == 0, allowing requests to proceed without tool
definitions.
ToolServer is vital infrastructure — it must never be nil. If the
initial dial fails, retry via ProcessKeeper (which respawns
ollie-remote). If still unavailable, fail agent creation with a
clear error asking the user to try again.
Reverted the nil-check band-aid in turn.go — ToolServer is now
guaranteed non-nil for any running agent.
Prevents nil pointer dereference when a newly created agent's
tool server connection failed to establish (keeper.Dial returned
nil, or session was restored with a dead toolsConn).
Models that ignore native tool schemas (via the API tools parameter)
now see full tool documentation in-context: usage docs, argument
definitions, examples, and the JSON schema.
This is appended as a '# Tool Documentation' section in the system
prompt, below the compact '# Available Tools' listing.