The Construct Image
What is the construct?
Section titled “What is the construct?”projectjackin/construct:trixie is the shared base Docker image for every agent — the foundation layer that every role extends. It provides system tools, shell environment, and container infrastructure, kept in one image so every agent inherits the same baseline.
Every agent Dockerfile starts from the construct:
FROM projectjackin/construct:0.3-trixieWhat’s inside
Section titled “What’s inside”The construct is built on Debian Trixie and includes:
System tools
Section titled “System tools”| Package | Purpose |
|---|---|
bash | Default shell for scripts |
zsh + Oh My Zsh | Default interactive shell for the agent user. Oh My Zsh runs with ZSH_THEME="" so the git plugin, autosuggestions plugin, and OSC 0/2 + OSC 7 auto-title hooks are active without overriding the Starship prompt. |
fish | Opt-in alternative shell. Pre-configured ~/.config/fish/config.fish initialises Starship and emits the same OSC 0/2 + OSC 7 pane title escapes as zsh, so pane border titles render identically. Enter with fish from a default zsh pane, or set as the login shell with sudo chsh -s /usr/bin/fish agent. |
git + Git LFS | Source control with large file support |
curl | HTTP client |
jq + yq | JSON and YAML processors |
openssh-client | SSH for git operations |
sudo | Privilege escalation (passwordless for agent user) |
tree | Directory visualization |
Search tools
Section titled “Search tools”| Package | Purpose |
|---|---|
ripgrep (rg) | Fast regex search |
fd-find (fd) | Fast file finder |
fzf | Fuzzy finder for interactive selection |
Development infrastructure
Section titled “Development infrastructure”| Package | Purpose |
|---|---|
mise | Polyglot language version manager |
| Docker CLI + Compose | Container operations via DinD |
GitHub CLI (gh) | Repository, PR, and issue operations |
| Starship prompt | Informative terminal prompt |
User environment
Section titled “User environment”The construct creates an agent user with:
- Home directory at
/home/agent - Zsh as the default shell, with fish available as an opt-in alternative (
fishfrom zsh, orsudo chsh -s /usr/bin/fish agentto change the login shell) - Passwordless sudo access
- Oh My Zsh sourced with
ZSH_THEME=""so the git plugin, autosuggestions plugin, and OSC 0/2 + OSC 7 title hooks are active without competing with Starship for the prompt - Starship prompt configured for both zsh and fish so the prompt surface stays the same when switching shells
- Pane border title (
user@host:cwd) emitted via OSC 0/2 on every prompt — the jackin-capsule multiplexer reads it and renders it as the pane title (the same mechanism zellij uses) - mise shims in
$PATHfor both shells
How it’s built
Section titled “How it’s built”The construct source starts at docker/construct/Dockerfile in the jackin’ repository. The declarative build definition lives in docker-bake.hcl at the repo root, and the supported command wrapper is Justfile at the repo root.
docker/construct/versions.env remains the source of truth for the pinned tirith, shellfirm, and MISE_VERSION build args used by docker/construct/Dockerfile. mise is installed from the official rolling apt repository during the Docker build; pinning the apt package version gives Buildx a stable cache key, and Renovate bumps invalidate the mise install layer when upstream publishes a new package.
Build workflow
Section titled “Build workflow”Use just for day-to-day construct work. Docker Bake is the underlying build engine, but contributors should treat just as the supported command surface.
Local validation
Section titled “Local validation”Before opening a pull request for construct changes, validate the image locally:
just construct-init-buildxjust construct-build-localBy default, local validation loads the image into your Docker daemon as jackin-local/construct:trixie, so it does not silently replace the canonical projectjackin/construct:trixie base image that normal jackin workflows consume.
To test jackin load against your local construct build, set JACKIN_CONSTRUCT_IMAGE after building:
just construct-init-buildxjust construct-build-localexport JACKIN_CONSTRUCT_IMAGE="jackin-local/construct:trixie"With JACKIN_CONSTRUCT_IMAGE set, jackin’ validates role Dockerfiles against the canonical image name as usual (role repos reference a versioned construct tag such as projectjackin/construct:0.3-trixie), but substitutes your local image at derived-build time so docker build uses jackin-local/construct:trixie as the actual base.
Use just construct-inspect to print the fully resolved Bake config without building the image.
If builder state gets stale or confusing, run just construct-doctor-buildx to inspect it or just construct-reset-buildx to recreate it. Set BUILDX_BUILDER before running just if you want to isolate this workflow under a different local builder name.
Platform-specific debugging
Section titled “Platform-specific debugging”To force a specific target architecture during local debugging:
just construct-build-platform amd64just construct-build-platform arm64These commands work when your buildx builder supports the target platform natively or through emulation.
Advanced publish rehearsal
Section titled “Advanced publish rehearsal”If you need to rehearse the release path against a temporary registry, point REGISTRY_IMAGE at your own namespace instead of the canonical projectjackin/construct repository:
REGISTRY_IMAGE=ttl.sh/jackin-construct-$USER just construct-push-platform amd64REGISTRY_IMAGE=ttl.sh/jackin-construct-$USER just construct-push-platform arm64REGISTRY_IMAGE=ttl.sh/jackin-construct-$USER just construct-publish-manifestCI behavior
Section titled “CI behavior”GitHub Actions reuses the same just commands on native ubuntu-24.04 and ubuntu-24.04-arm runners. Construct CI triggers when changes touch docker/construct/**, docker-bake.hcl, Justfile, or .github/workflows/construct.yml.
Pull requests, plus manual workflow runs against non-main branches, build both architectures natively without pushing images. Those validation jobs use the GitHub Actions cache backend; the cache key includes the pinned MISE_VERSION, so a Renovate mise bump invalidates the apt install layer while unrelated earlier layers can still be reused. They still do not receive Docker Hub credentials.
Pushes to main, plus manual workflow runs against main, publish each platform by digest first, then assemble the final multi-platform manifest from those digests. The registry cache uses the same pinned MISE_VERSION keying behavior as PR builds. That keeps the public tag surface limited to the canonical release tags instead of leaving permanent public -amd64 and -arm64 tags behind.
Published images also carry explicit BuildKit provenance and SBOM attestations.
The published tags are:
projectjackin/construct:trixie— the stable tagprojectjackin/construct:trixie-<sha>— commit-specific tag
The derived image layer
Section titled “The derived image layer”When you load an agent, jackin’ doesn’t use the construct directly. It generates a derived Dockerfile that adds:
- User remapping — adjusts the
agentuser’s UID/GID to match your host user - Agent installation — installs every agent declared in the role manifest
- Plugin installation — any Claude plugins declared in the role manifest
- Runtime entrypoint + setup bridge — the script delegates deterministic setup to
jackin-capsule runtime-setup, then keeps the shell-native work: sourcing role hooks andexec-ing the selected agent. The Rust setup path handles one-time container git/GitHub initialization, the shared git trailer hook, durable agent-home seeding, auth handoff refreshes, and Claude MCP registration. It wires up GitHub ifghis already authenticated; it does not performgh auth login, so an unauthenticatedghis left alone with a notice.
Extending the construct
Section titled “Extending the construct”Role repos add their tools on top of the construct. The construct provides the foundation — agents provide the specialization:
┌─────────────────────────────────┐│ Derived Layer (jackin-managed) │ Agent CLIs, entrypoint, user mapping├─────────────────────────────────┤│ Agent Layer (your Dockerfile) │ Rust, Node, Python, custom tools├─────────────────────────────────┤│ Construct (shared base) │ Debian, git, Docker CLI, mise, zsh└─────────────────────────────────┘This layered approach means:
- Agent authors focus on their tools, not infrastructure
- The construct can be updated independently (security patches, new tools)
- Docker layer caching makes builds fast