Skip to content

Core Concepts

You are the operator. You sit outside every container and control what gets loaded into each one. 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 drive jackin’ from your host machine through two surfaces: the operator console (jackin console) — an interactive TUI that is the simplest and most-used way to work day-to-day — and the CLI (jackin load, jackin workspace, …) for advanced, scripted, or non-interactive flows.

An agent is an AI coding runtime (Claude Code, Codex, Amp, Kimi, or OpenCode today) running inside an isolated Docker container. Each agent:

  • Has its own filesystem, network, and process space
  • Runs at full speed inside the container — whatever “no permission prompts” mode the runtime ships (Claude Code’s --dangerously-skip-permissions, Codex’s YOLO, etc.) — because the boundary is the container, not the prompts
  • Can only access directories you explicitly mount
  • Can build and run its own containers (Docker-in-Docker), without touching your host’s Docker daemon
  • Persists its state between sessions (conversation history, runtime settings, GitHub CLI auth/config, plugins)

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

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

The name agent-smith is just a project-specific example. In practice, role 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 a role as answering: “What kind of agent is this?”

  • Which language toolchains are installed?
  • Which shell setup or helper scripts are present?
  • Which Claude Code plugins (or equivalent extensions for other runtimes) are installed?
  • Which defaults should this agent start with?

One project may intentionally use several roles. That is not redundancy. It is how you keep the agent’s world focused. A frontend-oriented role can carry UI tooling and plugins, while a backend-oriented role 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 role can have multiple running instances. Each instance is a separate container with its own state. This lets you run the same agent type against the same workspace or against different workspaces simultaneously.

An instance can also contain more than one agent session when the role supports multiple runtimes. For example, you can start Claude Code to implement a change, then start Codex inside the same running instance to review the same branch and run tests. For day-to-day workflows, see Parallel Agents.

Every running instance has a jackin’ Capsule inside it. The Capsule is the small control process that starts first in the container and stays there while the instance is alive.

From an operator’s point of view, the Capsule is what makes a running instance feel like a persistent agent workspace instead of a one-shot docker run:

  • It owns the in-container multiplexer: tabs, split panes, the status bar, the command palette, and the identity strip at the top of the terminal.
  • It keeps agent sessions running after your terminal disconnects, so closing a terminal tab detaches from the instance instead of killing the agent.
  • It lets you reconnect with jackin hardline, start another agent tab with jackin hardline --new, or open a shell tab with jackin hardline --shell.
  • It reports live session inventory back to jackin console and jackin hardline --inspect, including which agent tabs exist and which one is focused.
  • It performs container-local setup before an agent starts, such as preparing the durable agent home and applying the auth handoff that jackin’ already decided at launch.

The visible result is the two-line jackin’ chrome at the top of an attached terminal. The first line identifies the session and tabs; the second line shows the running instance identity and opens Container info when clicked. The rest of the terminal belongs to the focused agent or shell pane. Agent shortcuts, editors, full-screen TUIs, bracketed paste, mouse reporting, wheel scrolling, and normal terminal output still go to the focused pane unless the Capsule UI is explicitly active. Normal-screen panes use jackin’ scrollback and scroll chrome only when terminal history exists, including rows preserved before normal-screen clear/redraw; empty-history wheel gestures stay local to jackin’ instead of becoming prompt cursor keys. Full-screen TUIs that opt into mouse reporting receive pane-local mouse events.

That means one running instance can hold a small working room:

  • one tab running Claude Code to implement a change
  • another tab running Codex to review it
  • a shell tab for inspection or one-off commands
  • split panes when you want multiple views visible at once

All of those tabs share the same mounted files, branch, role tooling, forwarded credentials, and private Docker-in-Docker sidecar. They do not share conversation context: each agent runtime still owns its own prompt history and state.

The Capsule is not another agent and it is not a separate container. It is jackin’-owned runtime plumbing inside the role container. You normally interact with it through jackin load, jackin console, and jackin hardline, not by running jackin-capsule yourself.

The construct is the shared base Docker image that every agent starts from. It carries the operating system and the tools every agent is expected to have on day one — Debian, the Docker CLI, git, GitHub CLI, mise, ripgrep, fd, fzf, zsh with Oh My Zsh, and the Starship prompt.

Role repos extend the construct with their own tools. For example, a role for Rust development would add the Rust toolchain on top of the construct.

You don’t pull or maintain the construct yourself — jackin load does it for you the first time it is needed.

Each agent gets its own private Docker daemon. From the agent’s point of view that means it can run docker build, docker run, and docker compose inside its own container, without ever talking to your host Docker daemon.

The practical consequence: an agent can build and run containers as part of its work, but those containers cannot escape into your host’s Docker engine.

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 roles — optionally restrict which roles can use this workspace
  • default role — which role to highlight first in the console picker, and which role CLI context loading can use automatically

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

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

  • role = 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 roles.

  • 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 you create in the operator console (or with jackin workspace create from the CLI). 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.

Each agent keeps its own session state — conversation history, login state for tools you authenticated inside the container (such as gh), and any plugins the role installed. When you stop and restart an agent, it picks up where it left off.

To wipe an agent’s persisted state and start fresh, run jackin purge <role>.

When you run jackin load agent-smith ~/Projects/my-app, jackin’ takes care of every step needed to launch a usable agent — from your point of view, that looks like:

  1. Pick the role — fetch and validate the role repo.
  2. Build the agent image — extending the construct with the role’s tools and the agent runtime. Subsequent loads reuse Docker’s layer cache.
  3. Mount your project files — at the path the workspace says.
  4. Start the container in isolation — on its own Docker network, with its own private Docker daemon for any containers the agent itself needs to build.
  5. Drop you insideClaude Code (or another supported runtime — Codex, Amp, Kimi, or OpenCode) starts with full permissions inside that boundary.

That whole sequence is one command. If you want to read the full, under-the-hood account — derived Dockerfiles, networking, isolated worktrees, the post-attach finalizer — see Architecture in the internals section.