From eff00a7b2eade701d8da5d994b9272d661e45114 Mon Sep 17 00:00:00 2001 From: Levi Neely Date: Sat, 25 Apr 2026 09:14:48 +0200 Subject: [PATCH] docs: document httpgw and webui MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add HTTP gateway and web UI sections to USAGE.md: build instructions, runtime flags, HTTP→9P endpoint reference, nginx serving example, and Vite dev workflow. Add HTTP gateway architecture section to ARCHITECTURE.md with frontend comparison table. Update README.md with httpgw build target, dual remote-access paths (9P mount vs httpgw), and container example updated for both. Co-Authored-By: Claude Sonnet 4.6 --- README.md | 33 +++++++--- doc/ARCHITECTURE.md | 46 +++++++++++++- doc/USAGE.md | 152 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 221 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 3e53fad..ad7978c 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,8 @@ Or build specific components: mk core # Build core library mk tui # Build terminal UI mk 9p # Build 9p filesystem server +mk httpgw # Build HTTP gateway +mk webui # Build web UI (requires Node.js + npm) ``` For Emacs Lisp, copy `el/ellie.el` into your own Emacs configuration directory, and: @@ -59,25 +61,38 @@ Shell environment variables take precedence over the env file. ## Remote Access -Because `olliesrv` speaks 9P over TCP, a remote instance can be mounted into the local namespace using `9pfuse`. This means agent sessions, tools, and all other filesystem state on a remote host are accessible as ordinary files — no special client needed. +Two approaches: mount the 9P namespace directly with `9pfuse`, or reach it over HTTP via `ollie-httpgw`. -### Start a remote server +### 9P mount -On the remote host (or in a container): +Because `olliesrv` speaks 9P over TCP, a remote instance can be mounted into the local namespace using `9pfuse`. Agent sessions, tools, and all other filesystem state on a remote host become ordinary local files — no special client needed. ```sh +# On the remote host: olliesrv start -tcp :9564 -``` -### Mount the remote namespace locally - -```sh +# Locally: olliesrv mount remotehost:9564 ~/mnt/remotehost ls ~/mnt/remotehost # s/, t/, ... ``` Sessions created under `~/mnt/remotehost/s/` run on the remote host, so tool calls execute close to the remote filesystem rather than over the wire. +### HTTP gateway + +`ollie-httpgw` translates HTTP to 9P, letting any HTTP client interact with +`olliesrv` without a 9P library. It's also the backend for the web UI. + +```sh +# Connect to local server: +ollie-httpgw + +# Connect to remote server: +ollie-httpgw -net tcp -addr remotehost:9564 +``` + +See [doc/USAGE.md](doc/USAGE.md) for full details on the gateway and web UI. + ### Container A `Containerfile` is included for running a self-contained remote server: @@ -87,10 +102,12 @@ podman build --network=host -t olliesrv . podman run --network=host -e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY olliesrv ``` -Then mount locally: +Then mount locally or point httpgw at it: ```sh olliesrv mount localhost:9564 ~/mnt/container-ollie +# or +ollie-httpgw -net tcp -addr localhost:9564 ``` ## Development diff --git a/doc/ARCHITECTURE.md b/doc/ARCHITECTURE.md index 1d04987..4f17a3e 100644 --- a/doc/ARCHITECTURE.md +++ b/doc/ARCHITECTURE.md @@ -158,6 +158,50 @@ core := agent.NewAgentCore(agent.AgentCoreConfig{ If `superpowerd` is running, commands are additionally wrapped with `superpowers run-session` for privilege scoping (optional, detected at runtime). +## HTTP Gateway + +`ollie-httpgw` is a thin translation layer between HTTP and 9P. It connects to +`olliesrv` as a 9P client and exposes the same namespace over REST-style HTTP, +so any HTTP client can interact with ollie without a 9P library. + +Each HTTP method maps to a 9P primitive: `GET` → read/stat, `POST` → write, +`DELETE` → remove, `PATCH` → wstat (rename). The gateway serializes file content +to JSON where the format is well-defined (key-value files, tab-separated records, +session index); raw text falls through as-is. + +Sensitive internal paths (`tr/`, `help`, `statewait`, `systemprompt`, etc.) are +blocked at the gateway layer and never exposed over HTTP. + +``` +HTTP client (browser, curl, script) + │ HTTP/JSON :8080 + ▼ + ollie-httpgw + │ 9P protocol + ▼ + olliesrv ($NAMESPACE/ollie or tcp:9564) +``` + +The gateway can connect to a local server via the Plan 9 namespace (default) or +to a remote server via TCP (`-net tcp -addr host:9564`), making it equally useful +for local setups and container/remote deployments. + ## Frontends -The reference frontend is [ollie-tui](https://github.com/lneely/ollie-tui): a readline-based terminal UI that imports ollie as a library. It is the only consumer of `agent.Core` today, but the interface is intentionally frontend-agnostic. +All frontends interact with the same 9P namespace, either directly or via httpgw: + +| Frontend | Interface | Talks to | +|---|---|---| +| `s/sh` | terminal (readline) | 9P filesystem directly | +| ollie-tui | terminal (TUI) | `agent.Core` library | +| ellie | Emacs buffer | 9P filesystem directly | +| Web UI | browser (Preact SPA) | `ollie-httpgw` over HTTP | + +The web UI (`webui/`) is a Preact single-page application. It polls +`/s/{id}/chat` every two seconds for new output and proxies all API paths to +`ollie-httpgw`. It has no knowledge of 9P; the gateway is the only boundary. + +Frontends that use `agent.Core` directly (ollie-tui) embed the core library and +manage sessions in-process. Frontends that use the filesystem (s/sh, ellie, web +UI) are decoupled from the implementation entirely — they work equally well +against a local or remote `olliesrv`. diff --git a/doc/USAGE.md b/doc/USAGE.md index 0e29a70..4840b4d 100644 --- a/doc/USAGE.md +++ b/doc/USAGE.md @@ -371,11 +371,161 @@ OLLIE_TOOLS_PATH=~/mnt/toolserver/t OLLIE_TRANSCRIPT_PATH=~/mnt/archive/tr ``` +## HTTP gateway + +`ollie-httpgw` is an HTTP gateway that translates REST-style HTTP calls into 9P +filesystem operations. It lets any HTTP client — including the web UI, `curl`, or +custom scripts — interact with `olliesrv` without a 9P client library. + +### Build + +```sh +mk httpgw # from repo root +# or +cd httpgw && mk +``` + +Produces `~/bin/ollie-httpgw`. + +### Run + +```sh +ollie-httpgw # connect to local olliesrv via namespace; listen on :8080 +ollie-httpgw -listen :9090 # different port +ollie-httpgw -net tcp -addr host:9564 # connect to remote olliesrv over TCP +``` + +**Flags** + +| Flag | Default | Description | +|---|---|---| +| `-listen` | `:8080` | HTTP listen address | +| `-service` | `ollie` | 9P service name in the local namespace | +| `-net` | `` | Network type (`tcp`, `unix`); empty = use namespace | +| `-addr` | `` | 9P server address; required when `-net` is set | + +The gateway must be able to reach `olliesrv`. For a local server started with +`olliesrv start`, the defaults work as-is. For a remote server started with +`olliesrv start -tcp :9564`, use `-net tcp -addr remotehost:9564`. + +### HTTP → 9P mapping + +Each HTTP method maps to a 9P operation: + +| Method | 9P operation | Example | +|---|---|---| +| `GET` | read file / list dir | `GET /s/idx` | +| `POST` | write to file | `POST /s/new`, `POST /s/{id}/prompt` | +| `DELETE` | remove | `DELETE /s/{id}` | +| `PATCH` | rename (JSON `{"name":"..."}`) | `PATCH /s/{id}` | +| `HEAD` | stat (metadata in `X-9p-*` headers) | `HEAD /s/{id}` | + +The full API is described in `httpgw/openapi.json` and served live at +`GET /openapi.json`. + +### Key endpoints + +```sh +GET /s/idx # list sessions (JSON array) +GET /s/{id}/cfg # session config (key-value JSON) +GET /s/{id}/chat # conversation transcript (plain text) +POST /s/new # create session (JSON: {cwd, backend, model, agent}) +POST /s/{id}/prompt # submit prompt (JSON: {prompt: "..."}) +POST /s/{id}/ctl # send control command (JSON: {ctl: "stop"}) +DEL /s/{id} # kill and remove session +GET /backends # list available backends +GET /a/ # agent configs +GET /t/ # tool scripts +GET /m/ # memory files +GET /sk/ # skills +``` + +```sh +# Examples with curl: +curl http://localhost:8080/s/idx +curl -X POST http://localhost:8080/s/new \ + -d '{"cwd":"/home/user/project","backend":"anthropic"}' +curl -X POST http://localhost:8080/s/mysession/prompt \ + -d '{"prompt":"summarize the recent commits"}' +``` + +## Web UI + +The web UI is a Preact single-page application that talks to `ollie-httpgw`. It +provides session management, a chat interface, and a basic 9P filesystem browser +in the browser. + +### Build + +```sh +mk webui # from repo root +# or +cd webui && npm run build +``` + +Requires Node.js and npm. Output lands in `webui/dist/`. + +### Serve + +The `dist/` folder is a static site. Serve it with any HTTP server and proxy the +API paths to `ollie-httpgw`: + +**nginx example:** + +```nginx +server { + listen 3000; + root /path/to/ollie/webui/dist; + index index.html; + + location / { try_files $uri /index.html; } + + location ~ ^/(s|a|m|t|sk|backends|openapi\.json)(/|$) { + proxy_pass http://localhost:8080; + } +} +``` + +**Python one-liner (local testing only):** + +```sh +cd webui/dist && python3 -m http.server 3000 +# API calls will fail — use the Vite dev server instead for local testing +``` + +### Development + +Vite's dev server proxies API paths to httpgw automatically: + +```sh +# Terminal 1: gateway +ollie-httpgw -listen :8080 + +# Terminal 2: dev server (hot-reload, proxied API) +cd webui && npm run dev +# Open http://localhost:5173 +``` + +The proxy configuration is in `webui/vite.config.ts` and targets `localhost:8080` +by default. + +### Features + +- Session list in a sidebar with state, model, backend, and cwd +- Create, rename, and kill sessions +- Send prompts; streaming via 2-second poll +- Stop a running agent +- Markdown rendering of assistant responses +- 9P filesystem browser (navigate `s/`, `a/`, `t/`, `m/`, `sk/`) +- Two built-in themes: `midnight` (dark) and `acme` (Plan 9-inspired light); choice + persisted to `localStorage` + ## Alternative front-ends -The 9P filesystem is the lowest level interface to ollie. All interfaces are simply wrappers around filesystem operations, and `s/sh` is the standard chat interface. A couple of other front-ends are also provided: +The 9P filesystem is the lowest level interface to ollie. All interfaces are simply wrappers around filesystem operations, and `s/sh` is the standard chat interface. Other front-ends: - **[ollie-tui](https://github.com/lneely/ollie-tui)** — a fancier terminal UI for the less curmudgeonly - **[ellie](https://github.com/lneely/ollie-el)** — `ellie.el` is the Emacs front-end, just wire it into your `init.el` and `M-x ellie` +- **Web UI** — browser-based UI; requires `ollie-httpgw` (see above) See each repo's README for installation and usage.