Goal: keep the graph honest about the external source each entity came from. When a tenant's Terraform state, Atmos stacks, or S3 state changes after you last imported it, this recipe shows you how to see the divergence and reconcile it.
current, stale, or
missing.Three primitives carry cross-source drift:
sync_source) and when (last_synced_at). An entity is stale once its
stamp is older than a 24-hour threshold, and missing if it wasn't present in
the most recent scan of its source.terrantula import terraform / import atmos.human-approval policy, a rescan writes per-entity
diffs here for a human to approve or reject instead of mutating entities directly.List the registered import sources, then read a per-source drift rollup (totals plus any pending proposals). Import sources are project-scoped:
The rollup returns per-entity drift status (current / stale / missing) and
the count of pending proposals. For an ad-hoc query across the whole project, the
entities API also accepts a driftStatus filter — GET /<org>/<project>/envs/<env>/entities?driftStatus=stale.
Each import source carries exactly one policy. Pick it based on whether the external source is the undisputed source of truth:
| Policy | What a rescan does | Use it when… |
|---|---|---|
auto-update (default) | Applies incoming source state directly to the entities and re-stamps them. | The source is the source of truth — e.g. the TF state for a fleet you own end-to-end. |
human-approval | Computes per-entity diffs and writes them to drift proposals as pending; entities are not mutated. New entities still apply directly (creation is non-destructive). | The source might disagree with Terrantula about an entity's authoritative shape and you want a human to mediate — typically production cells. |
A repeated rescan under human-approval supersedes prior pending proposals
for the same entity, so a scheduled rescan loop never piles up zombie proposals.
Re-import (the simplest path). Pull fresh state and re-import against the same
source. Each successful import re-stamps the touched entities, clearing stale,
and refreshes the import-source record:
For a TFC-backed source, point --state straight at the workspace and skip the
manual pull:
Drop entities that are genuinely gone. If an entity is missing because the
resource was removed from the source, re-import with --replace (preview with
--dry-run first). --replace only deletes entities previously synced from the
same source:
Approve or reject proposals (human-approval sources). When a rescan produced pending diffs, decide each one. Approving applies the stored diff and re-stamps the entity; rejecting discards it.
Terrantula ships no built-in scheduler. Rescan is a plain HTTP endpoint your own
scheduler calls — and because every import terraform / import atmos refreshes
the import-source record, a scheduled re-import is itself a rescan with no glue
code. Wire any self-hosted scheduler:
A cron job, a GitLab CI schedule, an Atmos workflow, or a systemd timer works the same way. The whole path runs against the Apache 2.0 backend — no SaaS dependency, so an OSS-first deployment can drive it.
The graph reflects the current source state. stale entities are re-stamped to
current, missing entities are resolved (re-synced or dropped), and any pending
proposals are decided. Re-running the recipe is idempotent.
terraform apply. Actual infrastructure changes still flow through Actions → PRs → your CI.
Entities imported before import-source tracking existed are sync-stamped but have
no registered import-source record, so they're skipped by the per-source rollup
(it matches on the source URI). They still appear under the driftStatus entity
filter. To backfill, re-run import terraform / import atmos once against the
same source — registration is idempotent on (project, env, source URI)and
creates the record on the next run.
The UI is a read-only projection. Don't try to close a discrepancy by editing an entity's properties, state, or relationships in the dashboard — it can't write those. Reconcile the source (re-import) for observed state; open an Action's PR for intended changes.
(project, env, source URI).