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

# Developer quickstart

> Run the full Aperium stack on your workstation: toolchain, infrastructure, and the dev CLI.

This page gets Aperium running locally end to end — API, worker, and UI against local
infrastructure — using the `dev` command-line tool. If you only want to *use* a hosted
deployment, you don't need any of this; see the [Admin Console](/admins/getting-started).

<Note>
  Everything below assumes a checkout of the Aperium monorepo. The same `dev` CLI also
  drives downstream product repos that depend on it — see [The `dev` CLI](/develop/dev-cli#project-awareness).
</Note>

## Toolchain

The repo pins its toolchain with [`mise`](https://mise.jdx.dev/) via `mise.toml`, so a
single `mise install` provisions everything at the versions the repo expects. The pinned
tools include:

| Tool                               | Used for                                                       |
| ---------------------------------- | -------------------------------------------------------------- |
| Python                             | Backend (`>=3.12,<3.15`)                                       |
| [`uv`](https://docs.astral.sh/uv/) | Python dependency + workspace management                       |
| Node.js + pnpm                     | The UI workspace (`ui/` and overlays)                          |
| Rust                               | The experimental [terminal client](/develop/terminal-cli) only |
| Ruff, prettier, pre-commit, trivy  | Lint, format, and hooks                                        |

You also need **Podman or Docker** for local infrastructure containers. The `dev` CLI
auto-detects `podman-compose`, `docker compose`, or `docker-compose`.

<Tip>
  If you don't use `mise`, install Python, `uv`, Node 20+, and pnpm yourself at compatible
  versions. `mise` is the supported path because it keeps every contributor on the same
  toolchain.
</Tip>

## First run

<Steps>
  <Step title="Create local config">
    Copy the templates. Repo-local files under `config/` work as a fallback; you can also
    keep them in your OS config directory so multiple worktrees share the same settings.

    ```bash theme={null}
    cp config/aperium.yaml.example config/aperium.yaml
    cp config/credentials.yaml.example config/credentials.yaml
    ```

    `credentials.yaml` holds the local key-encryption-key (KEK) material and any LLM
    provider keys. Follow the comments in the example file to generate local KEK values —
    never commit real secrets.
  </Step>

  <Step title="Install dependencies">
    Syncs the Python workspace and installs UI dependencies for each registered UI.

    ```bash theme={null}
    uv run dev install
    ```
  </Step>

  <Step title="Start the container runtime">
    First time only, initialize a Podman machine (skip if you use Docker Desktop or an
    already-running Podman machine).

    ```bash theme={null}
    podman machine init
    podman machine start
    ```
  </Step>

  <Step title="Start local infrastructure">
    Brings up PostgreSQL and the other local services via `compose.yml`.

    ```bash theme={null}
    uv run dev infra up
    ```
  </Step>

  <Step title="Apply database migrations">
    ```bash theme={null}
    uv run dev db migrate
    ```
  </Step>

  <Step title="Run the stack">
    Starts the API, worker, and UI, streaming each child process through a colored,
    prefixed log multiplexer (`[api]` / `[worker]` / `[ui]` / `[infra]`).

    ```bash theme={null}
    uv run dev run
    ```
  </Step>
</Steps>

When it's up, open:

| Surface        | URL                                 |
| -------------- | ----------------------------------- |
| UI             | `http://localhost:3002`             |
| API health     | `http://localhost:8090/api/healthz` |
| Temporal UI    | `http://localhost:8233`             |
| Phoenix traces | `http://localhost:6006`             |

The API port follows `port` in `config/aperium.yaml` (default `8090`); the UI port follows
`VITE_FRONTEND_PORT` (default `3002`).

<Tip>
  Two useful `dev run` variants: `--external-infra` (`-x`) runs only the app processes
  against PostgreSQL, Redis, Temporal, and Phoenix you started yourself; `--overlay <name>`
  (`-o`) runs a registered UI overlay instead of the default. See the
  [`dev run` reference](/develop/dev-cli#run).
</Tip>

## Local infrastructure services

`compose.yml` defines the local backing services. PostgreSQL always starts; the rest are
gated behind Compose **profiles** so you only run what you need:

| Service                | Profile       | Purpose                                  |
| ---------------------- | ------------- | ---------------------------------------- |
| PostgreSQL             | *(always on)* | Primary application database             |
| Redis                  | `redis`       | Cache / ephemeral state                  |
| Temporal + Temporal UI | `temporal`    | Local durable job runner (UI on `:8233`) |
| Phoenix                | `phoenix`     | Local trace viewer (`:6006`)             |

`uv run dev infra up` starts the set the local stack needs; `uv run dev infra down` stops
the containers while preserving their data volumes.

<Info>
  Locally, background jobs run on **Temporal** (`jobs.runner_backend: temporal` in
  `aperium.yaml`, with the Temporal UI at `:8233`). How orchestration is wired in a given
  production deployment is a deployment decision — see the
  [Deployment overview](/deployment/introduction). Verify against your target environment
  before relying on a specific orchestrator there.
</Info>

## Configuration model

Runtime configuration is **file-layered**, not purely environment variables. Values are
resolved with this precedence (highest first):

1. Process environment variables — an existing env var always wins.
2. YAML files listed in `APERIUM_CONFIG_FILE` (e.g. `config/aperium.yaml,config/credentials.yaml`).
3. Discovered default YAML when `APERIUM_CONFIG_FILE` is unset — the OS config directory,
   then `${XDG_CONFIG_HOME:-~/.config}/aperium/`, then system config directories, then
   repo-local `config/`.
4. Model defaults.

`uv run dev run` sets `APERIUM_CONFIG_FILE` for you when both `config/aperium.yaml` and
`config/credentials.yaml` exist. Keys in the YAML map to typed `aperium.config.Settings`
fields; unknown keys are silently ignored. Plugin configuration follows the
`<PLUGIN>_<FIELD>` environment convention (for example `ODOO_URL`, `ODOO_DB`).

For the full env-var catalog, see [Environment variables](/deployment/configuration).

### `APERIUM_ENV`

The `environment` key (env var `APERIUM_ENV`) marks the deployment posture and drives the
fail-closed boot gates:

| Value                    | Posture                                                                                                        |
| ------------------------ | -------------------------------------------------------------------------------------------------------------- |
| `local` / `dev` / `test` | Developer defaults; dev auth bypasses and the in-memory permission store are permitted.                        |
| `staging` / `production` | Reject dev auth bypasses and require a database-backed permission store; boot fails closed otherwise.          |
| `airgap`                 | Offline single-tenant production posture; also permits the in-memory job runner where Temporal is unavailable. |

Local development leaves this at the implicit dev posture — `uv run dev run` exports
`APERIUM_ENV=dev`, which the dev-only KEK provider requires. A real deployment must set it
explicitly.

## Next steps

<CardGroup cols={2}>
  <Card title="The dev CLI" icon="terminal" href="/develop/dev-cli">
    Every command group: run, check, infra, db, plugins, test, and more.
  </Card>

  <Card title="Build a plugin" icon="puzzle-piece" href="/develop/build-a-plugin">
    Scaffold, validate, and smoke-test a new integration.
  </Card>
</CardGroup>
