opagent-server is a minimal, local HTTP host for runtime.Runtime. It is
intended for CLIs, local apps, integration tests, and small developer tools—not
as a public multi-user service.
- Address:
127.0.0.1:19531 - Data:
~/.opagent - Token:
<baseDir>/run/local-connection-token - Header:
X-OpAgent-Connection-Token
v0.1 accepts only explicit loopback IP addresses. /health and /version are
public probes; every /v1 endpoint requires the token. The token is a
32-byte random base64url capability stored in a 0600 regular file below a
0700 run directory.
The Server also embeds /web/, a static single-Workspace console. Static assets
load without a Token so the connection screen can render; all data APIs remain
authenticated.
| Method and path | Purpose |
|---|---|
GET /health |
Liveness response |
GET /version |
Server name and version |
GET /v1/config/models |
List safe model summaries without API Tokens |
PUT /v1/config/model |
Add or update one standalone provider model |
GET /v1/workspace/list |
List Server-authorized Workspace roots |
POST /v1/workspace/open |
Register a directory when the host opted in |
GET /v1/files?workspaceID=...&path=... |
List one Workspace directory |
GET /v1/file?workspaceID=...&path=... |
Read one bounded UTF-8 text file |
POST /v1/thread/create |
Create a Runtime-owned thread |
POST /v1/chat/stream |
Submit or reconnect to a turn over SSE |
POST /v1/chat/control |
Interrupt a thread turn |
GET /v1/thread/snapshot?threadID=... |
Read the persisted Runtime snapshot |
Create request:
{"agentID":"agent-web","workspaceID":"workspace-...","title":"First chat"}Existing embedders may continue to pass an explicit cwd; callers must not
send both workspaceID and cwd. A workspaceID request first sets that
Workspace to trusted and selects Runtime's full profile with host-file and
internet access confirmed; the explicit cwd form retains the host's existing
permission workflow.
Model save request:
{
"providerKey": "openai",
"providerLabel": "OpenAI",
"api": "openai-responses",
"baseURL": "https://api.openai.com/v1",
"apiToken": "secret",
"modelID": "gpt-5.4",
"modelLabel": "GPT 5.4"
}apiToken may be omitted when updating an existing model. The Server preserves
the saved value, writes models.json atomically with mode 0600, reloads
Runtime configuration, and returns only hasAPIToken: true.
Options.Workspaces registers explicit filesystem roots. If none are supplied
to the Go API or CLI, <baseDir>/workspace is created and used. With standalone
defaults, that path is ~/.opagent/workspace. AllowWorkspaceOpen is false by
default; the command enables dynamic opening, but never infers the process
working directory as a Workspace.
File paths are always relative to a registered root. The Server resolves
symlinks and uses a traversal-resistant directory capability for the actual
open. Preview is limited to regular UTF-8 text files no larger than 2 MiB.
Runtime state and Workspace roots containing <baseDir> are rejected. v0.1
does not write, rename, upload, or delete Workspace files.
Chat request:
{
"threadID": "thread-...",
"modelKey": "provider:model",
"message": "Explain this repository",
"turnRequestID": "turnreq-client-generated"
}turnRequestID is generated when omitted. Retrying an existing ID must use
the same thread, model, and message or the Server returns 409.
Interrupt request:
{"threadID":"thread-...","action":"interrupt"}Each SSE data value is a Protocol GeneralContent. Event IDs have the form
<turnRequestID>:<sequence>. Reconnect by resending the identical chat request
with Last-Event-ID. The Server retains at most 256 events per turn and 128
active/recent turns for five minutes; an expired replay returns 409.
Slow clients are detached from the live stream instead of blocking Runtime. Disconnecting a client does not cancel the turn. Use the interrupt endpoint for explicit cancellation. Runtime shutdown cancels all in-flight handlers.
srv, err := server.New(server.Options{
BaseDir: "/absolute/data",
Workspaces: []string{"/absolute/workspace"},
})
if err != nil { /* handle */ }
handler := srv.Handler() // httptest or another loopback host
err = srv.Run(ctx) // owns Runtime + HTTP lifecyclePass Runtime in Options to reuse a ready-compatible implementation. Its
BaseDir must match the Server base directory.
Ready() synchronizes browser launch and WebURL(true) returns a local bootstrap
URL with the connection Token in the fragment. The Web client immediately moves
that Token to per-origin sessionStorage and removes the fragment.
The Server has no second message store, websocket surface, file mutation, terminal, SSH manager, user accounts, tenant auth, public-network listener, or OpenAI-compatible endpoint. For remote use, forward the remote loopback port and connect the browser to that local forwarded URL; ongoing file and chat requests then execute on the target Server machine.