Self-hosted departure checklist
Retire a self-hosted install in order. Each step names a command or route and its expected result. A blank rehearsal record follows.
Use this checklist when your organization leaves CodeHerder, or retires an install. Your operator runs it. Rehearse it once on a test install first. Your support agreement says whether the support contact takes part.
Run Self-hosted exit and data preservation first. Do not start step I1 until every export passes its completeness check. A step marked irreversible cannot be undone.
Record each step in the rehearsal record. A step is done when you see its expected result.
Identity
| # | Step | Command or route | Expected result |
|---|---|---|---|
| I1 | List the people | ch member list |
Every human in the workspace. |
| I2 | Deprovision each human | POST /v1/workspaces/{id}/members/{memberId}/deprovision, from the member action in the web app. With SCIM, deactivate the user in your identity provider. |
The member is disabled. Its roles, API keys, MCP grants, CLI installations and device links are revoked. See Offboard a person. |
| I3 | Revoke every credential of each human (belt and braces) | ch human revoke-all <human> --yes. Instance operator only. |
The reply shows the revoked counts and boundSeconds. Every server process refuses the credentials within that bound. |
| I4 | Revoke the SCIM token | DELETE /v1/sso-connections/{id}/scim-token |
Your identity provider’s next SCIM call fails with 401. |
| I5 | Revoke each agent key | ch member keys list <agent>, then ch member keys delete <hash> for each key. Then ch agent disable <agent>. |
The key list shows no active key. The agent is paused. |
| I6 | Disable the Cognito app client, then the pool | AWS console, or aws cognito-idp delete-user-pool-client. To delete the pool, first aws cognito-idp update-user-pool --deletion-protection INACTIVE, then aws cognito-idp delete-user-pool. Irreversible. |
A sign-in at the hosted UI fails. See Self-hosted Cognito sign-in. |
The Cognito pool is not part of the database. A database restore does not change it.
Devices
| # | Step | Command or route | Expected result |
|---|---|---|---|
| D1 | List the devices | ch device list |
Every linked device. |
| D2 | Unlink each device from each workspace | ch device workspaces delete <device> --workspace <workspace> |
The device drops the workspace from its served set. On its next reaper cycle it removes the repo mirrors, pool directories, shared knowledge folder and transcripts for that workspace. |
| D3 | Revoke each device token | ch device revoke-token <device> <tokenId> |
The tunnel closes. A reconnect with that token gets 401. |
| D4 | Archive each device | ch device archive <device> |
The device leaves every list and placement. All its tokens are revoked. |
Do the next steps on each device host.
| # | Step | Command | Expected result |
|---|---|---|---|
| D5 | Stop the device server, then delete the session root | Stop the process that runs ch device-server. Then delete $CH_SESSION_ROOT (default ~/codeherder-sessions). |
ls finds no session root. |
| D6 | Sign out, then delete the local roots | ch logout, then delete ~/.codeherder (or $CH_CONFIG_DIR) and the credential store root if you moved it with CH_CLAUDE_CREDENTIAL_STORE. |
ls finds no directory. |
| D7 | Delete harness transcripts kept by Docker stages | Delete ~/.claude/projects/. |
ls finds no directory. |
| D8 | Remove the tool-cache volumes | docker volume ls, then docker volume rm <name> for each /opt/ch-tools volume. |
docker volume ls shows none. |
ch logout revokes the CLI credential on the server and removes the cached credential. It does not delete the local store, the shared-document cache or the local tasks. Step D6 deletes them. This is a known gap.
What a device keeps
Every row below is a store the device server or ch writes. The last column names the step that removes it.
| Store | Path | Removed by |
|---|---|---|
Session worktree and sandbox |
<root>/<sandboxId>/ (checkouts, session files) |
Step D5: delete the session root. |
Per-session knowledge copy |
<root>/<sandboxId>/<leaf>/knowledge/ |
Step D5: delete the session root. |
Agent CLI config redirect |
<root>/<sandboxId>/<session area>/isolated-config/ (aws, docker, kube, gh, glab) |
Step D5: delete the session root. |
Repo mirrors |
<root>/.mirrors/<workspaceId>-<repoHash>/ (bare clones) |
Step D5: delete the session root. |
Warm worktree pool |
<root>/.pool/<workspaceId>-<repoHash>/ |
Step D5: delete the session root. |
Shared knowledge folder |
<root>/.knowledge/<workspaceId>/, with .staging/ and .retired/ beside it |
Step D5: delete the session root. |
Transcript archive |
<root>/.transcripts/<anchorId>/<harness>/ |
Step D5: delete the session root. |
Reclaimed work bundles |
<root>/.reclaimed/ |
Step D5: delete the session root. |
Harness config area |
under the sandbox directory: the relocated harness config dir (transcripts, harness settings) |
Step D5: delete the session root. |
Provision parameters |
<root>/.provision-params/<sessionId>.json (repo URLs, branches) |
Step D5: delete the session root. |
Spawn cwd pins |
<root>/.spawn-cwd/<sessionId>.json |
Step D5: delete the session root. |
Foreign-path attestations |
<root>/.foreign-attest/<sandboxId>.json |
Step D5: delete the session root. |
Foreign-path anchors |
<root>/.foreign-anchor/<sandboxId>.json |
Step D5: delete the session root. |
Git common-dir anchors |
<root>/.git-common-dir-anchors/<sandboxId>/ |
Step D5: delete the session root. |
Agent, git-credential and device-local sockets |
the agent socket dir, <runtime dir>/git-credential/ and the device-local bridge dir (unix sockets, no data at rest) |
Stopping the device server removes the sockets. Nothing to delete. |
Empty git hooks directory |
~/.codeherder/empty-git-hooks/ (empty; core.hooksPath target) |
Step D6: delete ~/.codeherder (or CH_CONFIG_DIR). |
Session state files |
~/.codeherder/sessions/*.json (PTY holder state) |
Step D6: delete ~/.codeherder (or CH_CONFIG_DIR). |
Execution receipts |
~/.codeherder/sessions/receipts/ and receipts/refused/ |
Step D6: delete ~/.codeherder (or CH_CONFIG_DIR). |
Egress denial outbox |
~/.codeherder/sessions/egress-outbox/<runId>/<reportId>.json (destination host, port, transport, denial category, counts) |
Step D6: delete ~/.codeherder (or CH_CONFIG_DIR). |
Docker stage-run files |
~/.codeherder/stage-runs/<runId>/ (env file, bearer dir, pi auth, transcript mount) |
Step D6: delete ~/.codeherder (or CH_CONFIG_DIR). |
Host harness transcripts |
~/.claude/projects/<cwd slug>/ (Docker stages; unrelocated fallback) |
Step D7: delete ~/.claude/projects/. |
Tool-cache Docker volume |
Docker volume mounted at /opt/ch-tools, one per task worktree |
Step D8: docker volume rm. |
Credential store and pool |
<credential store>/credentials/<harness>.env and <harness>.d/ (pool entries) |
Step D6: delete the credential store root. Then revoke the credential at its provider (I14). |
Local launch directories |
~/.codeherder/launches/<launchId>/ (status, registration, runtime log) |
Step D6: delete ~/.codeherder (or CH_CONFIG_DIR). |
Device-server log |
~/.codeherder/logs/device-server.log (+ .1) and last-trim.json |
Step D6: delete ~/.codeherder (or CH_CONFIG_DIR). |
ch local store |
~/.codeherder/local.db (+ backups); sync outbox, bases, cursors |
Step D6: delete ~/.codeherder (or CH_CONFIG_DIR). |
Local attachment blobs |
~/.codeherder/blobs/ |
Step D6: delete ~/.codeherder (or CH_CONFIG_DIR). |
Shared-document cache |
<CLI config home>/shareddocs/<endpoint>/<workspaceId>/collection.json |
Step D6: delete ~/.codeherder (or CH_CONFIG_DIR). |
CLI endpoint credentials |
<CLI config home>/endpoints/<endpoint>/ (CLI tokens) |
Step D6: delete ~/.codeherder (or CH_CONFIG_DIR). |
Cost markers |
~/.codeherder/cost-markers/ |
Step D6: delete ~/.codeherder (or CH_CONFIG_DIR). |
Held cost evidence |
~/.codeherder/cost-held/<transcriptHash>/<turnIndex>.json |
Before departure, resolve pending usage evidence. Step D6 then deletes this root, including expired and quarantined entries; normal workspace unlink and sandbox teardown retain it. |
Stage-tools template |
~/.codeherder/stage-tools/ (injected stage config and gitconfig) |
Step D6: delete ~/.codeherder (or CH_CONFIG_DIR). |
Integrations
| # | Step | Command or route | Expected result |
|---|---|---|---|
| I7 | Delete each integration | GET /v1/workspaces/{id}/integrations, then DELETE /v1/integrations/{id} for GitHub, GitLab, Slack and PagerDuty. In the web app: Settings → Integrations. |
The list is empty. |
| I8 | Revoke the token or uninstall the app at the provider | The provider’s console. | The provider shows no CodeHerder token or app. |
| I9 | Delete each outbound webhook | ch webhook list, then ch webhook delete <id> |
ch webhook list shows none. |
| I10 | Delete each inbound endpoint | ch inbound-endpoint list, then ch inbound-endpoint delete <ref> |
The list is empty. A sender’s next POST gets a 404. |
| I11 | Delete each device git token | On each device host: ch device git-token list, then ch device git-token delete <label> |
The pool is empty. |
| I12 | Delete each device credential pool entry | On each device host: ch device credential list, then ch device credential delete <label> |
The pool is empty. |
| I13 | Delete variables | ch variable list, then ch variable unset <KEY> at each scope |
ch variable list shows none. |
| I14 | Revoke each AI key at its provider | The Anthropic console, Bedrock IAM, or your gateway. | A call with the old key fails. |
Backups
| # | Step | Command or route | Expected result |
|---|---|---|---|
| B1 | State the retention | Read your snapshot and dump retention. | A written number of days for the database, the bucket and the revocation journal. |
| B2 | Keep the revocation journal | Keep revocation-journal/ or CH_REVOCATION_JOURNAL_DIR at least as long as the longest backup. |
The journal is older than the oldest backup. |
| B3 | Restore a pre-departure snapshot into a scratch environment | See Recover. Start the server fenced. | The server starts and refuses to send email or to accept devices. |
| B4 | Try a revoked API key, and read a revoked device token’s row | curl -H "Authorization: Bearer <key>" <addr>/v1/workspaces. Then, in the restored database: SELECT revoked_at FROM device_tokens WHERE id = '<tokenId>'; |
Before replay, the key may work and revoked_at may be NULL. Note both results. |
| B5 | Replay the revocations | ch instance restore-fence replay --yes |
The command succeeds. |
| B6 | Check that no entry is left | ch instance restore-fence show |
No pending journal entry. |
| B7 | Try the same key again, and read the same token row | Repeat B4. | The key gets 401. revoked_at shows a time. |
| B8 | Promote | ch instance restore-fence promote --yes |
The server leaves the fence. Never promote before B7 passes. |
Erased and revoked data stays in each snapshot until that snapshot expires. See Erased data in backups. The restore fence replays revocations and erasures. It does not delete a Cognito identity. Delete it by hand if you also rolled the pool back.
A device token does not sign in to a REST route, so B4 reads its row instead. A fenced server refuses every device tunnel, so a tunnel test cannot run before B8. After B8, you can try the revoked token on a device. Expect the server to refuse the tunnel.
CodeHerder has no automated test that a restored database never revives access. Use B3 to B7 as your proof until that test exists.
Retire the workspaces
Do this only after every export passed. Irreversible.
- Archive:
ch workspace archive <workspace>. Expect the workspace to leave every list. - Delete:
ch workspace delete <workspace>. Only an owner can run it. Expect the workspace to be gone.
Rehearsal record
Your operator and a witness fill this table during a rehearsal on a test install. Leave a row blank until the step runs. Evidence is the command output, a screenshot, or a ticket id.
| Area | Step | Date | Who ran it | Evidence | Result (pass, fail) |
|---|---|---|---|---|---|
| Exit | Export and completeness check | ||||
| Identity | I1 to I3 | ||||
| Identity | I4 to I6 | ||||
| Devices | D1 to D4 | ||||
| Devices | D5 to D8 | ||||
| Integrations | I7 to I10 | ||||
| Integrations | I11 to I14 | ||||
| Backups | B1 to B2 | ||||
| Backups | B3 to B8 | ||||
| Retire | Archive and delete |
Signed off by (operator): ______________________ Date: ____________
Witnessed by: ______________________ Date: ____________
Last updated