|
1 | 1 | --- |
2 | 2 | title: Kit examples |
3 | 3 | linkTitle: Examples |
4 | | -description: Copy-and-adapt spec.yaml snippets for common mixin and agent kit patterns — static files, install commands, background services, initFiles, Claude Code skills, and agent forks. |
| 4 | +description: Copy-and-adapt spec.yaml snippets for common mixin and agent kit patterns — static files, install commands, shell customization, background services, initFiles, Claude Code skills, and agent forks. |
5 | 5 | keywords: sandboxes, sbx, kits, mixins, examples, patterns, skills |
6 | 6 | weight: 25 |
7 | 7 | --- |
@@ -72,6 +72,90 @@ step should run as the agent user — for example, `npm install -g` |
72 | 72 | against a user-scoped prefix, or anything that writes to |
73 | 73 | `/home/agent/`. |
74 | 74 |
|
| 75 | +Install steps run under `sh`, not bash, so bash-only builtins such as |
| 76 | +`source` fail with `sh: source: not found`. Pipe explicitly to `bash` |
| 77 | +(`curl … | bash`) or wrap the step in `bash -c '…'` when you need them. |
| 78 | + |
| 79 | +Downloads are subject to the sandbox's |
| 80 | +[deny-by-default network policy](../governance/local.md). A domain that |
| 81 | +resolves from your host can still be blocked inside the sandbox — for |
| 82 | +example, `get.sdkman.io` returns a 403 until you allow it with |
| 83 | +`sbx policy allow network get.sdkman.io`. A tool may also need base |
| 84 | +packages that aren't in the image: [SDKMAN!](https://sdkman.io/), for |
| 85 | +instance, needs `zip` and `unzip`, so add an |
| 86 | +`apt-get install -y zip unzip` step (as root) before installing it. |
| 87 | + |
| 88 | +> [!WARNING] |
| 89 | +> `curl … | bash` masks download failures. The pipe's exit status is |
| 90 | +> bash's, and bash exits `0` on empty input, so a blocked or failed |
| 91 | +> download still reports success — the sandbox is created with no error |
| 92 | +> even though nothing was installed. Download first, then run, so a |
| 93 | +> failed fetch fails the step: |
| 94 | +> |
| 95 | +> ```yaml |
| 96 | +> commands: |
| 97 | +> install: |
| 98 | +> - command: "curl -fsSL https://example.com/install.sh -o /tmp/install.sh && bash /tmp/install.sh" |
| 99 | +> user: "1000" |
| 100 | +> ``` |
| 101 | + |
| 102 | +## Customize the shell environment |
| 103 | + |
| 104 | +Some tools install into a versioned directory and expect you to source |
| 105 | +an init script from your shell profile so their commands land on `PATH`. |
| 106 | +Version managers like [nvm](https://github.com/nvm-sh/nvm) and |
| 107 | +[SDKMAN!](https://sdkman.io/) follow this pattern. To make the tool |
| 108 | +available in every shell, append the source line to |
| 109 | +`/etc/sandbox-persistent.sh` in an install command. |
| 110 | + |
| 111 | +`/etc/sandbox-persistent.sh` is the sandbox's persistent environment |
| 112 | +file. It's sourced before every bash invocation — interactive shells and |
| 113 | +non-interactive ones, including agents started with `sbx run` and |
| 114 | +commands run with `sbx exec`. Appending here makes the tool available to |
| 115 | +the agent regardless of how its shell is launched. The same file is where |
| 116 | +you'd set a custom environment variable; see the |
| 117 | +[FAQ](../faq.md#how-do-i-set-custom-environment-variables-inside-a-sandbox). |
| 118 | + |
| 119 | +```yaml {title="nvm/spec.yaml"} |
| 120 | +schemaVersion: "1" |
| 121 | +kind: mixin |
| 122 | +name: nvm |
| 123 | +displayName: nvm |
| 124 | +description: Node version manager available in every shell |
| 125 | +
|
| 126 | +commands: |
| 127 | + install: |
| 128 | + - command: "curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash" |
| 129 | + user: "1000" |
| 130 | + description: Install nvm |
| 131 | + - command: | |
| 132 | + cat >> /etc/sandbox-persistent.sh <<'EOF' |
| 133 | + export NVM_DIR="$HOME/.nvm" |
| 134 | + unset NPM_CONFIG_PREFIX |
| 135 | + [ -s "$NVM_DIR/nvm.sh" ] && source "$NVM_DIR/nvm.sh" |
| 136 | + EOF |
| 137 | + description: Source nvm for every shell |
| 138 | +``` |
| 139 | + |
| 140 | +The install step runs as `user: "1000"` so the tool lands under |
| 141 | +`/home/agent/`. The append step runs as root (the default), since |
| 142 | +`/etc/sandbox-persistent.sh` is a system file. The `$HOME` in the |
| 143 | +appended lines resolves per user at source time, so the agent user finds |
| 144 | +its own install. Append to the file rather than overwriting it — the |
| 145 | +sandbox relies on its existing contents. |
| 146 | + |
| 147 | +The base image ships its own Node and sets `NPM_CONFIG_PREFIX`, which |
| 148 | +nvm won't activate alongside. `unset NPM_CONFIG_PREFIX` before sourcing |
| 149 | +`nvm.sh` clears that conflict. Sourcing makes the `nvm` command |
| 150 | +available; it doesn't put a Node version on `PATH`. Run |
| 151 | +`nvm install --lts` to add one — wrap it in `bash -c '…'` if you script |
| 152 | +it as an install step, since install steps run under `sh`. |
| 153 | + |
| 154 | +Append only the init script, not the tool's tab-completion script. |
| 155 | +Because `/etc/sandbox-persistent.sh` is sourced before every command, |
| 156 | +completion scripts — which rely on variables that exist only during |
| 157 | +completion — can break non-interactive shells that agents rely on. |
| 158 | + |
75 | 159 | ## Install an internal CA certificate |
76 | 160 |
|
77 | 161 | If your organization uses a proxy that inspects HTTPS traffic, install |
|
0 commit comments