agents/openai.yaml
interface:
display_name: "AI Coding Agents — Execution Sandbox"
short_description: "Design sandbox and isolation models for coding agents"
default_prompt: "Use $ai-coding-agents-execution-sandbox to design process isolation, filesystem policy, network controls, workspace mounts, or destructive-command boundaries for a coding-agent runtime."
data/sources.json
{
"metadata": {
"skill": "ai-coding-agents-execution-sandbox",
"title": "AI Coding Agents Execution Sandbox - Sources",
"description": "Official documentation and implementation references for sandboxing, process isolation, filesystem policy, network controls, and execution safety in coding-agent runtimes",
"last_updated": "2026-07-11",
"updated": "2026-07-11",
"total_sources": 12,
"version": "1.1"
},
"categories": {
"official_documentation": [
{
"name": "Claude Code Documentation",
"url": "https://code.claude.com/docs/en/",
"type": "documentation",
"relevance": "Primary product documentation for runtime execution, approvals, and local operating model",
"update_frequency": "monthly",
"access": "free",
"add_as_web_search": true
},
{
"name": "Claude Code — Configure the sandboxed Bash tool",
"url": "https://code.claude.com/docs/en/sandboxing",
"type": "documentation",
"relevance": "Primary source for the shipping Bash sandbox: settings.json keys, mode names, platform backends, credential deny/mask, TLS-blind allowlist caveat, and documented compatibility failures. Fetched and cross-checked 2026-07-11.",
"update_frequency": "monthly",
"access": "free",
"add_as_web_search": true
},
{
"name": "OpenAI Codex — Sandboxing concept doc",
"url": "https://developers.openai.com/codex/concepts/sandboxing",
"type": "documentation",
"relevance": "Primary source for Codex sandbox mode names (read-only/workspace-write/danger-full-access) and the separate approval-policy axis (untrusted/on-request/never). Fetched and cross-checked 2026-07-11.",
"update_frequency": "monthly",
"access": "free",
"add_as_web_search": true
},
{
"name": "Model Context Protocol Specification",
"url": "https://modelcontextprotocol.io/",
"type": "specification",
"relevance": "Reference for tool and server capability boundaries when execution crosses process or transport layers",
"update_frequency": "quarterly",
"access": "free",
"add_as_web_search": true
}
],
"implementation_references": [
{
"name": "Claude Code GitHub Repository",
"url": "https://github.com/anthropics/claude-code",
"type": "repository",
"relevance": "Primary implementation reference for sandbox mode, working-directory boundaries, and approval integration",
"update_frequency": "weekly",
"access": "free",
"add_as_web_search": false
},
{
"name": "Codex CLI Repository",
"url": "https://github.com/openai/codex",
"type": "repository",
"relevance": "Cross-runtime comparison point for command execution, approvals, and sandbox boundaries",
"update_frequency": "monthly",
"access": "free",
"add_as_web_search": false
},
{
"name": "OpenAI Codex Core Sandbox Support Matrix",
"url": "https://github.com/openai/codex/blob/9f42c89c0112771dc29100a6f3fc904049b2655f/codex-rs/core/README.md",
"type": "repository_source",
"relevance": "Pinned first-party source for macOS Seatbelt, Linux Landlock/bubblewrap, Windows sandbox backend, split policy fallback, and fail-closed behavior",
"update_frequency": "pinned",
"access": "free",
"add_as_web_search": false
},
{
"name": "OpenAI: Building a safe, effective sandbox to enable Codex on Windows",
"url": "https://openai.com/index/building-codex-windows-sandbox/",
"type": "engineering_post",
"relevance": "May 2026 first-party explanation of sandbox design tradeoffs, useful defaults, full-access risk, and process-tree enforcement",
"update_frequency": "static",
"access": "free",
"add_as_web_search": true
}
],
"security_references": [
{
"name": "OWASP Application Security Verification Standard",
"url": "https://owasp.org/www-project-application-security-verification-standard/",
"type": "standard",
"relevance": "Useful security baseline for least privilege, environment separation, and command execution boundaries",
"update_frequency": "yearly",
"access": "free",
"add_as_web_search": true
},
{
"name": "OWASP Docker Security Cheat Sheet",
"url": "https://cheatsheetseries.owasp.org/cheatsheets/Docker_Security_Cheat_Sheet.html",
"type": "guide",
"relevance": "Practical isolation patterns when coding-agent execution uses containers or microVMs",
"update_frequency": "quarterly",
"access": "free",
"add_as_web_search": true
}
],
"goose_aaif_references": [
{
"name": "Goose moves to the Agentic AI Foundation (AAIF)",
"url": "https://goose-docs.ai/blog/2026/04/07/goose-moves-to-aaif/",
"type": "announcement",
"relevance": "April 7, 2026 post documenting transfer of goose from Block to AAIF (Linux Foundation). Repository moved to aaif-goose/goose, documentation to goose-docs.ai.",
"update_frequency": "static",
"access": "free",
"add_as_web_search": false
},
{
"name": "OpenTelemetry GenAI Agent Spans Semantic Conventions",
"url": "https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-agent-spans/",
"type": "specification",
"relevance": "Experimental OTel spec for gen_ai agent spans: gen_ai.operation.name, gen_ai.agent.name/id/version, tool child spans gen_ai.tool.name / gen_ai.tool.call.id. Relevant to sandbox denial events and agent-span observability.",
"update_frequency": "quarterly",
"access": "free",
"add_as_web_search": true
}
]
}
}
learnings.consolidated.md
# ai-coding-agents-execution-sandbox — Consolidated Learnings
Curated, dated, committed memory for this skill. Pruned from raw `learnings.md` via `agents-skills-feedback-loop/scripts/consolidate.py`. Human-approved.
Cap: 60 entries. When exceeded, promote durable rules to `references/`.
## Filter Override
<!-- Add 2-4 bullets that sharpen what counts as a learning for this skill. Leave empty to use the default filter from agents-skills-feedback-loop/references/learnings-format.md. -->
## Patterns That Work
## Mistakes to Avoid
## Domain Knowledge
## Open Questions
## Consolidated Principles
learnings.md
# ai-coding-agents-execution-sandbox — Raw Learnings
- 2026-07-11: July 2026 audit pass (web-verified against code.claude.com/docs/en/sandboxing and developers.openai.com/codex/concepts/sandboxing). Two concrete facts worth remembering for future edits: (1) Claude Code's Bash sandbox has a real read/write default asymmetry — write defaults to cwd + temp, but read defaults to the whole filesystem except a denylist, which still permits reading `~/.aws/credentials` and `~/.ssh/` unless `sandbox.credentials` or explicit `denyRead` closes it; this is an easy, non-obvious gap to miss when auditing a sandbox config. (2) Both Claude Code and Codex enforce their sandbox on a narrow tool surface (Bash / exec) only — Read/Edit/Write/WebFetch/computer-use go through the separate permission system, not the process sandbox, so "the agent is sandboxed" is a category error unless scoped to a tool class. Also confirmed the reference doc's cited Codex source (`codex-rs/core/README.md`, pinned commit) is not fabricated — its content matches the current `main` branch and the public sandboxing concept doc.
references/claude-code-bash-sandbox-mechanics.md
# Claude Code Bash Sandbox Mechanics
Source: `code.claude.com/docs/en/sandboxing`, checked 2026-07-11. Version-gated features are marked with the Claude Code release that introduced them; verify against the live doc before treating a gate as current, since these move with point releases.
## Table of Contents
- [Scope: Bash Only](#scope-bash-only)
- [Two Independent Modes](#two-independent-modes)
- [Platform Backends](#platform-backends)
- [Default Read/Write Asymmetry](#default-readwrite-asymmetry)
- [Settings Keys](#settings-keys)
- [Credential Protection: Deny Vs Mask](#credential-protection-deny-vs-mask)
- [Network: Allowlist Without TLS Inspection](#network-allowlist-without-tls-inspection)
- [The Escape Hatch](#the-escape-hatch)
- [Known Compatibility Failures](#known-compatibility-failures)
- [Known Traps](#known-traps)
## Scope: Bash Only
The sandbox is not a runtime-wide isolation boundary. It restricts Bash subprocesses (and their children) at the OS level. Read, Edit, Write, WebFetch, MCP tools, and computer-use each go through the ordinary permission-rule system instead, and computer-use runs on the real desktop, not inside an isolation boundary. A design that assumes "sandboxed" implies protection for every tool call is wrong; audit each tool class separately.
Subagents run in the same process as the parent session and inherit its sandbox configuration — a subagent cannot have a wider Bash sandbox than its parent.
## Two Independent Modes
`/sandbox` exposes a mode axis (auto-allow vs. regular permissions) that is deliberately separate from permission modes (default, auto, `--dangerously-skip-permissions`):
- **Auto-allow**: sandboxed Bash commands run without a prompt because the OS boundary contains them. Explicit deny rules, `rm`/`rmdir` against `/` or the home directory, and content-scoped ask rules (e.g. `Bash(git push *)`) still force a prompt even in auto-allow.
- **Regular permissions**: every Bash command still goes through the normal prompt flow even though it also runs sandboxed.
Do not conflate this with the model's own "auto mode," which uses a classifier to decide whether to prompt at all — the two axes compose independently.
## Platform Backends
- **macOS**: Seatbelt, built in, nothing to install.
- **Linux and WSL2**: bubblewrap (filesystem isolation) plus socat (network relay to the sandbox proxy); both must be installed by the user. An optional seccomp filter (installed via `npm install -g @anthropic-ai/sandbox-runtime`) adds Unix-domain-socket blocking.
- **WSL1 and native Windows**: unsupported. Windows users must run inside a WSL2 distribution.
- Ubuntu 24.04+ ships an AppArmor policy that blocks bubblewrap's unprivileged user-namespace creation; a dedicated `bwrap` AppArmor profile is required as a workaround (see the live doc for the exact profile).
## Default Read/Write Asymmetry
Write access defaults to narrow (current working directory plus the session temp directory). Read access defaults to broad (the entire filesystem except a denylist) — and that default still permits reading `~/.aws/credentials` and `~/.ssh/`. A sandbox with locked-down writes but stock read defaults is not a secrets boundary; it must be paired with `sandbox.credentials` or explicit `denyRead` entries to actually protect credential files.
## Settings Keys
All keys live under the `sandbox` object in `settings.json` (merged across managed/project/local/user scopes; project wins on conflict for scalars, arrays merge):
| Key | Purpose |
|---|---|
| `sandbox.enabled` | Turn the sandbox on for the scope |
| `sandbox.failIfUnavailable` | Hard-fail startup instead of silently running unsandboxed when a dependency is missing (use in managed settings) |
| `sandbox.allowUnsandboxedCommands` | Set `false` for "strict sandbox mode" — disables the retry-outside-sandbox escape hatch entirely |
| `sandbox.excludedCommands` | Commands that always run outside the sandbox (e.g. `docker *`) |
| `sandbox.filesystem.allowWrite` / `denyWrite` | Widen or narrow writable paths beyond cwd + temp |
| `sandbox.filesystem.denyRead` / `allowRead` | Narrow readable paths, then re-open specific paths within a denied region |
| `sandbox.credentials.files[].mode` | `"deny"` — block reads of a credential file inside the sandbox |
| `sandbox.credentials.envVars[].mode` | `"deny"` (unset) or `"mask"` (sentinel substitution, see below) |
| `sandbox.network.allowedDomains` / `deniedDomains` | Domain allowlist/denylist for the sandbox network proxy |
| `sandbox.network.allowManagedDomainsOnly` | Managed-settings-only lockdown: non-managed `allowedDomains` entries are ignored, unlisted domains are blocked instead of prompted |
| `sandbox.network.tlsTerminate` | Experimental: proxy terminates TLS itself; required for `mask` credential substitution |
| `sandbox.allowManagedReadPathsOnly` | Managed-settings-only lockdown for `allowRead` |
| `sandbox.allowAppleEvents` | macOS only; lifts the Apple Events block but removes code-execution isolation (see Known Traps) |
Settings files themselves (`settings.json` at every scope, plus the managed settings directory) are always write-denied inside the sandbox — a sandboxed command cannot rewrite its own policy.
## Credential Protection: Deny Vs Mask
`deny` removes a credential entirely from the sandboxed process — simplest, but breaks tools that need the value (`gh`, `npm`). `mask` substitutes a per-session sentinel; the real value is injected only when a request leaves the sandbox for a host listed in `injectHosts`, and only if `network.tlsTerminate` is configured (otherwise the sentinel reaches the server unchanged and auth fails — Claude Code reports this at startup rather than failing silently). `mask` entries, `tlsTerminate`, and `credentials.allowPlaintextInject` are honored only from user/managed/CLI settings — a repo's own `.claude/settings.json` cannot enable credential injection for itself.
## Network: Allowlist Without TLS Inspection
By default the sandbox's built-in proxy makes its allow/deny decision from the client-supplied hostname (SNI/Host header) and does not terminate or inspect TLS. Allowing a broad domain such as `github.com` can therefore be defeated by domain fronting or similar techniques that reach a different host behind the same front. Treat a domain allowlist as connectivity policy, not as a content-inspection boundary, unless `network.tlsTerminate` plus a custom inspecting proxy is in place.
## The Escape Hatch
When a sandboxed command fails because of the sandbox boundary, Claude Code can retry it with `dangerouslyDisableSandbox`, which routes the retry through the ordinary permission prompt instead of failing the task. This is a deliberate escalation path, not a silent fallback — but it does mean "the sandbox blocked it" is not the end of the story unless `allowUnsandboxedCommands: false` is set.
## Known Compatibility Failures
- `jest` hangs under the sandbox when `watchman` is present — run with `--no-watchman`.
- `docker` is fully incompatible — exclude it rather than trying to make it work inside the sandbox.
- Go-based CLIs (`gh`, `gcloud`, `terraform`) can fail TLS verification under macOS Seatbelt — exclude them or address it via `enableWeakerNetworkIsolation` only if a MITM proxy with a custom CA is already in play.
- On WSL2, the sandbox blocks calls out to Windows binaries (`cmd.exe`, `powershell.exe`, `/mnt/c/...`) because WSL hands them off over a Unix socket the sandbox blocks; add them to `excludedCommands` if a workflow genuinely needs them.
- `open`/`osascript`/browser-based auth flows fail with macOS error `-600` because Apple Events are blocked by default.
## Known Traps
- Assuming "sandboxed" covers every tool call — it covers Bash only.
- Treating the read-access default as equivalent to the write-access default; they are not symmetric, and the gap leaks credential files unless explicitly closed.
- Enabling `allowAppleEvents` to fix a broken `open`/`osascript` call without registering that it removes code-execution isolation on macOS (sandboxed commands can then launch other unsandboxed applications and drive them via AppleScript, gated only by the OS's own automation-consent prompt).
- Allowing a Unix domain socket such as `/var/run/docker.sock` through `allowUnixSockets`, which is equivalent to granting host access through the Docker daemon.
- Believing a domain allowlist inspects content; without `tlsTerminate` it only checks the requested hostname.
references/escape-path-test-matrix.md
# Escape-Path Test Matrix
Checklist of sandbox escape attacks to verify before shipping any execution sandbox. Run against every new sandbox configuration, every interpreter upgrade, and every network-policy change.
---
## How to Use
For each row: mark **Status** as `pass`, `fail`, or `skip` (with reason). A sandbox is not shippable until all non-skipped rows are `pass`. Re-run after any change to the allowlist, mount points, or interpreter set.
---
## 1. Symlink Attacks
Goal: traverse outside the allowed filesystem root by following symlinks.
| ID | Attack | Description | Expected Result | Resolution if Failing |
|----|--------|-------------|-----------------|----------------------|
| SYM-01 | Absolute symlink outside sandbox root | Create a symlink pointing to `/etc/passwd` inside the sandbox work dir, then read it | Read blocked by mount namespace or realpath check | Add realpath normalization before every file open; reject paths resolving outside the allowed tree |
| SYM-02 | Relative symlink traversal (`../../../`) | Create a symlink with a `..`-heavy target pointing to `/etc/shadow` | Blocked | Resolve symlinks before path permission check; do not check the link itself |
| SYM-03 | Symlink to a device file | Create a symlink targeting `/dev/sda` inside the sandbox | Blocked — device file outside allowed types | Disallow device-type files in allowed path list; mount with `nodev` |
| SYM-04 | Symlink chain to allowed path that later escapes | Create a chain where the final target escapes the sandbox root | Blocked at chain resolution | Limit symlink depth (e.g. ≤ 8) and re-check final target after each hop |
---
## 2. Shell and Interpreter Wrappers
Goal: escape by invoking a different binary that bypasses the allowlist.
| ID | Attack | Description | Expected Result | Resolution if Failing |
|----|--------|-------------|-----------------|----------------------|
| INT-01 | Calling an unlisted interpreter via PATH | Invoke `perl` (not in allowlist) to shell out to a host command | Blocked — execve denied for unlisted binary | Enforce execve allowlist via seccomp or ptrace; PATH alone is insufficient |
| INT-02 | Invoking interpreter via absolute path | Run an unlisted interpreter using its full path rather than its name | Blocked if binary not in allowlist | Allowlist must be path-based, not name-based |
| INT-03 | Using `env` to indirectly exec | Use the `env` utility to launch an unlisted interpreter | Blocked | `env` itself should be scrutinized; deny exec of unlisted binaries launched from it |
| INT-04 | SUID binary escalation | Call any SUID binary present in the sandbox image | No SUID binaries present | Build images with zero SUID binaries; mount with `nosuid` |
| INT-05 | Script shebang bypass | Write a script whose shebang line points to an unlisted interpreter | Blocked — shebang interpreter not in allowlist | Shebang execution must respect the interpreter allowlist |
---
## 3. Environment Variable Injection
Goal: manipulate sandbox behavior by injecting or overriding env vars.
| ID | Attack | Description | Expected Result | Resolution if Failing |
|----|--------|-------------|-----------------|----------------------|
| ENV-01 | `LD_PRELOAD` injection | Set `LD_PRELOAD` to a hostile shared library before exec | Ignored — `LD_PRELOAD` stripped from child env | Strip `LD_PRELOAD`, `LD_LIBRARY_PATH`, `LD_AUDIT` before exec |
| ENV-02 | `PYTHONPATH` / `NODE_PATH` injection | Override module search path to a directory containing a hostile module | Hostile module not loaded | Reset or whitelist interpreter-specific path vars |
| ENV-03 | `HOME` override to writable path | Set `HOME=/tmp`; tools that auto-write to `~/.config` now write outside sandbox | Writes contained inside sandbox root | Validate `HOME` and `XDG_*` vars; map them to sandbox-scoped paths |
| ENV-04 | `TMPDIR` redirect outside sandbox | Point `TMPDIR` to a host path mounted read-write | Writes land inside sandbox | Override `TMPDIR` to a sandbox-internal temp dir |
| ENV-05 | `PATH` injection of hostile binary | Prepend `/tmp` to `PATH`; place a hostile shim named after a trusted binary | Shim blocked by execve allowlist | Enforce execve allowlist; do not rely solely on `PATH` ordering |
---
## 4. Package-Manager Network Calls
Goal: exfiltrate data or fetch hostile packages via package-manager side channels.
| ID | Attack | Description | Expected Result | Resolution if Failing |
|----|--------|-------------|-----------------|----------------------|
| NET-01 | `pip install` to arbitrary registry | Install from a non-approved index URL | Blocked — outbound HTTP to non-approved host denied | Network egress policy: allow only approved registry hosts; use `--no-index` flag by default |
| NET-02 | `npm install` with `postinstall` script | Install a package whose `postinstall` runs a network call | Network call blocked | Both exec and network allowlists must be enforced during install |
| NET-03 | `cargo fetch` to unapproved registry | Run `cargo fetch` when crates.io is not approved | Blocked or routed through approved mirror | Add approved registries to network allowlist; block others |
| NET-04 | DNS exfiltration via package registry lookup | Craft a package name that encodes data in its DNS query | DNS to non-approved resolver blocked | Block DNS to non-approved resolvers; use internal DNS with logging |
| NET-05 | Build-time arbitrary code via `setup.py` | Install a package whose build script calls out to the network | Blocked by exec allowlist or network block | Combine exec and network allowlists; pre-vet wheels and disable network during install |
---
## 5. Additional Attack Surface (extend as needed)
| ID | Area | Note |
|----|------|------|
| PROC-01 | `/proc` self-maps | Ensure `/proc` is not mounted or is mount-masked |
| PROC-02 | Ptrace of sibling process | Deny `ptrace` via seccomp `PTRACE_ATTACH` block |
| FS-01 | Bind-mount inside sandbox | Deny `mount` syscall via seccomp |
| FS-02 | `chroot` / `pivot_root` inside sandbox | Deny via seccomp |
| SOCK-01 | Unix domain socket to host | Only permit sockets within sandbox network namespace |
---
## Pass Criteria
A sandbox passes this matrix when:
- Every `SYM-*` and `ENV-*` row returns the expected block.
- Every `INT-*` row returns a block for binaries absent from the interpreter allowlist.
- Every `NET-*` row returns a block or redirect through the approved egress policy.
- No test results in data exfiltration, privilege escalation, or filesystem access outside the sandbox root.
references/network-approval-and-destructive-action-guards.md
# Network, Approval, And Destructive-Action Guards
Sandbox design fails when network and destructive actions are treated as afterthoughts.
## Network policy
Model outbound access explicitly:
- no network
- host allowlist
- package-manager exceptions
- unrestricted after approval
Do not bundle network access into the generic “dangerous command” bucket. Package install, API calls, git fetch, and browser verification often need different policies.
## Destructive-action classes
Create explicit classes for:
- file deletion
- force reset or checkout
- privileged execution
- branch or remote mutation
- workspace cleanup outside owned roots
Each class should map to either:
- deny
- allow in safe scope
- require approval
## Guard design rules
- Detect dangerous intent before the shell runs.
- Treat shell control operators, redirection, and nested execution carefully.
- Make policy outcomes explainable to the user and traceable in telemetry.
- Re-run failed-but-important actions with explicit escalation rather than silently weakening the sandbox.
## Edge cases
- **Destructive command through helper script**: classify the effective action, not just the wrapper name.
- **Network needed after sandbox failure**: escalation should be deliberate and visible, not an automatic fallback.
- **Background worker prompts**: if workers cannot surface approval, they need a safe escalation path back to the lead or UI.
- **Prefix approvals**: keep persistent command approvals narrow enough that they do not become an accidental escape hatch.
## Practical tip
Users trust a coding agent more when “denied,” “allowed,” and “needs approval” feel mechanically consistent. That consistency is a product feature, not just a security feature.
## TLS-blind allowlists are a real exfiltration path
A network policy that allows a domain by hostname but does not terminate or inspect TLS is a connectivity control, not a content-inspection boundary — a broad allowed host can be abused via domain fronting or similar techniques to reach a different destination behind the same front. Do not describe hostname-only allowlisting as "network isolation" without that caveat. If content inspection matters for the threat model, TLS termination at the proxy (with the sandbox trusting a proxy-issued CA) is a separate, opt-in control that most default sandbox proxies do not enable. See [`claude-code-bash-sandbox-mechanics.md`](claude-code-bash-sandbox-mechanics.md) for a concrete example of this tradeoff, including how credential masking depends on the same TLS-termination control.
references/openai-codex-sandbox-guardrails-may-2026.md
# OpenAI Codex Sandbox Guardrails May 2026
Source snapshot: OpenAI Codex `codex-rs/core/README.md` (commit `9f42c89c0112771dc29100a6f3fc904049b2655f`, 2026-05-24), `codex-rs/linux-sandbox`, `codex-rs/windows-sandbox-rs`, and `codex-rs/protocol/src/permissions.rs`. Re-verified against the current `codex-rs/core/README.md` on `main` and `developers.openai.com/codex/concepts/sandboxing` on 2026-07-11 — the mode names, backend split, and fail-closed behavior below still match.
Web sources checked 2026-05-25 (re-checked 2026-07-11):
- OpenAI, "Building a safe, effective sandbox to enable Codex on Windows", May 13, 2026: https://openai.com/index/building-codex-windows-sandbox/
- OpenAI, "Running Codex safely at OpenAI": https://openai.com/index/running-codex-safely/ (exact publish date not independently confirmable as of this pass; treat the date as approximate, not the content)
- OpenAI, Codex sandboxing concept doc: https://developers.openai.com/codex/concepts/sandboxing
## Table Of Contents
- [Sandbox Modes](#sandbox-modes)
- [Design Goal](#design-goal)
- [Default Useful Sandbox](#default-useful-sandbox)
- [Platform Backends](#platform-backends)
- [Fail-Closed Policy Translation](#fail-closed-policy-translation)
- [Security Telemetry](#security-telemetry)
- [Known Traps](#known-traps)
## Sandbox Modes
Codex names three modes explicitly — copy these names when mapping a runtime's own modes onto the Codex model, since "sandbox mode" and "approval policy" are separate axes here too:
- **`read-only`**: inspect files; no writes, no command execution without approval.
- **`workspace-write`** (default): read broadly, write only inside the workspace, run routine commands inside that boundary.
- **`danger-full-access`**: no filesystem or network restriction — treat as equivalent to disabling the sandbox, not as a stronger permission tier.
Approval policy is orthogonal: `untrusted`, `on-request` (default), `never`. A `workspace-write` sandbox with `never` approvals is a materially different posture than `workspace-write` with `untrusted` — audit both axes, not just the sandbox mode name.
## Design Goal
The sandbox should be useful enough that developers do not disable it, while still enforcing real process, filesystem, and network boundaries. OpenAI's May 2026 Windows write-up frames the bad alternatives clearly: approving nearly every command is too slow, while full access removes the boundary.
## Default Useful Sandbox
Codex's public sandbox framing is a practical default:
- read broadly enough to inspect code and dependencies
- write only inside the workspace
- deny internet access unless explicitly enabled
- propagate constraints down the process tree
Copy the product principle, not only the implementation: a default sandbox must let normal build/test/edit loops work without training users to reach for full access.
## Platform Backends
Codex uses different enforcement backends per platform:
- macOS: Seatbelt via `sandbox-exec`; workspace-write policy keeps `.git` and `.codex` read-only even inside writable roots.
- Linux and WSL2: bubblewrap (`bwrap`) is the primary backend — Codex prefers the first `bwrap` found on `PATH`, with a bundled fallback helper; Landlock remains for legacy-compatible policies. WSL1 is rejected outright (bubblewrap needs kernel features WSL1 lacks).
- Windows: two backends, not one — an **elevated** backend supporting split filesystem policies (needs system read roots such as `C:\Windows` to run at all) and an **unelevated, restricted-token** backend for simpler/legacy configurations. Native Windows in PowerShell uses the Windows-native backend; running Codex inside WSL2 uses the Linux backend instead.
Keep a backend capability matrix. Do not assume a policy that works on macOS can be enforced the same way on Windows or Linux, and do not assume "Windows" is a single backend — elevated and unelevated Windows sandboxes have different capabilities.
## Fail-Closed Policy Translation
Codex keeps legacy sandbox modes but translates newer split filesystem policies only when semantics are preserved. Policies that cannot be enforced directly or round-trip safely should fail closed.
Required tests:
- writable root with read-only child
- denied parent with writable reopened descendant
- symlink and junction traversal
- protected metadata under writable roots
- missing helper binary fallback
- unsupported Windows/WSL backend behavior
## Security Telemetry
OpenAI's safety post emphasizes agent-native telemetry: user prompt, approval decisions, tool results, MCP usage, and network proxy decisions. Sandbox denials should be observable as first-class security events, not just stderr text.
Design implication:
- emit structured sandbox denial events
- include network allow/deny/prompt decisions
- keep enough context for a security triage agent to distinguish expected behavior, benign mistakes, and suspicious activity
## Known Traps
- Treating "sandboxed" as a single boolean.
- Silently weakening a policy when a platform backend cannot enforce it.
- Making the sandbox so restrictive that users switch to full access for ordinary work.
- Logging process execution without the prompt, approval, or network-policy context that explains why it happened.
- Forgetting descendant processes: a sandbox that does not propagate is not a coding-agent sandbox.
references/sandbox-policy-format.md
# Sandbox Policy Format
Documents the canonical format for expressing an execution sandbox's interpreter allowlist and filesystem/network policy. This format is runtime-agnostic: it describes what a policy must specify; translating it to seccomp BPF, macOS sandbox-exec profiles, or container OCI specs is a separate step.
## Table of Contents
- [Policy File Structure](#policy-file-structure)
- [Field Reference](#field-reference)
- [Common Traps](#common-traps)
---
## Policy File Structure
A sandbox policy is a single TOML file (or equivalent JSON/YAML) stored at `.agent/sandbox-policy.toml` (project-level) or `~/.agent/sandbox-policy.toml` (user-level). Project policy is merged with user policy; project wins on conflict.
```toml
# sandbox-policy.toml
[meta]
version = "1"
description = "Sandbox policy for the coding-agent session"
# ── Interpreter allowlist ──────────────────────────────────────────────────────
# Each entry specifies a binary path (exact) that may be exec'd.
# Glob paths are NOT supported — exact paths only, to prevent wildcard escapes.
# The list is checked against the resolved realpath of the target binary.
#
# Trap: listing a directory rather than a binary allows any binary inside it.
# Resolution: always list the specific binary path.
[[interpreters]]
path = "/usr/bin/bash"
version = ">=5.0" # advisory; enforced only if version_check = true below
[[interpreters]]
path = "/usr/bin/python3"
version = ">=3.11"
[[interpreters]]
path = "/usr/bin/node"
version = ">=20.0"
[[interpreters]]
path = "/usr/local/bin/rg" # ripgrep — read-only tool, no shell
[interpreters_policy]
version_check = false # set true to enforce version constraints above
deny_unlisted = true # deny exec of any binary not in [[interpreters]]
shebang_follows = true # shebang interpreter must also be in allowlist
# ── Filesystem policy ─────────────────────────────────────────────────────────
# allowed_read : paths the agent may open for reading
# allowed_write : paths the agent may open for writing (implies read)
# denied : explicit deny; takes precedence over allowed_* above
[filesystem]
sandbox_root = "/sandbox" # all relative paths are anchored here
resolve_symlinks = true # always resolve symlinks before checking
max_symlink_depth = 8
allowed_read = [
"/sandbox",
"/usr/lib",
"/usr/share",
"/etc/localtime",
"/etc/resolv.conf", # DNS resolver lookup only
]
allowed_write = [
"/sandbox/work",
"/sandbox/tmp",
]
denied = [
"/etc/passwd",
"/etc/shadow",
"/proc",
"/sys",
"/dev",
"/root",
"/home",
]
# ── Network policy ────────────────────────────────────────────────────────────
# egress_allow : CIDR or hostname patterns permitted for outbound connections
# dns_resolvers: only these resolvers may be queried
# Trap: allowing "*.pypi.org" permits subdomain takeover; use exact hostnames.
# Resolution: list exact hostnames or narrow CIDR ranges.
[network]
allow_egress = false # default deny; entries below override per-host
[[network.egress_allow]]
host = "pypi.org"
port = 443
protocol = "tcp"
[[network.egress_allow]]
host = "files.pythonhosted.org"
port = 443
protocol = "tcp"
[[network.egress_allow]]
host = "registry.npmjs.org"
port = 443
protocol = "tcp"
[network.dns]
resolvers = ["127.0.0.1"] # internal resolver only
log_queries = true
block_data_exfil = true # block DNS names > 63 chars per label (common exfil pattern)
# ── Environment variable policy ───────────────────────────────────────────────
[env]
# Variables to strip before exec (injection vectors)
strip = [
"LD_PRELOAD",
"LD_LIBRARY_PATH",
"LD_AUDIT",
"PYTHONPATH",
"NODE_PATH",
"RUBYLIB",
"PERL5LIB",
]
# Variables to force-set (override anything the caller provides)
[env.force]
TMPDIR = "/sandbox/tmp"
HOME = "/sandbox/home"
PATH = "/usr/local/bin:/usr/bin:/bin"
```
---
## Field Reference
### `[interpreters_policy]`
| Field | Type | Default | Meaning |
|-------|------|---------|---------|
| `version_check` | bool | `false` | If `true`, reject a binary whose reported version does not satisfy the `version` constraint |
| `deny_unlisted` | bool | `true` | Reject `execve` for any binary not in `[[interpreters]]` |
| `shebang_follows` | bool | `true` | A script's shebang interpreter must also appear in `[[interpreters]]` |
### `[filesystem]`
| Field | Type | Meaning |
|-------|------|---------|
| `sandbox_root` | string | All relative paths resolved against this root |
| `resolve_symlinks` | bool | Resolve symlinks before permission check (must be `true`) |
| `max_symlink_depth` | int | Maximum symlink chain length before abort |
| `allowed_read` | string[] | Paths open for read (prefix match after realpath) |
| `allowed_write` | string[] | Paths open for write (implies read) |
| `denied` | string[] | Explicit deny; overrides `allowed_*` |
### `[network]`
| Field | Type | Meaning |
|-------|------|---------|
| `allow_egress` | bool | Master egress switch; `false` = default deny |
| `egress_allow[].host` | string | Exact hostname (no globs) |
| `egress_allow[].port` | int | TCP/UDP port |
| `egress_allow[].protocol` | string | `"tcp"` or `"udp"` |
| `dns.resolvers` | string[] | Permitted DNS resolver IPs |
| `dns.log_queries` | bool | Log all DNS queries for audit |
| `dns.block_data_exfil` | bool | Block DNS labels > 63 chars |
---
## Common Traps
**Trap:** Listing `/usr/bin` in `allowed_read` exposes all binaries to read and copy.
**Resolution:** Only include specific binaries in `[[interpreters]]`; do not add interpreter directories to `allowed_read`.
**Trap:** Using glob patterns for `egress_allow` hosts.
**Resolution:** Use exact hostnames only. Globs allow subdomain takeover and can be exploited via crafted DNS.
**Trap:** Forgetting to strip `LD_PRELOAD` before exec allows attacker-controlled shared libraries to run inside the allowed binary.
**Resolution:** The `[env].strip` list is mandatory; do not omit it even for "trusted" binaries.
**Trap:** Symlink-resolved path falls inside `allowed_write` but the symlink target is outside the sandbox root.
**Resolution:** `resolve_symlinks = true` and check resolved path against `sandbox_root` prefix before allow.
references/sandbox-process-and-filesystem-model.md
# Sandbox Process And Filesystem Model
Start by defining explicit execution modes rather than one vague “sandboxed” state.
Typical modes:
- **read-only**: inspect files and run safe commands without writes
- **workspace-write**: writes allowed only inside the active workspace or allowlisted roots
- **restricted-network**: workspace-write plus outbound network denied or narrowly scoped
- **unrestricted**: full local execution after explicit approval
- **worker-reduced**: child tasks inherit a narrower subset of the parent envelope
## Filesystem boundary rules
- Resolve symlinks before policy checks.
- Check both the target path and the effective working directory.
- Keep writable roots explicit.
- Treat temporary directories as separate policy objects, not as hidden global escape hatches.
- Do not assume shell glob expansion preserves safe path boundaries.
## Process model
- Classify commands by risk before execution.
- Keep interpreters and shells under the same policy system as direct binaries.
- Prefer a central command runner so policy checks, telemetry, and cancellation live in one place.
- Make background workers inherit a reduced envelope by default.
## Edge cases
- **Path traversal through symlinked workspace content**: resolve real paths before approval or execution.
- **Relative working-directory escapes**: a safe command in the wrong cwd can become unsafe.
- **Tool wrappers**: wrapper tools must not silently bypass the command policy path.
- **Shared temp directories**: if temp is writable, document whether it is trusted, isolated, or scrubbed.
## Practical tip
If your policy language cannot explain “why this command is safe here but unsafe there,” the filesystem model is still too implicit.
## Reference implementations to check before designing your own
Do not invent execution-mode names from scratch; two shipping runtimes already name them clearly and are worth copying the shape of:
- Claude Code's Bash sandbox distinguishes sandbox mode (auto-allow vs. regular permissions) from permission mode, and defaults writes to cwd + temp while defaulting reads much broader — an asymmetry that leaks credential files unless closed explicitly. See [`claude-code-bash-sandbox-mechanics.md`](claude-code-bash-sandbox-mechanics.md).
- Codex names three sandbox modes explicitly (`read-only`, `workspace-write`, `danger-full-access`) as an axis separate from approval policy (`untrusted`, `on-request`, `never`). See [`openai-codex-sandbox-guardrails-may-2026.md`](openai-codex-sandbox-guardrails-may-2026.md).
Both products also warn that the sandbox is scoped to specific tool classes (Bash for Claude Code; the exec surface for Codex) — file-edit, fetch, and computer-use tool calls are typically governed by the separate permission system, not the process sandbox. Verify this scope boundary explicitly for any runtime you are modeling; do not assume "sandboxed" is a whole-agent property.
SKILL.md
---
name: ai-coding-agents-execution-sandbox
description: "Designs execution sandboxes for coding agents. Use when modeling process isolation, filesystem policy, network controls, workspace mounts, or destructive-command boundaries."
compatibility: Portable core. Works on Claude Code and Codex.
version: "1.1"
last_validated: 2026-07-11
---
# AI Coding Agents Execution Sandbox
Use this skill to design or review the execution substrate for a coding-agent runtime: process isolation, filesystem mounts, network policy, workspace boundaries, environment exposure, and destructive-command controls.
This skill covers where and how code runs. It complements permission routing by defining the actual isolation and policy envelope around execution.
For **remote** execution — managed sandbox providers, ephemeral cloud workspaces per task, hosted agent runtimes, egress policy across a network boundary, and cost per task — use `ai-coding-agents-cloud-sandboxes` instead.
## ASCII Flow
```text
requested execution
|
v
classify action
read | write | network | process | destructive | secret-bearing
|
v
sandbox policy
filesystem roots + workspace mounts + env exposure + network policy
|
v
decision
allow in sandbox | ask permission | deny | require safer workspace
|
v
run process with bounded cwd, mounts, env, network, and cleanup rules
```
## Quick Reference
| Question | Read | Outcome |
|----------|------|---------|
| How should process, filesystem, and workspace isolation work? | [`references/sandbox-process-and-filesystem-model.md`](references/sandbox-process-and-filesystem-model.md) | Execution modes, mounts, working directories, and write boundaries |
| How should network, approvals, and destructive actions be controlled? | [`references/network-approval-and-destructive-action-guards.md`](references/network-approval-and-destructive-action-guards.md) | Outbound policy, command classes, escalation triggers, and guardrails |
| What sandbox mode names and backend split should runtime builders copy from Codex? | [`references/openai-codex-sandbox-guardrails-may-2026.md`](references/openai-codex-sandbox-guardrails-may-2026.md) | `read-only`/`workspace-write`/`danger-full-access` modes, platform backends, fail-closed policy translation, security telemetry |
| What does a shipping Bash sandbox actually enforce, and where does its scope end? | [`references/claude-code-bash-sandbox-mechanics.md`](references/claude-code-bash-sandbox-mechanics.md) | Read/write asymmetry, credential deny-vs-mask, TLS-blind allowlists, tool-scope limits, known compatibility failures |
| What is the canonical policy format for interpreter allowlists and filesystem/network rules? | [`references/sandbox-policy-format.md`](references/sandbox-policy-format.md) | Runtime-agnostic policy fields, common traps, and translation notes |
| How do I verify a sandbox actually holds before shipping it? | [`references/escape-path-test-matrix.md`](references/escape-path-test-matrix.md) | Symlink, interpreter-wrapper, env-injection, and package-manager escape tests with pass criteria |
## When To Use
- Design execution modes for local or remote coding agents
- Define filesystem write boundaries and workspace mount rules
- Add network restrictions, env-var policy, or secret exposure controls
- Review how destructive commands should be blocked or escalated
- Model how worker or teammate sandboxes should inherit or narrow permissions
## Use Other Skills
| Need | Use Instead |
|------|-------------|
| Approval routing and permission prompts | [`../ai-coding-agents-permissions/SKILL.md`](../ai-coding-agents-permissions/SKILL.md) |
| Remote bridge and local or remote execution model | [`../ai-coding-agents-remote-runtime/SKILL.md`](../ai-coding-agents-remote-runtime/SKILL.md) |
| Tool contract and execution pipeline | [`../ai-coding-agents-tools/SKILL.md`](../ai-coding-agents-tools/SKILL.md) |
| Broader coding-agent architecture | [`../ai-coding-agents/SKILL.md`](../ai-coding-agents/SKILL.md) |
## Default Workflow
1. **Define execution modes.** For example: read-only, workspace-write, unrestricted, remote-bridged, or worker-reduced.
2. **Set the mount model.** Decide which directories are readable, writable, hidden, or remapped.
3. **Control process spawning.** Define which shells, interpreters, and subprocess classes are allowed by default.
4. **Separate network policy.** Outbound access, host allowlists, and package-manager exceptions should be explicit.
5. **Constrain environment exposure.** Make secret inheritance opt-in and scoped to the minimum execution surface.
6. **Classify destructive actions.** Delete, reset, force-push, and privileged commands need stricter rules than normal edits.
7. **Protect privileged config surfaces.** Settings files, policy files, and skill directories should usually be non-writable even when the workspace is otherwise writable.
8. **Narrow worker inheritance.** Child tasks and teammates should inherit the minimum effective envelope, not the widest parent one.
9. **Test escape paths.** Validate symlink tricks, path traversal, shell expansion, and tool-wrapper bypass attempts.
## Host Rules
- Keep sandbox mode distinct from approval mode; they are related but not identical.
- Apply policy before execution, not after output returns.
- Treat path resolution and symlink resolution as part of the security boundary.
- Model network access independently from filesystem access.
- Make the default sandbox conservative and escalate only when justified.
- Ensure worker tasks never gain more power than the actor that launched them unless a fresh approval path exists.
- Distinguish path semantics for permission rules from path semantics for substrate mounts if the runtime supports both; do not assume one resolver is correct for both layers.
- Scope the sandbox explicitly to the tool classes it covers. Both shipping references this skill tracks (Claude Code's Bash sandbox, Codex's exec sandbox) restrict subprocess execution but leave file-edit, fetch, and computer-use tool calls to a separate permission system — "the agent is sandboxed" is a category error unless you name which tool surface that applies to.
- Do not let default read policy stay broad while write policy is locked down and call the result a secrets boundary; a sandbox that can still read `~/.ssh` or `~/.aws/credentials` because only writes were restricted is a common, easy-to-miss gap.
- Treat a hostname-based network allowlist as connectivity policy, not content inspection, unless the proxy actually terminates and inspects TLS — otherwise domain fronting through an allowed host is a viable exfiltration path.
## Build Order
1. Define execution modes and their trust levels.
2. Implement canonical path resolution and mount policy.
3. Add process and interpreter allowlists.
4. Add network policy and host exceptions.
5. Add env-var exposure rules and secret filtering.
6. Protect settings, policy, and skill directories as privileged config surfaces.
7. Add destructive-command classification and escalation hooks.
## Core Invariants
- The sandbox boundary must exist in the execution substrate, not only in prompts.
- Filesystem, network, and environment policy are separate control planes.
- Canonical path resolution is part of the security boundary.
- Child workers inherit the minimum effective envelope by default.
- Destructive capability must never be implied by tool name or user intent alone.
- Privileged config surfaces should remain protected even when ordinary workspace edits are allowed.
## Failure Modes
- Symlink or path-traversal writes escaping the allowed workspace.
- Wrapper tools bypassing interpreter or command allowlists.
- Network-denied commands succeeding through unclassified package-manager helpers.
- Child workers inheriting parent unrestricted mode silently.
- Secrets leaking through inherited environments into commands that did not need them.
- Workspace-write modes that accidentally allow mutation of policy or skill roots.
## Minimal Viable Version
- One conservative default sandbox mode.
- Canonical readable and writable root enforcement.
- One subprocess allowlist and one deny path for privileged classes.
- One explicit network policy.
- One protected-config-surface list.
- One escalation path for destructive or restricted actions.
## What Strong Implementations Add
- Worker-specific narrowed envelopes.
- Host-specific mount remapping and temp-space policies.
- Auditable destructive-command classes and explicit justifications.
- Network host allowlists and package-manager exception handling.
- Separate path resolvers or canonicalization rules for permission matching versus substrate mount enforcement.
- Escape-path tests for symlinks, shell expansion, wrapper binaries, and env indirection.
## Known Traps
- Assuming path-prefix checks are sufficient while symlinks, wrapper binaries, env indirection, or shell expansion bypass the intended boundary.
- Treating approval prompts as if they enforce isolation when the substrate itself still allows broad process, filesystem, or network access.
- Reusing the parent worker’s envelope for convenience and accidentally granting broader write or network privileges to delegated tasks.
- Forgetting that package-manager installs, build tools, and test runners often write outside obvious workspace paths unless mounts and temp policies are explicit.
- Classifying a top-level command as safe without evaluating the actual subprocess tree it can spawn.
- Enabling a compatibility escape hatch (macOS Apple Events, a MITM-friendly weaker-isolation flag, an unelevated Windows backend chosen for convenience) to fix one broken tool without registering what isolation guarantee that escape hatch removes for every command that follows it in the same session.
- Allowing a Unix domain socket such as a container runtime's control socket through the sandbox; a single such exception can be equivalent to full host access even when every filesystem and network rule looks tight.
## Common Anti-Patterns
- Treating approval prompts as if they were the sandbox.
- Assuming workspace-write is safe without canonical path checks.
- Allowing arbitrary interpreters because the top-level tool looked harmless.
- Reusing the parent worker’s full envelope for convenience.
- Treating settings and policy files as ordinary editable workspace content.
- Trusting wrapper commands without classifying what they actually execute.
## Cross-Platform Patterns (Goose)
Goose is now maintained under the Agentic AI Foundation (AAIF) at the Linux Foundation (founding contributors Block, Anthropic, OpenAI; transferred April 7, 2026). Repository: `aaif-goose/goose`; documentation: `goose-docs.ai`. Goose 2.0 (April 2026) ships a TypeScript TUI and is migrating the desktop app from Electron to Tauri; both surfaces communicate with a shared ACP daemon rather than separate runtimes. For cloud-hosted devbox execution, the isolation substrate is microVM/Firecracker-style (matching the pattern used for Codex cloud tasks).
Goose's sandbox posture adds two patterns the core skill does not model directly: build-time supply-chain gates, and distribution-layer allowlist baking.
### Build-time supply-chain gates (`deny.toml`, recipe-scanner)
Sandboxing stops code from misbehaving at runtime. It does not stop a compromised dependency from shipping. Goose uses `deny.toml` (cargo-deny) to gate licenses, advisories, and source allowlists at build, and `recipe-scanner/` to validate YAML recipes before they enter the shipping artifact.
- **Pattern:** pair every runtime substrate control with a build-time gate. If a tool or extension should not be allowed at runtime, it also should not appear in the shipping artifact. The sandbox is the runtime enforcement; build-time gates are the artifact enforcement.
- **Anti-pattern:** relying solely on runtime sandboxing to contain shipped-but-disallowed code. An attacker who compromises the build pipeline bypasses the runtime check entirely.
- **Recipe:** include `deny.toml`-equivalent gates (license, advisory, source allowlist) for every language ecosystem your agent uses. Statically scan shipped YAML recipes and plugin manifests for declared tools that exceed the distribution's allowlist.
### Custom-distro preconfigured allowlists
Custom distributions (see `ai-coding-agents-release-distribution`) ship with a narrowed extension/tool/provider allowlist *baked into the binary*. The runtime sandbox then enforces a tighter envelope than the open-source stable.
- **Pattern:** treat distribution-layer allowlists as a sandbox policy layer above the user's own settings. Users cannot broaden beyond what the distro allows; they can only narrow within it.
- **Anti-pattern:** ship the open-source binary to enterprise customers with a "policy file" they must install separately. Separation between binary and policy creates drift, stale-policy risk, and bypass-by-rename attacks.
- **Recipe:** add `distro_envelope: Option<ExtensionAllowlist>` as an immutable field in the merged settings source. The sandbox enforces it at execution time; the settings layer shows it as a read-only source (see `ai-coding-agents-settings-policy`).
## Navigation
### References
- [`references/sandbox-process-and-filesystem-model.md`](references/sandbox-process-and-filesystem-model.md) — Execution modes, process isolation, mounts, and write boundaries
- [`references/network-approval-and-destructive-action-guards.md`](references/network-approval-and-destructive-action-guards.md) — Network policy, escalation triggers, and destructive-command controls
- [`references/openai-codex-sandbox-guardrails-may-2026.md`](references/openai-codex-sandbox-guardrails-may-2026.md) — OpenAI Codex sandbox guardrails: mode names, backend matrix, fail-closed translation, and telemetry (re-verified 2026-07-11)
- [`references/claude-code-bash-sandbox-mechanics.md`](references/claude-code-bash-sandbox-mechanics.md) — Claude Code's shipping Bash sandbox: settings keys, read/write asymmetry, credential deny-vs-mask, TLS-blind allowlists, tool-scope limits
- [`references/sandbox-policy-format.md`](references/sandbox-policy-format.md) — Runtime-agnostic canonical policy format for interpreter allowlists and filesystem/network rules
- [`references/escape-path-test-matrix.md`](references/escape-path-test-matrix.md) — Escape-attack checklist to run before shipping any sandbox configuration
### Data
- [`data/sources.json`](data/sources.json) — Primary docs and implementation references for coding-agent sandbox design
### Related Skills
- [`../ai-coding-agents-permissions/SKILL.md`](../ai-coding-agents-permissions/SKILL.md)
- [`../ai-coding-agents-remote-runtime/SKILL.md`](../ai-coding-agents-remote-runtime/SKILL.md)
- [`../ai-coding-agents-tools/SKILL.md`](../ai-coding-agents-tools/SKILL.md)
## Fact-Checking
- Known bugs, regressions, framework/compiler/runtime footguns, and version-specific crash or workaround guidance must be verified against current primary web sources before being treated as current fact.
- Sandbox details are highly product-specific and may depend on host OS, terminal model, and packaging strategy. Preserve the security model, but verify exact enforcement points in the target runtime.
- Do not infer real safety from prompt instructions alone; the boundary must exist in the execution substrate.
## Learnings Loop
Before applying this skill on a non-trivial task, read `learnings.consolidated.md` in this directory (and `learnings.md` if present).
After applying it, if you encountered a pattern worth remembering, a mistake worth preventing, or a domain fact that surprised you, append one dated bullet to `learnings.md` via `agents-skills-feedback-loop/scripts/append_learning.py`. Do not modify `SKILL.md` itself.