Identifiers
Read this when you are:
- changing how Crabbox names leases, slugs, runs, or claims;
- debugging "why does
crabbox run --id <x>not find this lease?"; - adding a new lookup form (a slug, a provider ID, anything that should resolve
to a lease).
Crabbox names every long-lived thing twice: once with a stable canonical ID that machines compare, and once with a friendly slug that people type. This page lists each identifier, where it comes from, and how --id lookup resolves across them.
#Lease ID
Canonical lease IDs look like:
cbx_abcdef123456
The format is fixed: the literal cbx_ prefix followed by 12 lowercase hex characters. newLeaseID mints one from 6 random bytes, and the regex ^cbx_[a-f0-9]{12}$ (isCanonicalLeaseID) decides whether a value is a canonical ID; anything that fails the pattern is treated as a slug.
The CLI mints a provisional lease ID before calling the broker. The broker may return a different final ID (when the Worker dedupes a retried request, for example). When that happens, the CLI moves the local SSH key directory from the provisional ID to the final ID with MoveStoredTestboxKey (an atomic os.Rename of the per-lease directory) and re-keys the claim and other references accordingly.
Provider resources reference the lease ID through a Crabbox label (the label key is literally lease):
lease=cbx_abcdef123456
Crabbox-created machines also carry a crabbox=true marker label. crabbox list and crabbox cleanup discover machines by that marker and then read the lease label to map a provider machine back to a Crabbox lease.
#Slug
Slugs are friendly, human-typeable lease names. They look like:
blue-lobster
amber-crab
silver-shrimp
By default a slug is generated from a stable hash of the lease ID (newLeaseSlug), so the same lease always gets the same generated slug. The vocabulary is deliberately small (14 adjectives x 8 nouns = 112 base combinations) to match Crabbox's small-fleet model. Lease-creating commands can request a custom slug with --slug <name>:
crabbox warmup --slug update-flow-smoke
crabbox run --slug update-flow-smoke -- pnpm test:changed
crabbox checkpoint fork chk_abc123def456 --slug update-flow-smoke
--slug is creation-time metadata, not a rename. It is honored only when Crabbox is creating a new lease; existing leases keep their assigned slug.
Slugs are normalized everywhere they are accepted. normalizeLeaseSlug lowercases, keeps only [a-z0-9], collapses every other run of characters into a single -, and trims leading and trailing dashes — so Blue_Lobster and BLUE-LOBSTER both resolve to blue-lobster. A requested slug must contain at least one letter or digit and is capped at 41 characters after normalization, so collision suffixes and provider names stay portable.
When a requested or generated slug collides with an existing active lease (a matching server label or a matching local claim), slugWithCollisionSuffix appends a 4-hex suffix derived from a per-attempt seed:
blue-lobster-1f3a
Allocation tries up to 20 suffixed candidates before settling. Collisions are rare in normal use — a single user's active leases seldom approach the 112 base slugs.
#Provider Name
Each managed lease also gets a per-provider resource name that includes the slug and a hash of the lease ID, so the provider console shows something legible:
crabbox-blue-lobster-7f8a2c1d
This is what appears as the EC2 Name tag, the Hetzner server name, the Daytona sandbox name, and so on. It comes from leaseProviderName(leaseID, slug); when the slug is empty the function falls back to crabbox-cbx-abcdef123456 (the lease ID with _ rewritten to -).
#Run ID
Each crabbox run against a coordinator also gets a durable run handle:
run_abcdef123456
Like lease IDs, run IDs are the run_ prefix plus 12 lowercase hex characters (newRunID in the coordinator, from 6 random bytes). The coordinator mints the run record before the lease is acquired, so events can be appended for leasing failures, sync failures, and command output even when the run never reaches command-start. A run ID is stable across a single invocation; retrying the same command produces a new run.
crabbox history, crabbox events, crabbox attach, crabbox logs, and crabbox results all accept run IDs. Slugs do not resolve to runs — only to leases.
#Local Claims
Reusable leases get a JSON claim file under the Crabbox state directory:
$XDG_STATE_HOME/crabbox/claims/cbx_abcdef123456.json
When XDG_STATE_HOME is unset, the state directory sits next to the user config directory: ~/Library/Application Support/crabbox/state/claims on macOS or ~/.config/crabbox/state/claims on Linux.
A claim payload looks like:
{
"leaseID": "cbx_abcdef123456",
"slug": "blue-lobster",
"provider": "aws",
"repoRoot": "/Users/alice/Projects/my-app",
"claimedAt": "2026-05-07T07:42:18Z",
"lastUsedAt": "2026-05-07T07:55:12Z",
"idleTimeoutSeconds": 1800
}
Claims do three things:
- bind a lease to one repo so wrappers and agents do not silently reuse a lease
- give
crabbox run --id blue-lobstera slug-to-canonical-ID translation - power "is this lease still mine?" checks before destructive operations such as
against a different checkout;
without round-tripping the broker;
stop, cleanup, and actions register.
A conflicting claim (same lease, different repoRoot) refuses commands by default with a use --reclaim error; --reclaim overrides the check and rewrites the claim atomically.
Static SSH leases (provider: ssh) record extra endpoint fields in the claim — staticHost, staticUser, staticPort, staticWorkRoot, targetOS, and windowsMode — so the resolver knows the lease bypasses the coordinator and can reconnect without re-provisioning. Claims may also cache a resolved endpoint (sshHost, sshPort, tailscaleIPv4, tailscaleFQDN, bridgeURL) and the pond label once the lease is up.
#SSH Key Storage
Per-lease SSH key directories are keyed by lease ID, under the user config directory (not the state directory):
~/.config/crabbox/testboxes/cbx_abcdef123456/id_ed25519
~/.config/crabbox/testboxes/cbx_abcdef123456/id_ed25519.pub
Keys are ed25519 by default; AWS and Azure Windows leases use a 4096-bit RSA key instead (ensureTestboxKeyForConfig). The provisional-to-final lease ID move renames the whole directory so the private key, public key, and any known_hosts entries migrate together. The provider key name registered with the cloud account is crabbox-cbx-abcdef123456 (providerKeyForLease).
#Resolving An Identifier
crabbox <command> --id <value> accepts:
- a canonical
cbx_...lease ID; - a normalized slug —
blue-lobster,Blue Lobster, andBLUE_LOBSTERall - in coordinator mode, the slug as the broker knows it (case-insensitive).
resolve to the same lease;
Resolution order:
- Read the local claim store.
resolveLeaseClaimfirst tries the literal - If a matching claim exists, use its
leaseIDas the canonical handle. - If no claim is found and a coordinator is configured, ask the coordinator to
- For static SSH and direct-provider modes, fall back to the provider's
identifier as a claim filename, then scans claims/*.json for any claim whose leaseID or normalized slug matches.
resolve the identifier (slug or canonical ID).
Resolve implementation on SSHLeaseBackend.
The first source that returns a hit wins. This is why --id blue-lobster works from any directory once a warmup ran in some other repo — the local claim translates the slug to a lease ID before the broker is ever involved.
#Identifier Lifetime
provisional lease ID newLeaseID() before the broker call
final lease ID broker may return a different ID; key dir + claim re-keyed to it
slug computed on first lease creation, stable for that lease
provider name derived from final lease ID + slug
run ID minted per crabbox run when a coordinator is configured
Slugs are not reserved after a lease ends. The next lease that happens to hash to the same base slug will reuse it; the small vocabulary makes that possible but uncommon in practice.
Related docs: