change-the-image
Skill2 starsChanged 15 days agoMITView on GitHub
Add, upgrade or remove a tool in the sandbox image, or change its layout. Covers where versions live, both architectures, the Lima VM that provision.sh also provisions, what fctl and derived images rely on, the image's size, and verifying a change with a local build or the pull request's Image and Develop fctl workflows. Use for any change to Dockerfile, provision.sh, check.sh or check-fctl.sh.
- Installs packages
The file
We split this skill into the rules it gives an agent
3 rules. About 0 are common, 0 are distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 17
Install it in
provision.sh: Prefer Debian's package: add it to the apt-get install list. - Very specific: line 28
Check for it: Add the command to check.sh's list of tools, and to the --version runs when it could be there but broken (a proxy without its …
- Very specific: line 44
Two architectures: Every download works on amd64 and arm64: pick the file with dpkg --print-architecture (amd64, arm64) or uname -m …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Changing the image
provision.shinstalls everything, as root; the Dockerfile only runs it and sets the user and the PATH. The versions are at the top, asNAME="${NAME:-default}", so a build can override one.check.shis the layout fctl and images builtFROMthis one rely on, checked in every build.- README.md lists the tools with their versions, and the layout.
Adding or upgrading a tool
- Install it in
provision.sh. Prefer Debian's package: add it to theapt-get installlist. Otherwise use the project's own installer or release archive, with the version pinned at the top of the script, and check the download against the checksum the project publishes, when it publishes one. A toolchain agents extend (more versions, targets, global tools) goes in the agent's home throughas_agent, like rustup and Bun; anything else system-wide. - Make it work from the PATH alone. fctl-agent passes Claude the PATH, HOME and the locale, nothing else from the image. A tool that needs an environment variable gets a wrapper or a config file instead. A new PATH entry is a layout change (below).
- Check for it. Add the command to
check.sh's list of tools, and to the--versionruns when it could be there but broken (a proxy without its toolchain). - List it in README.md's "What's inside", with its version.
- Say what it costs. The Image workflow's summary lists each architecture's size; put the difference in the pull request.
An upgrade changes the version at the top of provision.sh and in README.md.
Rust follows fctl's rust-toolchain.toml; Claude Code and fctl aren't pinned
here (the workflow passes the versions it builds with).
Removing a tool breaks images and sessions that use it: a breaking change
(the commit skill) with a reason.
What bites
- Two architectures. Every download works on amd64 and arm64: pick the
file with
dpkg --print-architecture(amd64,arm64) oruname -m(x86_64,aarch64). - The Lima VM. fctl's Lima driver runs
provision.shin a Debian 13 VM (Lima's cloud image, nottrixie-slim), or a Debian 12 one with Lima before 2.0 and on hosts of fctl 0.14 and earlier, so keep it working on both. It runs as root, withAGENT_USERset to the VM's user, who already exists and may not be uid 1000. Use$AGENT_USERand$AGENT_HOME, neveragentor/home/agent, and don't rely on what only the Dockerfile sets. - Login shells. Setup scripts and the Lima driver run
bash -l, which reads/etc/profile.d/fctl.sh. Keep its PATH and the Dockerfile'sENV PATHthe same. - apt's lists are removed after the first installs; a later
apt-get installneeds its ownapt-get updateand cleanup. - Python is externally managed. No
pip installinto the system: useuv tool install(as the agent) or a Debian package. - Playwright's version is its browsers' and their libraries'. Bumping
PLAYWRIGHT_VERSIONmoves all three:playwright install-depstakes the libraries from Playwright's own list for the Debian release it runs on (Lima's Debian 12 included), and the globalplaywrightinstalls the browsers into the agent's~/.cache/ms-playwright. Playwright removes browsers that no installed copy of it uses whenever it installs others, so the copy that installs them must stay in the image. - No auto-updates and no daemons. fctl turns off Claude Code's auto-updater, and sessions start only fctl-agent; a tool that expects a service running won't find one.
Changing the layout
The user, its home, ~/workspace, /opt/fctl/bin and the PATH are an
interface: installed fctl hosts and images built FROM this one rely on
them. Look for a way that keeps them first. If there is none:
- Make it a breaking change (
feat!:with aBREAKING CHANGE:paragraph). - Change
check.shand README.md's Layout with it. - Change fctl's Sandbox images page (
docs/sandbox-images.mdin hyperstructure/fctl) to match, and fctl itself when hosts must adapt, released before this merges. An fctl session's token covers only its own repository: name what hyperstructure/fctl needs, and tell the person.
The newest fctl release's tag is rebuilt from main, so its hosts get the
change the next time they pull the image.
Verifying
- With Docker:
docker build -t sandbox:dev ., thendocker run --rm -i sandbox:dev sh -s < check.sh, and try the tool:docker run --rm sandbox:dev bash -lc 'psql --version'. Add--platform linux/amd64(orarm64) to try the other architecture under emulation, slowly. - In an fctl session (no Docker): open the pull request. The Image
workflow builds both architectures with the latest fctl and Claude Code
and runs
check.shin each:gh pr checks N --watch --fail-fast, then the run's summary for the sizes. The Develop fctl workflow runscheck-fctl.shin each too: fctl's own checks, sessions and screenshots, as sessions working on fctl do them, with fctl's branch of the same name when there is one. - With fctl: on a host,
docker build -t sandbox:dev .and set it as a project's image (Settings → Sandbox → Image), orfctl host image build --source .from a checkout, which builds it under the host's image name (with Lima: provisions the base VM). Then start a session and use the tool.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

