Extending Takuto Core
You will often need tools that aren’t baked into the official image — kubectl,
terraform, an internal vendor CLI, or a pinned version of claude. Takuto Core has
a three-tier extension model, plus a fourth path for runtime-only tweaks. Pick the
one that matches your need.
| Your need | Mechanism | Where to write it |
|---|---|---|
| Add a single binary CLI (kubectl, terraform, vendor CLI) | Provisioning | [provisioning].install_commands in config.toml |
| Pin a baked tool to a specific version | Provisioning (PATH shadowing) | [provisioning].install_commands |
| Add system packages (apt) or libraries | Custom Dockerfile | New Dockerfile FROM ghcr.io/takuto-team/takuto-core:latest |
| Add an environment variable everywhere | Compose override | docker-compose.override.yml |
| Mount an extra host directory | Compose override | docker-compose.override.yml |
The guiding principle: Baked = required for advertised features, Provisioning = admin preferences, Custom image = specialized OS-level needs.
Mechanism 1 — [provisioning].install_commands
The most common case. At every Takuto startup, the entrypoint runs a SHA-gated install pass:
- It hashes the
install_commandslist. - If the hash matches the last successful run → skip (the fast path; runs every boot when nothing changed).
- If it differs → it exports
TAKUTO_TOOLS_BIN=/opt/takuto-tools/binand runs each command viabash -cas root. Per-command failures log a warning but don’t abort. The new hash is recorded only on full success, so partial failures retry next boot.
The tools land in the takuto-tools Docker volume, bind-mounted read-only into
every worker, editor, and run-command container, with /opt/takuto-tools/bin first
on $PATH — so anything you drop there is available everywhere and shadows baked
tools of the same name.
Idempotency is your responsibility
Re-runs happen whenever the list changes — including when you add a command (the existing ones re-run too). Guard each command with an existence check:
[provisioning]
install_commands = [
'[ -f "$TAKUTO_TOOLS_BIN/kubectl" ] || (curl -fsSLo "$TAKUTO_TOOLS_BIN/kubectl" https://dl.k8s.io/release/v1.31.0/bin/linux/amd64/kubectl && chmod +x "$TAKUTO_TOOLS_BIN/kubectl")',
]
After a restart, every workflow can call kubectl directly.
Pin claude to a specific version
[provisioning]
install_commands = [
'[ -f "$TAKUTO_TOOLS_BIN/claude" ] || (npm install -g --prefix "$TAKUTO_TOOLS_BIN/.npm" @anthropic-ai/claude-code@2.1.140 && ln -sf "$TAKUTO_TOOLS_BIN/.npm/bin/claude" "$TAKUTO_TOOLS_BIN/claude")',
]
PATH precedence makes the pinned version win over the runtime-installed @latest. To revert:
remove the line, restart, and rm /opt/takuto-tools/bin/claude.
Install a private vendor CLI
install_commands = [
'[ -f "$TAKUTO_TOOLS_BIN/mycli" ] || curl -fsSL -H "Authorization: token $MYCO_TOKEN" https://internal.example.com/cli/mycli-v2.tgz | tar -xz -C "$TAKUTO_TOOLS_BIN"',
]
Set MYCO_TOKEN in takuto.env so the install command can see it.
Force a re-install without changing config
The SHA gate skips re-runs when the list is unchanged. To force one (e.g. you suspect a broken binary):
docker exec --user root takuto-core-takuto-1 \
rm /opt/takuto-tools/.provisioning-sha
docker compose restart takuto
Wipe all customizations
docker compose down
docker volume rm takuto-core_takuto-tools
docker compose up -d
Mechanism 2 — Custom Dockerfile
Use this for system packages (apt libraries, daemons) or anything that touches
multiple OS directories (/etc, /usr/share, /var/lib). The takuto-tools volume
only writes a single bin/ directory, so provisioning is the wrong tool for
system-wide installs.
# my-takuto.Dockerfile
FROM ghcr.io/takuto-team/takuto-core:latest
USER root
RUN apt-get update && apt-get install -y --no-install-recommends \
awscli postgresql-client \
&& rm -rf /var/lib/apt/lists/*
USER takuto
Wire it into docker-compose.yml:
services:
takuto:
build:
context: .
dockerfile: my-takuto.Dockerfile
Then docker compose build takuto && docker compose up -d.
Mechanism 3 — docker-compose.override.yml
Compose merges docker-compose.override.yml automatically. Use it for runtime-only
tweaks that don’t need a rebuild.
Extra environment variables:
services:
takuto:
environment:
- GH_HOST=github.example.com # internal GHE instance
- MY_API_TOKEN=...
Extra bind mount:
services:
takuto:
volumes:
- /host/shared-cache:/home/takuto/.cache/shared:ro
Compose overrides affect the
takutoservice only. To propagate a mount or env var to spawned worker containers, the worker volume / passthrough-env lists in the engine must include them — see the Takuto Core source forWORKER_VOLUMESandPASSTHROUGH_ENV.
Tool inventory at a glance
- Baked (required for advertised features):
node,npm, the Rust toolchain (cargo/rustfmt/clippy),git,gh,jq,dockerCLI,iptables,ttyd,openvscode-server,mise, and the Playwright/Chromium libraries. - Installed at first start (not baked into the image): the agent CLIs
claude,codex,opencode,cursor-agent, and the Atlassian CLIacli— fetched into the sharedtakuto-toolsvolume, versioned perconfig.toml([agent.providers.*].version,[jira].acli_version). See Configuration. - Provisioning defaults (admin can pin/replace/disable): single-binary tools like the Figma and Lokalise CLIs.
- Removed (handle via custom image): tools like AWS CLI v2 that only a minority of deployments need.
Troubleshooting provisioning
- “My command isn’t running on restart.” The SHA gate skips unchanged lists — edit
something (even a comment) to change the hash, or
rm /opt/takuto-tools/.provisioning-shaand restart. - “Workers don’t see my tool.” Check it landed in the volume
(
docker exec takuto-core-takuto-1 ls /opt/takuto-tools/bin/) and that/opt/takuto-tools/binis first on the worker’s$PATH. Look for[provisioning] … WARNlines in the boot log for install failures.
For more, see troubleshooting.