- 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.
ProcessKeeper maintains a running ollie-remote process and respawns
it on failure. Multiple agents Dial() the same keeper to get
independent connections. If the process dies, the next Dial()
triggers a respawn (up to 3 attempts with backoff).
All session creation and restore paths now use ProcessKeeper.
Kill/Shutdown close the keeper (which closes the current process).
This fixes 'connection closed' errors persisting indefinitely
after ollie-remote crashes — the next tool call respawns it.
- Load ~/.config/ollie/env and set path defaults at startup (same as olliesrv)
- Remove hard exit on missing OLLIE_SESSION_ID; accept it from inherited env
or via set_env RPC (SSH bootstrap path)
- Wire OnEnvSet to propagate OLLIE_SESSION_ID into tool registry and process
env when it arrives dynamically; same for OLLIE_UNAME