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

> ## Agent Instructions
> Treat Stackdome as an application-delivery platform for coding agents and developers, not as a Kubernetes dashboard.
> Prefer the Stackdome agent plugin as the user entry point and the stackdome CLI as the execution interface.
> Route agents who need the maintained deploy skill to npx skills add stackdome/skills and the complete operational workflow to /guides/ai-agents.
> Verify commands and flags with stackdome --help. Run stackdome init before authoring stackfile.yaml and stackdome validate before deploying.
> Use -o json for automation and verify documented terminal states before claiming success.
> Never request a user's account password. Use API-token authentication.
> During alpha, Stackdome Cloud is ephemeral and capacity-limited, and each organization can connect one cluster.
> Do not expose Kubernetes as a user concern unless the task is self-hosting or infrastructure architecture.

# Self-hosted architecture

> How the Stackdome hub, PostgreSQL, cluster agent, and Kubernetes custom resources reconcile application state.

Stackdome presents stacks, resources, releases, and application endpoints to users. In a self-hosted installation, a hub-and-spoke Kubernetes architecture implements that application model. You do not need these details to define or deploy an application; use them when you operate the infrastructure or diagnose reconciliation.

<Warning>
  The architecture can address multiple clusters, which is why the diagram shows more than one spoke. During alpha, the product permits **one connected cluster per organization**. A fresh single-server install has already connected its local k3s cluster, so the diagram does not mean you can add a second cluster to that organization.
</Warning>

## Components

* **Hub API server and dashboard.** The API server accepts user, CLI, and dashboard requests, applies authorization and validation, and coordinates work on the connected cluster. The React dashboard is served by that same API-server binary.
* **PostgreSQL.** The hub stores organizations, application definitions, releases, encrypted credentials, and the latest status it presents through the API and dashboard.
* **Spoke agent.** Each connected cluster runs the `stackdome-agent` operator in the `stackdome-control-plane` namespace. It watches Stackdome custom resources and reconciles them into Kubernetes workloads and supporting objects.
* **Kubernetes custom resources.** These carry desired application state from the hub to the agent and observed status back to the hub. They are an implementation interface, not the object model users author directly.

<svg viewBox="0 0 920 570" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Stackdome architecture: one hub API server with PostgreSQL writes custom resources into each managed cluster, where the stackdome-agent reconciles them into Kubernetes workloads and reports status back to the hub." style={{width:'100%',height:'auto',fontFamily:"ui-sans-serif,system-ui,-apple-system,'Segoe UI',sans-serif"}}><defs><marker id="ah" viewBox="0 0 10 8" refX="9" refY="4" markerWidth="8" markerHeight="7" orient="auto"><path d="M0 0 L10 4 L0 8 z" fill="#6366f1" /></marker><marker id="ahm" viewBox="0 0 10 8" refX="9" refY="4" markerWidth="8" markerHeight="7" orient="auto"><path d="M0 0 L10 4 L0 8 z" fill="currentColor" fill-opacity="0.45" /></marker></defs><g fill="currentColor" stroke="currentColor"><rect x="392" y="16" width="136" height="38" rx="19" fill="currentColor" fill-opacity="0.05" stroke-opacity="0.18" /><text x="460" y="40" text-anchor="middle" font-size="14" stroke="none" fill-opacity="0.85">You</text><line x1="460" y1="54" x2="460" y2="98" stroke="#6366f1" stroke-width="1.75" marker-end="url(#ah)" /><text x="474" y="82" font-size="12" stroke="none" fill-opacity="0.6">web UI · REST API</text><rect x="196" y="104" width="528" height="150" rx="14" fill="#6366f1" fill-opacity="0.05" stroke="#6366f1" stroke-opacity="0.45" /><text x="220" y="130" font-size="12" stroke="none" fill="#6366f1" font-weight="600" letter-spacing="0.06em">HUB — ONE API SERVER YOU INSTALL</text><rect x="224" y="146" width="212" height="82" rx="10" fill="currentColor" fill-opacity="0.05" stroke-opacity="0.2" /><text x="330" y="180" text-anchor="middle" font-size="14" stroke="none" fill-opacity="0.9">API server</text><text x="330" y="200" text-anchor="middle" font-size="11.5" stroke="none" fill-opacity="0.55">REST API · web UI</text><path d="M512 158 h132 v58 a66 8 0 0 1 -132 0 z" fill="currentColor" fill-opacity="0.05" stroke="none" /><path d="M512 158 v58 a66 8 0 0 0 132 0 v-58" fill="none" stroke-opacity="0.2" /><ellipse cx="578" cy="158" rx="66" ry="8" fill="currentColor" fill-opacity="0.05" stroke-opacity="0.2" /><text x="578" y="196" text-anchor="middle" font-size="13" stroke="none" fill-opacity="0.85">PostgreSQL</text><line x1="436" y1="187" x2="506" y2="187" stroke-opacity="0.3" stroke-width="1.5" /><path d="M272 254 V288 H186 V330" fill="none" stroke="#6366f1" stroke-width="1.75" marker-end="url(#ah)" /><path d="M648 254 V288 H734 V330" fill="none" stroke="#6366f1" stroke-width="1.75" marker-end="url(#ah)" /><path d="M300 330 V312 H352 V254" fill="none" stroke-opacity="0.38" stroke-width="1.5" stroke-dasharray="5 4" marker-end="url(#ahm)" /><path d="M620 330 V312 H568 V254" fill="none" stroke-opacity="0.38" stroke-width="1.5" stroke-dasharray="5 4" marker-end="url(#ahm)" /><rect x="80" y="330" width="330" height="170" rx="14" fill="currentColor" fill-opacity="0.03" stroke-opacity="0.18" stroke-dasharray="6 4" /><text x="104" y="356" font-size="12" stroke="none" fill-opacity="0.5" letter-spacing="0.06em">MANAGED CLUSTER</text><rect x="104" y="372" width="128" height="60" rx="9" fill="currentColor" fill-opacity="0.06" stroke-opacity="0.22" /><text x="168" y="398" text-anchor="middle" font-size="12.5" stroke="none" fill-opacity="0.9">stackdome-</text><text x="168" y="415" text-anchor="middle" font-size="12.5" stroke="none" fill-opacity="0.9">agent</text><line x1="232" y1="402" x2="272" y2="402" stroke="#6366f1" stroke-width="1.6" marker-end="url(#ah)" /><rect x="278" y="360" width="112" height="118" rx="9" fill="currentColor" fill-opacity="0.06" stroke-opacity="0.22" /><text x="334" y="390" text-anchor="middle" font-size="12.5" stroke="none" fill-opacity="0.85">Deployments</text><text x="334" y="412" text-anchor="middle" font-size="12.5" stroke="none" fill-opacity="0.85">Services</text><text x="334" y="434" text-anchor="middle" font-size="12.5" stroke="none" fill-opacity="0.85">Ingresses</text><text x="334" y="458" text-anchor="middle" font-size="12.5" stroke="none" fill-opacity="0.85">Volumes</text><rect x="510" y="330" width="330" height="170" rx="14" fill="currentColor" fill-opacity="0.03" stroke-opacity="0.18" stroke-dasharray="6 4" /><text x="534" y="356" font-size="12" stroke="none" fill-opacity="0.5" letter-spacing="0.06em">MANAGED CLUSTER</text><rect x="534" y="372" width="128" height="60" rx="9" fill="currentColor" fill-opacity="0.06" stroke-opacity="0.22" /><text x="598" y="398" text-anchor="middle" font-size="12.5" stroke="none" fill-opacity="0.9">stackdome-</text><text x="598" y="415" text-anchor="middle" font-size="12.5" stroke="none" fill-opacity="0.9">agent</text><line x1="662" y1="402" x2="702" y2="402" stroke="#6366f1" stroke-width="1.6" marker-end="url(#ah)" /><rect x="708" y="360" width="112" height="118" rx="9" fill="currentColor" fill-opacity="0.06" stroke-opacity="0.22" /><text x="764" y="390" text-anchor="middle" font-size="12.5" stroke="none" fill-opacity="0.85">Deployments</text><text x="764" y="412" text-anchor="middle" font-size="12.5" stroke="none" fill-opacity="0.85">Services</text><text x="764" y="434" text-anchor="middle" font-size="12.5" stroke="none" fill-opacity="0.85">Ingresses</text><text x="764" y="458" text-anchor="middle" font-size="12.5" stroke="none" fill-opacity="0.85">Volumes</text><line x1="236" y1="528" x2="276" y2="528" stroke="#6366f1" stroke-width="1.75" marker-end="url(#ah)" /><text x="286" y="532" font-size="12" stroke="none" fill-opacity="0.65">hub writes custom resources</text><line x1="502" y1="528" x2="542" y2="528" stroke-opacity="0.38" stroke-width="1.5" stroke-dasharray="5 4" marker-end="url(#ahm)" /><text x="552" y="532" font-size="12" stroke="none" fill-opacity="0.65">agent reports status back</text></g></svg>

