opbox

The chat is the default interface. A user signs in, types, and a bounded agent answers by calling kernel verbs and streaming its work back live.

The frontend

The Next.js front end is the site root and sign-in surface (ADR-0038), served behind Caddy. Spotlight is the in-app AI surface (it superseded the retired copilot-app): a user signs in, opens Spotlight, and the agent answers over a streaming connection. The chat itself is AG-UI (the same event protocol CopilotKit consumes): agent-chat serves the bearer-gated /chat/* SSE stream, and the front end renders the events as they arrive.

The engine behind the chat

The chat is answered by a caged agent engine. The exercised engine is an unmodified upstream Nous Hermes agent run caged: its only tools are the kernel verbs over MCP plus an in-memory todo, with no terminal, browser, web, file, or code-exec access. The model is provider-configurable (default cloud GLM-4.6 via z.ai; a local Ollama is the no-egress fallback; any OpenAI-compatible provider works by config). The owned opbox_agent.py loop coexists as a driver and a fallback. See Agents & MCP.

The agent is reached through a small HTTP gateway with two faces: an OpenAI-compatible /v1 API (for OpenAI-style clients like OpenWebUI or LobeChat) and an AG-UI /chat/stream SSE endpoint (for the in-app chat surface). The owned opbox_agent.py loop also speaks AG-UI directly.

Dev/operator stack. The operator gateway and the commodity chat UIs are a dev/operator setup and a test build: they run with a dev-identity kernel, stub auth, and unauthenticated UIs, and are not a hardened shipped product surface. The architecture above is the truth of the engine; the operator stack lives in its own package, wlilley93/opbox-agent. Do not treat it as production.

Login

The chat requires authentication. The user signs in with email + password: the modal POSTs /auth/login, receives a SESSION token, stores it, and presents it as the Authorization bearer on every request. A 401 clears the token and re-shows the login.

There is no anonymous access. The SESSION bearer is the access gate; the agent then executes under a separate bounded WORKER identity (never the OWNER key) โ€” see Agents & MCP.

The streaming protocol

POST /chat/stream returns a text/event-stream of AG-UI events:

data: {"type":"RUN_STARTED","runId":"..."}
data: {"type":"TOOL_CALL_START","toolCallName":"matter.list",...}
data: {"type":"TOOL_CALL_RESULT","content":"{...}","ok":true}
data: {"type":"TEXT_MESSAGE_START",...}
data: {"type":"TEXT_MESSAGE_CONTENT","delta":"There are ..."}
data: {"type":"RUN_FINISHED","runId":"..."}

The frontend renders tool calls as live chips and the answer as streamed text. Frames are flushed per event and the proxy keeps buffering off (flush_interval -1), so the stream never stalls.

What the agent can do

Because the chat agent runs at autonomy 1 / MEMBER tier, it can read and create matters, forms, and documents, but cannot perform sensitive or owner operations. To let it do more, raise its tier deliberately - that is a deliberate choice, not a default.