Home / Docs / pg_tenantundo CLI
pg_tenantundo CLI reference
A single Go binary for local, standalone tenant recovery: classify the tenant graph, run the safety preflight, extract a bundle, diff against live data, and execute a hash-approved restore or erase.
Connection and the DSN split
Every command takes a Postgres DSN via -dsn or the TENANTUNDO_DSN environment variable. All read paths (classify, preflight, report, extract, diff, plan) require a read-only role. Only -execute and -erase-execute use a write-capable role — everything else refuses one.
| Flag | Argument | Purpose |
|---|---|---|
-dsn | DSN | Postgres DSN; read-only role required. Falls back to TENANTUNDO_DSN. |
-root | table | Tenant root table. Default: tenants. |
-overrides | file.yaml | YAML mapping of table → class to resolve ambiguous tables. |
-json | — | Emit the resolution as JSON instead of text. |
-preflight | — | Run the safety preflight and print every finding (blocks + warnings). |
-report | file | Write the HTML readiness report to this path. |
-extract-tenant | id | Extract this tenant's closure into the -out bundle directory. |
-out | path | Output: a directory for -extract-tenant; a file for -plan / -erase-plan. |
-tenant | id | Tenant id (bigint or UUID) for -diff, -plan, -erase-plan. |
-bundle | dir | Bundle directory for -diff, -plan, -execute. |
-diff | — | Diff live state against -bundle for -tenant (missing / changed / extra rows). |
-plan | — | Compute a merge plan (restore -tenant to bundle state), write it to -out, print its hash. |
-execute | plan file | Execute a merge plan. Requires -approve and -bundle. Write role. |
-approve | hash | The approved plan hash for -execute / -erase-execute. |
-erase-plan | — | Plan erasure of -tenant, write it to -out, print its hash. |
-erase-execute | plan file | Execute an erase plan. Requires -approve. Write role. |
Typical flow
With no mode flag, the tool prints the tenant graph — each table classified as root, owned, shared, ambiguous, or excluded.
# 0. Classify the tenant graph (read-only)
pg_tenantundo -dsn "$RO_DSN" # or add -json
# 1. Safety preflight — list every hazard that would block a live restore/erase
pg_tenantundo -dsn "$RO_DSN" -preflight
# 2. Readiness report (HTML)
pg_tenantundo -dsn "$RO_DSN" -report readiness.html
# 3. Extract one tenant's closure to a bundle directory
pg_tenantundo -dsn "$RO_DSN" -extract-tenant 42 -out ./acme-bundle
# 4. Diff live data against the bundle
pg_tenantundo -dsn "$RO_DSN" -tenant 42 -bundle ./acme-bundle -diff
# 5. Write a merge plan and print its approve hash
pg_tenantundo -dsn "$RO_DSN" -tenant 42 -bundle ./acme-bundle -plan -out ./acme.plan
# 6. Execute the approved plan (WRITE role) after a second person approves the hash
pg_tenantundo -dsn "$RW_DSN" -execute ./acme.plan -approve <hash> -bundle ./acme-bundle
Provable erase
# Plan the deletion — prints row/object counts and the approve hash
pg_tenantundo -dsn "$RO_DSN" -tenant 42 -erase-plan -out ./acme-erase.plan
# Execute after approval (WRITE role); emits signed proof, verifies others unchanged
pg_tenantundo -dsn "$RW_DSN" -erase-execute ./acme-erase.plan -approve <hash>
The safety invariant: -execute and -erase-execute refuse to run unless the plan's own hash matches -approve, and both verify that everything outside the target tenant is unchanged before committing. Ambiguous relationships must be resolved via -overrides first.
Run the CLI against a real schema
A Readiness Drill runs this exact flow, read-only, and hands back the graph, the blockers, and a signed report.
Book a recovery drill