12 KiB
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 03-sandbox-aware-prompting | 01 | execute | 1 |
|
true |
|
|
Purpose: Claude Code sessions inside claudebox currently have no context about their sandboxed environment. This causes Claude to attempt operations that will fail (SSH git, gpg signing) and miss capabilities it has (comma, nix shell). Injecting this context eliminates friction.
Output: Modified claudebox.sh that generates SANDBOX.md and manages CLAUDE.md import on every launch.
<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/03-sandbox-aware-prompting/03-CONTEXT.md @.planning/phases/03-sandbox-aware-prompting/03-RESEARCH.md @claudebox.sh Task 1: Add SANDBOX.md generation and CLAUDE.md import check to claudebox.sh claudebox.sh - claudebox.sh (current state, integration point at line 102-103) - .planning/phases/03-sandbox-aware-prompting/03-CONTEXT.md (locked decisions D-01 through D-08) - .planning/phases/03-sandbox-aware-prompting/03-RESEARCH.md (implementation patterns, SANDBOX.md content structure) Insert a new code block in claudebox.sh between line 102 (`mkdir -p "$HOME/.claudebox"`) and line 104 (`GIT_NAME=$(git config ...)`). The block does two things:Part 1: Write SANDBOX.md (per D-02 -- overwritten every launch)
Use a single-quoted heredoc (<< 'SANDBOXEOF') to write $HOME/.claudebox/SANDBOX.md. The content must follow D-04 (friendly guide tone, short prose paragraphs), D-05 (default restrictions with "by default" phrasing), and D-06 (git identity pre-configured, HTTPS preferred). Use this exact content:
# Sandbox Environment
You are running inside a bubblewrap (bwrap) sandbox managed by claudebox.
Your filesystem is isolated -- only the current working directory and
essential system paths are mounted.
## Installing Tools
You have two ways to install tools on the fly:
**Comma (preferred for quick one-off commands):**
`, ripgrep` runs ripgrep without permanent installation. Comma uses
nix-index to find the right package automatically.
**Nix shell (for persistent access within the session):**
`nix shell nixpkgs#python3 -c python3 script.py` runs a command with
a package available. To keep it in your PATH for the session:
`nix shell nixpkgs#python3` then use `python3` normally.
## Default Restrictions
By default, the following are not mounted into the sandbox:
- SSH keys (~/.ssh)
- GPG and age keys (~/.gnupg, age key files)
- Cloud credentials (~/.aws, ~/.config/gcloud)
- Tailscale state
If your setup has been customized, some of these may be available.
## Git
Your git identity (name and email) is pre-configured from the host.
The `safe.directory` setting trusts the mounted working directory.
For remote operations, prefer HTTPS URLs over SSH since SSH keys
are not available by default.
The heredoc line is: cat > "$HOME/.claudebox/SANDBOX.md" << 'SANDBOXEOF'
Closing delimiter is: SANDBOXEOF (flush-left, no indentation).
Part 2: Ensure CLAUDE.md has @SANDBOX.md import (per D-03, D-07, D-08, AWARE-01)
After writing SANDBOX.md, add the CLAUDE.md import check:
# Ensure CLAUDE.md has @SANDBOX.md import (D-03, D-08, AWARE-01)
CLAUDEMD="$HOME/.claudebox/CLAUDE.md"
if [[ ! -f "$CLAUDEMD" ]]; then
printf '%s\n' "@SANDBOX.md" > "$CLAUDEMD"
elif [[ "$(head -1 "$CLAUDEMD")" != "@SANDBOX.md" ]]; then
tmp=$(mktemp)
{ printf '%s\n' "@SANDBOX.md"; cat "$CLAUDEMD"; } > "$tmp"
mv "$tmp" "$CLAUDEMD"
fi
This creates CLAUDE.md with just the import if it does not exist (AWARE-01), or prepends the import if the first line does not match exactly @SANDBOX.md (D-08). Existing user content is preserved (D-03).
Add a section comment before the block: # === Sandbox-aware prompting (AWARE-01, AWARE-02) ===
cd /home/toph/code/tools/claudebox && nix build --no-link 2>&1 | tail -5 && echo "BUILD OK"
<acceptance_criteria>
- claudebox.sh contains cat > "$HOME/.claudebox/SANDBOX.md" << 'SANDBOXEOF'
- claudebox.sh contains the closing SANDBOXEOF heredoc delimiter
- SANDBOX.md heredoc contains # Sandbox Environment
- SANDBOX.md heredoc contains ## Installing Tools
- SANDBOX.md heredoc contains ## Default Restrictions
- SANDBOX.md heredoc contains By default, the following are not mounted into the sandbox:
- SANDBOX.md heredoc contains If your setup has been customized, some of these may be available.
- SANDBOX.md heredoc contains ## Git
- SANDBOX.md heredoc contains prefer HTTPS URLs over SSH
- claudebox.sh contains CLAUDEMD="$HOME/.claudebox/CLAUDE.md"
- claudebox.sh contains printf '%s\n' "@SANDBOX.md" > "$CLAUDEMD"
- claudebox.sh contains head -1 "$CLAUDEMD" for first-line check
- claudebox.sh contains mv "$tmp" "$CLAUDEMD" for atomic prepend
- The SANDBOX.md/CLAUDE.md block appears AFTER mkdir -p "$HOME/.claudebox" and BEFORE gitconfig generation
- nix build succeeds (shellcheck passes)
</acceptance_criteria>
claudebox.sh contains SANDBOX.md heredoc generation and CLAUDE.md import check between mkdir and gitconfig blocks. nix build succeeds with shellcheck passing.
Step 1: Clean slate test. Remove any existing SANDBOX.md and CLAUDE.md from ~/.claudebox/:
rm -f "$HOME/.claudebox/SANDBOX.md" "$HOME/.claudebox/CLAUDE.md"
Step 2: Run claudebox --dry-run (which executes all pre-bwrap logic including file generation, then prints the command and exits). This exercises the SANDBOX.md write and CLAUDE.md creation path (AWARE-01 -- first run, file does not exist).
Step 3: Verify SANDBOX.md was created with correct content:
head -1 ~/.claudebox/SANDBOX.mdshould output# Sandbox Environmentgrep -c "## " ~/.claudebox/SANDBOX.mdshould be 4 (four H2 sections: Installing Tools, Default Restrictions, Git, plus the H1 counts differently -- actually grep for^##to count H2s, expect 3: Installing Tools, Default Restrictions, Git)
Step 4: Verify CLAUDE.md was created with import line:
cat ~/.claudebox/CLAUDE.mdshould output exactly@SANDBOX.md
Step 5: Idempotency test. Run claudebox --dry-run again. Verify:
- SANDBOX.md was overwritten (check timestamp or content is identical)
- CLAUDE.md still has exactly one
@SANDBOX.mdline on line 1 (no duplication)
Step 6: Prepend test. Add user content to CLAUDE.md, remove the import line, then run again:
printf '%s\n' "# My custom instructions" "Do cool stuff" > ~/.claudebox/CLAUDE.md
Run claudebox --dry-run. Verify:
head -1 ~/.claudebox/CLAUDE.mdoutputs@SANDBOX.mdhead -3 ~/.claudebox/CLAUDE.mdshows import line followed by the user's content (preserved per D-03) cd /home/toph/code/tools/claudebox && rm -f "$HOME/.claudebox/SANDBOX.md" "$HOME/.claudebox/CLAUDE.md" && nix run . -- --dry-run --yes 2>/dev/null; head -1 "$HOME/.claudebox/SANDBOX.md" | grep -qF "# Sandbox Environment" && echo "SANDBOX.md OK" && cat "$HOME/.claudebox/CLAUDE.md" | head -1 | grep -qF "@SANDBOX.md" && echo "CLAUDE.md OK" && printf '%s\n' "# My stuff" > "$HOME/.claudebox/CLAUDE.md" && nix run . -- --dry-run --yes 2>/dev/null && head -1 "$HOME/.claudebox/CLAUDE.md" | grep -qF "@SANDBOX.md" && sed -n '2p' "$HOME/.claudebox/CLAUDE.md" | grep -qF "# My stuff" && echo "PREPEND OK" <acceptance_criteria>- After first run with no existing files: ~/.claudebox/SANDBOX.md exists and starts with
# Sandbox Environment - After first run with no existing files: ~/.claudebox/CLAUDE.md exists and contains exactly
@SANDBOX.md - After second run: CLAUDE.md still has exactly one
@SANDBOX.mdon line 1 (no duplication) - After removing import from CLAUDE.md and re-running:
@SANDBOX.mdis prepended, existing content preserved on subsequent lines - grep -c "@SANDBOX.md" ~/.claudebox/CLAUDE.md returns 1 (exactly one import line) </acceptance_criteria> SANDBOX.md generation, CLAUDE.md creation, CLAUDE.md import prepending, and idempotency all verified via dry-run execution.
- After first run with no existing files: ~/.claudebox/SANDBOX.md exists and starts with
<threat_model>
Trust Boundaries
| Boundary | Description |
|---|---|
| Host filesystem -> sandbox | Files written to ~/.claudebox/ on host are exposed as ~/.claude/ inside sandbox |
| claudebox script -> user CLAUDE.md | Script modifies a user-owned file (prepend only) |
STRIDE Threat Register
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|---|---|---|---|---|
| T-03-01 | Tampering | SANDBOX.md content | accept | SANDBOX.md is informational only (context for Claude). Tampering has no security impact -- it cannot grant sandbox permissions. Overwritten every launch anyway (D-02). |
| T-03-02 | Tampering | CLAUDE.md user content | mitigate | claudebox only modifies line 1 (import line). Uses mktemp+mv for atomic write. Preserves all existing content per D-03. No truncation risk. |
| T-03-03 | Information Disclosure | SANDBOX.md reveals sandbox topology | accept | SANDBOX.md tells Claude what is NOT available (SSH, GPG, cloud creds). This is useful context, not a secret. Does not reveal host paths or configuration details beyond what Claude can already discover via env and filesystem exploration. |
| T-03-04 | Denial of Service | CLAUDE.md write failure | accept | If mktemp or mv fails, set -euo pipefail aborts the script. User sees clear error. No data loss -- original CLAUDE.md unchanged (mv is atomic). |
| </threat_model> |
<success_criteria>
- claudebox.sh contains SANDBOX.md heredoc and CLAUDE.md import management code
- nix build passes shellcheck
- File generation works correctly for all three cases: first run (no files), repeat run (files exist), and recovery (import line missing)
- SANDBOX.md content matches D-04/D-05/D-06 requirements </success_criteria>