---
title: Workspaces
description: Save and manage project workspace configurations
---
import { Aside } from '@astrojs/starlight/components'


## What is a workspace?

A workspace is a saved configuration that tells jackin' how to mount your project directories into an agent container. Instead of typing long mount paths every time, you save a project boundary once and reference it by name.

A workspace is **not** the same thing as a role:

- **workspace** = which project files are available
- **role** = which tools, plugins, and defaults are installed

That means one workspace can be reused with multiple roles when the file access should stay the same but the runtime profile should differ.

In practice, that is one of the main reasons workspaces exist. They let you preserve the same file boundary while swapping in the role that best matches the work.

<Aside type="tip">
Every workspace setting on this page is managed through `jackin workspace …`
commands or the operator console (`jackin console`). You should never
need to hand-edit a configuration file to manage workspaces.
</Aside>

## The current directory workspace

The simplest way to use jackin' is from your project directory:

```bash
cd ~/Projects/my-app
jackin load agent-smith
```

This creates a current-directory workspace that mounts the current directory (`~/Projects/my-app`) into the container at the **same absolute path**. The agent sees the exact same directory layout you do.

## Why save a workspace?

Loading the current directory is perfect when you are already standing in the project and only need a simple one-directory mount.

Saved workspaces become useful when you want that setup to be reusable and predictable.

They let you:

- name a project boundary once and launch it from anywhere
- keep extra mounts consistent across sessions
- reuse the same project boundary with different specialized roles
- let the operator console (`jackin console`) auto-detect and preselect the project
- set a default role or restrict which roles may use the workspace
- set a default agent such as `claude`, `codex`, `amp`, `kimi`, or `opencode`

If you regularly work on the same project, a saved workspace turns your mount layout into durable operator configuration instead of something you rebuild from memory each time.

## Saving workspaces

For projects you work on regularly, save a workspace:

```bash
jackin workspace create my-app --workdir ~/Projects/my-app --mount ~/Projects/my-app
```

Now you can load agents into it from anywhere:

```bash
jackin load agent-smith my-app
```

Or load a different role into the same workspace:

```bash
jackin load the-architect my-app
```

This is the key pattern to keep in mind: the workspace stays the same because the project boundary stays the same, but the role changes because the job changes. You might use `chainargos/frontend-engineer` for UI work in the morning and `chainargos/backend-engineer` for API work in the afternoon, both against the same saved workspace.

### What `--workdir` does

The `--workdir` path sets the container's `cwd` when the agent starts. It does not mount anything by itself.

<Aside type="tip">
Use `--mount ~/Projects/my-app` when you want the host and container paths to stay identical. Keeping the paths the same avoids confusion when the agent references files.
</Aside>

### Adding extra mounts

Workspaces can include additional directories beyond the workdir:

```bash
jackin workspace create my-app \
  --workdir ~/Projects/my-app \
  --mount ~/Projects/my-app \
  --mount ~/cache:/cache:ro \
  --mount ~/shared-libs:/libs:ro
```

### Controlling the mount layout

If you need the container layout to differ from your host:

```bash
jackin workspace create monorepo \
  --workdir /workspace \
  --mount ~/src:/workspace
```

Here, `/workspace` is the container start path and `~/src:/workspace` is the explicit mount that makes it available.

## Per-mount isolation

By default, every workspace mount is `shared` — the host directory is bind-mounted as-is, and any agent that loads the workspace edits the same files you do on the host. That is the right default for most workflows, but it stops working as soon as you want two agents to work on the same project at the same time without stepping on each other.

Setting a mount's isolation to `worktree` tells jackin' to create a per-container `git worktree` of the host repo and mount that instead of the original directory. Each container gets its own checkout, its own scratch branch, and its own working tree — so concurrent agents no longer share a `.git` directory.

### Modes

| Mode | Behavior |
|---|---|
| `shared` (default) | Host path bind-mounted as-is. |
| `worktree` | A per-container `git worktree` is created from the host repo. The container sees its own checkout on a scratch branch; refs are still shared with the host repo, so branches the agent creates are visible to you immediately. |
| `clone` | A per-container `git clone --local` is created. The container has its own `.git/` and independent refs; branches appear on your host only after an explicit push. |

Use `worktree` when you want immediate host-side branch visibility and you trust the agent with the host repo's `.git/`. Use `clone` when ref isolation matters more than immediate host visibility.

### Setting isolation from the CLI

The `--mount-isolation <dst>=<type>` flag (repeatable) on `jackin workspace create` and `jackin workspace edit` sets isolation per mount destination:

```bash
jackin workspace create jackin \
  --workdir /workspace/jackin \
  --mount ~/projects/jackin:/workspace/jackin \
  --mount ~/.cache/jackin/target:/workspace/jackin/target \
  --mount-isolation /workspace/jackin=worktree
```

The agent sees an isolated checkout at `/workspace/jackin` while `target/` is backed by a shared host cache. jackin' arranges the mounts so the cache mount overlays the corresponding path inside the isolated worktree — the cache then survives across agents even when each agent has its own checkout.

### What happens when the agent exits

When you exit an agent that was using an isolated mount, jackin' looks at the per-container checkout and decides what to do automatically:

- **Everything is wrapped up** — your work is committed and pushed (or merged on the remote and the branch was deleted), with no stray edits left behind. jackin' deletes the per-container checkout for you. There is nothing to remember.
- **There is still work to deal with** — you have uncommitted edits, or commits that never made it to the remote. jackin' keeps the checkout exactly as it was and asks what to do: go back into the agent, leave it preserved so you can return later with `jackin hardline`, or throw the work away.

If you exited non-interactively (no terminal to ask), jackin' always preserves the checkout and tells you the path on disk plus how to return, inspect it, or discard it.

If a container crashed or was terminated unexpectedly, jackin' also keeps everything in place — `jackin hardline` can restart the container so you continue where the agent left off.