## Reconciliation paths

### Desired state: hub to cluster

1. A user, coding agent, or automation submits an application change through the CLI, dashboard, or REST API.
2. The hub validates and stores the application definition and release state in PostgreSQL.
3. The hub writes Stackdome custom resources into the organization's connected cluster.
4. `stackdome-agent` reconciles those resources into the Kubernetes objects that run the application.

### Observed state: cluster to hub

1. The agent observes builds, rollouts, networking, storage, and readiness in the cluster.
2. It writes conditions and status onto the relevant custom resources.
3. controller-runtime watchers in the hub observe status changes and update PostgreSQL.
4. The API, CLI, and dashboard return the recorded release and resource state.

This is an eventually consistent loop. An accepted deploy means the desired state was recorded; a terminal release state such as `Released` or `Failed` tells you how reconciliation finished.

## Implementation mapping

The dashboard and Stackfile stay application-facing. The agent performs the low-level mapping:

| Stackdome model           | Kubernetes implementation                                                                              |
| ------------------------- | ------------------------------------------------------------------------------------------------------ |
| Stack                     | A deployment boundary represented by a `Stack` custom resource and an isolated workload namespace      |
| Resource                  | A `StackResource` that becomes a Deployment or stateful workload, plus Services for declared ports     |
| Public port               | An Ingress and, when TLS is enabled, certificate-related configuration                                 |
| Volume                    | A Stackdome `Volume` custom resource reconciled to persistent storage and mounted into workloads       |
| In-cluster image registry | A `ClusterRegistry` custom resource reconciled into registry workload, Service, and persistent storage |

Kubernetes remains the runtime source of truth for live workloads. PostgreSQL is the hub's source of truth for users, application definitions, releases, encrypted connection data, and the status exposed through Stackdome interfaces.

## Cluster boundary and permissions

The hub reaches a connected cluster with a service-account URL, CA certificate, and token. The single-server installer creates those credentials in `stackdome-control-plane` and grants the specific cluster-scoped operations required for Stackdome resources, workload namespaces and Secrets, logs, metrics, and supporting infrastructure. See [Install Stackdome](/self-host/install) for the exact local role and its security warning, or [Connect compute](/self-host/connect-compute) for the manual credential path.

<Card title="Stacks and resources" icon="boxes" href="/concepts/stacks-and-resources">
  Return to the application model you use in the CLI, Stackfile, and dashboard.
</Card>
