Repository navigation
Add Docker Sandbox setup #2292
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Add Docker Sandbox setup #2292
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
4b04e9c
Add agent instructions
theseanything c4b0486
Add Docker Sandbox setup for local development
theseanything 838fd94
Point sandbox at AGENTS.md for commit rules
theseanything e1386ae
Add Chrome to sandbox for browser specs
theseanything c7a8ac3
Turn off PR attribution in the sandbox
theseanything aea7bf2
Bump sandbox kit and require sbx 0.48.0
theseanything 75e3023
Remove model overrides from gateway kit
theseanything a841737
Run Claude in fullscreen mode in the sandbox
theseanything ab1fb2c
Allow docs sites in the sandbox
theseanything 20e173d
Add an optional status line to the sandbox
theseanything File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| { | ||
| "attribution": { | ||
| "pr": "" | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| # Agent instructions | ||
|
|
||
| The Docker sandbox in `local/sbx/` tells Claude to follow these rules in every | ||
| GOV.UK Forms repo, so keep them general and keep this file at this path. | ||
|
|
||
| ## Commits | ||
|
|
||
| - Split features into well-scoped commits. Each commit should leave the tests | ||
| green. | ||
| - Commit titles: 50 characters or fewer, imperative, naming only the thing | ||
| changed ("Add Brand model", not "Add Brand model backed by database table"). | ||
| - Commit bodies: explain why the change is needed, and include only context | ||
| the diff doesn't show, such as external constraints or why an approach was | ||
| forced. | ||
| - Fold additional changes into the commit they belong to rather than adding | ||
| fixup commits. | ||
| - Don't push or update pull requests unless asked. Committing locally is fine. | ||
|
|
||
| ## Pull requests | ||
|
|
||
| - Use `.github/PULL_REQUEST_TEMPLATE.md`. | ||
| - Keep descriptions to a few short paragraphs, with only context a reviewer | ||
| can't see in the diff. | ||
| - Don't mention AI tooling in pull request descriptions. | ||
|
theseanything marked this conversation as resolved.
theseanything marked this conversation as resolved.
|
||
| - Don't describe fixes as security or vulnerability issues in public pull | ||
| requests. Describe what the code now enforces. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,211 @@ | ||
| # GOV.UK Forms in a Docker Sandbox | ||
|
|
||
| Use this to work on GOV.UK Forms with Claude Code in a [Docker Sandbox][sbx]. | ||
| A sandbox is an isolated Linux virtual machine. Claude can only see and change | ||
| what's inside it. | ||
|
|
||
| The sandbox has: | ||
|
|
||
| - the folder holding forms-admin, forms-runner, forms-product-page and | ||
| forms-deploy, shared with your machine so changes show on both sides | ||
| straight away. Claude starts in that folder, and can see anything else you | ||
| keep in it | ||
| - the Ruby and Node versions each app needs | ||
| - Postgres and Valkey | ||
| - Chrome and chromedriver, for the specs that run in a browser | ||
| - each app's gems, npm packages and databases, ready to use | ||
| - Claude Code, connected to the team's model gateway | ||
|
|
||
| The sandbox cannot see files outside that folder, so don't keep anything in it | ||
| you wouldn't want Claude to read. It also cannot see your gateway key or | ||
| GitHub token. | ||
|
|
||
| [sbx]: https://docs.docker.com/ai/sandboxes/ | ||
|
|
||
| ## Before you start | ||
|
|
||
| You need: | ||
|
|
||
| - [Docker Sandboxes][install] 0.48.0 or newer installed, and to be signed in | ||
| with `sbx login`. Check with `sbx version`, and upgrade with | ||
| `brew upgrade --cask sbx` if you installed it with Homebrew | ||
| - the GOV.UK Forms repos cloned side by side, as described in | ||
| [`../README.md`](../README.md) | ||
| - your model gateway key, which starts with `sk-` | ||
|
|
||
| Your repos should look like this: | ||
|
|
||
| ``` | ||
| top-level/ | ||
| ├── forms-admin | ||
| ├── forms-deploy | ||
| ├── forms-product-page | ||
| └── forms-runner | ||
| ``` | ||
|
|
||
| If you want Claude to push and open pull requests, you also need a | ||
| [fine-grained GitHub token][pat]. Give it read and write access to | ||
| **Contents** and **Pull requests** on the govuk-forms repos. Without a token, | ||
| Claude can commit in the sandbox, and you push from your machine as usual. | ||
|
|
||
| [install]: https://docs.docker.com/ai/sandboxes/install/ | ||
| [pat]: https://github.com/settings/personal-access-tokens/new | ||
|
|
||
| ## Set up the sandbox | ||
|
|
||
| You only need to do this once. | ||
|
|
||
| 1. Run the setup script: | ||
|
|
||
| ```bash | ||
| cd forms-deploy/local/sbx | ||
| ./setup.sh | ||
| ``` | ||
|
|
||
| 2. Choose whether to add a GitHub token. | ||
| 3. Paste your model gateway key when asked. | ||
| 4. Choose whether to add the status line. | ||
|
|
||
| The script: | ||
|
|
||
| - stores your gateway key and GitHub token as sbx secrets | ||
| - installs the [commit messages skill][skill] | ||
| - adds your git name and email to `~/.sbxenv.yaml`, so your commits in the | ||
| sandbox are in your name | ||
| - if you choose to, copies [`statusline.sh`](statusline.sh) into `.claude/` in | ||
| the folder holding the repos and sets it in `.claude/settings.local.json` | ||
| there. Claude then shows the model, folder, git state, context use and cost | ||
| under the prompt, in the sandbox and when you run Claude in that folder on | ||
| your machine | ||
|
|
||
| The sbx proxy adds your secrets to requests as they leave the sandbox, so the | ||
| sandbox never sees them. | ||
|
|
||
| You can safely run the script again. It skips anything already done. To | ||
| answer the questions up front, use `--github` or `--no-github`, and | ||
| `--statusline` or `--no-statusline`. | ||
|
|
||
| [skill]: https://gitlab.com/gitlab-org/ai/skills/-/blob/main/skills/commit-messages/SKILL.md | ||
|
|
||
| ## Start the sandbox | ||
|
|
||
| From this directory, run: | ||
|
|
||
| ```bash | ||
| sbx env run | ||
| ``` | ||
|
|
||
| Always run `sbx env` commands from this directory, without a path. Otherwise | ||
| sbx will not use your `~/.sbxenv.yaml`, and your commits will not have your | ||
| name and email. sbx also loses track of the sandbox if you mix the two. | ||
|
|
||
| The first run takes a few minutes to build and create the sandbox. After that, | ||
| it reconnects to the same sandbox and keeps your files, gems and databases. | ||
|
|
||
| Each time Claude starts, the sandbox installs anything missing and prepares | ||
| the databases in the background. This takes about a minute the first time and | ||
| a few seconds after that. Claude knows to wait for it before running specs. | ||
|
|
||
| ## Run the apps | ||
|
|
||
| When you or Claude run an app in the sandbox, open it on your machine: | ||
|
|
||
| - forms-admin: http://localhost:3100 | ||
| - forms-runner: http://localhost:3101 | ||
| - forms-product-page: http://localhost:3102 | ||
|
|
||
| These are not the apps' usual ports, so the sandbox can run alongside the | ||
| [Docker Compose setup](../README.md). | ||
|
|
||
| ## Manage the sandbox | ||
|
|
||
| Run these commands from this directory. | ||
|
|
||
| | To | Run | | ||
| | ---------------------------- | --------------------------- | | ||
| | Run a command in the sandbox | `sbx env exec -- <command>` | | ||
| | Stop the sandbox | `sbx stop govuk-forms` | | ||
| | Delete the sandbox | `sbx env rm` | | ||
|
|
||
| Deleting the sandbox does not affect your repos. | ||
|
|
||
| ## Change the sandbox | ||
|
|
||
| Changes to `env:` in `sbxenv.yaml` apply the next time you run `sbx env run`. | ||
|
|
||
| Changes to kits, bindings or secrets only apply when the sandbox is created. | ||
| To pick them up, delete the sandbox with `sbx env rm`, then run `sbx env run`. | ||
|
|
||
| ## How it works | ||
|
|
||
| - [`sbxenv.yaml`](sbxenv.yaml) defines the sandbox: its kits, repos, | ||
| environment variables and ports, and which hosts can receive each secret. | ||
| - `~/.sbxenv.yaml` holds your personal settings. sbx merges it with | ||
| `sbxenv.yaml`. | ||
| - The agent is Docker's [Claude Code kit][claude-kit]. The 2 [kits][kits] in | ||
| this directory add to it. Each has a descriptor (`<kit>.yaml`), and | ||
| forms-dev also has a Dockerfile for the files it adds. | ||
| - [`ai-gateway/`](ai-gateway) connects Claude Code to the model gateway. | ||
| Claude only sees a placeholder in `ANTHROPIC_AUTH_TOKEN`. The sbx proxy | ||
| replaces it with your key on requests to the gateway, and nowhere else. | ||
| - [`forms-dev/`](forms-dev) installs build tools, mise and Chrome, allows the | ||
| domains the setup needs, and declares the optional `github` secret. Each time the | ||
| sandbox starts, it runs: | ||
| - `forms-dev-up`, which starts Postgres and Valkey and gives each app a | ||
| separate `node_modules` in the sandbox. This keeps Linux builds of | ||
| packages like esbuild and rolldown out of your machine's `node_modules`. | ||
| - `forms-app-setup`, which installs everything each app needs. | ||
| - forms-dev also gives Claude | ||
| [notes about the sandbox](forms-dev/forms-dev-context.md), and tells it to | ||
| follow the commit and pull request rules in this repo's | ||
| [`AGENTS.md`](../../AGENTS.md) in every repo. Change the rules there. | ||
| - forms-dev turns off the Claude Code footer on pull requests and turns on | ||
| fullscreen rendering in the sandbox user's Claude settings, so both apply | ||
| in every repo. | ||
| - The sandbox cannot use SSH, so inside the sandbox git rewrites GitHub | ||
| remotes to HTTPS. The proxy adds your GitHub token to those requests. | ||
|
|
||
| [claude-kit]: https://hub.docker.com/r/docker/sbx-kit-claude | ||
| [kits]: https://docs.docker.com/ai/sandboxes/customize/use-kits/ | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| ### Specs fail before they run | ||
|
|
||
| The app setup may not have finished, or it may have failed. In the sandbox, | ||
| check `/tmp/forms-app-setup.status` and `/tmp/forms-app-setup.log`. If there is | ||
| no status file, the setup has not started. To run the setup again, run | ||
| `forms-app-setup`. It stops straight away if the setup is still running. | ||
|
|
||
| ### Claude gets a 401 error from the gateway | ||
|
|
||
| Your gateway key is missing or wrong. Run `sbx secret ls` to check there's a | ||
| global `ai-gateway` secret. To replace it, run | ||
| `sbx secret rm ai-gateway -f && ./setup.sh`, then delete and recreate the | ||
| sandbox. | ||
|
|
||
| ### Building a kit fails with "failed to connect to the docker API" | ||
|
|
||
| If the `docker` command is installed, sbx uses Docker to build the kits in | ||
| this directory. Start Docker Desktop and try again. | ||
|
|
||
| ### A download or request is blocked | ||
|
|
||
| Run `sbx policy log govuk-forms` to see which domains were blocked. Add them | ||
| to the network policy's `runtime` list in | ||
| [`forms-dev/forms-dev.yaml`](forms-dev/forms-dev.yaml). | ||
|
|
||
| ### `git push` or `gh` fails in the sandbox | ||
|
|
||
| The sandbox needs a GitHub token to push. Push from your machine instead, or | ||
| run `sbx secret set github` and then delete and recreate the sandbox. | ||
|
|
||
| ### Vite fails on your machine after using the sandbox | ||
|
|
||
| Linux packages have been written to your machine's `node_modules`. Run | ||
| `npm ci` in that app on your machine. | ||
|
|
||
| ### Claude Code's full screen view will not scroll in tmux | ||
|
|
||
| Add `set -g mouse on` to `~/.tmux.conf` to turn on mouse mode, or use the | ||
| Page Up and Page Down keys. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| # syntax=docker/sandbox-kit:3 | ||
| # | ||
| # Points Claude Code at the team's model gateway, a LiteLLM proxy, and has | ||
| # the sbx proxy supply each person's gateway key. The key stays in the host's | ||
| # secret store under the `ai-gateway` service (setup.sh stores it). The | ||
| # sandbox only sees a placeholder in ANTHROPIC_AUTH_TOKEN, and the proxy | ||
| # replaces the Authorization header on requests to the gateway. | ||
| schemaVersion: "3" | ||
| kind: mixin | ||
| displayName: AI Engineering Lab model gateway | ||
| description: >- | ||
| Routes Claude Code through the AI Engineering Lab LiteLLM gateway, with | ||
| the gateway key supplied by the sandbox proxy. | ||
| version: "1.0.0" | ||
|
|
||
| # Hooks run after the kits they require, so the hook below runs after the | ||
| # claude kit writes settings.json | ||
| requires: ["claude"] | ||
|
|
||
| build: | | ||
| FROM scratch | ||
| ENV ANTHROPIC_BASE_URL=https://licenseportal.aiengineeringlab.co.uk | ||
|
|
||
| capabilities: | ||
| - type: com.docker.sandbox/network-policy@1 | ||
| config: | ||
| runtime: | ||
| allow: | ||
| - licenseportal.aiengineeringlab.co.uk | ||
|
|
||
| - type: com.docker.sandbox/credential@1 | ||
| description: Model gateway key | ||
| config: | ||
| service: ai-gateway | ||
| phase: runtime | ||
| apiKey: | ||
| name: ANTHROPIC_AUTH_TOKEN | ||
| proxyManaged: true | ||
| inject: | ||
| - domain: licenseportal.aiengineeringlab.co.uk | ||
| header: Authorization | ||
| format: "Bearer %s" | ||
|
|
||
| # The claude kit adds an apiKeyHelper when the person has an anthropic | ||
| # secret, and Claude Code warns when that and ANTHROPIC_AUTH_TOKEN are both | ||
| # set. jq comes with the claude kit's image. | ||
| - type: com.docker.sandbox/lifecycle@1 | ||
| config: | ||
| install: | ||
| - description: Remove the claude kit's apiKeyHelper | ||
| user: agent | ||
| command: > | ||
| f=~/.claude/settings.json; | ||
| [ ! -s "$f" ] || | ||
| { new=$(jq 'del(.apiKeyHelper)' "$f") && printf '%s\n' "$new" > "$f"; } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.