docs: document httpgw and webui

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 <noreply@anthropic.com>
This commit is contained in:
Levi Neely 2026-04-25 09:14:48 +02:00
parent c3df30df3c
commit eff00a7b2e
3 changed files with 221 additions and 10 deletions

View File

@ -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

View File

@ -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`.

View File

@ -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.