fs: add /help ctl command — returns command reference

This commit is contained in:
Ollie Agent 2026-08-09 03:16:15 +02:00
parent 05e9c45495
commit 25924d0909
10 changed files with 42 additions and 89 deletions

View File

@ -53,11 +53,9 @@ Everything lives under `$XDG_CONFIG_HOME/ollie/` (default: `~/.config/ollie/`)
| Capability | How | | Capability | How |
|---|---| |---|---|
| **CLI** | `o` — unified namespace CLI: `read`, `write`, `ls`, `ctl`, `prompt`, `tui`, `env`, `generate`, `complete`, `route` | | **CLI** | `o` — unified namespace CLI: `read`, `write`, `ls`, `ctl`, `prompt`, `tui`, `env`, `generate` |
| **Terminal TUI** | `o tui` — tmux layout, no widgets | | **Terminal TUI** | `o tui` — tmux layout, no widgets |
| **One-shot LLM** | `o generate "explain monads"` or `echo "prompt" \| o generate` | | **One-shot LLM** | `o generate "explain monads"` or `echo "prompt" \| o generate` |
| **Code completion** | `o complete '{"file":"main.go","prefix":"func "}'` or `echo '{"file":"..."}' \| o complete` |
| **Task routing** | `o route "implement login"` or `echo "task" \| o route` → `backend=X model=Y` |
| **Run an agent** | Create a session + agent via 9P — then connect with any frontend ([ellie](doc/ellie.md), KDE (GUI/KRunner/Kate), `o tui`) | | **Run an agent** | Create a session + agent via 9P — then connect with any frontend ([ellie](doc/ellie.md), KDE (GUI/KRunner/Kate), `o tui`) |
| **Remote execution** | Set `remote=user@host` in session config | | **Remote execution** | Set `remote=user@host` in session config |
| **Agents** | Write a JSON config in `data/agents/` with agent prompt in `data/prompts/` | | **Agents** | Write a JSON config in `data/agents/` with agent prompt in `data/prompts/` |
@ -98,7 +96,7 @@ graph TB
TUI["o tui<br>(tmux + o read/ctl)"] TUI["o tui<br>(tmux + o read/ctl)"]
KDE[KDE GUI<br>ollie-9p native client] KDE[KDE GUI<br>ollie-9p native client]
KATE[Kate plugin] KATE[Kate plugin]
EMACS[Emacs<br>ellie.el] EMACS[Emacs<br>ellie.el · ollie-9p]
ACME[Plan 9 acme] ACME[Plan 9 acme]
SCRIPTS[Shell scripts<br>o read · o ctl · o write] SCRIPTS[Shell scripts<br>o read · o ctl · o write]
end end
@ -109,9 +107,8 @@ graph TB
subgraph "olliesrv" subgraph "olliesrv"
P9[9P Filesystem<br>session/ namespace] P9[9P Filesystem<br>session/ namespace]
SM[Session Manager] SESS[session.Session<br>tool server conn · persistence]
AG[agent.Agent<br>loop · compaction<br>prompt assembly] AG[agent.Agent<br>loop · compaction<br>prompt assembly]
ROUTE[Router<br>complete · generate · route]
TOOLS[toolsrv.Server<br>dynamic dispatch · sandbox] TOOLS[toolsrv.Server<br>dynamic dispatch · sandbox]
end end
@ -124,22 +121,19 @@ graph TB
end end
subgraph Execution subgraph Execution
LOCAL[Tool Scripts<br>loaded via ctl<br>· shell, reasoning_think<br>· file_*, lsp_*, memory_*<br>· gui_*, subagent_*] EXEC[Tool Scripts<br>loaded via ctl<br>· shell, reasoning_think<br>· file_*, lsp_*, memory_*<br>· gui_*, subagent_*]
REMOTE[ollie-remote<br>via SSH · no embedded tools]
end end
TUI & SCRIPTS & EMACS & ACME --> O TUI & SCRIPTS & ACME --> O
O --> P9 O --> P9
KDE & KATE --> P9 KDE & KATE & EMACS --> P9
P9 --> SM P9 --> SESS
SM --> AG SESS --> AG
AG --> ROUTE SESS -->|shared RPC conn| TOOLS
AG --> TOOLS
AG -->|streaming| OLL & OAI & ANT & COP & KIRO AG -->|streaming| OLL & OAI & ANT & COP & KIRO
TOOLS --> LOCAL TOOLS --> EXEC
TOOLS -->|SSH| REMOTE
``` ```
`olliesrv` exposes the agent runtime over a single surface: a 9P2000 filesystem. `olliesrv` exposes the agent runtime over a single surface: a 9P2000 filesystem.

