156 lines
7.4 KiB
Markdown
156 lines
7.4 KiB
Markdown
# Workspace / Runtime / Docker launch boundary
|
|
|
|
Yoi's browser-facing deployment is a three-process boundary: WebUI, Workspace Backend, and Worker Runtime. Docker Compose currently exercises that boundary with locally loaded Nix-built images; it is not a separate authority model.
|
|
|
|
This document records the current design state for the split launch path, Docker image layout, and working-directory ownership rules. It is intentionally about boundaries and invariants rather than a complete operations manual.
|
|
|
|
## Process boundary
|
|
|
|
The browser launch path is:
|
|
|
|
```text
|
|
Browser WebUI
|
|
-> Workspace Backend Server
|
|
-> Worker Runtime
|
|
-> Worker process
|
|
```
|
|
|
|
Responsibilities are split as follows:
|
|
|
|
- WebUI renders the workspace and submits browser-safe requests. It does not hold filesystem authority, raw runtime paths, raw socket paths, or local Worker names as operation authority.
|
|
- Workspace Backend Server is the workspace control plane. It owns workspace-scoped API identity, Runtime registry projection, Worker registry projection, Ticket/workspace records, memory backend access, and browser-safe launch options.
|
|
- Worker Runtime owns runtime-specific process spawning, Worker controller state, workdir materialization, runtime-local workdir cleanup, and Worker protocol connectivity.
|
|
- Worker process owns model turns, tool execution inside its granted scope, session history append, and Worker protocol handling.
|
|
|
|
The Backend can project Runtime and Worker state, but it should not become a hidden filesystem/runtime implementation. Runtime observations should be reconstructable from Runtime APIs and committed Backend records.
|
|
|
|
## Docker image layout
|
|
|
|
Docker images are built through Nix `dockerTools.buildImage`, not through a root Dockerfile.
|
|
|
|
Current image roles:
|
|
|
|
```text
|
|
yoi-runtime:latest
|
|
worker-runtime-rest-server
|
|
|
|
yoi-server:latest
|
|
yoi-workspace-server
|
|
|
|
yoi-webui:latest
|
|
nginx serving built WebUI assets and proxying API requests
|
|
```
|
|
|
|
The Compose setup assumes those images have already been loaded into the local Docker daemon. Compose is a local wiring layer, not the builder.
|
|
|
|
Typical development flow:
|
|
|
|
```text
|
|
nix build .#docker-runtime
|
|
nix build .#docker-server
|
|
nix build .#docker-webui
|
|
docker load < result
|
|
# repeat load for each built image result
|
|
docker compose up
|
|
```
|
|
|
|
The Compose files live at:
|
|
|
|
```text
|
|
compose.yaml
|
|
docker/workspace/.yoi/workspace.toml
|
|
docker/workspace/.yoi/workspace-backend.local.toml
|
|
```
|
|
|
|
The WebUI container serves static assets and proxies `/api` to the Backend Server. The Backend Server registers the Runtime container as a remote Runtime such as `docker-runtime`. The Runtime container runs `worker-runtime-rest-server` and owns Worker spawning/materialization for that runtime.
|
|
|
|
Container user and writable data directories matter: runtime/server images must be able to write their configured data directories and named volumes. The current local-image Compose setup avoids an image-level `User` override and sets data-directory permissions accordingly.
|
|
|
|
## Worker launch path
|
|
|
|
A browser-created Worker follows this control flow:
|
|
|
|
```text
|
|
WebUI new-worker form
|
|
runtime_id / profile / initial input / optional workdir selection
|
|
|
|
Workspace Backend create-worker API
|
|
validate workspace scope
|
|
resolve Runtime by canonical runtime_id
|
|
resolve profile/manifest using Backend authority
|
|
convert browser workdir selection into a Runtime working-directory claim
|
|
forward a typed Worker creation request to the selected Runtime
|
|
|
|
Worker Runtime create_worker
|
|
reject a requested primary workdir if an existing live/registered Worker already owns it
|
|
spawn the Worker through the runtime execution backend
|
|
return Worker detail, run state, and workdir binding
|
|
|
|
Workspace Backend post-spawn projection
|
|
sync Worker registry
|
|
sync workdir registry from Runtime summary
|
|
sync Worker/workdir link
|
|
return browser-safe Worker detail
|
|
```
|
|
|
|
The Runtime guard against assigning the same primary workdir to two active Workers is required even when the Backend has a registry projection. It is the last authority that sees runtime-local Worker requests and execution bindings.
|
|
|
|
Worker interaction uses the unified Worker protocol WebSocket path. The older event-only stream is not an operation authority. Normal interaction should go through protocol transport and runtime/backend forwarding rather than raw local sockets.
|
|
|
|
## Working-directory model
|
|
|
|
A working directory is a materialized repository for a workspace on a concrete Runtime.
|
|
|
|
The normal invariant is:
|
|
|
|
```text
|
|
workdir {
|
|
workspace_id # Backend workspace scope
|
|
runtime_id # concrete Runtime that owns the materialization
|
|
repository_id # repository being materialized
|
|
working_directory_id
|
|
selector / resolved commit
|
|
materialization status
|
|
cleanliness
|
|
}
|
|
```
|
|
|
|
`repository_id` is part of the normal model. A workdir without a repository is not a normal reusable workspace workdir; it should be treated as diagnostic/orphan/corrupted state rather than as a first-class launch candidate.
|
|
|
|
The removed `management_kind` state must not be reintroduced. Whether a row was first authored by Backend creation or later observed from Runtime is provenance, not current workdir authority. Reuse eligibility must be derived from current state and ownership:
|
|
|
|
- Runtime reports the workdir as active/present;
|
|
- cleanliness is clean;
|
|
- no active Runtime Worker owns it as a primary workdir;
|
|
- Backend worker/workdir links do not show an existing owner;
|
|
- `primary_worker_id` is absent in the browser-safe summary.
|
|
|
|
Runtime-observed workdirs that satisfy those conditions are valid reusable candidates for the selected Runtime. Hiding them because Backend did not originally author the registry row creates a stale provenance bug.
|
|
|
|
## Workspace and Runtime sharing assumption
|
|
|
|
The current Docker and browser launch path treats a configured Runtime as serving the Workspace that registered it. Runtime workdir summaries do not carry independent workspace authority sufficient for arbitrary multi-workspace sharing.
|
|
|
|
If one Runtime is later shared by multiple Workspace Backends, the Runtime workdir materialization record/API must carry enough workspace identity to let a Backend decide whether a workdir belongs to its workspace. That should be modeled explicitly as workspace identity on materialization records, not through a vague managed/unmanaged kind.
|
|
|
|
Until that exists, do not infer cross-workspace ownership from display names, local paths, Runtime labels, or Backend registry provenance.
|
|
|
|
## Memory backend launch pitfall
|
|
|
|
Workspace memory backend HTTP operations run inside async Worker/runtime paths. They must use async HTTP clients. Blocking HTTP clients such as `reqwest::blocking` can panic when created/dropped inside a Tokio async context and can kill Worker controller tasks.
|
|
|
|
The current memory backend HTTP path uses async `reqwest::Client`. New Backend/Runtime launch code should preserve that boundary.
|
|
|
|
## Current validation surface
|
|
|
|
The local-image Compose path has been checked by building/loading the Nix Docker images, running `docker compose config`, starting the Compose stack, loading WebUI `/`, and confirming `/api/runtimes` sees the remote Runtime.
|
|
|
|
Code-level changes around Runtime/Backend/WebUI boundaries should generally be checked with the relevant Rust crates, WebUI check, and whitespace validation, for example:
|
|
|
|
```text
|
|
nix develop -c cargo check -p yoi-workspace-server -p worker-runtime -p client
|
|
nix develop -c cargo test -p yoi-workspace-server --lib
|
|
cd web/workspace && deno task check
|
|
git diff --check
|
|
```
|