Architecture
High-level architecture
Section titled “High-level architecture”┌──────────────────────────────────────────────────────┐│ Host Machine ││ ││ ┌─────────────┐ ││ │ jackin CLI │ Operator interface ││ └──────┬──────┘ ││ │ ││ ▼ ││ ┌──────────────────────────────────────────────┐ ││ │ Docker Engine │ ││ │ │ ││ │ ┌─────────────────────────────────────────┐ │ ││ │ │ jackin-agent-smith-net │ │ ││ │ │ │ │ ││ │ │ ┌──────────────┐ ┌─────────────────┐ │ │ ││ │ │ │ Agent │ │ DinD Sidecar │ │ │ ││ │ │ │ Container │ │ (docker:dind) │ │ │ ││ │ │ │ │ │ │ │ │ ││ │ │ │ Claude Code │──│ Docker daemon │ │ │ ││ │ │ │ Agent tools │ │ tcp://...:2375 │ │ │ ││ │ │ │ Mounted dirs │ │ │ │ │ ││ │ │ └──────────────┘ └─────────────────┘ │ │ ││ │ └─────────────────────────────────────────┘ │ ││ └──────────────────────────────────────────────┘ ││ ││ ~/.jackin/data/ persisted runtime state ││ ~/.jackin/agents/ cached agent repos ││ ~/.config/jackin/ operator config │└──────────────────────────────────────────────────────┘jackin’ deliberately uses your existing Docker engine as the operator control plane.
That creates an important split:
- build time happens on the host Docker engine
- runtime Docker commands issued by the agent go to the per-instance DinD sidecar
So jackin’ gets host-side cache reuse for building agent images, while still keeping the agent away from your host Docker daemon during runtime.
Design constraints
Section titled “Design constraints”jackin’s architecture is shaped by a few explicit decisions:
- Local development first. The first target is a developer machine that already knows how to run Docker.
- Environment as source code. Agent classes should be normal git repos reviewed like normal software.
- Workspace boundary separate from tool profile. File visibility and installed tooling are different control planes on purpose.
- Operator-owned infrastructure, not black-box runtime. The implementation should stay inspectable and patchable.
- Container isolation is acceptable for the first target. jackin’ does not claim a microVM boundary today.
Image layers
Section titled “Image layers”┌─────────────────────────────────┐│ Derived Layer (jackin-managed) ││ - UID/GID remapping ││ - Claude Code installation ││ - Pre-launch hook (if declared)││ - Runtime entrypoint ││ - Plugin bootstrap │├─────────────────────────────────┤│ Agent Layer (agent repo) ││ - Language runtimes ││ - Development tools ││ - Custom configuration │├─────────────────────────────────┤│ Construct Base ││ - Debian Trixie ││ - Docker CLI + Compose ││ - Git, GitHub CLI ││ - mise, ripgrep, fd, fzf ││ - zsh + Oh My Zsh │└─────────────────────────────────┘The agent repo owns the environment layer. jackin’ owns the derived runtime layer.
That means an agent class defines the tools and conventions, while jackin’ injects the runtime-specific pieces such as Claude installation, the entrypoint, and UID/GID remapping.
Container lifecycle
Section titled “Container lifecycle”Loading an agent
Section titled “Loading an agent”- Resolve agent class — map the selector to a repo, clone or update it, and reject dirty cached checkouts
- Validate the repo contract — require
jackin.agent.tomland a valid Dockerfile path, validate manifest strictly - Resolve environment variables — prompt the user for interactive env vars declared in the manifest
- Generate a derived build context — copy the repo, inject runtime assets (entrypoint + pre-launch hook), and render a derived Dockerfile
- Build the image on the host Docker engine — reusing host-side Docker cache where possible
- Create a per-agent Docker network
- Start a privileged
docker:dindsidecar - Start the agent container — mounts, resolved env vars, labels, and
DOCKER_HOSTall point at the sidecar - Run Claude Code with full permissions inside that boundary
Reconnecting
Section titled “Reconnecting”jackin hardline simply attaches to the running agent container.
Stopping
Section titled “Stopping”jackin eject removes:
- the agent container
- the DinD sidecar
- the per-agent network
Persisted state remains unless you also purge it.
Networking
Section titled “Networking”Each agent gets an isolated Docker network:
- network name is derived from the runtime container name
- the agent container and DinD sidecar share that network
- the agent reaches the daemon through
DOCKER_HOST=tcp://{dind}:2375 - different agents do not share a network by default
State management
Section titled “State management”~/.jackin/├── agents/ # Cached agent repos│ └── github.com/│ └── donbeave/│ └── jackin-agent-smith/├── data/ # Persisted state per instance│ └── jackin-agent-smith/│ ├── .claude/│ ├── .claude.json│ ├── .config/gh/│ └── plugins.jsonThis is what persists across sessions:
- Claude history and settings
- jackin’ plugin metadata
ghstate acquired inside the runtime
This is what does not persist:
- packages installed interactively into the runtime container
- ad-hoc root filesystem changes outside mounted paths
- DinD images, containers, and cache
That means jackin’ is biased toward reproducible agent classes rather than mutable long-lived sandboxes.
If a tool should always exist, put it in the agent repo Dockerfile instead of installing it ad hoc during a session.
Why Docker instead of microVMs?
Section titled “Why Docker instead of microVMs?”Because jackin’ is solving a slightly different problem.
Using plain Docker lets jackin’:
- reuse a toolchain developers already have
- keep the implementation smaller and easier to inspect
- build agent images with normal Docker workflows
- share host-side build cache across agent classes
- stay local-first without introducing a separate VM product layer
The cost of that choice is straightforward:
- weaker isolation than a microVM
- shared host kernel
- privileged DinD sidecars
- no hypervisor boundary
If the main thing you need is the strongest local boundary for autonomous agents on a laptop, microVM-based products such as Docker Sandboxes are ahead.
Current technical debt and limitations
Section titled “Current technical debt and limitations”- DinD transport is not authenticated. The runtime reaches the sidecar over plain TCP.
- Claude installation is not fully pinned. The derived image installs Claude Code from the upstream installer.
- Derived build context rejects symlinks. Agent repos with symlink-heavy layouts are not supported yet.
- Cached agent repos must stay clean. jackin’ refuses to build from a dirty or origin-mismatched cache.
- Runtime mutability is intentionally thin. That keeps sessions cleaner, but makes ad-hoc package installs non-persistent.
Technology stack
Section titled “Technology stack”jackin’ itself is built in Rust:
| Component | Technology |
|---|---|
| CLI parsing | clap |
| Terminal UI | ratatui + crossterm |
| Table output | tabled |
| Configuration | serde + toml |
| Dockerfile parsing | dockerfile-parser |
| Error handling | anyhow + thiserror |
| Colored output | owo-colors |
The project targets Rust edition 2024 with Rust 1.87+ and forbids unsafe code.