View File

@ -614,15 +614,15 @@ Attaches to the last session if it still exists; otherwise creates a new one."
(defun ellie--complete-send (prefix suffix) (defun ellie--complete-send (prefix suffix)
"Send a completion request with PREFIX and SUFFIX text. "Send a completion request with PREFIX and SUFFIX text.
Returns the raw response from the server." Returns the raw response from the server via /generate."
(let ((payload (format "%s\n__COMPLETE_SEPARATOR__\n%s" prefix suffix))) (let ((payload (format "Complete the code between the markers. Return ONLY the completion, no explanation.\n\n```\n%s<CURSOR>%s\n```" prefix suffix)))
(with-temp-buffer (with-temp-buffer
(insert payload) (insert payload)
(let ((rc (call-process-region (point-min) (point-max) (let ((rc (call-process-region (point-min) (point-max)
"ollie-9p" t t nil "rdwr" "complete"))) "ollie-9p" t t nil "rdwr" "generate")))
(if (zerop rc) (if (zerop rc)
(buffer-string) (buffer-string)
(error "ollie-9p complete failed (exit %d)" rc)))))) (error "ollie-9p generate failed (exit %d)" rc))))))
(defun ellie-complete-at-point (&optional prefix suffix) (defun ellie-complete-at-point (&optional prefix suffix)
"Request a completion for the region around point. "Request a completion for the region around point.

View File

@ -27,7 +27,7 @@ set -euo pipefail
# ── Path classification ───────────────────────────────────────── # ── Path classification ─────────────────────────────────────────
# Root-level entries (no context needed) # Root-level entries (no context needed)
ROOT_ENTRIES="session bypass agents backends models help ctl eventwait complete generate route aliases tools" ROOT_ENTRIES="session bypass agents backends models help ctl eventwait generate aliases tools"
# Session-level files (exist directly under session/{name}/) # Session-level files (exist directly under session/{name}/)
SESSION_FILES="env paused connected ctl name id bypass" SESSION_FILES="env paused connected ctl name id bypass"
@ -235,40 +235,6 @@ cmd_generate() {
printf '%s' "$prompt" | ollie-9p rdwr generate printf '%s' "$prompt" | ollie-9p rdwr generate
} }
cmd_complete() {
# Code completion via /complete (no session/agent needed)
# Usage: o complete '{"file":"...","prefix":"...","suffix":"..."}'
# echo '{"file":"..."}' | o complete
local json=""
if [[ $# -gt 0 ]]; then
json="$*"
else
json=$(cat)
fi
[[ -z "$json" ]] && { echo "usage: o complete <json>" >&2; exit 1; }
printf '%s' "$json" | ollie-9p rdwr complete
}
cmd_route() {
# Task routing via /route (no session/agent needed)
# Usage: o route "task description"
# echo "task" | o route
local task=""
if [[ $# -gt 0 ]]; then
task="$*"
else
task=$(cat)
fi
[[ -z "$task" ]] && { echo "usage: o route <task>" >&2; exit 1; }
printf '%s' "$task" | ollie-9p rdwr route
}
cmd_ctl() { cmd_ctl() {
if [[ $# -lt 1 ]]; then if [[ $# -lt 1 ]]; then
echo "usage: o ctl <command> [args...]" >&2 echo "usage: o ctl <command> [args...]" >&2
@ -518,10 +484,8 @@ Commands:
ls [path] List namespace entries ls [path] List namespace entries
generate <prompt> One-shot generation (no session needed) generate <prompt> One-shot generation (no session needed)
complete <json> Code completion (no session needed)
route <task> Route task to best model (no session needed)
ctl <cmd> [s] [a] Send control command (session or agent level) ctl <cmd> [args] Send control command (rdwr: gets response)
prompt Interactive multi-line prompt REPL prompt Interactive multi-line prompt REPL
log [-n N] Show last N lines of agent log (default 1000) log [-n N] Show last N lines of agent log (default 1000)
@ -562,8 +526,6 @@ case "$subcmd" in
write) cmd_write "$@" ;; write) cmd_write "$@" ;;
ls) cmd_ls "$@" ;; ls) cmd_ls "$@" ;;
generate) cmd_generate "$@" ;; generate) cmd_generate "$@" ;;
complete) cmd_complete "$@" ;;
route) cmd_route "$@" ;;
ctl) cmd_ctl "$@" ;; ctl) cmd_ctl "$@" ;;
prompt) cmd_prompt "$@" ;; prompt) cmd_prompt "$@" ;;
log) cmd_log "$@" ;; log) cmd_log "$@" ;;

View File

@ -64,7 +64,7 @@ for s in session/*/agent/*/prompt; do echo "run tests" > "$s"; done
for s in session/*/agent/*/statewait; do cat "$s" > /dev/null; done for s in session/*/agent/*/statewait; do cat "$s" > /dev/null; done
# Grep all agent plans # Grep all agent plans
grep -r "TODO" session/*/plan grep -r "TODO" session/*/agent/*/plan
# Monitor costs # Monitor costs
cat session/*/agent/*/cost cat session/*/agent/*/cost
@ -78,7 +78,7 @@ with a 10-line shell script instead of a framework.
### Plan 9 patterns ### Plan 9 patterns
- **`/net/dns` pattern** — `/complete`, `/generate`, `/route` are stateless - **`/net/dns` pattern** — `/generate` and `ctl` are stateless
per-fid: write a request, read back the result per-fid: write a request, read back the result
- **`ctl` files** — control operations (stop, kill, rename, compact) are writes - **`ctl` files** — control operations (stop, kill, rename, compact) are writes
to a control file, not method calls to a control file, not method calls
@ -95,21 +95,6 @@ cat main.go | ollie-9p rdwr generate
echo '{"prompt":"explain recursion"}' | ollie-9p rdwr generate echo '{"prompt":"explain recursion"}' | ollie-9p rdwr generate
``` ```
### `/complete` — code completion
Fill-in-the-middle:
```sh
echo '{"file":"main.go","prefix":"func ","suffix":""}' | ollie-9p rdwr complete
```
### `/route` — task routing
```sh
echo 'implement login page' | ollie-9p rdwr route
# backend=anthropic model=claude-sonnet-4-20250514
```
### Key files per agent ### Key files per agent
| File | Mode | Description | | File | Mode | Description |

View File

@ -205,7 +205,6 @@ Agent configs declare prompts as a JSON array of shell commands. Each command is
├── {name}/ ├── {name}/
│ ├── env session environment variables │ ├── env session environment variables
│ ├── ctl session control (rdwr: kill, save, invalidate, pause, resume) │ ├── ctl session control (rdwr: kill, save, invalidate, pause, resume)
│ ├── plan session-scoped markdown checklist
│ ├── id immutable session UUID │ ├── id immutable session UUID
│ ├── name mutable session name (write to rename) │ ├── name mutable session name (write to rename)
│ ├── bypass per-session bypass policy │ ├── bypass per-session bypass policy

View File

@ -15,12 +15,12 @@ to its `name` file moves the entire directory subtree.
|------|---------| |------|---------|
| `/session/new` | Create an empty session (write `name=...`, read back name) | | `/session/new` | Create an empty session (write `name=...`, read back name) |
| `/session/{name}/agent/new` | Create an agent within a session (write `cwd=... backend=...`) | | `/session/{name}/agent/new` | Create an agent within a session (write `cwd=... backend=...`) |
| `/session/{name}/plan` | Session-scoped markdown checklist |
| `/session/{name}/env` | Session environment variables | | `/session/{name}/env` | Session environment variables |
| `/session/{name}/id` | Immutable session UUID | | `/session/{name}/id` | Immutable session UUID |
| `/session/{name}/name` | Mutable session name (write to rename) | | `/session/{name}/name` | Mutable session name (write to rename) |
| `/session/{name}/agent/{aname}/prompt` | Submit a prompt | | `/session/{name}/agent/{aname}/prompt` | Submit a prompt |
| `/session/{name}/agent/{aname}/chat` | Streaming chat log (blocking read) | | `/session/{name}/agent/{aname}/chat` | Streaming chat (filtered text) |
| `/session/{name}/agent/{aname}/plan` | Agent-scoped markdown checklist |
| `/session/{name}/agent/{aname}/cfg` | Agent config KV: backend, model, agent, cwd, params | | `/session/{name}/agent/{aname}/cfg` | Agent config KV: backend, model, agent, cwd, params |
| `/session/{name}/agent/{aname}/statewait` | **Blocking read** — returns when state changes | | `/session/{name}/agent/{aname}/statewait` | **Blocking read** — returns when state changes |
| `/session/{name}/agent/{aname}/ctl` | Control commands: `stop`, `kill`, `compact`, `rn <name>` | | `/session/{name}/agent/{aname}/ctl` | Control commands: `stop`, `kill`, `compact`, `rn <name>` |
@ -32,16 +32,14 @@ Global request-response files provide stateless operations without sessions:
| File | Purpose | | File | Purpose |
|------|---------| |------|---------|
| `/generate` | Write prompt, read response (one-shot generation) | | `/generate` | Write prompt, read response (one-shot generation) |
| `/complete` | Write JSON `{file, prefix, suffix}`, read code completion |
| `/route` | Write task description, read `backend=X model=Y` recommendation |
Global namespaces are shared across all sessions: Global namespaces are shared across all sessions:
| Path | Purpose | | Path | Purpose |
|------|---------| |------|---------|
| `/session/idx` | Session index (id, state, cwd, backend, model) | | `/session/idx` | Session index (id, state, cwd, backend, model) |
| `/session/{name}/plan` | Shared session-scoped checklist | | `/session/{name}/agent/{aname}/plan` | Agent checklist |
| `/session/{name}/agent/{aname}/chat` | Full chat history (searchable) | | `/session/{name}/agent/{aname}/chat` | Streaming filtered text |
## Spawning Agents ## Spawning Agents
@ -84,7 +82,7 @@ flowchart TB
``` ```
A root agent reasons about a task and delegates subtasks to workers. Workers A root agent reasons about a task and delegates subtasks to workers. Workers
report back via their chat history; the conductor reads `/session/{name}/agent/{aname}/chat` after report back via their log; the conductor reads `/session/{name}/agent/{aname}/log` after
`statewait` unblocks. `statewait` unblocks.
```sh ```sh

View File

@ -71,8 +71,6 @@ o read chat # stream chat output
| `o ls [path]` | List namespace entries | | `o ls [path]` | List namespace entries |
| `o ctl <cmd> [args]` | Send control command (rdwr: gets response) | | `o ctl <cmd> [args]` | Send control command (rdwr: gets response) |
| `o generate <prompt>` | One-shot generation (no session needed) | | `o generate <prompt>` | One-shot generation (no session needed) |
| `o complete <json>` | Code completion |
| `o route <task>` | Route task to best model |
| `o tui` | Launch tmux TUI | | `o tui` | Launch tmux TUI |
| `o env [session] [agent]` | Print export statements for context | | `o env [session] [agent]` | Print export statements for context |

View File

@ -774,6 +774,23 @@ var agentCtlHandlers = map[string]rdwrHandler{
"systemprompt": func(ctx HandlerCtx, _ []string) ([]byte, error) { "systemprompt": func(ctx HandlerCtx, _ []string) ([]byte, error) {
return []byte(ctx.Agent.SystemPrompt() + "\n"), nil return []byte(ctx.Agent.SystemPrompt() + "\n"), nil
}, },
"help": func(_ HandlerCtx, _ []string) ([]byte, error) {
return []byte(`stop — interrupt running agent
compact — compact context
clear — clear history
inject <text> — inject prompt mid-turn (overwrites pending)
agent [name] — show/switch agent profile
model [name] — show/switch model
models — list available models
tools — list loaded tools
tool_load <n> — load a tool
cwd [path] — show/change working directory
name [name] — show/rename agent
backend — show backend
systemprompt — show rendered system prompt
help — this message
`), nil
},
} }
func readAgentStats(ctx HandlerCtx) ([]byte, error) { func readAgentStats(ctx HandlerCtx) ([]byte, error) {

2
kde

@ -1 +1 @@
Subproject commit ec3419aa4e710eb63d449be612995a4e4b6f46ca Subproject commit c6da56310992d19049a60910955ab2b915a9e5aa

View File

@ -165,7 +165,7 @@ echo '{"file":"main.go","prefix":"func "}' | ollie-9p rdwr complete
| File | Mode | Purpose | | File | Mode | Purpose |
|---|---|---| |---|---|---|
| `plan` | r/w | Session-scoped markdown checklist; survives compaction | | `plan` | r/w | Agent-scoped markdown checklist; survives compaction |
| `env` | read | Session environment variables | | `env` | read | Session environment variables |
| `agent/` | dir | Agents within this session | | `agent/` | dir | Agents within this session |