Operations
Detecting configuration drift: lock, diff and drift
How ahena.lock records what your stack is, how ahena drift finds changes made in provider dashboards, and what Continuous Doctor monitors.
In short
Configuration drift is a provider setting that changed outside your normal process, usually in the provider's own dashboard. Ahena keeps two git-safe files: ahena.config.ts says what your app wants, and ahena.lock records what the stack is. ahena diff compares the config with the providers; ahena drift compares the lock with them and lets you fix, accept or ignore each change. Continuous Doctor runs the same drift check on a schedule (daily for production by default) and emails people only when something changes. It reads; it never repairs.
What drift is, and why it happens
Configuration drift is the gap between how a system is supposed to be configured and how it actually is. For an application's external services it usually starts innocently: someone widens CORS on a bucket in the Cloudflare dashboard to debug an upload, disables a webhook in Stripe during an incident, or edits a redirect URL in Supabase by hand. The change works, nobody records it, and weeks later production behaves differently from staging and nobody remembers why.
Drift is hard to see because provider dashboards show the current state, not the intended one. Detecting it needs two things: a record of what the state should be, and a way to read what it is.
Wanted, recorded and live
Ahena keeps three views of each environment apart:
- Wanted:
ahena.config.ts, the configuration your app declares (bucket names, CORS origins, auth redirect URLs, webhook endpoints, products and prices). It's committed to git and never holds a secret. - Recorded:
ahena.lock, what the stack is. Per environment, it lists which provider fills each capability, the non-secret identifiers needed to reach the same resources, and the live values Ahena manages. It's committed too. - Live: what the provider reports right now.
Two comparisons fall out of that. Wanted against live is a plan: what has to change to match the config. Recorded against live is drift: what changed outside Ahena since the stack was last recorded.
Recording the stack with ahena lock
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.
# ahena.lock
version: 1
organization: acme
project: leo
environments:
production:
providers:
cloudflare:
state:
r2.bucket.leo.cors:
label: R2 leo CORS origins
severity: high
value:
- https://leo.appThe file is git-safe by construction: only non-secret connection settings are written, provider state passes through redaction, and the CLI refuses to write the file if any value looks like a credential.
When Ahena itself applies a change (ahena apply, ahena configure, ahena doctor --fix, the MCP server), it re-reads only the providers it changed into the lock, so its own changes aren't reported as drift. Every other provider keeps its locked values. A change made somewhere else stays reported until someone reviews it.
What's tracked depends on the provider:
- Supabase: auth URLs and policies.
- Cloudflare: buckets, CORS, declared DNS records and zone status.
- Resend: domain status and webhooks.
- Stripe: key mode, account readiness and webhooks.
- Firebase: registered apps.
AI providers (OpenAI, Anthropic, Ollama) have no infrastructure for Ahena to track, so they have no drift.
ahena diff and ahena drift
ahena diff plans every connected provider against ahena.config.ts, like an infrastructure-as-code plan, and applies after you approve. ahena drift compares live values with ahena.lock:
$ ahena drift
Configuration Drift Detected
Cloudflare · Production
R2 leo CORS origins
Expected: https://leo.app
Actual: *
Severity: HIGHEvery drift item has a severity. A provider that has been disconnected is reported as high-severity drift, since everything the lock recorded for it is now unreachable.
Fix, accept or ignore
For each provider with drift, you choose what happens:
- Fix re-applies what
ahena.config.tsdeclares (not the lock's values) with the same approvals asahena doctor --fix, then checks again. CONFIRMATION_REQUIRED changes ask (or take--yes), billable or destructive ones also need--allow-billable, and changes that matter are approved in the Ahena dashboard. Values the config doesn't declare can't be restored automatically, and Ahena says so. - Accept records the current values in
ahena.lock. Ifahena.config.tsdeclares those values, update it too, or Doctor reports the mismatch. - Ignore for 7 days stops reporting those values until then. The decision is recorded in
ahena.lock, so teammates and CI see it too.
ahena drift --accept # the changes were intentional: record them
ahena drift --fix -e production # restore what ahena.config.ts declares
ahena drift --fix --yes --allow-billable # in a script (dashboard approval still applies)The choice is the point. Drift isn't always a mistake: sometimes the dashboard change was right and the config is out of date. Ahena shows you the difference and makes you pick, rather than silently reverting a fix someone made during an incident.
Server-side drift and Continuous Doctor
You don't need a checkout to see drift. Every CLI command shares a secret-free copy of the parsed config and the lock with Ahena, and Ahena can run the same comparison on its servers (the code is shared with the CLI and tested against it). Each provider is read with that environment's own credentials. A provider that can't be read is noted and the check is marked partial, never guessed. Without a lock entry for an environment the result is no_lock: run ahena lock and commit it.
In the dashboard, the project's Drift page lists each changed setting per environment with the expected and actual values, severity, when it was first seen and the recommended repair, and the Stack Graph shows the drift count per provider. Server-side drift never repairs: provider state is only read. Repairs are a plan you review and approve.
Continuous Doctor runs Doctor and this drift check on a schedule. It's on by default for production (daily) and off for other environments until someone turns it on; the schedule can be daily or hourly. A scheduled run checks that stored credentials still work, runs each provider's checks, capability coverage, required secrets and environment separation, then drift against ahena.lock. It never changes anything at a provider.
It emails the organization's owners and admins (or chosen members) only when something changes, compared with the previous scheduled run:
- health got worse, with the new findings' titles;
- new drift;
- a provider rejected Ahena's credentials, or they expired;
- a provider stopped answering;
- recovery: problems before, none now.
The first run sets a baseline without emailing. A provider that couldn't be read keeps its earlier drift (unknown, not gone), so an outage at a provider doesn't produce "new drift" or a false recovery. Emails name checks, settings and providers, never secret values, drift values or provider responses. AI agents can't change these settings, because an agent could otherwise silence the alerts about its own changes. Scheduled runs don't count as actions on your plan.
Keep the scope in mind: this is configuration health (credentials, settings, drift, coverage), not uptime monitoring. Ahena isn't in your request path, so it doesn't know whether your app is up.
Drift in CI
ahena deploy-check runs Doctor for one environment, plus repository checks and drift against ahena.lock, and exits 1 when the environment isn't ready. High-severity drift is a blocker; medium and low drift are warnings that fail the build only with --strict.
ahena lock && git add ahena.lock # so CI checks drift too
ahena ci init # writes a GitHub Actions workflow
ahena ci token create --raw | gh secret set AHENA_TOKENCI tokens are read-only, capped at viewer, scoped to one project and expire. For scripts outside Actions, ahena drift --json exits 1 when drift is found.
Try it on your own stack
Start free with one project. Connect the providers you already use, run Doctor, and see the plan before anything changes.