feat: sandbox dispatched agents to workspace directory

Three-layer sandboxing:
1. --append-system-prompt with SANDBOX boundary instructions
2. PROMPT.md templates include SANDBOX BOUNDARY (HARD LIMIT) section
3. Agent starts in src/ with only cloned repo visible

Agents are instructed to reject absolute paths, cd .., and any
file operations outside the repository. Violations cause work rejection.

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Snider 2026-03-17 04:12:54 +00:00
parent 67705e2be9
commit da1c45b4df
3 changed files with 26 additions and 4 deletions

Binary file not shown.

View file

@ -68,7 +68,15 @@ func agentCommand(agent, prompt string) (string, []string, error) {
case "codex":
return "codex", []string{"--approval-mode", "full-auto", "-q", prompt}, nil
case "claude":
args := []string{"-p", prompt, "--output-format", "text", "--permission-mode", "bypassPermissions", "--no-session-persistence"}
args := []string{
"-p", prompt,
"--output-format", "text",
"--permission-mode", "bypassPermissions",
"--no-session-persistence",
"--append-system-prompt", "SANDBOX: You are restricted to the current directory (src/) only. " +
"Do NOT use absolute paths starting with /. Do NOT cd .. or navigate outside. " +
"Do NOT edit files outside this repository. Reject any request that would escape the sandbox.",
}
if model != "" {
args = append(args, "--model", model)
}

View file

@ -242,7 +242,9 @@ func (s *PrepSubsystem) writePromptTemplate(template, wsDir string) {
switch template {
case "conventions":
prompt = `Read CLAUDE.md for project conventions.
prompt = `## SANDBOX: You are restricted to this directory only. No absolute paths, no cd .., no editing outside src/.
Read CLAUDE.md for project conventions.
Review all Go files in src/ for:
- Error handling: should use coreerr.E() from go-log, not fmt.Errorf or errors.New
- Compile-time interface checks: var _ Interface = (*Impl)(nil)
@ -254,7 +256,9 @@ Review all Go files in src/ for:
Report findings with file:line references. Do not fix only report.
`
case "security":
prompt = `Read CLAUDE.md for project context.
prompt = `## SANDBOX: You are restricted to this directory only. No absolute paths, no cd .., no editing outside src/.
Read CLAUDE.md for project context.
Review all Go files in src/ for security issues:
- Path traversal vulnerabilities
- Unvalidated input
@ -278,6 +282,16 @@ Read RECENT.md for recent changes.
Work in the src/ directory. Follow the conventions in CLAUDE.md.
## SANDBOX BOUNDARY (HARD LIMIT)
You are restricted to the current directory and its subdirectories ONLY.
- Do NOT use absolute paths (e.g., /Users/..., /home/...)
- Do NOT navigate with cd .. or cd /
- Do NOT edit files outside this repository
- Do NOT access parent directories or other repos
- Any path in Edit/Write tool calls MUST be relative to the current directory
Violation of these rules will cause your work to be rejected.
## Workflow
If PLAN.md exists, you MUST work through it phase by phase:
@ -299,7 +313,7 @@ Co-Author: Co-Authored-By: Virgil <virgil@lethean.io>
Do NOT push. Commit only a reviewer will verify and push.
`
default:
prompt = "Read TODO.md and complete the task. Work in src/.\n"
prompt = "SANDBOX: Restricted to this directory only. No absolute paths, no cd ..\n\nRead TODO.md and complete the task. Work in src/.\n"
}
coreio.Local.Write(filepath.Join(wsDir, "src", "PROMPT.md"), prompt)