Skip to content

Core Concepts

You are the operator. In The Matrix, the operator sits outside the simulation and controls what gets loaded into it. In jackin’, you decide:

  • Which agent to load
  • Which directories to mount (and whether they’re read-only)
  • Which workspace configuration to use
  • When to eject (stop) an agent

The operator never enters the container. You interact with jackin’s CLI and TUI from your host machine.

An agent is an AI coding runtime (like Claude Code) running inside an isolated Docker container. Each agent:

  • Has its own filesystem, network, and process space
  • Runs with full permissions inside the container (--dangerously-skip-permissions)
  • Can only access directories you explicitly mount
  • Has Docker-in-Docker (DinD) enabled, so it can build and run Docker containers inside its own container
  • Persists its state between sessions (Claude history, settings, GitHub CLI auth/config, plugins)

An agent class is a reusable tool profile for creating agent containers. It’s defined by a GitHub repository that contains a Dockerfile and a manifest file (jackin.agent.toml). For example:

  • agent-smith — the default agent class
  • the-architect — an agent with the full Rust toolchain (used for jackin’ development)
  • chainargos/backend-engineer — a namespaced agent for backend work in the chainargos organization

The name agent-smith is just a project-specific example. In practice, agent class names can reflect the job they are designed for:

  • frontend-engineer
  • backend-engineer
  • infra-operator
  • docs-writer
  • security-reviewer

When you run jackin load agent-smith, jackin’ clones the jackin-agent-smith repository, builds a Docker image from it, and launches a container.

Think of an agent class as answering: “What kind of agent is this?”

  • Which language toolchains are installed?
  • Which shell setup or helper scripts are present?
  • Which Claude plugins are installed?
  • Which defaults should this agent start with?

One project may intentionally use several agent classes. That is not redundancy. It is how you keep the agent’s world focused. A frontend-oriented class can carry UI tooling and plugins, while a backend-oriented class can carry server tooling and database clients, even if both point at the same workspace. The smaller and more relevant that environment is, the less out-of-scope context the agent has to inspect.

A single agent class can have multiple running instances. Each instance is a separate container with its own state. This lets you run the same agent type against different workspaces simultaneously.

In The Matrix, the construct is the empty white space where programs are loaded before a mission. In jackin’, the construct is the shared base Docker image that every agent starts from:

projectjackin/construct:trixie

The construct provides:

ComponentPurpose
Debian TrixieStable base OS
Docker CLI + ComposeSo agents can build/run containers (via DinD)
Git + Git LFSSource control
GitHub CLIRepository and PR operations
miseLanguage version management (Node, Python, Go, etc.)
ripgrep, fd, fzfFast search tools
zsh + Oh My ZshShell environment with autosuggestions
Starship promptInformative terminal prompt

Agent repos extend the construct with their own tools. For example, an agent for Rust development would add the Rust toolchain on top of the construct.

Each agent gets its own Docker daemon via a DinD sidecar container. This means agents can:

  • Build Docker images (docker build)
  • Run containers (docker run)
  • Use Docker Compose (docker compose up)

All within their own isolated Docker environment. The agent’s Docker daemon is completely separate from your host’s Docker daemon.

A workspace defines how your project directories are mounted into an agent container. It specifies:

  • workdir — the working directory inside the container
  • mounts — which host directories to mount, where, and with what permissions
  • allowed agents — optionally restrict which agent classes can use this workspace
  • default agent — which agent class to auto-select when loading this workspace

Think of a workspace as answering: “Which project files can this agent see, and where do they appear in the container?”

This is why agent classes and workspaces are separate instead of being one concept.

  • agent class = the environment
  • workspace = the accessible files

That separation gives you two kinds of control. You can keep the same project boundary while changing the agent’s tool profile, or keep the same tool profile while changing the project boundary.

Example: one monorepo workspace can be shared by two different agent classes.

  • chainargos/frontend-engineer sees the monorepo files and has Node, Playwright, and UI plugins
  • chainargos/backend-engineer sees the same monorepo files but has Rust, Postgres tools, and backend-specific plugins

That keeps tool and plugin scope small even when the project scope is shared.

Workspaces can be:

  1. Current-directory workspace — the current directory, mounted at the same path. This is what you get with jackin load agent-smith from any directory.

  2. Saved — named configurations stored in ~/.config/jackin/config.toml. Saved workspaces are useful when you want to reuse the same project boundary across sessions, launch from anywhere, preserve a multi-mount layout, or keep a preferred/default agent attached to that project.

When you load an agent, jackin’ doesn’t use the construct image directly. Instead, it generates a derived Dockerfile that:

  1. Starts from the agent’s Dockerfile (which itself starts from the construct)
  2. Remaps the container user to match your host UID/GID
  3. Installs Claude Code (or another agent runtime)
  4. Injects the runtime entrypoint script
  5. Copies in Claude plugins if declared in the manifest

The resulting derived image is cached locally. Subsequent loads skip the build step unless you pass --rebuild.

Agent state is persisted between sessions at ~/.jackin/data/<container-name>/. This includes:

  • .claude/ — Claude Code session history and configuration
  • .claude.json — Claude settings
  • .config/gh/ — GitHub CLI authentication and settings when you authenticate inside the container
  • plugins.json — installed Claude plugins

When you stop and restart an agent, it picks up where it left off. Use jackin purge to delete persisted state and start fresh.

Here’s what happens when you run jackin load agent-smith ~/Projects/my-app:

1. Resolve agent class "agent-smith"
└─ Clone/update github.com/donbeave/jackin-agent-smith
2. Validate agent repo contract
└─ Check jackin.agent.toml and Dockerfile
3. Generate derived Dockerfile
└─ Construct base → Agent layer → Claude install → Entrypoint
4. Build derived Docker image (cached if unchanged)
5. Create per-agent Docker network
└─ jackin-agent-smith-net
6. Launch DinD sidecar container
└─ jackin-agent-smith-dind on jackin-agent-smith-net
7. Launch agent container
├─ Mount ~/Projects/my-app at the same path
├─ Mount persisted state from ~/.jackin/data/
├─ Connect to jackin-agent-smith-net
├─ Set DOCKER_HOST to DinD sidecar
└─ Run Claude Code with --dangerously-skip-permissions
8. You're inside — Claude Code is ready