Atelier is an installable CLI for workspace-based, agent-assisted development inside local Git repos. It turns each unit of work into its own workspace with a dedicated git worktree, explicit intent, and a predictable launch path for agents and humans. Atelier is Git-first by design; provider integrations are optional and best-effort.
Atelier can manage multiple projects on one machine; each project is identified by its local enlistment path and stored under the Atelier data directory.
The goal is to simulate web-based agent development on a local machine: you can hand off and resume workspaces easily, take the wheel at any time, and coordinate multiple agents across parallel tasks without losing context.
Atelier is:
- a per-repo tool, not a global project manager
- a workspace-first workflow, not a branch-switching helper
- a convention with sharp edges, not a flexible framework
Provider integrations are intentionally minimal: GitHub gets the best support,
and other providers are best-effort when project.provider metadata is set.
Atelier is inspired by the ideas explored in Shipping at Inference Speed, which argues that many traditional Git workflows introduce unnecessary cognitive overhead when working with fast, capable coding agents.
In particular, the essay highlights the value of:
- minimizing mental context switches
- evolving codebases linearly when coordination cost is low
- treating LLMs as collaborators, not batch tools
Atelier adopts these ideas where they help, while still supporting branch- and review-based workflows when coordination and safety matter. It's an adaptation of the essay's philosophy, not a clone.
Read more in docs/inspiration.md.
Atelier (pronounced ah-tuh-lee-AY) is the French word for a workshop.
The name reflects how this tool is intended to be used: as a place where work is shaped iteratively, with humans and tools collaborating closely.
Atelier is not a factory pipeline or a fully automated system. It favors explicit intent, interruption, and hands-on control over invisible automation.
Agents are collaborators, not background jobs—and the human is always allowed to step back in and take the reins.
The name is meant to signal craft and collaboration, not art, magic, or opacity.
Read more in docs/atelier-name.md.
- One workspace = one unit of work = one branch
- Intent is captured before code (epic planning)
- Workspaces are isolated worktrees with their own git checkout
- Projects are identified by their local enlistment path (each repo you initialize is a separate project), not Git origin
- The filesystem is the source of truth
See docs/behavior.md for the compact behavioral overview.
Command-specific details live in module docstrings under src/atelier/commands.
- Git (for worktrees and branch operations)
bd>= 0.56.1on your PATH (Atelier's local planning store)
The reusable Beads client published under atelier.lib.beads supports a bounded
v1 bd surface. See
docs/beads-client-contract.md for the supported
command inventory, version/capability policy, and downstream adoption rules. See
docs/beads-adoption-guide.md for the current
decision boundary between direct low-level Beads usage, in-memory test usage,
and work that should wait for the future at-njpt4 store layer.
This repository uses a repo-local hook path (.githooks/) for fast local
quality gates:
pre-commit: staged Python lint/format checks plus pyright viascripts/lint-gate.sh --staged-python.pre-push: full repository test gate viajust test.commit-msg: Conventional Commit validation viacommitlint.config.cjs.
Canonical lint gate for local/CI workflows:
bash scripts/lint-gate.shGitHub Actions CI publishes these check names:
ci / lint: lint gate (bash scripts/lint-gate.sh).ci / test: Python + shell test suite.ci / lint-test: temporary compatibility check that mirrorslint+test.
Branch protection should require ci / lint and ci / test. Keep
ci / lint-test only during migration from the legacy single check, then remove
it once rulesets are updated.
Troubleshooting:
ci / lintfailed: lint or type checks failed.ci / testfailed: tests failed.ci / lint-testfailed while either check above failed: expected legacy mirror behavior.
Bootstrap or repair hooks for an existing clone:
bash .githooks/worktree-bootstrap.shThe bootstrap step is idempotent and does the following:
- sets
core.hooksPath=.githooksin the repository's common Git config - ensures tracked hook scripts (
pre-commit,pre-push,commit-msg,post-checkout) are executable - keeps linked worktrees aligned through
.githooks/post-checkout
If your environment does not expose commitlint, the commit hook falls back to
npx. If you use a custom binary path, set ATELIER_COMMITLINT_BIN.
If your environment does not expose uv or ruff, set ATELIER_RUFF_BIN to an
executable Ruff binary path. If your environment does not expose uv or
pyright, set ATELIER_PYRIGHT_BIN to a pyright executable path. If your
environment does not expose just, set ATELIER_JUST_BIN to a compatible
executable path.
Atelier launches the agent CLI configured in agent.default. Install and
authenticate the agent CLI you want to use and set agent.default accordingly.
Atelier validates that the configured agent is available on your PATH (using
--version when possible) and exits early if no agent CLI is available.
- Launch agents from the workspace directory
- Best-effort session resumption when the agent CLI supports it
- Opening prompt containing the workspace ID (Codex only)
Agent options support both legacy global settings and role-scoped overrides:
agent.options.<agent>applies to bothatelier planandatelier work.agent.launch_options.planner.<agent>applies only to planner sessions.agent.launch_options.worker.<agent>applies only to worker sessions.
Precedence is deterministic: worker/planner scoped options override legacy global options for the same flag.
Example:
{
"agent": {
"default": "claude",
"options": {
"claude": ["--model", "sonnet"]
},
"launch_options": {
"planner": {
"claude": ["--model", "opus"]
},
"worker": {
"claude": ["--print", "--output-format=stream-json", "--verbose"]
}
}
}
}Claude worker sessions default to print-mode with
--output-format=stream-json --verbose unless explicitly overridden, while
planner Claude sessions remain interactive by default.
Atelier sets these environment variables when launching editors, shells, and agents:
ATELIER_WORKSPACE: workspace branch nameATELIER_PROJECT: project enlistment path (repo root)ATELIER_WORKSPACE_DIR: workspace root directory
Example shell prompt (bash/zsh):
PS1='${ATELIER_WORKSPACE:+[${ATELIER_WORKSPACE}] }\\w$ 'Example editor title (VS Code settings):
{
"terminal.integrated.title": "${env:ATELIER_WORKSPACE} - ${env:ATELIER_PROJECT}"
}Atelier is intentionally small. The CLI:
- registers a local enlistment as a project in the Atelier data directory
- creates per-epic worktrees under the data directory
- maintains minimal
config.sys.json/config.user.jsonstate for projects - stores optional project-wide policy for agents
- bootstraps policy/context files (
AGENTS.md) and installs workspace skills - tracks changeset branch mappings for each workspace
- launches your editor and shells in a predictable way
<atelier-data-dir>/
└─ projects/
└─ <project-key>/
├─ config.sys.json
├─ config.user.json
├─ templates/
│ ├─ AGENTS.md
└─ worktrees/
├─ .meta/
│ └─ <epic-id>.json
└─ <epic-id>/
└─ <git worktree checkout>
Notes:
<project-key>is the enlistment basename plus a short SHA-256 of the full enlistment path.- Worktrees are keyed by epic id; mappings live in
worktrees/.meta/.
Create a brand-new local project:
atelier new [path]If path is omitted, the current directory must be empty.
Initialize a project:
atelier initRun this inside an existing Git repo; Atelier stores state in the data directory and does not write files into the repo.
You can run atelier init in multiple repos; each enlistment becomes its own
project entry.
Start a worker session (one changeset per session):
atelier work
atelier work at-epic123
atelier work --mode auto
atelier work --select first-eligible
atelier work --run-mode once
atelier work --run-mode watch
atelier work --run-mode watch --no-restart-on-update
atelier work --run-mode default --restart-on-update
atelier work --run-mode watch --watch-interval 30
atelier work --reconcileatelier work will:
- claim or select the epic to work on
- pick the next ready changeset
- ensure the worktree and changeset branch mapping exist
- repeat or watch depending on
--run-mode(--watch-intervalfor watch cadence)
Supported ATELIER_* -> CLI-default translations for atelier work:
| CLI default | Env var | Built-in default | Accepted env values |
| -------------------------- | ------------------------ | ---------------- | ------------------------------ |
| --mode | ATELIER_MODE | prompt | prompt, auto |
| --run-mode | ATELIER_RUN_MODE | default | once, default, watch |
| --watch-interval-seconds | ATELIER_WATCH_INTERVAL | 60 | positive integer |
| --yes | ATELIER_WORK_YES | false | 1/true/yes/on, 0/false/no/off |
Example:
ATELIER_WORK_YES=1 atelier workUnsupported keys for this CLI-default translation layer: ATELIER_PLAN_TRACE,
ATELIER_WORK_TRACE, ATELIER_LOG_LEVEL, ATELIER_NO_COLOR. Use global CLI
flags instead: --log-level and --color/--no-color.
Plan epics and changesets:
atelier planOpen a workspace worktree in your editor:
atelier edit <workspace-branch>
atelier edit <workspace-branch> --workspaceOpen a shell in a workspace worktree (or run a command there):
atelier open <workspace-branch>
atelier open <workspace-branch> -- python -m http.server
atelier open <workspace-branch> --workspaceShow project status:
atelier status
atelier status --format=jsonDetect prefix-migration drift (read-only):
atelier doctor
atelier doctor --format=jsonApply explicit prefix normalization repairs (operator-invoked):
atelier doctor --fix
atelier doctor --fix --force
atelier doctor --fix --format=jsonOperator triage + rollback runbook and convergence harness:
List workspaces:
atelier listClean up stale hooks/claims and orphaned worktrees:
atelier gc- The epic record is the execution contract for each workspace.
AGENTS.mdis a managed prologue used to configure agents.atelier policyshows the project-wide policy shared by planning and work agents.- The
publishskill records integration guidance derived from project config and applies it to changeset branches. - Configuration lives in
config.sys.json/config.user.jsonunder the Atelier data directory. - Worktrees live under the data directory and are keyed by epic id.
Use atelier --help to view all commands and options. Use atelier --version
to print the installed version and exit.
Create a new local Git repo, register it as an Atelier project, and start planning.
Usage:
atelier new [path]Options:
--branch-prefix: Prefix for workspace branches (e.g.,scott/).--branch-pr-mode: Pull request mode for workspace branches (none,draft,ready).--branch-history: History policy (manual,squash,merge,rebase).--agent: Agent name.--editor-edit: Editor command for blocking edits (e.g.,subl -w).--editor-work: Editor command for opening the repo (e.g.,code).
Example:
atelier new ~/code/greenfieldRegister the current Git repo as an Atelier project. This command writes configuration into the Atelier data directory and never modifies the repo.
Usage:
atelier initOptions:
--branch-prefix: Prefix for workspace branches (e.g.,scott/).--branch-pr-mode: Pull request mode for workspace branches (none,draft,ready).--branch-history: History policy (manual,squash,merge,rebase).--agent: Agent name.--editor-edit: Editor command for blocking edits (e.g.,subl -w).--editor-work: Editor command for opening the repo (e.g.,code).
Example:
atelier init --branch-prefix scott/ --branch-pr-mode none --branch-history rebaseInspect or update configuration. Without arguments, prints the merged project config. With a workspace branch, prints that workspace config.
Usage:
atelier config
atelier config scott/feat/new-searchOptions:
--installed: Operate on installed defaults instead of the current project.--prompt: Prompt for user-editable settings (branch/agent/editor roles).--reset: Reset user-editable settings to installed defaults.--edit: Edit user config ineditor.edit.
Examples:
atelier config --prompt
atelier config --reset
atelier config --installed --promptShow or edit project-wide agent policy.
Usage:
atelier policy
atelier policy --editOptions:
--role: Select policy role (planner,worker, orboth).--edit: Edit policy ineditor.edit; without this flag policy is printed.
Open the workspace repo in the configured work editor.
Usage:
atelier edit feat/new-searchOptions:
--raw: Treat the argument as the full branch name (no prefix lookup).--workspace: Open the worktree root instead of the default repo path.--set-title: Emit a terminal title escape (best-effort).
Start a worker session for the next ready changeset. If no epic id is provided,
Atelier selects one based on --mode (prompt or auto).
Usage:
atelier work
atelier work at-epic123
atelier work --mode autoOptions:
--mode: Worker selection mode (promptorauto).--select: Startup selector policy (first-eligibleoroldest-feedback). Defaults toworker.selectin config, thenoldest-feedback.--run-mode: Worker loop mode (once,default, orwatch).--restart-on-update: Self-reexec at idle boundaries after runtime changes. Defaults to on inwatchmode and off in other run modes.--no-restart-on-update: Disable idle-boundary self-reexec even inwatchmode.--yes: Accept defaults for interactive choices (ATELIER_WORK_YES).--reconcile: Run a fail-closed reconcile sweep before startup selection. This auto-finalizes orphanedin_progresschangesets only when PR lifecycle is terminal (merged/closed) and no live worker hook owns the epic.- Watch polling defaults to
ATELIER_WATCH_INTERVAL(seconds) in watch mode.
Auto-restart controls:
atelier work --run-mode watchenables restart-on-update by default.atelier work --run-mode watch --no-restart-on-updatekeeps watch polling but disables self-reexec.atelier work --run-mode default --restart-on-updateopts long-lived non-watch workers into the same idle-boundary restart behavior.- Restart checks happen only between worker sessions, never during an active changeset execution.
- If restart attempts fail or retrigger too quickly, Atelier logs bounded cooldown diagnostics and keeps running the current process instead of looping indefinitely.
Debugging restart behavior:
- Confirm the effective mode/flags in the launch command you used.
- Watch for
Runtime update detected,auto-restart is cooling down, andrestart failedlog lines in the worker output. - Use
--no-restart-on-updateto keep a long-lived worker stable while you investigate repeated runtime changes or install failures.
Start a planner session for epics. Planner sessions run in a dedicated worktree and use the agent runtime for interactive planning.
By default, Atelier resumes an existing planner session when possible:
- If
planner_session.idis saved on the planner agent bead and still exists for this planner workspace, Atelier resumes that exact session id. - If no saved pointer exists, Atelier resumes the most recent matching planner session.
- If a saved pointer is stale or missing, Atelier starts a fresh session and clears the stale pointer.
Use --new-session to bypass resume lookup and always start fresh.
Planner sessions automatically sync their planner worktree to the configured
default branch at startup, then continue periodic freshness checks while the
session is active. Sync metadata is recorded on the planner agent bead under
planner_sync.* fields (last synced sha/time, last attempt/result).
Usage:
atelier planOptions:
--epic-id: Plan against an existing epic id.--new-session: Always start a fresh planner session (skip resume lookup).- In an active planner session, run
python3 skills/planner-startup-check/scripts/refresh_overview.pyto refresh the same read-only startup overview on demand. This command now hardens the previously uncovered mode where projected planner scripts were launched by an ambient interpreter that did not match the repo dependency runtime.
Open a shell in a workspace worktree, or run a command there. If
<workspace-branch> is omitted, you will be prompted to choose one. Use
--shell to override the interactive shell selection. Use --workspace to run
in the worktree root instead of the default repo path.
Options:
--shell: Shell path or name for interactive mode.--workspace: Run in the worktree root instead of the default repo path.--set-title: Emit a terminal title escape.--raw: Treat the workspace name as the full branch name (no prefix lookup).
atelier open runs a command when arguments are provided; otherwise it opens an
interactive shell.
Show project status for epics, hooks, and changesets.
Usage:
atelier status
atelier status --format=jsonOptions:
--format=json: Emit deterministic JSON output.
Detect prefix-migration branch/worktree drift and report multi-check health.
Read-only by default. Use atelier doctor --fix for explicit
normalization/repair.
Usage:
atelier doctor
atelier doctor --format=json
atelier doctor --fix
atelier doctor --fix --forceOptions:
--format=json: Emit deterministic JSON output.--fix: Apply drift repairs instead of read-only detection.--force: Override active-hook deferrals when used with--fix.
List workspaces for the current project (names only).
Usage:
atelier listClean up stale hooks and orphaned worktrees.
Usage:
atelier gcOptions:
--stale-hours: Treat heartbeats older than this many hours as stale.--stale-if-missing-heartbeat: Treat missing heartbeats as stale.--dry-run: Show planned actions without applying them.--yes: Apply without confirmation.
Atelier is a Python 3.11+ CLI packaged with uv.
Global install (recommended for day-to-day use):
uv tool install --editable .
uv tool update-shellThen open a new shell so the tool bin directory is on your PATH.
Common tasks (requires just):
just install
just install-dev
just test
just test-integration
just lint
just formatInstall just with brew install just or cargo install just.
just test-integration runs publish-skill evals and requires the codex CLI to
be installed and authenticated.
Local quality gates intentionally pin uv to Python 3.11 to match the current
CI baseline. Ambient Python 3.14 interpreters and pre-existing 3.14 .venv
directories are not part of the supported publish/test matrix yet.
bash scripts/supported-python.sh venv
uv pip install -e .[dev]Run the CLI locally:
uv run atelier --helpRun tests:
bash scripts/supported-python.sh run python -m atelier.skill_frontmatter_validation
bash scripts/supported-python.sh run pytest
bash tests/shell/run.shatelier.skill_frontmatter_validation enforces required AgentSkills frontmatter
rules (name, description, format/length, and name-directory match).
Planner and worker unit-service suites should use the in-memory Beads backend
from atelier.testing.beads by default. Keep real-bd coverage explicit in
shell tests and command-integration tests that verify subprocess wiring or
publish flows. See
docs/beads-adoption-guide.md for contributor
guidance about where direct atelier.lib.beads usage is still in bounds, and
see
docs/in-memory-beads-testing-guide.md
for the backend-selection rule, an example harness, and current migrated
coverage.
MIT. See LICENSE.