1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
|
= SBX: Docker Sandbox Environment
:toc: left
:toclevels: 3
:sectnums:
:icons: font
== Overview
SBX is Docker's sandboxed environment system that provides isolated, persistent development containers with controlled network access, environment persistence, and Git integration. It enables secure development workflows with fine-grained policy control.
== Core Features
=== Environment Persistence
SBX provides a persistent environment file at `/etc/sandbox-persistent.sh` that is automatically sourced across all shell contexts:
* **Non-interactive shells**: via `BASH_ENV=/etc/sandbox-persistent.sh`
* **Login shells**: via `/etc/profile.d/sandbox-persistent.sh`
* **Interactive shells**: via `/etc/bash.bashrc` and `~/.bashrc`
.Adding Persistent Variables
[source,bash]
----
echo "export VAR_NAME=value" >> /etc/sandbox-persistent.sh
----
[IMPORTANT]
====
**Never add shell completion scripts to `/etc/sandbox-persistent.sh`**. Completion scripts break the bash tool because the persistent file is sourced before every command execution, not just during initialization. Only add core initialization scripts (like `nvm.sh` or `sdkman-init.sh`), never completion scripts (like `bash_completion`).
====
=== Network Access and Security
SBX includes a firewall that restricts outbound network access with policy-based controls.
==== Blocked Request Handling
Blocked HTTP/HTTPS requests return **HTTP 403** with structured explanations:
[horizontal]
Blocked by local rule:: A developer-added deny rule (global or per-sandbox) is blocking the host
Blocked by org policy:: Centralized organization policy enforcement
No matching allow rule:: Domain not on any allow list (default deny)
.Inspecting Connection Policy
[source,bash]
----
sbx policy log # Shows host, rule, reason, last-seen time
sbx policy ls # Shows active rules and suppressed rules
----
.Allowing Network Access
[source,bash]
----
sbx policy allow network <domain>[,<domain>…] # Allow specific domains
sbx policy allow network "**" # Allow all (not on denylist)
----
.Removing Deny Rules
[source,bash]
----
sbx policy rm network --resource <host> # Remove global deny
sbx policy rm network --sandbox <sandbox> --resource <host> # Remove sandbox-scoped deny
----
==== Port Publishing
Services in the sandbox are not directly accessible from the host. To expose ports:
[source,bash]
----
sbx ports <sandbox-name> --publish [[HOST_IP:]HOST_PORT:]SANDBOX_PORT[/PROTOCOL]
----
.Example: Publishing Web Server
[source,bash]
----
sbx ports <sandbox-name> --publish 8080:8080/tcp
sbx ports <sandbox-name> # List published ports
sbx ports <sandbox-name> --unpublish 8080:8080/tcp # Unpublish
----
[NOTE]
====
Services must listen on the `eth0` interface (not just `127.0.0.1`). Bind to `0.0.0.0` (IPv4) or `::` (IPv6) to be reachable via port publishing.
====
==== Accessing Host Services
The sandbox has its own `localhost`. To reach services on the host machine:
[source,bash]
----
curl http://host.docker.internal:3000
----
==== IP Stack Configuration
If connectivity fails, the proxy may be using the wrong IP protocol version. Configure with:
[source,bash]
----
DOCKER_SANDBOXES_IP_STACK=ipv4only # Only IPv4
DOCKER_SANDBOXES_IP_STACK=ipv6only # Only IPv6
DOCKER_SANDBOXES_IP_STACK=dual-stack # Try both (may be slow if one fails)
----
==== .NET Aspire IPv6 Workaround
.NET Aspire's DCP uses bracketed IPv6 loopback `http://[::1]:<port>`. Add to `NO_PROXY`:
[source,bash]
----
cat >> /etc/sandbox-persistent.sh <<'EOF'
if [ -z "${SBX_ASPIRE_NOPROXY_DONE:-}" ]; then
export NO_PROXY="${NO_PROXY:+$NO_PROXY,}[::1]"
export no_proxy="$NO_PROXY"
export SBX_ASPIRE_NOPROXY_DONE=1
fi
EOF
----
=== Git Integration
==== Authentication
The sandbox proxy handles GitHub authentication automatically by injecting credentials for HTTPS Git operations. No need to run `gh auth login` inside the sandbox.
[IMPORTANT]
====
`gh auth status` will show "not logged in" inside the sandbox. This is expected and does not affect Git operations.
====
.Configuring GitHub Token
[source,bash]
----
# For existing sandbox (immediate effect)
sbx secret set github --sandbox <sandbox-name> -t "$(gh auth token)"
# Globally for all future sandboxes (requires recreate)
sbx secret set github -t "$(gh auth token)"
----
[TIP]
====
Find the sandbox name using `$SANDBOX_NAME`, `hostname`, or the deprecated `$SANDBOX_VM_ID` inside the sandbox.
====
==== Git Workspace Modes
SBX supports two workspace modes. Check your mode:
[source,bash]
----
if [ -d /run/sandbox/source ]; then echo "clone mode"; else echo "direct mode"; fi
----
===== Direct Mode (Default)
The host working tree is mounted directly. Edits, commits, and branches appear on the host **immediately**. No separate copy to sync.
===== Clone Mode (`--clone`)
A standalone Git clone made at sandbox creation time:
* **HEAD** matches the host repo's state at creation
* **Commits stay in sandbox** until fetched by the host
* **Host fetches with**: `git fetch sandbox-<name>`
* **Read-only host mount** at `/run/sandbox/source`
.Syncing from Host in Clone Mode
[source,bash]
----
git fetch /run/sandbox/source # Fetch host commits
git log HEAD..FETCH_HEAD --oneline # See what's new on host
git pull /run/sandbox/source <branch> # Merge host branch
----
.Host Retrieving Sandbox Commits
[source,bash]
----
git fetch sandbox-<name> # On host machine
----
[WARNING]
====
Commits not pushed to a remote (like GitHub) are lost if the sandbox is removed, as the git-daemon only runs while the sandbox is active.
====
==== Pushing and Pull Requests
Push and open PRs **directly from inside the sandbox**:
[source,bash]
----
git remote -v # Check available remotes
git checkout -b <branch> # Create working branch
git add -A && git commit -m "…"
git push -u origin <branch> # Push to mirrored remote
gh pr create --fill # Create PR
----
.Pushing to Fork
[source,bash]
----
git push -u <fork-remote> <branch>
gh pr create --repo <org>/<repo> --head <fork-user>:<branch> --fill
----
== Claude Code Integration
=== Environment File
The `CLAUDE_ENV_FILE` variable is set to `/etc/sandbox-persistent.sh`, which is sourced before each Bash command execution, ensuring environment persistence across tool invocations.
[CAUTION]
====
Apply the same shell completion restriction: never add completion scripts to this file, as it's sourced before every command, not just shell initialization.
====
=== Using the Bash Tool
When tools are not found in PATH after installation:
[source,bash]
----
bash -l -c "your-command" # Use login shell
bash -l -c "java -version" # Example: SDKMAN-installed Java
bash -l -c "node --version" # Example: NVM-installed Node
----
[TIP]
====
Login shells always source the persistent environment file fresh, ensuring the latest configuration is honored even if shell snapshots contain cached state.
====
== Kits System
SBX supports installable "kits" that provide specialized functionality. Kit documentation is available under `/Users/k33g/kDrive/Rickub/bots-garden/kits-agent-context/` and should be read only when relevant to the task.
.Example: Ori Kit
The `ori` kit provides an ACP web client for Claude Code, serving a browser-based interface with:
* React SPA with Zed-style agent panel
* Workspace panel with file tree and Monaco editor
* Interactive terminal
* Markdown and AsciiDoc rendering
== Common Operations
=== Troubleshooting Connectivity
.Check Host IP Addresses
[source,bash]
----
# macOS
ifconfig | grep 'inet ' # IPv4
ifconfig | grep 'inet6 ' # IPv6 (ignore fe80::)
# Linux
ip -4 addr show scope global
ip -6 addr show scope global
----
=== Managing Secrets
[source,bash]
----
sbx secret set <name> --sandbox <sandbox-name> -t "value" # Per-sandbox
sbx secret set <name> -t "value" # Global
----
=== Docker Network Access
Direct access to container ports requires adding the container's network to the `no_proxy` configuration, as Docker daemon access is provided but port routing needs explicit configuration.
== Best Practices
[arabic]
. **Never add shell completions to persistent environment files** - only core initialization
. **Use login shells (`bash -l -c`)** when tools aren't found after installation
. **Bind services to `0.0.0.0` or `::`** not just `127.0.0.1` for port publishing
. **Use `host.docker.internal`** to access host services, not `localhost`
. **Push and create PRs from inside the sandbox** - it's the authorized workflow
. **Set IP stack explicitly** if dual-stack causes slow connections
. **Configure GitHub tokens as sandbox secrets** for Git push operations
== References
* Sandbox policy management: `sbx policy`
* Port publishing: `sbx ports`
* Secret management: `sbx secret`
* Git authentication: Automatic via proxy credential injection
* Environment persistence: `/etc/sandbox-persistent.sh`
|