Skip to content

Keep your tools' code away from your keys

Under kindgi dev, your pack's tools run in a pack service on your machine, as you. Much of that code is often written by a coding agent. kindgi dev runs the pack service sandboxed, so the code reaches what it needs (the app, the runtime that runs it, the network) and not the rest of what you can reach. So does the indexer, which loads every tool, agent and flow module to list them, and with them any code at a module's top level.

At start, kindgi dev says it's on:

✓ dev sandbox: macOS Seatbelt: your tools' code can't read your keys or files outside the app, write outside it, or reach Docker; it still has the network and the app's own files

kindgi doctor checks it too:

✓ Dev sandbox: kindgi dev runs your tools' code sandboxed (macOS Seatbelt): it can't read your keys or reach Docker.
Closed to your tools' code Still open
Your home folder: SSH keys, cloud credentials (~/.aws, ~/.config/gcloud), registry tokens (~/.npmrc), other projects The app's own files, read and write: its code and its data
Secrets in the app, wherever they are: .env*, Kindgi's .kindgi folder, .git, kindgi.env, pack.env, .kindgirc.json, .npmrc, .pypirc, .netrc The runtime that runs it and the app's dependencies, to read
The Docker socket, and every other UNIX socket (ssh-agent, a local database's socket); on Linux, those under the home folder, /tmp, /var/tmp and /run (Docker's, ssh-agent's, a local database's): a socket elsewhere stays reachable The network: any API a tool calls
Other tools' temp files; on Linux, other processes too Its own temp folder (TMPDIR)
Writing anywhere outside the app: on macOS every other folder (/opt/homebrew, /Users/Shared, /Applications), where a program it replaced would run later outside the sandbox; on Linux the system is read-only What kindgi dev hands it: the app's own settings from its env files, and the secrets a tool declares (ctx.secrets)
Writing Kindgi's configuration (kindgi.config.*, pyproject.toml): kindgi dev loads it, and it says how wide the sandbox is
On macOS, the keychain, and LaunchServices and Apple Events (opening an app, or a file with one, outside the sandbox); on Linux, the terminal kindgi dev runs in (the code gets its own session)

A process the code starts, such as a git or a curl, is inside the sandbox too.

What it doesn't do:

  • It doesn't stop the network. Code that can read a value can send it anywhere. What the pack service is handed matters as much, which is why Kindgi's own secrets and your model provider keys never reach its environment (Keep local values in env files). On Linux that includes abstract UNIX sockets (an X11 display's @/tmp/.X11-unix/X0, some D-Bus buses), which share the network's namespace.
  • It doesn't protect the app's own files, or what runs them later. A tool can read and change your app's code and data, as the coding agent can, including files something outside the sandbox runs later: git hooks in the tree (a core.hooksPath such as .husky/), package.json scripts, a Makefile. Review what the agent writes before you run it outside kindgi dev.
  • It covers kindgi dev only. In a deployment, the pack's image is the boundary, and the pack service keeps only the names the pack declares (Declare the environment your code reads).

The runtime is opened to read wherever it is, and nothing else around it:

  • Node.js, from nvm or Homebrew;
  • a Python interpreter's own paths (a venv, a uv-managed Python under ~/.local/share/uv);
  • a JDK and every jar on the pack's classpath (~/.m2/repository, coursier's cache).

A path that would open your whole home folder never is, and kindgi dev says so.

A tool that uses the AWS SDK's credential chain reads ~/.aws. One that talks to a local Postgres over its socket connects to /tmp/.s.PGSQL.5432 (over TCP, localhost:5432 needs nothing). Open what it needs in the pack's config, rather than turning the sandbox off:

// in kindgi.config.ts
dev: {
sandbox: {
allowRead: ['~/.aws'],
allowUnixSockets: ['/tmp/.s.PGSQL.5432'],
},
},

In a Java or Scala pack it's "dev": { "sandbox": { … } } in kindgi.config.json. A path is absolute, starts with ~/, or is relative to the pack's root. kindgi dev names each one at every start, so an opening an agent adds shows on screen as well as in the diff:

✓ dev sandbox: macOS Seatbelt: your tools' code can't read your keys or files outside the app, write outside it, or reach Docker; it still has the network and the app's own files
also reads /Users/…/.aws (dev.sandbox.allowRead)

The secret files listed above stay closed wherever they are, even inside a path you open.

  • macOS: Seatbelt (sandbox-exec), always there. Inside another sandbox that restricts anything (a coding agent's, say), macOS doesn't let kindgi dev add its own: run it in your own terminal.

  • Linux: bubblewrap (bwrap). Install it if your system doesn't have it:

    Terminal window
    sudo apt-get install bubblewrap # Debian, Ubuntu
    sudo dnf install bubblewrap # Fedora

    Ubuntu 23.10 and later restrict the user namespaces bwrap needs (Ubuntu's announcement). Allow it with an AppArmor profile for /usr/bin/bwrap, then reload AppArmor:

    Terminal window
    printf 'profile bwrap /usr/bin/bwrap flags=(unconfined) {\n userns,\n}\n' | sudo tee /etc/apparmor.d/bwrap
    sudo systemctl reload apparmor

    On Linux the secret files in the app are found each time the pack service starts. A .env file created while kindgi dev runs stays readable until the next start: a save restarts it.

  • Windows: none kindgi dev can use. Run kindgi dev under WSL, where it uses the Linux one.

  • Inside a container (a dev container, CI): the container is the boundary, and bwrap can't run inside a default one.

Where it can't run, kindgi dev warns at start and runs your tools without it:

⚠ Your tools run without the dev sandbox on this system: they can read your files and keys.
Why: kindgi dev is already inside a sandbox (a coding agent’s?) that won’t let it add its own. Run kindgi dev in your own terminal.
More: https://docs.kindgi.com/v0.1/guides/secrets/dev-sandbox/. To refuse to run without it: KINDGI_DEV_SANDBOX=required; to drop this warning: KINDGI_DEV_SANDBOX=off.

That one is from a Mac, inside another sandbox; the Why: line names the reason on each system.

With the sandbox on, kindgi dev starts only with one Kindgi configuration in the app: the code it runs can't change the one in use, but could add another by a name looked up first.

kindgi dev: more than one Kindgi configuration in /Users/…/acme-probe: kindgi.config.ts, kindgi.config.mts. With the dev sandbox on, kindgi dev starts with one only: the code it runs can't change it, but could add another by a name looked up first. Keep the one you use and remove the others.

KINDGI_DEV_SANDBOX sets it for a machine or a shell:

Value What kindgi dev does
on (default) Runs the pack service sandboxed where it can; elsewhere, warns and runs it without.
required Runs it sandboxed, or stops before anything starts.
off Runs it without, and says so at every start.

For one project, dev: { sandbox: false } in its config turns it off; KINDGI_DEV_SANDBOX wins over it. Turned off, kindgi dev says so:

⚠ dev sandbox: off (KINDGI_DEV_SANDBOX=off): your tools' code can read your files and keys as you can