fs: add /help ctl command — returns command reference
This commit is contained in:
parent
05e9c45495
commit
25924d0909
26
README.md
26
README.md
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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 "$@" ;;
|
||||||
|
|
|
||||||
|
|
@ -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 |
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 |
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
2
kde
|
|
@ -1 +1 @@
|
||||||
Subproject commit ec3419aa4e710eb63d449be612995a4e4b6f46ca
|
Subproject commit c6da56310992d19049a60910955ab2b915a9e5aa
|
||||||
|
|
@ -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 |
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue