---
title: Core Concepts
description: The mental model behind jackin' — operators, agents, roles, constructs, and workspaces
---
import { Aside } from '@astrojs/starlight/components'


## The operator

**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.

## Agents

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)

### Roles

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.

### Agent instances

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](/guides/parallel-agents/).

## The construct

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.

<Aside type="note">
If you want to know exactly what the `construct` contains and how it
is built, see [The Construct Image](/developing/construct-image/) in
the internals section. Operators rarely need that level of detail.
</Aside>

## Docker-in-Docker

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.

## Workspaces

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.

<Aside type="tip">
Saved workspaces are managed exclusively through `jackin workspace …`
commands or the operator console — there is no need to hand-edit any
configuration file. Every operator-level setting has a CLI flow; the
common ones (workspace mounts, workspace env, per-(workspace × role)
auth) additionally have a TUI flow in the operator console. Global
mounts, global env, and a few advanced flags are CLI-only today.
</Aside>

## State persistence

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>`.

## Putting it all together

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 inside** — `Claude 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 `Dockerfile`s, networking, isolated
worktrees, the post-attach finalizer — see
[Architecture](/reference/architecture/) in the internals section.
