From 61985cb1d21abe4bf2efe7ac7590b906ba9c980d Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 1 May 2026 09:26:32 +0100 Subject: [PATCH] chore: simplify crabbox integration --- .agents/skills/blacksmith-testbox/SKILL.md | 3 + .agents/skills/crabbox/SKILL.md | 78 ++++++++++++++++++++++ .crabbox.yaml | 7 +- .github/workflows/crabbox-hydrate.yml | 36 ++++++++++ .gitignore | 2 + docs/ci.md | 11 +++ package.json | 4 ++ 7 files changed, 135 insertions(+), 6 deletions(-) create mode 100644 .agents/skills/crabbox/SKILL.md diff --git a/.agents/skills/blacksmith-testbox/SKILL.md b/.agents/skills/blacksmith-testbox/SKILL.md index 7df209fd010..1827bcc475e 100644 --- a/.agents/skills/blacksmith-testbox/SKILL.md +++ b/.agents/skills/blacksmith-testbox/SKILL.md @@ -10,6 +10,9 @@ description: Run Blacksmith Testbox for CI-parity checks, secrets, hosted servic Use Testbox when you need remote CI parity, injected secrets, hosted services, or an OS/runtime image that your local machine cannot provide cheaply. +For OpenClaw, Crabbox is a supported alternative when Blacksmith is unavailable +or owned cloud capacity is preferable. + Do not default to Testbox for every local test/build loop. If the repo has documented local commands for normal iteration, use those first so you keep warm caches, local build state, and fast feedback. diff --git a/.agents/skills/crabbox/SKILL.md b/.agents/skills/crabbox/SKILL.md new file mode 100644 index 00000000000..2bed7e59cb2 --- /dev/null +++ b/.agents/skills/crabbox/SKILL.md @@ -0,0 +1,78 @@ +--- +name: crabbox +description: Use Crabbox for OpenClaw remote Linux validation, warmed reusable boxes, GitHub Actions hydration, sync timing, logs, results, caches, and lease cleanup. +--- + +# Crabbox + +Use Crabbox when OpenClaw needs remote Linux proof on owned capacity, a large +runner class, reusable warm state, or a Blacksmith alternative. + +## Before Running + +- Run from the repo root. Crabbox sync mirrors the current checkout. +- Prefer local targeted tests for tight edit loops. +- Prefer Blacksmith Testbox when the task explicitly asks for Blacksmith or a + Blacksmith-specific CI comparison. +- Use Crabbox for broad OpenClaw gates when owned AWS/Hetzner capacity is the + right remote lane. +- Check `.crabbox.yaml` for repo defaults before adding flags. +- Install with `brew install openclaw/tap/crabbox`; auth is required before use: `crabbox login`. + +## OpenClaw Flow + +Warm a reusable box: + +```sh +pnpm crabbox:warmup -- --idle-timeout 90m +``` + +Hydrate it through the repository workflow: + +```sh +pnpm crabbox:hydrate -- --id +``` + +Run broad proof: + +```sh +pnpm crabbox:run -- --id --shell "OPENCLAW_TESTBOX=1 pnpm check:changed" +pnpm crabbox:run -- --id --shell "corepack enable && pnpm install --frozen-lockfile && pnpm test" +``` + +Stop boxes you created before handoff: + +```sh +pnpm crabbox:stop -- +``` + +## Useful Commands + +```sh +crabbox status --id --wait +crabbox inspect --id --json +crabbox sync-plan +crabbox history --lease +crabbox logs +crabbox results +crabbox cache stats --id +crabbox ssh --id +``` + +Use `--debug` on `run` when measuring sync timing. + +## Hydration Boundary + +`.github/workflows/crabbox-hydrate.yml` is repo-specific on purpose. It owns +OpenClaw checkout, setup-node, pnpm setup, provider env hydration, ready marker, +and keepalive. Crabbox owns runner registration, workflow dispatch, SSH sync, +command execution, logs/results, local lease claims, and idle cleanup. + +Do not add OpenClaw-specific setup to Crabbox. Put repo setup in the hydration +workflow and generic lease/sync behavior in Crabbox. + +## Cleanup + +Crabbox has coordinator-owned idle expiry and local lease claims, so OpenClaw +does not need a custom ledger. Default idle timeout is 30 minutes unless config +or flags set a different value. Still stop boxes you created when done. diff --git a/.crabbox.yaml b/.crabbox.yaml index e31d8f86bc2..ab0046d8ce9 100644 --- a/.crabbox.yaml +++ b/.crabbox.yaml @@ -9,6 +9,7 @@ capacity: - eu-west-1 actions: workflow: .github/workflows/crabbox-hydrate.yml + job: hydrate ref: main runnerLabels: - crabbox @@ -26,14 +27,8 @@ sync: baseRef: main exclude: - .artifacts - - .cache - .codex - .DS_Store - - .turbo - - coverage - - dist - - dist-runtime - - node_modules - playwright-report - test-results env: diff --git a/.github/workflows/crabbox-hydrate.yml b/.github/workflows/crabbox-hydrate.yml index b26f599d246..35da86a752f 100644 --- a/.github/workflows/crabbox-hydrate.yml +++ b/.github/workflows/crabbox-hydrate.yml @@ -7,10 +7,19 @@ on: description: "Crabbox lease ID" required: true type: string + ref: + description: "Git ref to hydrate" + required: false + type: string crabbox_runner_label: description: "Dynamic Crabbox runner label" required: true type: string + crabbox_job: + description: "Hydration job identifier expected by Crabbox" + required: false + default: "hydrate" + type: string crabbox_keep_alive_minutes: description: "Minutes to keep the hydrated job alive" required: false @@ -30,6 +39,8 @@ jobs: timeout-minutes: 120 steps: - uses: actions/checkout@v6 + with: + ref: ${{ inputs.ref || github.ref }} - name: Setup Node environment uses: ./.github/actions/setup-node-env @@ -81,12 +92,37 @@ jobs: shell: bash run: | set -euo pipefail + job="${{ inputs.crabbox_job }}" + if [ -z "$job" ]; then job=hydrate; fi mkdir -p "$HOME/.crabbox/actions" state="$HOME/.crabbox/actions/${{ inputs.crabbox_id }}.env" + env_file="$HOME/.crabbox/actions/${{ inputs.crabbox_id }}.env.sh" + services_file="$HOME/.crabbox/actions/${{ inputs.crabbox_id }}.services" + write_export() { + key="$1" + value="${!key-}" + if [ -n "$value" ]; then + printf 'export %s=%q\n' "$key" "$value" + fi + } + { + for key in CI GITHUB_ACTIONS GITHUB_WORKSPACE GITHUB_REPOSITORY GITHUB_RUN_ID GITHUB_RUN_NUMBER GITHUB_RUN_ATTEMPT GITHUB_REF GITHUB_REF_NAME GITHUB_SHA GITHUB_EVENT_NAME GITHUB_ACTOR RUNNER_OS RUNNER_ARCH RUNNER_TEMP RUNNER_TOOL_CACHE; do + write_export "$key" + done + } > "${env_file}.tmp" + mv "${env_file}.tmp" "$env_file" + { + echo "# Docker containers visible from the hydrated runner" + docker ps --format '{{.Names}}\t{{.Image}}\t{{.Ports}}' 2>/dev/null || true + } > "${services_file}.tmp" + mv "${services_file}.tmp" "$services_file" tmp="${state}.tmp" { echo "WORKSPACE=${GITHUB_WORKSPACE}" echo "RUN_ID=${GITHUB_RUN_ID}" + echo "JOB=${job}" + echo "ENV_FILE=${env_file}" + echo "SERVICES_FILE=${services_file}" echo "READY_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)" } > "$tmp" mv "$tmp" "$state" diff --git a/.gitignore b/.gitignore index b3a56ddb49b..a882138473d 100644 --- a/.gitignore +++ b/.gitignore @@ -104,6 +104,8 @@ USER.md .agents/skills/* !.agents/skills/blacksmith-testbox/ !.agents/skills/blacksmith-testbox/** +!.agents/skills/crabbox/ +!.agents/skills/crabbox/** !.agents/skills/gitcrawl/ !.agents/skills/gitcrawl/** !.agents/skills/openclaw-ghsa-maintainer/ diff --git a/docs/ci.md b/docs/ci.md index b6684891789..5cb2e35d66c 100644 --- a/docs/ci.md +++ b/docs/ci.md @@ -419,6 +419,17 @@ The sanity check fails fast when required root files such as `pnpm-lock.yaml` di `pnpm testbox:run` also terminates a local Blacksmith CLI invocation that stays in the sync phase for more than five minutes without post-sync output. Set `OPENCLAW_TESTBOX_SYNC_TIMEOUT_MS=0` to disable that guard, or use a larger millisecond value for unusually large local diffs. +Crabbox is the repo-owned second remote-box path for Linux proof when Blacksmith is unavailable or when owned cloud capacity is preferable. Warm a box, hydrate it through the project workflow, then run commands through the Crabbox CLI: + +```bash +pnpm crabbox:warmup -- --idle-timeout 90m +pnpm crabbox:hydrate -- --id +pnpm crabbox:run -- --id --shell "OPENCLAW_TESTBOX=1 pnpm check:changed" +pnpm crabbox:stop -- +``` + +`.crabbox.yaml` owns provider, sync, and GitHub Actions hydration defaults. It excludes local `.git` so the hydrated Actions checkout keeps its own remote Git metadata instead of syncing maintainer-local remotes and object stores, and it excludes local runtime/build artifacts that should never be transferred. `.github/workflows/crabbox-hydrate.yml` owns checkout, Node/pnpm setup, `origin/main` fetch, and the non-secret environment handoff that later `crabbox run --id ` commands source. + ## Related - [Install overview](/install) diff --git a/package.json b/package.json index eec39ace283..456b3f9b54f 100644 --- a/package.json +++ b/package.json @@ -1305,6 +1305,10 @@ "config:docs:gen": "node --import tsx scripts/generate-config-doc-baseline.ts --write", "config:schema:check": "node --import tsx scripts/generate-base-config-schema.ts --check", "config:schema:gen": "node --import tsx scripts/generate-base-config-schema.ts --write", + "crabbox:hydrate": "sh -c 'if [ \"${1-}\" = \"--\" ]; then shift; fi; bin=crabbox; if [ -x ../crabbox/bin/crabbox ]; then bin=../crabbox/bin/crabbox; fi; exec \"$bin\" actions hydrate \"$@\"' --", + "crabbox:run": "sh -c 'if [ \"${1-}\" = \"--\" ]; then shift; fi; bin=crabbox; if [ -x ../crabbox/bin/crabbox ]; then bin=../crabbox/bin/crabbox; fi; exec \"$bin\" run \"$@\"' --", + "crabbox:stop": "sh -c 'if [ \"${1-}\" = \"--\" ]; then shift; fi; bin=crabbox; if [ -x ../crabbox/bin/crabbox ]; then bin=../crabbox/bin/crabbox; fi; exec \"$bin\" stop \"$@\"' --", + "crabbox:warmup": "sh -c 'if [ \"${1-}\" = \"--\" ]; then shift; fi; bin=crabbox; if [ -x ../crabbox/bin/crabbox ]; then bin=../crabbox/bin/crabbox; fi; exec \"$bin\" warmup \"$@\"' --", "deadcode:ci": "pnpm deadcode:report:ci:knip", "deadcode:dependencies": "pnpm --config.minimum-release-age=0 dlx knip@6.8.0 --config knip.config.ts --production --no-progress --reporter compact --dependencies --no-config-hints", "deadcode:knip": "pnpm dlx knip --config knip.config.ts --production --no-progress --reporter compact --files --dependencies",