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

# How it works

> The architecture behind a clone — CLI, contract, providers, shared infra, and templates.

asymmetric has four moving parts. Understanding how they fit makes every command
predictable.

```
        you ──▶ asymmetric CLI ───────────────┐
                  (apps/cli)                   │ speaks
                       │                        ▼
                       │              @repo/clone-contract
                       │              (CloneProvider, types, errors)
                       ▼                        ▲
              ┌──────── provider ───────┐       │ implements
              │  LocalDockerProvider     │──────┘
              │  (shells to docker)      │
              └──────────┬───────────────┘
                         │ docker compose
                         ▼
        ┌──────────────────────── asym-shared network ──────────────────────┐
        │                                                                     │
        │   shared Postgres            shared Redis        per-clone services │
        │   db: clone_<id>             prefix: <id>:        compose: asym-<id> │
        │                                                                     │
        │   ┌─ slack-a1b2 ─┐   ┌─ stripe-c3d4 ┐   ┌─ … ─┐                      │
        │   │ backend :3001 │   │ backend :3003 │                             │
        │   │ frontend  …   │   │  (api-only)   │                             │
        │   └───────────────┘   └───────────────┘                             │
        └─────────────────────────────────────────────────────────────────────┘
```

## The CLI (`apps/cli`)

The `asymmetric` command. Each verb lives in its own `commands/*` module and
calls into a service layer that holds a single `provider`. Every error funnels
through one renderer, so you get an actionable sentence and a meaningful exit
code — never a stack trace.

## The contract (`@repo/clone-contract`)

The seam. It defines the `CloneProvider` interface
(`create` / `start` / `stop` / `destroy` / `status` / `logs` / `seed` / `reset`),
the data shapes (`CloneRecord`, `CloneInstance`, `CloneStatus`, `CloneTokens`,
`SeedSpec`, `Environment`, `FidelityScore`), the `TemplateManifest`, the on-disk
registry shapes, and one named error per failure mode.

The CLI depends on the contract, not on any clone. That's what lets the same
commands drive a local Docker engine today and a remote control plane later.
See the [contract reference](/reference/clone-contract).

## Providers

A provider is the engine that actually does the work behind each verb.

* **`LocalDockerProvider`** runs inside the CLI and shells out to `docker` and
  `docker compose`. No server, no daemon — this is the default and the only one
  today.
* **`CloudProvider`** (planned) will be a thin client to a control-plane API,
  implementing the same interface. Swap the engine, keep the commands.

## Shared infrastructure

Spinning a clone does **not** start a fresh database per clone. asymmetric runs
**one shared Postgres and one shared Redis** on a Docker network called
`asym-shared`, and isolates clones inside them:

* Each clone gets its own **database**, named `clone_<id>` (hyphens in the id
  become underscores — `slack-a1b2` → `clone_slack_a1b2`).
* Each clone gets a Redis **key prefix**, `<id>:`.
* Each clone's services run as their own compose project, `asym-<id>`, on host
  ports drawn from your configured range (default `3000–3999`).

This keeps a fleet of clones cheap to run while keeping their data fully
separate.

## Templates

A template is a directory with a `clone.manifest.json` that declares the clone's
services, run modes, database/migrations, Redis prefix, and seed sources. Six
templates ship today — **Slack, Stripe, Notion, HubSpot, GitHub, and Linear**.
The CLI reads the manifest to know what to run, which ports to expose, where the
migrations live, and how to health-check the clone. See
[Templates](/concepts/templates).

Backends ship as **published images** (`ghcr.io/asymmetric-ai/…`), so the CLI
pulls and runs them with no source present and pins the resolved digest — that
digest pin is what makes `reset` and re-spin byte-identical even as `:latest`
moves.

## What `spin` does, end to end

`asymmetric spin slack` runs this sequence:

<Steps>
  <Step title="Allocate an id">
    `slack-<random hex>`, unique across your registry.
  </Step>

  <Step title="Resolve the template and mode">
    Read `clone.manifest.json`; validate the requested mode (default: the
    template's first mode).
  </Step>

  <Step title="Pull the image">
    Pull the backend's published image and resolve it to a content digest, which
    is pinned on the clone so reset/re-spin stay byte-identical.
  </Step>

  <Step title="Allocate ports">
    One host port per service in the mode, from your port range, avoiding
    collisions with existing clones.
  </Step>

  <Step title="Ensure shared infra">
    Start shared Postgres + Redis on `asym-shared` if they aren't up.
  </Step>

  <Step title="Create the database and migrate">
    `CREATE DATABASE clone_<id>`, then run every `.sql` migration in order.
  </Step>

  <Step title="Compose up">
    `docker compose -p asym-<id> up -d`, injecting the database URL, Redis
    URL/prefix, a random JWT secret, and the bind address. The backend runs from
    the pinned image — no local build.
  </Step>

  <Step title="Wait for health">
    Poll the backend's health endpoint until healthy, or fail after 90s.
  </Step>

  <Step title="Provision tokens">
    Call the clone's bootstrap endpoint to mint a default app and its bot + user
    tokens (the DB stores only hashes). Templates without a provision surface
    skip this step.
  </Step>

  <Step title="Record it">
    Write the clone to `~/.asymmetric/registry.json`. On any failure, roll back:
    compose down `-v` and drop the database, so you never get a half-clone.
  </Step>
</Steps>

`spin` takes **one or more** templates (`asymmetric spin slack stripe`) and can
drop them straight into a named [environment](/concepts/environments) with
`--group`.

Next: [Clones, environments, and the registry](/concepts/clones) and
[Environments](/concepts/environments).
