Skip to main content

kule exec

Run a command inside the task's copy, in the sandbox, then show what it changed.

Synopsis​

kule exec [OPTIONS] <TASK> -- <COMMAND>...

Description​

kule exec is kule run without the agent: you name the command. It is how you build, test or try something in a task, and how you run a script or an installer you do not trust yet to see what it would change.

The command runs in the task's copy (its working directory is the copy), inside the operating system's sandbox: Seatbelt on macOS, Landlock and namespaces on Linux. By default:

  • It can write only to the copy, the task's own TMPDIR, /tmp, and the task's own package caches.
  • It cannot read your credentials (~/.ssh, ~/.aws, ~/.npmrc, cargo's registry token and many more), your own folders (Documents, Desktop, Downloads, Pictures, cloud storage), Kule's home, or the projects beside the workspace.
  • Its home is the task's home layer: what it writes in ~/.zshrc or ~/.config is caught for review with kule home.
  • Its network goes through the task's proxy. Package registries pass; anything else the policy does not let through is refused, since the CLI has nobody to ask. Every connection is logged.
  • Its environment holds only what tools need to find themselves. Tokens and agent sockets in your environment are left out.
  • KULE_TASK holds the task's id.

If the sandbox cannot be set up, the command does not run.

When the command ends, Kule prints the copy's changes (all of them, not only this command's), the connections it made, home writes, and on macOS what the sandbox refused. kule exec exits with the command's own exit code.

exec does not make steps; steps are an agent's tool calls. Commit and rollback are refused while an exec runs in the task.

See The sandbox for the full list of what is hidden and why.

Arguments​

NameRequiredMeaning
TASKyesThe task's full id. See Naming a task.
COMMAND...yesThe program and its arguments, after --. It is run directly, not through a shell; use sh -c '…' for pipes, && or globs.

Options​

OptionValueDefaultMeaning
--allow-writepathAlso let the command write under this path. Repeatable.
--hidepathAlso hide this path from the command. Repeatable.
--revealpathLet the command read a path that is hidden by default, such as ~/Library/Keychains for an agent's own login, or a project beside the workspace (read-only). Repeatable. Kule's home and the task's own folder are never revealed.
--pass-envnamePass this environment variable on to the command. Repeatable.
--no-networkShut TCP networking for the command, localhost included.
--open-networkLet the command connect anywhere, bypassing the proxy and the policy.
--no-sandboxRun without the sandbox. The command can write anywhere you can and reach any host; the options above mean nothing then.
--homepath~/.kuleKule's home (also KULE_HOME). See global options.
warning

--reveal, --allow-write, --open-network and --no-sandbox open holes that Kule closes on purpose. Use them for a command you trust, and as narrowly as you can: --reveal one folder rather than its parent.

Examples​

Run the tests:

kule exec 3422f830 -- cargo test

See what a command changed:

$ kule exec 3efe1ca8 -- sh -c 'echo notes > NOTES.md; ./update-main.sh'
2 file changes: +1 ~1 -0
+ NOTES.md
~ src/main.rs
~ function main
+ function wave

What the sandbox refuses (macOS):

$ kule exec 3efe1ca8 -- sh -c 'ls ~/.ssh; echo hi > ~/notes.txt'
ls: /Users/me/.ssh: Operation not permitted
sh: /Users/me/notes.txt: Operation not permitted
sandbox: refused file-read-metadata /Users/me/.ssh (ls)
sandbox: refused file-write-create /Users/me/notes.txt (bash)

The network goes through the proxy:

$ kule exec 3efe1ca8 -- sh -c 'curl -sI https://registry.npmjs.org/ >/dev/null; curl -sI https://example.com/'
net: registry.npmjs.org:443 · tunneled (package-registries)
net: example.com:443 · refused, would wait for approval; the command line asks no one (no-rule-lets-it-pass)

To let a host through every time, see kule rules allow.

No network at all:

kule exec 3422f830 --no-network -- ./build.sh

Try an installer you do not trust yet:

kule exec 3422f830 -- sh ./install.sh
kule status 3422f830 # what it would have changed
kule home 3422f830 # what it tried to write in your home
kule rollback 3422f830 # throw it all away

Build against a project beside the folder:

kule exec 3422f830 --reveal ../shared -- npm run build

To open it for every task on the folder, use kule reveal add.

Run a headless agent CLI yourself (instead of kule run):

kule exec "$TASK" --reveal ~/Library/Keychains \
--allow-write ~/.claude --allow-write ~/.claude.json \
-- claude -p "Fix the failing test, run cargo test." \
--allowedTools "Bash,Read,Edit,Write"

Output​

LineMeaning
the command's own outputPrinted as it runs.
N file changes: +a ~m -d and the listEverything the copy holds that the workspace does not, as kule status shows it.
N ignored by the workspace, staying in the copy …Paths the workspace's .gitignore excludes (build output, .env). A commit leaves them behind unless you pass --include-ignored.
git:Repository changes. See Git.
net: <host>:<port> · tunneled (<rule>)A connection the policy let through, and the rule that did.
net: <host>:<port> · refused, …A connection the policy did not let through.
sandbox: refused <operation> <path> (<program>)What the sandbox refused, on macOS. They are also kept in the task's sandbox.jsonl.
kule: running without the sandboxYou passed --no-sandbox.
kule: network open, bypassing the proxy and the policyYou passed --open-network.

Errors and fixes​

MessageWhat to do
Operation not permitted from the commandThe sandbox refused it. Check the sandbox: lines; if the command really needs that path, use --reveal or --allow-write for it.
a net: … refused line and a failed downloadLet the host through with kule rules allow, or use the app, where the connection waits for your answer.
kule: could not run <program>The program is not on the PATH the command sees, or is not executable.
kule: an agent is at work in task <id> …Wait for the agent's run to end.

On Linux without unprivileged user namespaces, see kule isolation.

In the app​

The app has no field for a single command. Open the task's Terminal (Ctrl+`) to run commands yourself; note that the terminal is outside the sandbox, like kule shell.

See also​