Recover a failing workspace
Repair sign-in, schema and stalled work, then restore saved records and private files with verified recovery steps.
Updated October 5, 2026 6 min read
You need: the checkout, a .env.local that points at a Supabase project you control, and PostgreSQL client tools for migration commands. Inspect the project ref and database host each command prints before continuing. Do not run mutating verify scripts against a customer production database.
Revenue Recovery at /admin/recovery is a demand playbook. Skip it here.

Recover sign-in access
On the sign-in screen, choose Forgot password?, enter the configured admin email, and choose Send reset link. Open the recovery message to continue. If the link has expired, request a new one from the same screen. Back to sign in returns you to the email and password fields.
Diagnose on the operator screens
- Sign in at
/admin. - Open Setup (
/admin/setup). Note every Action needed or Degraded row, including Operations health. - Open Today (
/admin/today) and read Connection and job health. - Open Tenant operations (
/admin/tenants) if sign-in works but the shell has no workspace. - Open Activity (
/admin/activity) after a repair to confirm a new receipt.
Then run only the command that matches the row. The commands below are defined in package.json; use the release checkout whose schema you are verifying.
Schema and identity
When Core system schema is Action needed, or login says Connect your Supabase project:
npm run db:migrate:all
npm run db:verify-schema
npm run db:verify-schema -- --record
npm run verify:bootstrap-identity
| Command | Environment | Working reference |
|---|---|---|
npm run db:migrate:all | Local checkout; .env.local pooler vars for a project you control | scripts/run-all-migrations.mjs |
npm run db:verify-schema | Same; read-only metadata | scripts/verify-revenue-schema.ts |
npm run db:verify-schema -- --record | Same; writes a schema verification receipt Setup reads | scripts/verify-revenue-schema.ts |
npm run verify:bootstrap-identity | Same; confirms the seed is not the reference identity | scripts/verify-bootstrap-identity.mjs |
Re-running db:migrate:all after a fix is safe on a new install. On a long-lived database, prefer db:verify-schema instead of replaying the full list; see docs/self-hosting/REVENUE-OS-SETUP.md. Refresh Setup. Ready means the contract receipt matches, not that email is healthy.
Health, stalled jobs, and the scheduler
Health is loadOperationalHealth in src/lib/revenue-os/health.ts. A job stuck running longer than 30 minutes is stalled. Failed webhook receipts stay visible for 48 hours. Empty failed/partial counts must not make the system look green.
There is no operator Unstick button. The next authenticated cron claim takes a stale row over inside claim_revenue_job_run (migrations/20260819-stale-claim-recovery.sql). Setup reports the takeover on Operations health.
If the 15-minute system-health snapshot never wakes:
npm run scheduler:configure
| Command | Environment | Working reference |
|---|---|---|
npm run scheduler:configure | .env.local with production HTTPS NEXT_PUBLIC_SITE_URL (no localhost) and CRON_SECRET of at least 32 characters. Stores the endpoint and bearer in Supabase Vault and does not print them. | scripts/configure-command-center-scheduler.mjs |
Prove the health rules on a disposable project:
npm run test:setup-status
npm run verify:health-truth
npm run verify:stale-claim-recovery
| Command | Environment | Working reference |
|---|---|---|
npm run test:setup-status | Local, no database. Keys without receipts stay Action needed. | scripts/test-setup-status.ts |
npm run verify:health-truth | Local .env.local project you control. Inserts then deletes synthetic stalled-job and failed-webhook rows. | scripts/verify-health-truth.ts |
npm run verify:stale-claim-recovery | Same. Uses a reserved job key and removes it. | scripts/verify-stale-claim-recovery.ts |
Saved result: Operations health no longer lists the stalled key, and the next snapshot job has a terminal receipt. verify:health-truth and verify:stale-claim-recovery print a pass line and exit 0.
Membership and founder access
If the admin shell has no workspace, follow Founder authority and tenant membership. Activate the tenant, invite the operator, and match ADMIN_EMAIL to the Auth user. There is no CLI that grants platform rights.
Feature Board claims
Feature Board (/admin/features) is founder-only. Leases last 30 minutes. Heartbeat from a worker checkout:
npm run agent:heartbeat -- --card <key>
Release a claim you still hold:
npm run agent:release -- --card <key>
| Command | Environment | Working reference |
|---|---|---|
npm run agent:heartbeat -- --card <key> | Local; WORK_BOARD_URL and a founder-issued WORK_BOARD_TOKEN. Session files stay outside Git. | scripts/agent-dispatch.ts |
npm run agent:release -- --card <key> | Same; only the holder with the unexpired token can release. | scripts/agent-dispatch.ts |
Work volume is advisory. Run npm run agent:go -- --card <key> to resume specifically authorized expired work through revision-checked recovery. The runner preserves retained source and audit history and refuses takeover of a live claim. Use the configured private board profile; keep every other worker checkout intact.
Missing providers
Leave unused providers unset. Add one, then prove it with a receipt on Setup:
- Resend: verified sender, then an outbound
sentmessage. - OpenRouter: tenant key, then an AI run receipt.
- Google: OAuth connect, then a named sync.
- Calendly: signed booking or cancellation receipt.
Configuration without that receipt stays Action needed. That is the truthful state.
Restore saved records and uploaded files
When an installation must be rebuilt, keep its database backup, uploaded files and encryption configuration together as a recorded recovery point. The database contains file metadata, so it cannot replace the bytes of an uploaded document. Before importing customer records, follow the repository's backup and recovery guide and restore a controlled copy into a separate installation.
With the reviewed source configuration, create a private file copy and checksum manifest:
npm run workspace:files -- backup --project YOUR_SOURCE_REF --directory /absolute/private/new-files-copy
Encrypt that copy before moving it off-host. Select the target configuration and inspect the read-only restore plan:
npm run workspace:files -- restore --project YOUR_TARGET_REF --directory /absolute/private/files-copy
Add --apply only for the reviewed restore. Conflicting files or bucket settings are refused, and matching files remain intact if you repeat a stopped restore. Run the read-only plan again afterward; it should show no pending files.
Keep provider connections and schedules disabled while you verify sign-in, saved records, memberships, document downloads and action receipts. Review the provider's own records for effects since the backup point before preparing retries, because an absent local receipt does not prove a send never happened. The Connected fork workflow's recovery receipt measures a controlled native restoration with real Auth and file APIs; hosted restoration, your Auth settings and a human recovery trial still require installation-specific verification.
Confirm the repair
Return to Setup, press Refresh checks, and confirm the failing row moved. Open Activity for the migrate, sync, or task you ran. If the row is still Degraded, stop and keep the error text; do not rotate keys in a loop.