Delete dbus/dbus.go — the entire D-Bus SessionManager service is gone.
No more 150ms poll loop, no more signal emission, no more method handlers.
- Remove ollie/dbus import, nodbus flag, dbusAdapter variable
- Remove OnSessionCreated/Killed/Renamed hooks from Config
- Remove EnableDBus from Config
- Elevation notifications connect to session bus directly (godbus stays
as a dependency solely for org.freedesktop.Notifications)
All clients now use 9P exclusively. D-Bus is dead.
- Rename 'chat' to 'log': returns last 64KB sliding window (static read).
Tail still works via Qid.Vers. Full history persisted to disk per turn.
- Add 'chat' streaming file: blocking read that delivers new output as
the agent produces it. Per-fid offset tracked via waitBase. Blocks
indefinitely between turns (no EOF). EOF only on kill/session death.
- Add LongBlock interface to File: streaming files bypass the 5s read
timeout. Server returns content directly (ignores Tread offset for
streaming files since waitBase tracks position).
- Add 'kill'/'.'' ctl aliases with FIXME: currently kills entire session.
When multi-agent-per-session lands, kill should kill agent only.
- Rewrite acme frontend (cmd/Ollie) to use 9P client directly instead
of FUSE mount. streamChat() is a blocking read loop — no polling.
All file operations (read, write, ls) go through plan9/client.
- Add 9P streaming prototype in experiments/9p-stream demonstrating
the blocking-read pattern for token delivery.
The key insight: 9P's request-response model gives natural streaming.
Server holds the Tread until data arrives, client blocks on Read().
No polling, no signals, no offset tracking needed.
skill_list and skill_load are now external shell scripts (data/tools/).
Removed from builtins: SkillList, SkillLoad, SkillActive.
Removed: toolsrv/skills.go, tools/builtin/skill.go, WithSkillsRegistry,
SkillsRegistry accessor, ListSkillsTools.
ollie-remote no longer initializes a skills registry.
The demarcation: built-ins mutate agent internals (tool schema, context
injection). Skills are just file reads — no special treatment needed.
skill_list and skill_load are now simple shell scripts that read
SKILL.md files from OLLIE_SKILLS_PATH. No built-in registry needed.
skill_load returns the file body as tool result (tier:hot, survives compaction).
skill_active dropped — model uses skill_list instead.
Logseq 2.0.1 has bug #12413 where POST /mcp always returns 400.
Switched to the REST API at POST /api which works correctly.
Requires OLLIE_LOGSEQ_TOKEN env var.
Commands: listPages, getPage, searchBlocks, listTags, listProperties,
upsertNodes, getCurrentGraph
- Embed the full sandbox/default.yaml instead of sandbox-remote.yaml
so local ollie-remote subprocesses get proper sandbox permissions
(DNS, git config, etc.)
- justfile copies sandbox/default.yaml temporarily during build
- Register builtins + ToolRegistry + SkillsRegistry on ollie-remote
- Pdeathsig: kernel auto-SIGTERMs children when parent dies
- Cleanup: SIGTERM → 3s grace → SIGKILL (guaranteed kill)
- Atomic counter for unique socket paths (no collisions)
Execution is now identical for local and remote:
- Session calls Spawn()/SpawnRemote() → owns *Process with socket
- Clients call Dial(LocalAddr(socket)) → *Conn over Unix socket
- ollie-remote serves --listen mode with multi-client accept loop
- Builtins (shell, tool_load, skill_load) run in subprocess with registries
Lifecycle:
- Pdeathsig ensures children die with parent (no orphans)
- Cleanup: SIGTERM → 3s grace → SIGKILL (guaranteed)
- Socket paths use atomic counter for uniqueness
- Session Kill() closes Process
Protocol:
- Extended RPC: set_env, set_cwd, detach, list_detached, etc.
- Shell goes through builtin dispatch (parses 'cmd' field correctly)
- Streaming output via JSON-RPC notifications
Shell results were returned as raw strings but the agent expects
structured content blocks ({content:[{type:text,text:...}]}). Fixed
shell handler to return the same format as the local Server.CallTool.
Shell errors now return as isError content blocks rather than RPC
errors, matching local behavior (output is preserved in errors).
The default RPC handler now dispatches to srv.CallTool() for any
unknown method, enabling named tools (file_read, file_grep, etc.)
from the embedded tools to be called remotely.
Before each CallTool, check if the local ollie-remote binary hash
differs from what was deployed. If so, close the SSH connection,
re-dial (triggering bootstrap to upload the new binary), and swap
the connection transparently.
Emits info events when upgrade is detected and when it completes.
ExecuteInSandbox uses StreamFunc(ctx) to emit partial output. The
context passed to it lacked a WithOutputStream callback, so no output
was ever streamed back to the client.
Fix: wrap ctx with WithOutputStream that encodes output as JSON-RPC
notifications (id=0, result={data:...}). The client side already
handles these via the outputNotification path in CallTool.
The bootstrap script now also checks for and deploys the landrun
sandbox binary to ~/.cache/ollie/bin/landrun on the remote host.
Without this, ollie-remote couldn't sandbox tool execution.
Protocol extended: OLLIE_LOADER_START now includes need_landrun field.
Transfers are sequential: ollie-remote first, then landrun if needed.
Each binary has independent hash-based caching.
- Skip cwd existence check when remote is specified (cwd is on remote)
- Add BatchMode=yes to SSH: pubkey-only, no password fallback
- Add StrictHostKeyChecking=accept-new: auto-accept new hosts, reject
changed keys
- Deploy failure already propagates as session creation error via
RemoteDial returning error
When a session is created with a cwd that doesn't exist, all tool
execution fails with a confusing 'fork/exec landrun: no such file or
directory' because exec.Command sets cmd.Dir to the non-existent path.
Validate that cwd exists and is a directory at session creation time,
returning a clear error instead of allowing a broken session.
Also includes the earlier USER/NAMESPACE env export fix (agent.go,
shell.go) for the ollie-9p namespace path issue.
ollie-9p computes its namespace path from $USER and $DISPLAY via
client.Namespace(). When run inside the sandboxed shell, USER was not
guaranteed to be in the environment, producing /tmp/ns..:0/ollie.
Fix: explicitly inject USER into envExtra in SetSessionEnv (alongside
OLLIE_SESSION_ID and OLLIE_UNAME). Also export the computed NAMESPACE
to cmd.Env so ollie-9p can use it directly without recomputing.
Adds system_logs with two variants:
- journalctl (systemd hosts): unit, since, lines, grep
- dmesg (any Linux): source, lines, grep
Both declare sudo: true — privilege escalation is handled by dispatch.
Also adds OR support in match conditions: array values mean any must
pass. Combined with AND across keys:
{"binary": ["journalctl", "systemd-cat"], "os": "linux"}
= (journalctl OR systemd-cat) AND linux
A .meta file can now declare multiple variants, each gated by match
conditions. The first variant where all conditions pass determines the
tool's schema, documentation, and executable. If no variant matches,
the tool is hidden from the registry on that host.
Match conditions:
binary — exec.LookPath or absolute path stat
file — os.Stat (file or dir exists)
os — runtime.GOOS
arch — runtime.GOARCH
env — environment variable is non-empty
nenv — environment variable is empty
This enables network-transparent tool declarations: one .meta file
works across heterogeneous hosts (systemd vs syslog, apt vs pacman,
GUI vs headless). When ollie-remote deploys to a different machine,
tools adapt their contract to what's actually available.
No variants field = current behavior, zero breaking changes.