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

# Environments

> Long-lived dev, staging, and prod branches mapped 1:1 to GitHub Environments, with per-environment YAML config and a typed Python loader.

Artemis City ships with three long-lived environment branches that map 1:1 to GitHub Environments and deploy targets. Use them to separate integration work from pre-production rehearsals and production traffic, and to keep production credentials unreachable from lower environments.

The names `dev`, `staging`, and `prod` are kept identical across the branch, the GitHub Environment, and the file under `config/environments/` so there is no mapping layer to forget.

## When to use this

* You are deploying Artemis City from a fork or self-hosted clone and need a promotion path between dev, staging, and prod.
* You want CI to run on every push and PR to each environment branch, with the active config validated automatically.
* You want production secrets and approvals enforced by GitHub Environments rather than living in repo-wide secrets.

If you only run Artemis City locally, you can ignore the branch and workflow setup and just set `ARTEMIS_ENV=dev` (the default) when loading config.

## Branches and approvals

| Branch    | GitHub Environment | Purpose                                  | Approvals |
| --------- | ------------------ | ---------------------------------------- | --------- |
| `dev`     | `dev`              | Integration of feature work              | 0         |
| `staging` | `staging`          | Pre-production rehearsal, synthetic data | 1         |
| `prod`    | `prod`             | Production. Default branch.              | 2         |

Promotion flow:

```
feature/* --PR--> dev --push--> [Promote cascade] --ff--> staging --ff--> prod
```

Feature branches always target `dev`. A push to `dev` triggers the `Promote` cascade, which runs the test gate and then fast-forwards `staging` and `prod` to the tested commit in a single run. Approval gates live on the CircleCI deploy workflows, not on promotion PRs — the cascade only moves branch pointers.

## Configuration files

Each environment has a YAML file under `config/environments/`:

* `config/environments/dev.yaml`
* `config/environments/staging.yaml`
* `config/environments/prod.yaml`

A `dev.yaml` looks like this:

```yaml theme={null}
name: dev
description: Local and shared developer integration environment.

mcp:
  base_url: http://localhost:3000
  log_level: DEBUG

obsidian:
  base_url: http://localhost:27124

exo:
  base_url: http://localhost:52415

vector_store:
  path: data/vector_store.dev.db

governance:
  strict_atp: false
  trust_default_level: 2

deploy:
  branch: dev
  github_environment: dev
  approvals_required: 0
```

Keep the same top-level keys across all three files so the loader can return a consistent shape. Secrets do **not** belong in these YAML files — they live in per-environment GitHub Environment secrets.

## Selecting the active environment

The active environment is selected by the `ARTEMIS_ENV` variable. Valid values are `dev`, `staging`, and `prod`; unset defaults to `dev`.

```bash theme={null}
# .env or shell
ARTEMIS_ENV=staging
```

Load the matching config in code:

```python theme={null}
from src.utils.environments import load_environment, current_environment

env = current_environment()      # "dev" | "staging" | "prod"
cfg = load_environment()         # respects ARTEMIS_ENV, defaults to dev
cfg = load_environment("prod")   # or load an explicit environment
```

`load_environment()` raises `ValueError` if `ARTEMIS_ENV` is set to anything outside the valid set, and `FileNotFoundError` if the YAML file for the requested environment is missing — both surface early in CI.

## CI/CD pipeline

CircleCI (`.circleci/config.yml`) is the **primary CI/CD system** for the repo. GitHub Actions retains a single workflow, `promote.yml`, which drives the promotion cascade between environment branches.

### CircleCI — primary CI/CD

`.circleci/config.yml` runs on every branch and PR and holds the deploy jobs for each environment:

* **`docs-mirror`** — fails the build if `CLAUDE.md` and `AGENTS.md` have drifted from being byte-for-byte identical.
* **`python-checks`** — matrix over Python 3.11, 3.12, and 3.13. Installs `requirements.txt` + `requirements-dev.txt`, validates every `config/environments/*.yaml` with `src.utils.environments.load_environment`, then runs `python -m pytest src/tests`.
* **`typescript-api`** — Node 24 typecheck and test job for the Express API under `app/api/`.
* **`secrets-check`** — secret-scanning gate.
* **`deploy`** — per-environment deploy job used by the `dev`, `staging`, and `prod` workflows. Staging and prod are guarded by CircleCI approval steps that map to the approval counts in the table above.

The `dev`, `staging`, and `prod` workflows are branch-filtered; a `pr-checks` workflow runs the same gates on pull requests without deploying.

### GitHub Actions — `promote.yml`

`promote.yml` is the only workflow under `.github/workflows/`. It advances the environment branch pointers; it does **not** deploy — the branch advance is what triggers the matching CircleCI deploy workflow.

**Triggers**

* Push to `dev`.
* Manual `workflow_dispatch` (promotes the current `dev` tip).

**Jobs (sequential)**

1. **`resolve`** — pins the exact `dev` commit being promoted.
2. **`docs-mirror`** and **`test`** — gates. Nothing promotes unless both are green.
3. **`promote-staging`** — fast-forwards `staging` to the tested commit.
4. **`promote-prod`** — fast-forwards `prod` to the same commit.

All actions in `promote.yml` are SHA-pinned, and every job runs on a hosted GitHub runner (`ubuntu-22.04` for the gates and staging promotion, `ubuntu-latest` for the final prod fast-forward). No self-hosted runner is required to promote.

## One-time setup after merge

1. **Default branch.** Settings → Branches: rename `main` → `prod`, set `prod` as the default branch, and delete the old `main` ref.
2. **GitHub Environments.** Settings → Environments: create `dev`, `staging`, and `prod`. Attach required reviewers, wait timers, and per-environment secrets (cloud credentials belong here, not in repo-wide secrets).
3. **Branch protection.** Require CircleCI green and the approval counts above on `dev`, `staging`, and `prod` before merging. These rules live under Settings → Rules → Rulesets as `Protect dev`, `Protect staging`, and `Protect prod`.
4. **CircleCI project.** Enable the repo in CircleCI so `.circleci/config.yml` runs on every push and PR. Add per-environment deploy credentials as CircleCI contexts, and wire the placeholder `deploy` step in the config to your provider (AWS, Azure, GCP, etc.).

## Secrets model

Secrets are scoped per GitHub Environment (for the promotion cascade) and per CircleCI context (for deploys), not per repo, so production credentials are unreachable from `dev` or `staging` runs. A CircleCI job that targets the `dev` environment can only read `dev` context values, even if it runs from a branch with write access to the repo. Required approvals for `staging` and `prod` are configured on the CircleCI deploy workflow, so a promotion always passes through reviewer gates regardless of who pushed to `dev`.


## Related topics

- [Secrets and environment setup](/Documentation/operations/secrets-setup.md)
- [Agentic Memory Layer (MCP server)](/Documentation/integrations/agentic-memory-layer.md)
- [Changelog](/Changelog/changelog.md)
- [API Reference](/api/api-reference.md)
- [Embodied Cognition](/Documentation/concepts/embodied-cognition.md)