For the exact safety policy (which branches count as safe, how the squash-merged-and-pruned case is detected, what the per-mount state file records), see [Foreground session finalization](/reference/architecture/#foreground-session-finalization) in the internals section.

### Validation

`worktree` and `clone` mounts have a few preconditions enforced before materialization:

- The mount source must be a git repository **root** (not a subdirectory).
- The host repo must not be mid-rebase, mid-merge, or mid-cherry-pick.
- Read-only is not allowed for an isolated mount — a forked working copy must be writable.
- Sensitive paths (`~/.ssh`, `~/.aws`, etc.) are rejected.
- Two isolated mounts whose destinations nest (one inside the other) are rejected.

If a precondition is not met, the command fails with a clear error pointing at the offending mount.

<Aside type="caution">
The worktree branches from your host repo's current `HEAD`. If your
host tree has uncommitted changes, those edits stay on the host —
they do not travel into the agent's worktree. Pass
`jackin load --force` (non-interactive) or confirm in the TUI to
acknowledge that work-in-progress stays behind.
</Aside>

To inspect what's been materialized for a container, use
`jackin workspace show <name>` (the **Isolation** column shows the
effective mode for every mount) or `git worktree list` on the host
repo. If you need the on-disk layout details, see
[Architecture](/reference/architecture/) in the internals section.

## Managing workspaces

### List all workspaces

```bash
jackin workspace list
```

### Show workspace details

```bash
jackin workspace show my-app
```

### Edit a workspace

```bash
# Change the workdir
jackin workspace edit my-app --workdir ~/Projects/my-app-v2

# Add a mount
jackin workspace edit my-app --mount ~/data:/data:ro

# Remove a mount by its container destination
jackin workspace edit my-app --remove-destination /old-mount
```

### Delete a workspace

```bash
jackin workspace remove my-app
```

## Restricting roles

You can limit which roles are allowed to use a workspace:

```bash
jackin workspace create secure-api \
  --workdir ~/Projects/secure-api \
  --allowed-role agent-smith \
  --default-role agent-smith
```

- `--allowed-role` — only these roles can load this workspace (repeatable)
- `--default-role` — role highlighted first in the operator console picker, and used automatically by CLI context loading when no role is passed
- `--default-agent` — default agent used by `jackin load` unless `--agent` is passed for that launch

This is especially useful when one workspace should only be used with a very specific tool profile, such as a production-infra role or a security-review role.

### Editing role restrictions

```bash
# Grant access to another role
jackin workspace edit secure-api --allowed-role the-architect

# Revoke access
jackin workspace edit secure-api --remove-allowed-role the-architect

# Change default role
jackin workspace edit secure-api --default-role neo

# Clear the default role
jackin workspace edit secure-api --clear-default-role

# Change default agent
jackin workspace edit secure-api --default-agent codex

# Clear default agent back to Claude fallback
jackin workspace edit secure-api --clear-default-agent
```

## Keeping the host awake

Long-running agent work — large builds, test suites, dataset pulls — can outlast your screen-saver and the host's idle-sleep timer. macOS will then suspend the machine and the agent stops making progress until you wake it up.

Workspaces can opt in to a per-workspace keep-awake reconciler that prevents this. While any agent in any keep-awake workspace is running, jackin' keeps a single `caffeinate -imsu` process alive in the background; when the last keep-awake agent stops, jackin' releases it.

<Aside type="caution">
Keep-awake is **macOS-only** today. On Linux and Windows the flag is
silently accepted but has no effect — useful when sharing settings
across machines, but the host will still sleep. If you need it on
another platform, please open an issue.
</Aside>

Other workspaces (those without the flag) are unaffected: their containers do not contribute to the keep-awake count, and the host is free to sleep if no opted-in agent is running.

### Setting keep-awake

You can opt in (or out) from the CLI or the operator console.

**CLI** — paired flags on `workspace create` and `workspace edit`:

```bash
# Opt in at creation time
jackin workspace create my-app --workdir ~/Projects/my-app --mount ~/Projects/my-app --keep-awake

# Toggle on an existing workspace
jackin workspace edit my-app --keep-awake
jackin workspace edit my-app --no-keep-awake
```

`--keep-awake` and `--no-keep-awake` are mutually exclusive. Omit both for "no change."

**Operator console** — the **General** tab of the workspace editor has a `Keep awake` row. Press `Space` to toggle it; the change persists when you save the workspace.

`jackin workspace show <name>` surfaces a `Keep Awake: enabled (macOS only)` row when the flag is on, so you can confirm at a glance which workspaces are holding power assertions.

## Git pull on entry

When you open a workspace, your local branches may have drifted behind their remotes. The git-pull-on-entry toggle runs `git pull` on every mounted git repository from the **host** before the agent container starts — so the agent always sees the latest committed code without you needing to remember a manual pull first.

Failures are **non-fatal**: if a pull fails (offline, uncommitted changes, protected branch, etc.) jackin' prints a warning and continues the launch. The workspace remains fully usable — the toggle is a convenience, not a gate.

<Aside type="caution">
`git pull` is run on the **host** directory, not inside the container.
Any uncommitted local changes or an active rebase will cause the pull
to fail; jackin' will warn and proceed.
</Aside>

### Setting git pull on entry

**CLI** — paired flags on `workspace create` and `workspace edit`:

```bash
# Opt in at creation time
jackin workspace create my-app --workdir ~/Projects/my-app --mount ~/Projects/my-app --git-pull

# Toggle on an existing workspace
jackin workspace edit my-app --git-pull
jackin workspace edit my-app --no-git-pull
```

`--git-pull` and `--no-git-pull` are mutually exclusive. Omit both for "no change."

**Operator console** — the **General** tab of the workspace editor has a `Git pull` row. Press `Space` to toggle it; the change persists when you save the workspace.

`jackin workspace show <name>` surfaces a `Git Pull: on entry` row when the flag is on.

## Workspace auto-detection

When you open the operator console (`jackin console`), it checks whether your current directory falls under a saved workspace's host `workdir` or one of its mounted host paths. If it does, that workspace is preselected — saving you a selection step and reinforcing the value of naming project boundaries once. Container-only `workdir` values like `/workspace` can still be auto-detected as long as one of the workspace's mounted host paths contains your current directory. You can always override the preselection by choosing a different workspace or "Current directory."
