The Adapter was pure boilerplate - every method just delegated to the
package-level generic function. Removing it simplifies the API:
- Delete fsedsl/adapter.go
- Update fs/adapter.go to call fsedsl functions directly
- Update README.md to document direct usage
- Remove adapter tests (now redundant)
Coverage remains at 94.8%.
- Add step-by-step integration guide for other projects
- Document the adapter pattern with complete examples
- Add API reference with tables for constructors and options
- Document Binding struct and Tree operations
- Link to ollie/fs/adapter.go as real-world example
- Add Adapter[Ctx] type that provides all EDSL methods specialized for a context type
- NewAdapter[Ctx]() creates an adapter instance
- Update ollie/fs/edsl.go to use the adapter explicitly
- Update README with adapter-based examples
The adapter makes it explicit that we're building a type-specialized
interface to the generic EDSL library.
- Create fsedsl/ as embedded library with generic types:
- FsNodeDecl[Ctx], Binding[Ctx], NodeOption[Ctx]
- BuildTree[Ctx], GenerateHelp[Ctx]
- Tree, File, FileConfig, SyntheticFileInfo
- Update ollie/fs to use fsedsl via type aliases:
- type FsNodeDecl = fsedsl.FsNodeDecl[HandlerCtx]
- Wrapper functions for constructors and options
- Migrate binding functions to Applier pattern:
- Binding.Applier replaces direct field assignment
- Cleanly separates EDSL mechanics from domain types
- Add replace directive in go.mod for local module
The library can be extracted to a separate repo later by
changing the module path and removing the replace directive.
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.