# Architecture
## Design objective
K1412 Agent is a multi-user web coding Agent whose loop can be changed
independently of its account system and user interface. The architecture keeps
the high-cost experimental surface small: researchers should be able to change
context, memory, scheduling, tools, delegation, or completion policy without
forking authentication, chat history, Docker lifecycle, or the whole frontend.
The system deliberately has one Agent path. The earlier idea of a lightweight
Chat loop beside a custom Work loop was removed because it duplicated product
behavior, confused model selection, and increased the amount of frontend and
backend code that had to remain compatible.
## System context
```mermaid
flowchart LR
U["Browser user"] --> P["DNS, TLS and Nginx Proxy Manager"]
P --> W["Open WebUI
auth, RBAC, history, UI"]
W --> R["Agent Runtime
loop, context, memory, model routing"]
R --> M["Model providers
K1412 API or DeepSeek"]
R --> G["Workspace Gateway
identity and execution policy"]
G -->|Tailscale + SSH Docker| X["Per-user workspace container
home-node-itx"]
W --> DB["PostgreSQL
users and chats"]
R --> DB
W --> Q["Redis
coordination"]
```
Only Web is publicly reachable. Runtime, Gateway, PostgreSQL, and Redis live on
private Compose networks. Workspace containers run on a separate physical
Docker host, receive no application secrets, and expose no host ports.
## Responsibility boundaries
| Layer | Owns | Must not own |
| --- | --- | --- |
| Open WebUI | Registration, login, sessions, admin approval, RBAC, chat persistence, rendering | Agent scheduling, provider secrets, Docker access |
| Agent Runtime | Model catalog, context policy, Agent loop, tools, scheduling, delegation, memory, plans, run events, evidence gates | Browser sessions, Docker socket |
| Workspace Gateway | Signed identity enforcement, workspace path policy, per-user locks, Docker lifecycle, file delivery | Model calls, public authentication UI |
| Workspace container | User code, dependencies, generated files, command execution | Other users' data, service credentials, Docker socket |
| PostgreSQL | Open WebUI durable state plus Runtime events, plans, and memories | Execution |
| Shared infrastructure | TLS, registry, source hosting, private routing, model serving | Agent behavior |
This separation lets the Web UI be upgraded on its own schedule while the
Agent loop can iterate frequently.
## Request lifecycle
### Agent request
```mermaid
sequenceDiagram
participant B as Browser
participant W as Open WebUI
participant R as Runtime
participant M as Model provider
participant G as Gateway
participant X as User workspace
B->>W: Authenticated chat request
W->>R: OpenAI-compatible request + service key + signed user identity
R->>R: Verify identity, build context, record run.created
loop Until evidence-backed completion or budget exhausted
R->>M: Recent context + tools + provider policy
M-->>R: Assistant content and/or tool calls
R->>R: Normalize, validate, limit, and schedule calls
R->>G: Tool request + service key + freshly signed identity
G->>G: Verify identity and bind user workspace
G->>X: Execute with resource and path constraints
X-->>G: Exit code, output, or file result
G-->>R: Structured tool result
R->>R: Persist events and evaluate completion evidence
end
R-->>W: SSE answer and completed tool detail blocks
W-->>B: Rendered Agent response
```
The identity sent by Open WebUI is verified once when Runtime accepts the
request. Runtime then signs the already verified identity again for every
Gateway call. This prevents a long Agent run from reusing an identity token
that expired while the model or a tool was working.
### Workspace file request
```text
browser with Open WebUI session
-> /api/v1/k1412/workspace/*
-> Open WebUI verifies the logged-in user
-> Web signs a short-lived user identity
-> Gateway verifies service key + signed identity
-> Gateway selects only the hashed container and volume for that user
-> browse, download, or streamed archive response
```
The browser never receives a Gateway service key and never connects to Docker.
## Runtime internals
Runtime is an OpenAI-compatible provider from Open WebUI's point of view, but
normal chat completions are implemented by the K1412 loop:
- `ModelProvider` translates the internal model spec to a provider request and
normalizes streamed completion responses.
- `ContextPolicy` removes rendered tool-detail markup, prepends the system
contract and durable memories, and keeps the newest visible messages within
a per-model character budget.
- `ToolRegistry` declares tool schemas and routes workspace tools to Gateway or
state tools to `RuntimeStore`.
- `AgentLoop` owns iteration, tool normalization, validation, scheduling,
recovery, delegation, and evidence-gated completion.
- `RuntimeStore` persists run events, per-chat plans, and user memories.
More detail is in [agent-loop.md](agent-loop.md).
## Workspace architecture
`local-docker` and `ssh-docker` implement the same `ExecutionProvider`
contract. Production uses `ssh-docker`: Gateway talks to Docker on
`home-node-itx` through a dedicated SSH configuration mounted read-only.
Each immutable Open WebUI user ID maps to a SHA-256-derived workspace ID and
therefore to exactly one:
- container named `k1412-ws-`;
- named volume `k1412-ws-data-`;
- bridge network `k1412-ws-net-`.
Containers run as UID/GID 1000 with a read-only root filesystem, all Linux
capabilities dropped, `no-new-privileges`, PID/CPU/memory limits, no Docker
socket, and no published ports. `/workspace` is the only persistent writable
filesystem. `/tmp` is writable but mounted `noexec`.
Python environments live at `/workspace/.venv`. User-level home and package
caches live below `/workspace/.agent`. The image puts the virtual environment
and user binary directories first on `PATH`. Commands run under Bash with
`pipefail`, so a failed install cannot be hidden by a successful `tail` or
similar pipeline stage.
When `WORKSPACE_IMAGE` changes to a new immutable tag, Gateway replaces a stale
container on its next access but reattaches the existing named volume. Image
upgrades therefore change the execution environment without deleting user
files.
## Networks and deployment
Production runs as one Unraid Compose Manager project:
- `public`: Web ingress;
- `internal`: private service-to-service traffic;
- `egress`: Runtime provider access and Gateway SSH access.
Only Web publishes NAS port `12004`. Nginx Proxy Manager on the VPS terminates
TLS for `agent.k1412.top` and forwards over Tailscale. Images are built for
`linux/amd64`, pushed to `docker.k1412.top/wuyang/*` with immutable
timestamp-and-commit tags, and deployed by updating only the relevant service.
The documentation portal is packaged inside the Web image at `/doc/`. It does
not add a public service, port, database, or proxy rule.
## Stable and experimental surfaces
Stable platform contracts:
- authenticated Web-to-Runtime request;
- signed Runtime/Web-to-Gateway identity;
- `ExecutionProvider` workspace semantics;
- per-user volume isolation;
- run-event persistence;
- public model IDs;
- workspace file API.
Expected experiment surfaces:
- prompt and context policy;
- memory selection;
- tool catalog and intent routing;
- scheduler and parallelism;
- delegation;
- recovery and evidence rules;
- model budgets and routing.
Version experiment-sensitive behavior in `run.created` so results remain
comparable after the implementation changes.