The control plane
The control plane is a TanStack Start application running on Bun. It is the only component your browser talks to, and the only component that holds secrets. It owns:- Identity: accounts, sessions, invitations, and optional OIDC.
- Configuration: encrypted provider credentials, models, and MCP servers.
- Conversations: the durable message history in PostgreSQL.
- Model streaming: it calls the model provider and streams the response.
- Reconciliation: it creates and scales the Kubernetes objects per user.
Workspaces
Every user maps to a deterministic set of Kubernetes objects, named from a hash of the user ID:
The complete PVC mounts at
/home/r5d. The chart never uses subPath, which
keeps it compatible with runtimes like Kata.
Inside the pod, r5dchat daemon exposes a private authenticated HTTP API for
file, search, and process operations. The control plane calls it with the
workspace’s bearer token. The browser never receives that token, and all
file traffic is proxied through the control plane.
Tenant pods run as root on purpose so agents can install packages, but they
receive no service-account token, host path, runtime socket, or Linux
capability. See Security for the full model and its
limits.
The idle lifecycle
Workspaces are expensive to keep running and cheap to restart, so they scale to zero automatically.1
Activity starts the workspace
A chat run, file operation, upload, preview, or command scales the
Deployment to one and waits for the daemon’s readiness probe. A chat
response starts answering meanwhile; only its workspace tools wait.
2
Leases track in-flight work
Long-running operations such as shell commands take an active lease so a
busy workspace is never reaped mid-task.
3
Idle workspaces scale to zero
When every lease has ended and
WORKSPACE_IDLE_SECONDS has elapsed, a
reconciler running every 60 seconds scales compute to zero.4
The data stays
The Service, identity Secret, database records, and PVC all remain. The next
request scales the same Deployment back up and remounts the same home
directory.
Providers and models
A provider is an OpenAI-compatible endpoint: a base URL, an API key, and optional custom headers. A model belongs to a provider and adds a provider model ID, a display name, a context-window limit, and a maximum output size. Each user configures their own providers. Credentials are encrypted withSETTINGS_ENCRYPTION_KEY and never leave the control plane.
Exactly one model per user is the default, enforced by a partial unique index in
the database. Deleting or disabling the default promotes the oldest remaining
enabled model, so a user is never left without one.
Configure providers
Base URLs, custom headers, the outbound URL guard, and default-model rules.
Projects and collaborative conversations
A project groups multiple conversations under one membership list and one shared artifact namespace. Owners and admins manage project access; members can use its conversations and artifacts. A standalone conversation can also have multiple participants without belonging to a project, in which case it owns a separate chat artifact namespace. Project conversations inherit access from project membership. Standalone conversations use their participant list. Message history and artifacts are shared in either case, while each participant still runs tools in their own private workspace with their own authorized model and MCP preferences.Moving and archiving
A conversation can move into a project, out of one, or between projects from its menu in the sidebar. A standalone conversation’s files move with it into the project’s namespace and keep their paths, unless one is already taken there, in which case they all move into one folder named after the conversation. A project conversation’s files belong to the project and stay there when the conversation leaves.artifact:// links keep working either way, because they
name the artifact rather than its path.
Archiving tidies a conversation or project away without deleting anything.
Archived items are listed under Archived in the sidebar, where they can be
opened, restored, or deleted. An archived conversation can be read but not
continued until it is unarchived. Archiving a project applies to every member
and pauses new responses in its conversations until an owner or admin restores
it.
Conversations and fresh context
A conversation owns one ordered message stream. Starting a fresh context does not create a new conversation: it appends a flagged system prompt to the same stream. Provider context begins at the most recent flag, while the durable transcript stays complete. This lets the agent recover earlier detail on demand from inside the workspace:Optional session memory and handover
The agent is told about a private working-memory folder at/home/r5d/.r5dchat/memory/<conversation-id>/. It can keep concise checkpoints,
decisions, file references and next steps there using ordinary file tools. Reads
and writes are voluntary; the first write creates the folder. Notes persist in
the workspace across context resets and restarts. They are not published artifacts,
not automatically read into every request, and not automatically deleted with a
conversation. Do not put secrets in memory notes.
For automatic context rollover in durable interactive chats, the control plane
makes a separate, tool-free request to the same model for a concise handover at
a settled tool boundary. A valid handover is embedded in the new context as
working notes, alongside the exact current request and steering inputs. The
request has a token/size bound and a 60-second timeout, makes no tool calls, and
is not retried. If it fails, returns invalid output, or does not fit, the agent
continues using memory and targeted history instead. Stop still cancels the run.
This auxiliary request uses the configured upstream provider and may incur its
normal inference usage.
Artifacts
Artifacts are remote objects owned by the control plane, not files under/home/r5d in a workspace. Project chats resolve to project/<id> and share
one namespace across the project; standalone chats resolve to chat/<id> and
share it only with their participants. Browser uploads and agent deliverables
live on the dedicated artifact PVC.
The runtime receives the active scope as ARTIFACT_SCOPE. Users and agents use
canonical Markdown links such as [filename](artifact://<artifact-id>); the
stable root ID keeps references valid if an artifact is moved, renamed, or
amended. Each root points at a current head and retains immutable revisions for
change control. Agents pass the artifact:// target to r5dchat artifacts read
or pull, publish amendments with push --force, inspect history, and create
a new head from an earlier revision with rollback. Revised content is stored
as a raw snapshot or, when smaller, a Zstandard dictionary-compressed binary
delta against the root snapshot. The browser resolves links to the current head
through authenticated previews and downloads.
In private chat transcripts, canonical links labelled with a .md or
.markdown filename (case-insensitive) open a rendered Markdown dialog, just
as raster image links open an image preview. The Markdown dialog has an
explicit Download link and an accessible Close control; Escape closes
it and returns focus to the link. Headings, lists, tables and code are rendered
with the chat’s sanitizing renderer, with raw HTML disabled. Each opening
fetches the current head again, so reopening the same canonical link after an
amendment shows the latest revision. Previews are limited to 1 MiB; empty,
failed or oversized previews still leave Download available.
Links labelled with other filenames remain downloads. Explicit
/api/artifacts?id=<artifact-id>&operation=download links always download,
including Markdown; neither preview nor download bypasses artifact namespace
authorization. Public snapshots do not expose private artifact previews.
How a message flows
1
The browser posts to the control plane
POST /api/chat with the conversation ID and the new message.2
The control plane prepares the run
It authenticates the session, resolves the model (one picked for the
conversation, otherwise the current default), decrypts the provider
credentials, and ensures the workspace is running.
3
The model streams back
Text, reasoning, and tool calls stream to the browser as they arrive.
4
Tool calls execute in the workspace
Each tool call becomes an authenticated request to the workspace daemon,
refreshing the activity timestamp.
5
Everything is persisted
Messages and tool results are written to PostgreSQL, so a reload or a new
device shows the same conversation.
Full architecture
Component boundaries, trust boundaries, and the threat model.