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
최근 소스 활동
2026년 6월 18일 19:14
감지된 SKILL.md 언어
영어
스타
0
포크
0

설치 방법

기본적으로 소스를 먼저 확인하는 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에서 보기