Skip to content

Sandbox

Every tool call in KodaCode is sandboxed to your project directory by default. File reads, writes, searches, and shell commands are confined — escaping the project boundary requires explicit user permission.

File-based tools are automatically confined to the project directory:

ToolConfined Parameter
readfilePath
writefilePath
editfilePath
globpath
greppath

Paths are resolved through symlinks (handling macOS /tmp/private/tmp consistency), then checked against the project directory and any configured allowed_paths. If a path escapes, the sandbox prompts for permission before proceeding.

Shell commands get two layers of safety checking:

Bash commands are parsed into an AST using a full shell parser (mvdan.cc/sh). The sandbox walks the AST and checks each argument for external paths:

  • Home directory expansion (~, ~/...)
  • Environment variables ($HOME, ${VAR}, including inside double quotes)
  • Absolute paths (/etc/passwd)
  • Parent traversal (..) that escapes the project root
  • Redirect targets (> /tmp/file, >> /external/log)

Quoted arguments (single or double quotes) are only flagged if the path actually exists on disk. This prevents false positives on grep/sed patterns like grep "// @ts-ignore" while still catching cat '/etc/passwd'.

Content commands (echo, printf) have their arguments skipped entirely — only redirect targets are checked.

See sandbox-limitations.md for known limitations and edge cases.

rm and rmdir commands are gated separately via the bash_rm permission rule:

permission:
bash:
"rm *": ask # ask before any delete
"rm -rf *": deny # block recursive deletes

The following paths are allowed without prompting, even outside the project directory:

PathReason
~/.config/kodacode/KodaCode’s own config, agents, themes, and prompts
/dev/nullStandard output sink
/dev/zeroZero byte source
/dev/urandom, /dev/randomRandom data sources
/dev/stdin, /dev/stdout, /dev/stderrStandard I/O streams

Configure additional directories that tools can access without prompting:

allowed_paths:
- /path/to/shared/library
- /tmp/build-artifacts
- ~/shared-libs

Allowed paths are merged from global config (~/.config/kodacode/config.yaml) and project-local config (./kodacode.yaml).

allowed_paths:
- ../shared-utils # sibling directory in monorepo
- /opt/company/sdk # shared SDK

The sandbox enforces ignore patterns that prevent tools from traversing noisy directories. Built-in defaults include:

node_modules/**, .git/**, __pycache__/**, .next/**, dist/**,
build/**, vendor/**, .cache/**, coverage/**, .tox/**,
.venv/**, venv/**, .gradle/**, target/**, .idea/**, .vscode/**

Add your own patterns in config (appended to defaults, never replaces them):

ignore_patterns:
- "*.generated.go"
- "vendor/**"
- ".terraform/**"
- "*.min.js"

MCP tools (prefixed with their server name) are dispatched directly to their MCP server without path confinement — the MCP server itself is responsible for its own access control.

Add paths outside your project that the model legitimately needs:

allowed_paths:
- ~/shared-libs # shared libraries used across projects
- /tmp # temporary files

Keep the model focused by excluding large or irrelevant directories:

ignore_patterns:
- "*.generated.go"
- ".terraform/**"
- "coverage/**"
  • False permission prompts: If you’re asked about paths inside your project, check that kodacode was started from the correct directory. The project root is determined by the working directory at startup.
  • Shell variables: Loop variables ($file, $i) don’t trigger prompts. Only path-bearing env vars like $HOME and $TMPDIR are checked.
  • Grep/sed patterns: Quoted patterns containing / characters (e.g. grep "// @ts-ignore") are not flagged unless the path exists on disk. If a grep pattern happens to match an existing external path (e.g. grep '/usr/local/bin'), you may see a prompt — approve it and continue.