Read when:
- choosing
provider: blacksmith-testbox; - wrapping an existing Blacksmith Testbox workflow with Crabbox;
- changing
internal/providers/blacksmith.
Blacksmith Testbox is a delegated-run provider. Crabbox does not provision,
bootstrap, rsync, or expose VNC for the remote machine. It shells out to the
authenticated blacksmith CLI and adds Crabbox ergonomics on top: stable lease
IDs and slugs, repo claims, timing summaries, proof artifacts, and normalized
list/status output. Target OS is Linux only.
Configured cache.volumes are forwarded
as Blacksmith sticky disks during Testbox warmup. Use them for package-manager
stores and other rebuildable dependency caches; keep secrets, checkout state,
and proof artifacts out of sticky disks.
Use Blacksmith when the repository already has a Testbox workflow and the remote workspace should be owned and synced by Blacksmith. Choose AWS, Hetzner, Static SSH, or Daytona instead when Crabbox needs to own SSH sync, interactive access, or VNC/code surfaces.
One-shot run:
crabbox run \
--provider blacksmith-testbox \
--blacksmith-org example-org \
--blacksmith-workflow .github/workflows/ci-check-testbox.yml \
--blacksmith-job test \
--blacksmith-ref main \
--timing-json \
-- pnpm testReuse an existing Testbox by ID or slug:
crabbox run --provider blacksmith-testbox --id tbx_123 -- pnpm test
crabbox status --provider blacksmith-testbox --id tbx_123
crabbox stop --provider blacksmith-testbox tbx_123Keep a Testbox between runs via a JSON session handle:
crabbox run --provider blacksmith-testbox --keep --lease-output /tmp/session.json -- npm test
lease_id="$(node -e 'console.log(require("/tmp/session.json").leaseId)')"
crabbox run --provider blacksmith-testbox --id "$lease_id" -- npm run smoke
crabbox stop --provider blacksmith-testbox "$lease_id"Warm a fresh Testbox:
crabbox warmup \
--provider blacksmith-testbox \
--blacksmith-org example-org \
--blacksmith-workflow .github/workflows/ci-check-testbox.yml \
--blacksmith-job test \
--blacksmith-ref mainblacksmith is accepted as an alias, but docs and scripts should prefer
blacksmith-testbox.
Run the shared smoke only when the selected workflow is a real Testbox workflow:
CRABBOX_LIVE=1 CRABBOX_LIVE_PROVIDERS=blacksmith-testbox CRABBOX_LIVE_REPO=/path/to/my-app scripts/live-smoke.shThe smoke exits before any Blacksmith list or run call when it cannot derive
an org, when the configured workflow file is missing, or when that workflow file
does not contain a useblacksmith/testbox, useblacksmith/begin-testbox, or
useblacksmith/run-testbox step. With a valid org and workflow, it lists the
current inventory and runs one delegated echo blacksmith-crabbox-ok && pwd
command through the configured workflow/job/ref.
Authentication lives entirely in the blacksmith CLI. Log in once before using
the provider:
blacksmith auth loginCrabbox never handles Blacksmith credentials directly; it invokes the
already-authenticated blacksmith binary on your PATH.
provider: blacksmith-testbox
blacksmith:
org: example-org
workflow: .github/workflows/ci-check-testbox.yml
job: test
ref: main
idleTimeout: 90m
debug: falseProvider flags (override config):
--blacksmith-org
--blacksmith-workflow
--blacksmith-job
--blacksmith-ref
Environment variables supply the same defaults:
CRABBOX_BLACKSMITH_ORG
CRABBOX_BLACKSMITH_WORKFLOW
CRABBOX_BLACKSMITH_JOB
CRABBOX_BLACKSMITH_REF
CRABBOX_BLACKSMITH_IDLE_TIMEOUT
CRABBOX_BLACKSMITH_DEBUG
blacksmith.workflow (or actions.workflow, when it is not a generic
hydrate/crabbox workflow name) is required only to create a new Testbox.
Reusing an existing ID or slug does not need it. idleTimeout falls back to the
global idleTimeout when unset, and debug passes --debug through to the
Blacksmith CLI.
--env-from-profile, --allow-env, and CRABBOX_ENV_ALLOW help SSH-backed
providers but cannot inject CLI-side environment values into a delegated Testbox
command. When any of those knobs are present, Crabbox prints an
env forwarding ... unsupported summary and exits before warmup. Put live
secrets in the Blacksmith workflow instead. Repo-level env allowlists are
ignored for this provider so they can still cover SSH-backed providers.
Crabbox forwards to the Blacksmith CLI:
blacksmith testbox warmup <workflow> ...
blacksmith testbox run --id <tbx-id> ...
blacksmith testbox list
blacksmith testbox list --all
blacksmith testbox stop --id <tbx-id>On warmup, Crabbox generates a per-Testbox SSH key locally, passes the public
key to blacksmith testbox warmup --ssh-public-key, parses the returned tbx_
ID, claims the Testbox for the current repo, and assigns a friendly slug. Reusing
a lease across repos needs --reclaim.
One-shot runs stop the Testbox and remove the local claim and key after the
command completes, unless --keep is set. --keep-on-failure keeps a failed
one-shot Testbox alive for debugging; successful runs still stop normally. A
failed Testbox otherwise remains available until idle timeout or an explicit
crabbox stop.
If list/status work but new warmups sit queued with no IP, Blacksmith is
accepting requests but not assigning capacity. Stop any queued IDs you created
and fall back to AWS, Hetzner, Static SSH, or Daytona until Blacksmith service,
billing, or org limits recover. A failed warmup triggers a best-effort cleanup
sweep of newly created Testboxes that match your configured workflow/job/ref.
Failed runs write a local failure bundle (stdout, stderr, timing, redacted env/config metadata) even though remote file capture is delegated to Blacksmith. Captured streams are size-capped so a verbose successful run does not fill local temp storage.
--emit-proof <path> works for successful Blacksmith runs. Crabbox renders the
same proof block used by SSH-backed runs from the delegated stdout/stderr
transcript, command timing, the Testbox ID, and any GitHub Actions run URL found
in the stream. When proof is requested, Crabbox also writes bounded transcript
artifacts under .crabbox/runs/<testbox-id>/:
blacksmith.stdout.log
blacksmith.stderr.log
timing.json
metadata.json
Crabbox terminates a local blacksmith invocation that stays in the sync phase
for five minutes without printing a sync-completion marker. Set
CRABBOX_BLACKSMITH_SYNC_TIMEOUT_MS=0 to disable the guard, or a larger
millisecond value for intentionally huge local diffs. (OPENCLAW_TESTBOX_SYNC_TIMEOUT_MS
is also honored for legacy compatibility.)
When coordinator auth is configured, crabbox list --provider blacksmith-testbox
syncs visibility-only Testbox rows into the portal lease table. If Crabbox can
infer the owning GitHub Actions run, the portal links the row to the run and
workflow, shows the Actions status/conclusion, flags long-queued or long-running
rows as stuck, exposes a copyable local stop command, and provides a
visibility-only detail page.
- SSH: no Crabbox SSH lease.
- Crabbox sync: no.
- Provider sync: yes, Blacksmith-owned.
- Desktop/browser/code: no Crabbox VNC/code surface.
- Proof: yes, from the delegated stream, timing, and metadata.
- Actions hydration: Blacksmith owns workflow setup; not Crabbox SSH hydration.
- Coordinator: no (always direct from the CLI).
--sync-only,--checksum, and--force-sync-largedo not apply because Blacksmith owns sync.--script,--script-stdin,--fresh-pr, local stdout/stderr captures, and--downloadare rejected because Blacksmith owns command transport and remote file transport. Use--emit-prooffor PR-ready transcript proof.--artifact-globand--require-artifactrun through the Blacksmith adapter: after command success, Crabbox asks the same Testbox to validate required globs and stream one bounded local tarball under.crabbox/runs/<lease>/.--actions-runneris rejected; Blacksmith owns runner hydration.--tailscale, desktop helpers, screenshots, VNC, andartifacts collectare rejected because Blacksmith owns machine connectivity.listandstatusare core-rendered from parsed Blacksmith CLI output.
Related docs: