Documentation menu

Core concepts

Lock, sync, diff and drift

Uses the Ahena CLI (beta). Install it with npm install -g @ahena/cli, or prefix commands with npx @ahena/cli. See Installation. The dashboard covers projects, connections, Doctor, the Stack Graph, plans and approvals without it.

ahena.config.ts says what the app wants. ahena.lock records what the stack is: per environment, which provider fills each capability, the non-secret identifiers needed to reach the same resources, and the live values Ahena manages. Both files are git-safe and meant to be committed.

# ahena.lock
version: 1
organization: acme
project: leo
environments:
  production:
    providers:
      cloudflare:
        settings:
          CLOUDFLARE_ACCOUNT_ID: 0123…
        state:
          r2.bucket.leo:
            label: R2 bucket leo exists
            severity: high
            value: true
          r2.bucket.leo.cors:
            label: R2 leo CORS origins
            severity: high
            value:
              - https://leo.app
      supabase:
        settings:
          SUPABASE_PROJECT_REF: abcdefghijklmnopqrst
        state:
          auth.siteUrl:
            label: Auth site URL
            severity: high
            value: https://leo.app
    stack:
      auth: supabase
      storage: cloudflare

ahena lock

Reads every connected provider (read-only) and writes ahena.lock. Keys are sorted, so re-locking an unchanged stack produces no git diff. Local providers (Ollama) are listed with their settings but never read by Ahena's servers.

After Ahena applies changes (ahena configure, ahena doctor --fix, ahena diff --apply, ahena apply, MCP), it re-reads only the providers it changed into ahena.lock, so its own changes aren't reported as drift. Every other provider keeps its locked values: a change made elsewhere stays reported until someone reviews it with ahena drift, or takes everything as it is now with ahena lock.

Git-safety: only non-secret connection settings are written, provider state passes through redaction in core, and the CLI refuses to write the file if any value looks like a credential.

ahena sync

For a developer who just cloned the repository:

$ ahena sync
Leo acme/leo · developer

This application requires:

Production
  ✓ cloudflare   healthy
  ✗ supabase     not connected

? Connect 1 provider now? Yes

Provider connections live in Ahena per environment, so teammates in the organization see the connections that already exist. Missing ones are connected with the usual flow (secrets from the environment, stdin or a hidden prompt), with the identifiers from ahena.lock pre-filled so everyone connects to the same resources. --no-connect only reports; -e limits it to one environment.

ahena diff

Plans every connected provider against ahena.config.ts, grouped by environment, like an infrastructure-as-code plan:

PROPOSED CHANGES

── Production ──

Cloudflare
+ Create R2 bucket leo (production)  [BILLABLE]
    Creating an R2 bucket may be billed to your Cloudflare account.
~ Set CORS on leo: https://leo.app  [CONFIRMATION_REQUIRED]

No destructive changes.
? Apply? (y/N)
  • Read-only until you approve. --json prints the plan without applying.
  • Billable/destructive changes need their own approval (--yes --allow-billable in scripts).
  • Changes that matter (beyond SAFE in production, billable or destructive anywhere) are then approved in the Ahena dashboard, signed in: the CLI opens the link and waits, once per provider. --yes doesn't replace it. See approvals.
  • What you saw is what runs: each provider applies only with the fingerprint of the plan shown. If the provider changed in between, Ahena refuses and asks you to diff again.
  • Email DNS records are included for the Cloudflare zone when dns and Resend's email.domain are both declared.

ahena drift

Compares the live values with ahena.lock to find changes made outside Ahena (for example in a provider's dashboard):

Configuration Drift Detected

Cloudflare · Production
  R2 leo CORS origins
    Expected: https://leo.app
    Actual:   *
    Severity: HIGH

? Cloudflare · Production
❯ Fix: restore what ahena.config.ts declares
  Accept current configuration: update ahena.lock
  Skip
  • Fix re-applies what ahena.config.ts declares (not ahena.lock's values) with the same approvals as ahena doctor --fix, then checks again: CONFIRMATION_REQUIRED changes ask (or take --yes); billable/destructive ones also need --allow-billable with --yes; changes that matter are then approved in the Ahena dashboard (the CLI opens it and waits). Values ahena.config.ts doesn't declare can't be restored automatically; Ahena says so.
  • Ignore for 7 days keeps the provider as it is and stops reporting those values until then. It's recorded in ahena.lock (ignore), so teammates and CI see the same decision.
  • Accept records the current values in ahena.lock. If ahena.config.ts declares those values, update it too, or Doctor reports the mismatch.
  • --fix / --accept choose for every provider without the menu (--fix still asks for approval unless --yes); --json reports and exits 1 when drift is found (useful in CI). A disconnected provider is reported as high-severity drift.

Server-side drift

Ahena also checks drift without your checkout, from the ahena.lock the CLI last shared (every CLI command shares the lock with the blueprint). The comparison is ahena drift's (shared code in @ahena/stack, tested against the CLI's): only values in the lock are compared, a missing or disconnected connection is one high-severity item, local providers (Ollama) are left to the CLI, and the lock's "ignore for 7 days" entries are honoured. Each provider is read with that environment's own credentials. A provider that can't be read is noted and the check is partial, never guessed.

  • Dashboard: project → Drift lists, per environment, each changed setting with expected (lock) and actual values, severity, provider and capability, when it was first seen, and the recommended repair. "Check now" runs a fresh check. The Stack Graph shows the count per provider and when it was last checked.
  • Continuous Doctor runs it on its schedule and emails on new drift (doctor.md).
  • API: GET /v1/orgs/:org/projects/:project/environments/:env/drift returns the latest check (or null); POST on the same path runs one now. CI tokens may use both.

It never repairs: provider state is only read. Repairs are what ahena drift --fix does (a plan you review and approve, with the same rules as any plan, including dashboard approval for production), or keep the new value with ahena drift --accept. Without an ahena.lock entry for an environment, the result is no_lock: run ahena lock and commit it.

Provider SDK

Providers opt in with state(ctx, expected): a read-only list of { key, label, value, severity } for the values Ahena manages, with arrays sorted so reordering isn't drift. Shipped: Supabase (auth URLs and policies), Cloudflare (bucket, CORS, declared DNS records, zone status), Resend (domain status, webhooks), Stripe (key mode, account readiness, webhooks), Firebase (registered apps). AI providers have no infrastructure to track.