This directory owns local tooling, script wrappers, and generated-artifact helper rules.
-
macOS-only Bash scripts use
#!/bin/bashand Bash 3.2-compatible syntax; invoke them directly or with/bin/bash, including fixtures. -
Portable Bash entrypoints using heredocs/here-strings (including sourced helpers) carry the inline Darwin Bash 5.3+ re-exec guard before those operations to prevent heredoc pipe deadlocks; stdin/sourced installers must request
/bin/bashwhen replay is impossible. -
Prefer existing wrappers over raw tool entrypoints when the repo already has a curated seam.
-
For tests, prefer
scripts/run-vitest.mjsor the rootpnpm test ...entrypoints over rawvitest runcalls. -
Never use bare
vitest ...in automation; it starts local watch mode unlessrunor--runis explicit. -
For lint/typecheck flows, prefer
scripts/run-oxlint.mjsandscripts/run-tsgo.mjswhen adding or editing package scripts or CI steps that should honor repo-local runtime behavior. -
For changed-file verification, prefer
scripts/check-changed.mjsand keep lane classification inscripts/changed-lanes.mjs. Usenode scripts/check-changed.mjs --dry-run [--staged|-- <files...>]to inspect the plan before running anything expensive. Do not copy path-scope rules into new hooks or ad hoc CI snippets. -
For one/few lint files, prefer direct
node scripts/run-oxlint.mjs --tsconfig <matching config> <files...>over shardedpnpm lint;check-changed.mjsowns this targeting for core, extension, and script diffs.
- Keep TypeScript implementation files under
scripts/**erasable by Node without transformation. Do not use parameter properties, runtime enums or namespaces, import-equals, export-assignment, or other transform-required TypeScript syntax. - This syntax rule does not make every script a plain-Node entrypoint. Keep
tsxfor closures that intentionally depend on source runtime trees, frozen checkouts, package aliases, or tsconfig/path resolution. - Native Node execution is opt-in per entrypoint and import closure. Use it only when runtime imports remain Node-resolvable and do not pull broader source trees into this syntax policy.
- Main freshness belongs to one
scripts/properation: nested entry/review guards share a captured main SHA; gate selection, publication after gates, and merge verification after CI each refresh it. Capture the canonical origin's main from the PR worktree's privateFETCH_HEAD, never a later shared-ref read. Main refreshes never write sharedorigin/main. Cold provisioning fetches into its existing per-PRtemp/pr-<PR>branch without writing canonicalFETCH_HEAD, then fully initializes from that seed before the private checkpoint; the seed is not checkpoint authority. Every standalone command and newly provisioned worktree starts fresh; coalescing must not skip containment, transition recovery, exact-head checks, or the separate Crabbox authority windows. scripts/prserializes review, prepare, and merge operations per PR across linked worktrees;scripts/pr gcskips active or indeterminate locks. Its subcommand classification table is the canonical wrapper trust boundary: a mismatched local wrapper may run only a classifiedadvisorysubcommand with--dev-wrapperorOPENCLAW_PR_DEV_WRAPPER=1; classifiedlandingsubcommands always require canonical/origin-main wrapper code. A worktree whose wrapper differs from origin/main (stale base or wrapper-editing branch) loudly substitutes the canonical checkout's wrapper when that checkout is clean and byte-identical to fetchedrefs/remotes/origin/main; it refuses only when no anchor-matching wrapper is available. A successful command return is the trusted synchronous-completion contract: every PR-state-mutating child must be joined before returning, and such work must never daemonize or explicitly escape both the operation group and lock-notification FD. Release on clean exit requires the leader's completion marker; an escaped descendant that merely holds the notify pipe then produces a loud warned release instead of retention (#124583), while all failure shapes still retain. A failed command auto-releases only while its explicit pre-side-effect validation marker remains active; failures after mutation/tool launch, interruptions, and controller loss stay locked because detached children cannot be disproved. After verifying no child tools remain, use the reported exact-OIDscripts/pr lock-recovercommand. Never bypass or delete these refs manually.- Materialized wrappers pin selective third-party dependencies to their installed real package directories before handoff, not mutable top-level
node_modulesaliases. Missing package directories fail before lock acquisition; restore frozen dependencies in a clean trusted-main checkout and retry. Do not link the whole workspace dependency tree or install during materialization. Keep the resolved package installation intact until the supervised command finishes; pinning paths does not copy or freeze package contents. OPENCLAW_PR_GATES_REMOTE=testboxruns the full-suitepnpm testgate on a Blacksmith Testbox throughscripts/crabbox-wrapper.mjs(same delegation ascheck:changed);pnpm build/pnpm checkstay local. Thetbx_lease id and Actions run URL land in.local/gates.env(REMOTE_GATES_*) and.local/prep.md. Use it for reviewed trusted code when a loaded host makes the local 88-shard run stall-kill; contributor/fork code stays on secretless CI or sanitized AWS unless a maintainer explicitly approves credentialed execution.OPENCLAW_PR_GATES_REMOTE=crabbox-awsis an explicit active-org-admin fallback, never the default.prepare-gatesrecords a pending handle; afterprepare-pushproves the exact remote head,scripts/pr-lib/ci-dispatch.mjs --backend crabboxsynchronously dispatches the protected-main publisher and waits for its exact-head check. That trusted workflow checksum-installs released Crabbox v0.46, resolves its/v1/whoamiservice principal, and creates sanitized direct AWS proof under the same token withumask 022, trustedscripts/crabbox-untrusted-bootstrap.sh,pnpm build,pnpm check, and the fail-closed PR-derived test plan from the repository's changed-test owner. Every executable changed path must independently resolve to concrete matched test files; broad fallback, partial plans, deleted executable paths, and unmatched/config targets are refused. Only explicit docs andAGENTS.md/CLAUDE.mdinstruction surfaces may produce zero tests. The canonical broker command binds the exact PR base, head, bootstrap hash, and plan digest. The publisher requires the PR base to be the merge base of its immutable workflow SHA and proves that each protected-main snapshot is identical to or descended from that workflow SHA, with an unchanged reread around each comparison. Main may advance during the long remote run, but not inside either validation window. It validates its newly created immutable broker run, ordered complete events, exact broker-resolved owner/org correlation between/v1/whoamiand the run, canonical bootstrap hash, exact command/base/head/plan, active admin actor, and open same-repository PR target before GitHub Actions adds the workflow SHA to the strict summary and publishes the distinctopenclaw/crabbox-gate; draft rejection remains a merge-time rule. Only after that success does.local/gates.envrecord provider/run/lease/URL recovery metadata from the trusted check. Retained logs are checked when present but are optional because released v0.46 can retain zero log bytes for a successful run. Normalopenclaw/ci-gatesemantics stay unchanged. Native merge may add--adminonly when the exact Crabbox check is successful from GitHub Actions, its immutable workflow SHA is an ancestor of a stable final protected-main snapshot, the actor is still an active organization admin, and the sole unsatisfied required check is a normal CI gate with GitHub-owned workflowstartup_failureor a recognized hosted, unacquired, zero-stepfailure/timed_outjob; cancellation, action-required, stale, an assigned runner, job log text, and any failed or executed workflow step never authorize bypass. The flow repeats this verification immediately before the pinned-head merge request; GitHub has no expected-base-OID merge precondition, so the Crabbox path compares the landed squash parent with that final main snapshot in.local/merge-crabbox-parent-audit.jsonand reports a match or intervening main movement after the completed merge. Normal merge paths do not perform this audit.
- If a script writes generated artifacts, keep the source-of-truth generator, the package script, and the matching verification/check command aligned.
- Prefer additive generator/check pairs like
*:genand*:checkover one-off undocumented scripts.
- Keep script-runner behavior, wrapper expectations, and generated-artifact guidance here.
- Leave repo-global verification policy in the root
AGENTS.md.
- Initial admission and OPEN/CLOSED/pending/uncertain reconciliation require exact full PR/main snapshot stability. Only a validated MERGED receipt may accept forward main advancement between its two observations: every PR fact must remain equal, acquire the reread's exact main commit through the same canonical trusted URL when absent locally, and prove the original observed main is its ancestor. Equal snapshots keep the fast path. Both snapshots stay pinned; never add a third reread loop. This completes an already-proven merge, never grants authority for a future merge; historical tree/source-base checks and receipt/comment/cleanup ownership remain unchanged.
- Local object-availability probes and strict retained-record reads use command-scoped
GIT_NO_LAZY_FETCH=1. Upstream Git 2.45 first supports this environment variable; older Git may still hydrate objects implicitly and cannot promise local-only probes. This is not a new all-command minimum or an offline workflow: explicit canonical fetches and actual tree/diff/archive/push/checkout operations remain available. Completed-receipt correctness depends on pinned facts and ancestry/tree proof, not this download avoidance. - Initial admission alone waits for UNKNOWN mergeability projections for at most three observations, sleeping one then two seconds, with all other facts and each already-known projection pinned; full final rereads and retained-outcome reconciliation never poll. Before intent on PRs without a merge queue, ordinary merges reject gh's BLOCKED/BEHIND/DIRTY refusals and admin merges reject DIRTY; queue and auto retain their distinct admission contracts.
merge-runowns remote dispatch separately from the process lock. Before any merge/auto/queue request it records the exact repository identity, PR, main target, prepared head, observed main, method, route, and attempt inrefs/openclaw/pr-merge-outcomes/<PR>. Private Git commits retain the required objects across worktree removal and GC. Do not delete or push these refs; process-lock recovery never clears them.- A failed request can already have merged. After the reported exact process-lock recovery, repeat
scripts/pr merge-run <PR>only for reconciliation.OPEN, a different head, reverted/partially applied content, elapsed time, or an absent process never proves non-execution. There is no automatic clear/retry override. Inspect the PR timeline, authoritative main history, andgit show refs/openclaw/pr-merge-outcomes/<PR>:outcome.json; unresolved uncertainty requires operator action outside this automatic path. Keep the record for that investigation. If an older wrapper left.local/merge-output.logwithout an outcome record, even an empty capture blocks a fresh dispatch; preserve it and reconcile the earlier request manually. - An explicit land/merge/ship request supplies standing operator authorization for investigated recovery on the same prepared head and merge method. Do not ask for renewed chat approval solely because main moved or a request failed. Investigate each retained outcome before deciding on a bounded recovery attempt; standing authorization does not establish non-execution or permit resubmission of accepted, pending, or unresolved requests.
- After that investigation, use
scripts/pr merge-recover <PR> <OUTCOME_OID> --confirmed-operator-recoveryunder the standing authorization above or explicit operator authorization for one new attempt. This is an operator decision, never proof that the prior request did not execute. It requires the exact current retained intent with no recorded acceptance, the same prepared head and merge method, fresh ordinary admission, and no auto/queue/admin route. If the operator separately approves a newly reviewed/prepared replacement head, append--replacement-head <SHA>with that exact full lowercase 40-character SHA; never infer it from PR/main/prep state. Replacement requires matching PR review stamps and prepare context, prepared-tree/gate bindings, completed CI proof, and a completed ClawSweeper review under the canonical freshness policy. Local evidence must remain unchanged through admission. Without the argument, changed-head recovery still fails. Recovery never rebases or bypasses CI, contributor-ancestry, branch, or owner gates. The successor-intent CAS consumes the exact outcome OID, retains the old outcome and objects as ancestry, and records the operator plus the explicit replacement head when supplied; each dispatch has its own capture. Replacement intent also snapshots existing regular capture files in its private Git tree under their original basenames, preserving the bytes through successful worktree cleanup and GC; symlink captures fail closed. Reusing the old outcome OID fails. Never infer authorization from an error string, an OPEN read, or a routine retry, and never clear the outcome ref. - Fresh direct PR/main reads and stable re-reads narrow races; they do not provide global exactly-once execution or a base-OID merge precondition. Immediate squash refuses
NO NET CHANGEwithout claiming the PR merged or all intended content remains present. Normal squash/merge receipts reconstruct the tree at the actual landed parent; merge also requires prepared-head ancestry. Rebase and queue receipts verify the aggregate reviewed delta in the historical landed tree using the unique source fork base of retained main/head, not the final rebased parent or recorded main itself. Missing or ambiguous source bases fail closed. Later main advancement or reverts do not authorize reapplication. A normal recorded squash that was empty at its landed parent warns for investigation; its receipt remains confirmed, with no resubmission or automatic revert. - Worktree cleanup (including GC dry-run and stale-entry provisioning) preserves
.local/merge-output.logat its original path unless the corresponding outcome passes local record and retained-object validation. Empty captures and dangling capture symlinks count. Preserve the worktree, metadata, and local branches for manual reconciliation; do not trash, rename, or manufacture a receipt.CLOSED/MERGEDand an absent process do not resolve dispatch uncertainty. Valid retained outcomes remain available after eligible cleanup; cleanup does not reconcile them or change process-lock recovery. - Before recording intent,
--auto-mergeselects immediate pinned squash forMERGEABLE/CLEANor auto forMERGEABLE/BEHIND, subject to all admission gates and queue policy. Accepted auto/queue requests are visible pending outcomes, not completion. The request carries--match-head-commit; confirmation still requires the exact attempted head. Existing or ambiguous auto/queue requests are never cancelled, re-armed, or followed by an immediate fallback. Ordinarygh pr mergecan enqueue when queue policy applies. - A confirmed merge receipt precedes audits, comments, and cleanup. A comment POST has one attempt marker and is never blindly repeated. Recovery searches authoritative comments for that marker, reports completion pending, and leaves cleanup to the operator after ownership checks; it works without the original worktree/prep artifacts. Normal uninterrupted completion preserves comments and cleanup, with exact-head leased remote deletion. Authoritative branch absence completes cleanup; inspect warnings for advanced or inaccessible branches. Delayed recovery never deletes a recreated branch by name.
- After ownership-checked cleanup, explicitly finish a verified receipt with
scripts/pr merge-complete <PR> <OUTCOME_OID> --confirmed-operator-completion. It revalidates the exact retained receipt and remote merge, requires native worktree/local branch/remote head branch absence, and never dispatches a merge or deletes resources. Amergedreceipt may post its first completion comment;commenting/commentedrequire the existing exact attempt marker and never repost. Missing or ambiguous comments preserve pending state. A first admin-route comment still requires its original landing audit and is not supported by delayed completion. Read the current outcome OID again after a state transition; stale OIDs are refused. Defaultmerge-runremains reconciliation-only.