Uninstall — completely removing Adjoint

This page is the complete removal story: every piece of Adjoint that exists anywhere — AWS infrastructure, control-plane records, the CLI, and local state — and the order to remove them in. Order matters: your local ~/.config/adj directory holds the OpenTofu state that deprovisioning needs, so it must be deleted last, after the AWS infrastructure is gone.

The full sequence:

  1. Destroy instances (optional — deprovision destroys them anyway)
  2. adj cluster deprovision — destroy the AWS data plane (per cluster)
  3. adj cluster rm — delete the cluster's control-plane record (per cluster)
  4. Sweep AWS for known residue (older versions leaked FSx backups)
  5. Clean up control-plane records — sources, then the org itself
  6. Remove the adj binary
  7. Delete ~/.config/adjonly now, never earlier

1. Destroy instances

$ adj ls
$ adj destroy <instance-id>

Strictly optional before a full teardown — adj cluster deprovision destroys every instance along with the cluster. Destroying them first matters only if you want clean per-instance audit entries, or if you're planning to use adj cluster rm on a cluster you are not deprovisioning (rm refuses with a 409 while any instance is registered).

2. Deprovision each cluster (destroys AWS infrastructure)

$ adj cluster ls
$ adj cluster deprovision <name>
This DESTROYS the AWS data plane (EKS + FSx + all clones) for cluster <name>. Proceed? [y/N]: y

This runs an OpenTofu destroy locally, deleting the EKS cluster, the FSx for OpenZFS filesystem, and every clone on it. Requirements and caveats:

Repeat for every cluster in adj cluster ls.

If you've lost the provisioning state

This is now the genuinely-lost case only — it does not apply just because the original provisioning machine is gone. Since state custody moved to the control plane, the primary recovery path for a missing local bundle is simply:

$ adj cluster deprovision <name>

run from any machine with an org-admin login — it pulls the control-plane copy of the state automatically. Try this first, always.

You're in the truly-lost scenario only if both of the following are true:

Only then, with no tofu state anywhere, delete the infrastructure directly in AWS as a last resort, in this order: the EKS cluster (and its node groups), then the FSx for OpenZFS filesystem, then any VPC resources the module created for it. adj cluster bundle export <dir> shows you the module's HCL, which doubles as an inventory of what was created.

3. Deregister each cluster

$ adj cluster rm <name>

Deletes the cluster's control-plane record. Pure bookkeeping — touches no AWS infrastructure — and returns a 409 while any instance is still registered (deprovisioning removes them).

4. Sweep AWS for known residue

An OpenTofu destroy removes what tofu created, but two classes of leftovers are known:

After the sweep, confirm with a cost check: the data-plane account should show no EKS, FSx, or orphaned EBS/backup charges for the region.

5. Control-plane records — what you can remove yourself

You can remove or disable most org content yourself:

$ adj catalog delete <golden>     # golden snapshots (metadata)
$ adj pool rm <pool>              # clone pools
$ adj users remove <email>        # members
$ adj users disable <email>       # or just disable
$ adj source rm <id>              # source registrations

Sources and the org itself are also self-service:

Removing a source

$ adj source rm 3e6f0a2b-7c8d-4e1f-9a2b-3c4d5e6f7a8b
Remove source 3e6f0a2b-7c8d-4e1f-9a2b-3c4d5e6f7a8b (prod-replica.abcdef.us-east-1.rds.amazonaws.com/app)? Import history is kept but unlinked. [y/N]: y
Source 3e6f0a2b-7c8d-4e1f-9a2b-3c4d5e6f7a8b removed.
Credentials Secret adjoint-import/adjoint-src-app deleted from the data-plane cluster.

Admin-only. Prompts for confirmation unless you pass --yes. Refuses with a 409 while any import job for that source is still running or pending (the error names the blocking job id(s) — wait for them to finish, or check with adj import get <id>, then retry). Past import history is kept: a removed source's jobs show - for source in adj import get, they just lose the source link.

On success, adj source rm best-effort deletes the source's credentials Secret from the data-plane cluster (namespace adjoint-import). If another source registration shares the same Secret name (a reused --creds-secret, or a colliding default adjoint-src-<dbname>), the Secret is not deleted — you'll see a warning naming the other source(s) still referencing it, plus the manual kubectl delete secret command to run once none do.

Deleting the org

$ adj org delete
You are about to permanently delete org "Acme Corp".
This cannot be undone: all users, catalog, sources, and the audit log will be deleted.

Password: ********
Type the org name (Acme Corp) to confirm: Acme Corp
Final audit export written to Acme Corp-audit-final.jsonl
Chain head: 3f9a1c7e2b8d4f0a6c5e9b2d1a8f7c3e0b6d4a9f2c1e8b7d3a0f9c6e2b1d8a4f
Org deleted. Your session is now invalid.

adj org delete is interactive only — there is no --yes/-y flag, because this is irreversible. It prompts for your password (no-echo, fresh re-auth against your own account) and then the org's exact display name (shown in the warning — this is the org name, not the slug) before doing anything. Admin-only.

Precondition: zero registered clusters. If any cluster is still registered, the command refuses with a 409 listing them by name and id, plus the required order — deprovision each (adj cluster deprovision), then deregister it (adj cluster rm) — same as steps 2–3 above.

On success:

If you'd rather not run this yourself, or need help recovering from a partial teardown, email [email protected] from an org-admin address.

6. Remove the CLI binary

The installer placed adj at /usr/local/bin/adj, or ~/.local/bin/adj if /usr/local/bin wasn't writable:

$ which adj
/usr/local/bin/adj
$ sudo rm /usr/local/bin/adj     # or: rm ~/.local/bin/adj

7. Delete local state — last

$ rm -rf ~/.config/adj

(Respect $XDG_CONFIG_HOME if you've set it: the directory is $XDG_CONFIG_HOME/adj.) This removes your session token, CLI config, and the provisioning bundles including the OpenTofu state. That state is the only record capable of destroying your AWS infrastructure — which is why this step is last. If you delete it while a cluster still exists, you're in the "lost the provisioning state" scenario above: manual AWS deletion.

Checklist