> ## Documentation Index
> Fetch the complete documentation index at: https://docs.r5d.chat/llms.txt
> Use this file to discover all available pages before exploring further.

# Core concepts

> The control plane, per-user workspaces, providers, conversations, and the idle lifecycle that ties them together.

r5d.chat has two moving parts: a **control plane** that owns identity and state,
and one **workspace** per user that does the actual work.

## 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.

PostgreSQL is authoritative for users, chats, messages, workspace intent, and
audit history.

## Workspaces

Every user maps to a deterministic set of Kubernetes objects, named from a hash
of the user ID:

| Object                | Purpose                                | Lifetime     |
| --------------------- | -------------------------------------- | ------------ |
| Deployment            | Runs the workspace container           | Scales 0 ↔ 1 |
| Service               | Stable in-cluster address on port 7337 | Permanent    |
| Secret                | Random per-workspace bearer identity   | Permanent    |
| PersistentVolumeClaim | The `/home/r5d` home directory         | Retained     |

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.

<Note>
  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](/operate/security) for the full model and its
  limits.
</Note>

## The idle lifecycle

Workspaces are expensive to keep running and cheap to restart, so they scale to
zero automatically.

<Steps>
  <Step title="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.
  </Step>

  <Step title="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.
  </Step>

  <Step title="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.
  </Step>

  <Step title="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.
  </Step>
</Steps>

## 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 with
`SETTINGS_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.

<Card title="Configure providers" icon="plug" href="/configure/providers">
  Base URLs, custom headers, the outbound URL guard, and default-model rules.
</Card>

## 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:

```bash theme={null}
r5dchat conversation overview <conversation-id>
r5dchat conversation turn <conversation-id> <turn-id>
r5dchat conversation read <conversation-id>
```

The CLI authenticates with workspace identity, and the server re-checks that the
requesting workspace's user actually owns the conversation.

## Artifacts

`/home/r5d/artifacts` is the convention for user-facing deliverables. Uploads
land there, and the agent is instructed to write outputs there and link them
with the workspace form `[filename](~/artifacts/filename)`. The UI turns those
links into authenticated downloads.

## How a message flows

<Steps>
  <Step title="The browser posts to the control plane">
    `POST /api/chat` with the conversation ID and the new message.
  </Step>

  <Step title="The control plane prepares the run">
    It authenticates the session, loads the user's default model, decrypts the
    provider credentials, and ensures the workspace is running.
  </Step>

  <Step title="The model streams back">
    Text, reasoning, and tool calls stream to the browser as they arrive.
  </Step>

  <Step title="Tool calls execute in the workspace">
    Each tool call becomes an authenticated request to the workspace daemon,
    refreshing the activity timestamp.
  </Step>

  <Step title="Everything is persisted">
    Messages and tool results are written to PostgreSQL, so a reload or a new
    device shows the same conversation.
  </Step>
</Steps>

<Card title="Full architecture" icon="sitemap" href="/reference/architecture">
  Component boundaries, trust boundaries, and the threat model.
</Card>
