Skip to main content

sandbox-preflight

At the start of a dispatched lifecycle (runner or bare dispatch), verify the tools you need are in the sandbox allowlist. Fail LOUD on a blocked tool -- do NOT produce a "run this yourself" artifact (the silent-degradation trap). For a known-safe set of common dev tools, auto-heal by adding to .claude/settings.local.json. Anything else: ask the user.

الانتقال إلى التثبيت

معلومات المصدر

المستودع
joshrotenberg/agent-tools
آخر نشاط في المصدر
١٨ يونيو ٢٠٢٦ في ١٩:١٤
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٠
التفرعات
٠

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
sandbox-preflight
description
At the start of a dispatched lifecycle (runner or bare dispatch), verify the tools you need are in the sandbox allowlist. Fail LOUD on a blocked tool -- do NOT produce a "run this yourself" artifact (the silent-degradation trap). For a known-safe set of common dev tools, auto-heal by adding to .claude/settings.local.json. Anything else: ask the user.
allowed-tools
Bash(git *) Bash(gh *)
# Sandbox preflight Before doing any real work, verify that the tools you'll need are actually runnable in the sandbox. The dangerous failure mode this prevents is **silent degradation**: a blocked tool (`gh`, `cargo`, etc.) makes the agent emit an output that *looks* complete -- a "run this command yourself" markdown artifact, or a report full of `BLOCKED` lines -- while no real state changed. The dispatcher gets a "completed" signal and trusts the wrong state. Two work-machine reports surfaced the same root cause: - **roba #112:** the runner returned a "run this yourself" markdown block when `gh` wasn't in the allowlist. Output looked finished; no GitHub state changed; the synchronous-lifecycle "complete" contract silently broke. - **roba #113:** a bare release-audit dispatch ran static checks but couldn't run the build gate (`cargo fmt/clippy/test`, `maturin build`) because those tools weren't allowlisted. It asked "want me to add the allowlist?" as a question and accumulated `BLOCKED` entries instead of acting. Both are sandbox-permission issues. The fix is one discipline: **check first, fail loud, auto-heal the known-safe set, ask for anything else.** ## When to apply - **Runner step 0.** Before fetching the issue, before composing any prompt. Referenced from [`../../agents/runner.md`](../../agents/runner.md). - **Bare dispatches** that will use build tools, `gh`, `git`, or any tool beyond `Read`/`Glob`/`Grep`. The [`orchestration-prompt-template`](../orchestration-prompt-template/SKILL.md) skill should add a pre-flight section near the top of such a prompt's steps. If the work is genuinely read-only (a Q&A or explainer that only needs `Read`/`Glob`/`Grep`), no pre-flight is needed. ## Tools to verify A minimum set the runner always needs: - `gh` -- GitHub CLI (issue / PR / CI-watch operations) - `git` -- branch + commit + push Plus project-detected tools, keyed off files in the repo root: | Detected file | Tools to verify | |---|---| | `Cargo.toml` | `cargo` | | `pyproject.toml` / `setup.py` | `pip`, `uv`, `maturin` (whichever the project references) | | `package.json` | `npm` (and `pnpm` / `yarn` if its lockfile is present) | | `go.mod` | `go` | | `mix.exs` | `mix` | | `pom.xml` | `mvn` | | `build.gradle` / `build.gradle.kts` | `gradle` | | `Makefile` / `build.sh` | `make` / `bash` | Check each by attempting a no-op version probe -- `<tool> --version` (or a tool-appropriate equivalent). If the call is **blocked** by the sandbox (not merely "command not found"), the tool is not in the allowlist. ## Step 0: the write-gate probe Bash allowlisting is only half the surface. A file-mutating dispatch launched in `default` permission mode also hits the **Edit/Write approval gate** on its first write -- "haven't granted it yet" -- and the Bash probes above will not catch it. This is a distinct gate from the Bash allowlist, and it is the most common silent-failure mode for editing dispatches: the session either stalls silently (fire-and-forget no-op, zero work done) or grinds through mechanical bypasses (`touch` + `git apply` heredocs, `tee`, `perl`, `python` redirects) for dozens of turns, producing corrupted output. So before any real edit, **probe the write gate directly** -- exercise the actual Edit/Write tool, not a Bash command: 1. Pick a scratch path the task will touch. If the task creates a **new top-level directory** (e.g. `skills/`, `src/new-module/`), probe a scratch file inside that new directory -- new-directory creation is a distinct write-gate trigger from editing an existing file, and a common one. If the task only edits existing files, probe a scratch path in the task's cwd. 2. Attempt a trivial `Write` to that scratch path (e.g. one line of content). 3. **Expected pass:** the write succeeds. Delete the scratch file and proceed. 4. **Expected fail:** the write returns the approval/permission gate message ("haven't granted", "permission to write", or similar). Treat this exactly like a blocked Bash tool: **fail loud immediately** with the exact gate message and do NOT proceed. The launch configuration is wrong -- the dispatch needs `--full-auto` or `--permission-mode acceptEdits` (or the Task-tool equivalent). Workarounds cannot fix a misconfigured launch. **Discipline (carry this into the run, not just preflight):** if a write is blocked by a permission/approval gate -- not a logic error -- STOP immediately and report the exact gate message. Do NOT attempt mechanical bypasses (`touch` + `git apply`, `perl` redirect, `tee`, `python` script). The launch configuration is wrong; workarounds cannot fix it. ## The fail-loud rule **Never produce a "run this yourself" artifact.** If a tool you need is blocked AND it is not in the auto-heal allowlist below, ABORT the lifecycle with a clear message and do NOT proceed: ``` ABORTED at sandbox preflight: <tool> is not in the sandbox allowlist. To unblock, add the following to .claude/settings.local.json under "permissions.allow": "Bash(<tool>:*)" Then re-dispatch this task. ``` The dispatcher sees an **abort**, not a fake "complete." That is exactly what the synchronous-lifecycle contract requires for trust: a blocked run is a legitimate hand-back, not a silently degraded success. ## Auto-heal allowlist For these well-known dev tools, self-heal by adding the appropriate `Bash(<tool>:*)` entry to `.claude/settings.local.json` instead of aborting: - `gh`, `git` - `cargo` (when `Cargo.toml` is present) - `npm`, `pnpm`, `yarn` (when `package.json` is present) - `pip`, `uv`, `maturin` (when `pyproject.toml` / `setup.py` is present) - `go` (when `go.mod` is present) - `mix` (when `mix.exs` is present) - `mvn` (when `pom.xml` is present) - `gradle` (when `build.gradle` or `build.gradle.kts` is present) - `make`, `bash`, `sh` (always -- they're the universal build glue) Self-healing is a **contained** action: it writes a single allowlist entry, surfaces what it added in the return summary, and proceeds. The user sees the addition in the returned report -- nothing happens silently. Anything outside this list: **ASK the user before adding.** Tools like `docker`, `kubectl`, `terraform`, or custom scripts are security-sensitive enough to require explicit consent. Don't auto-heal them; surface the need and wait. ## What to surface - **Pre-flight passes cleanly:** say nothing; proceed. - **Pre-flight self-heals:** include in the return summary `Auto-healed: added Bash(<tool>:*) to .claude/settings.local.json`. - **Pre-flight aborts:** emit the ABORT message above; do NOT proceed with the rest of the lifecycle. ## Anti-patterns - Producing "run this yourself" artifacts when a tool is blocked -- the dispatcher gets a fake "complete" signal. - Silently degrading to a partial run when a needed tool is missing from the allowlist -- abort loudly instead. - Auto-healing tools outside the known-safe list (docker, kubectl, terraform) -- these require explicit user consent. - Probing only Bash allowlisting and skipping the Step 0 write-gate probe -- a `default`-mode editing dispatch passes the Bash checks then stalls or corrupts on the first blocked Edit/Write. - Grinding through mechanical write bypasses (`touch` + `git apply`, `tee`, `perl`, `python` redirect) after a blocked write -- the launch config is wrong; STOP and report the gate message instead. ## Related - [`runner-synchronous-lifecycle`](../runner-synchronous-lifecycle/SKILL.md) -- why a blocked run must hand back honestly instead of returning a fake "complete." - [`orchestration-prompt-template`](../orchestration-prompt-template/SKILL.md) -- where to put the pre-flight section in a bare-dispatch prompt. - [`spiral-diagnosis`](../spiral-diagnosis/SKILL.md) -- the other "the run looked busy but produced nothing real" failure mode.
عرض على GitHub