Allow users to wrap shell commands in a sandbox (e.g. bubblewrap,
firejail, nsjail) via config, without nanobot baking in any sandbox
backend. The template supports {command} and {cwd} placeholders with
plain string replacement.
2.9 KiB
Exec Tool Sandbox (commandWrapper)
The tools.exec.commandWrapper config option wraps every shell command in a user-defined template before execution. This allows you to add a sandbox layer (e.g. bubblewrap, firejail, nsjail) without any code changes to nanobot.
Configuration
{
"tools": {
"exec": {
"commandWrapper": "<template>"
}
}
}
Leave empty (the default) to run commands directly with no wrapper.
Placeholders
Two placeholders are available in the template:
| Placeholder | Value |
|---|---|
{command} |
The original shell command generated by the LLM |
{cwd} |
Absolute path of the working directory |
nanobot performs plain string replacement — it does not parse, validate, or shell-escape the values. The wrapper template is trusted configuration.
Examples
bubblewrap
{
"tools": {
"exec": {
"commandWrapper": "bwrap --ro-bind /usr /usr --ro-bind-try /bin /bin --ro-bind-try /lib /lib --ro-bind-try /lib64 /lib64 --proc /proc --dev /dev --tmpfs /tmp --bind {cwd} {cwd} --chdir {cwd} -- sh -c \"{command}\""
}
}
}
Requires: apt install bubblewrap (or equivalent for your distro).
firejail
{
"tools": {
"exec": {
"commandWrapper": "firejail --noprofile --private={cwd} -- {command}"
}
}
}
nsjail
{
"tools": {
"exec": {
"commandWrapper": "nsjail -Mo --chroot /sandbox --cwd {cwd} -- {command}"
}
}
}
Caveats
Warning
Do not wrap
{command}in shell quotes. If the original command contains the same quote character, the shell will break the quoting context. For example,sh -c '{command}'will fail on any command that contains single quotes.
This is an inherent limitation of the template approach — nanobot substitutes {command} as a raw string and cannot safely shell-quote it (the command may contain compound syntax like &&, |, ; that must be preserved for the inner shell).
Interaction with create_subprocess_shell
nanobot executes the wrapped command via create_subprocess_shell, which adds an outer shell layer. Keep this in mind when designing your template:
- Without
sh -c(e.g.firejail ... -- {command}): The outer shell parses{command}directly. Compound commands with&&and|work as expected because they are parsed by the outer shell before the sandbox tool receives them. - With
sh -c(e.g.bwrap ... -- sh -c "{command}"): The command is passed through two shell layers. This is only needed if the sandbox tool requires a single command argument but you want to support compound syntax.
restrict_to_workspace is independent
The tools.restrictToWorkspace setting and commandWrapper are orthogonal features. The workspace restriction guards against path traversal in the original command (before wrapping). The sandbox wrapper provides OS-level isolation. You can use either or both — they address different threat models.