Worktree alone
Useful isolation, unfinished coordination
- Creates a separate checkout.
- Leaves task identity, checks, rebase, and cleanup to surrounding tools.
- Later attribution usually ends at a commit.
Local-first repository workflow for coding agents
AIT is a CLI that gives every coding request an isolated worktree, the exact revision that passed your checks, and a repository-owned record that survives the agent session. Use it with Codex, Claude, or another coding agent.
Illustrated outcomes · explore each step in the demo
Runs on your machine The only step that leaves it
No telemetry, no analytics, no update check. The one outbound step above
is your coding agent calling its own model — the behaviour you already
have, with or without AIT. AIT talks to exactly one other place: an
ait-server you configure as a remote, the same way you
configure a Git remote. With no remote configured, the local workflow
makes no network call at all.
ait blame src/LoginForm.tsx --line 84revision + recorded intent →One worktree per card Conflicts are never silently overwritten
Compatible work is cleanly rebased at closeout. Incompatible overlap stops in explicit conflict state for you to judge. Mechanical rebase does not prove semantic compatibility, so repository checks and human review remain necessary.
ait queue summarywhich cards can move, which wait on you →Follow an AIT Task
Watch AIT open an isolated worktree, verify a small change, and finish it back into the original project.
AIT first-task command recording — 2026-09-07
Actual command output. Absolute example roots are shortened to ~/ait-first-task.
The replay is edited for readability; playback is not an execution-time measurement.
Working directory: ~/ait-first-task
$ ait --version
ait 1.1.2
Exit code: 0
Working directory: ~/ait-first-task
$ node --test tests/baseline.test.mjs
✔ task titles preserve the input order and data (1.168458ms)
✔ the existing board title is unchanged (0.063583ms)
✔ the existing priorities are unchanged (0.046333ms)
ℹ tests 3
ℹ suites 0
ℹ pass 3
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 63.568458
Exit code: 0
Working directory: ~/ait-first-task
$ ait init
Initialized empty AIT repository in ~/ait-first-task/.ait (plan=zh-Hant-TW/concise)
Exit code: 0
Working directory: ~/ait-first-task
$ ait config set --user-name 'AIT Demo'
ait config set
user-name: AIT Demo
Exit code: 0
Working directory: ~/ait-first-task
$ cat docs/sprints/open-tasks.md
# Open tasks [plan-ref: example/open-tasks]
## Intent
Add openTasks(tasks) to src/tasks.mjs. Return a new array of tasks whose done property is not true, preserving order and object references without mutating the input. Keep taskTitles unchanged.
## Constraints
Only edit this Task worktree. Do not edit checks/, remove tests, or add packages. The root agent executes this task without subagents.
## Acceptance
Add a focused regression test for done true, false, missing, empty input, preserved order and identity. Run node --test tests/*.test.mjs and node checks/first-task.mjs before Task finish; verify acceptance again in the original directory afterward.
- [ ] Add non-mutating openTasks and focused tests. [ref: open-tasks]
Exit code: 0
Working directory: ~/ait-first-task
$ ait task start --from 'docs/sprints/open-tasks.md#open-tasks' --intent 'Add openTasks without mutating input'
ait task start
task: LT-0001
title: Add non-mutating openTasks and focused tests
next: cd ~/ait-first-task/.ait-worktree-links/lt-0001
Exit code: 0
Working directory: ~/ait-first-task/.ait-worktree-links/lt-0001
$ node --test tests/baseline.test.mjs tests/open-tasks.test.mjs
✔ task titles preserve the input order and data (1.041042ms)
✔ the existing board title is unchanged (0.053041ms)
✔ the existing priorities are unchanged (0.048583ms)
✔ openTasks returns unfinished tasks without changing input or objects (1.224417ms)
ℹ tests 4
ℹ suites 0
ℹ pass 4
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 63.11
Exit code: 0
Working directory: ~/ait-first-task/.ait-worktree-links/lt-0001
$ node checks/first-task.mjs
FIRST_TASK_ACCEPTED
Exit code: 0
Working directory: ~/ait-first-task/.ait-worktree-links/lt-0001
$ ait snapshot create LT-0001 --message 'Add non-mutating openTasks'
ait snapshot create
snapshot_id: SNP-0B558114ECDB
task_id: LT-0001
line_name: feature/lt-0001
parent_snapshot_id: SNP-2B43A5F97E11
message: Add non-mutating openTasks
Exit code: 0
Working directory: ~/ait-first-task/.ait-worktree-links/lt-0001
$ ait task finish LT-0001 --local
finished: LT-0001 -> main @ SNP-0B558114ECDB
closed: task, worktree, line, sprint
title: Add non-mutating openTasks and focused tests
Exit code: 0
Working directory: ~/ait-first-task
$ node --test tests/baseline.test.mjs tests/open-tasks.test.mjs
✔ task titles preserve the input order and data (0.987959ms)
✔ the existing board title is unchanged (0.050417ms)
✔ the existing priorities are unchanged (0.042292ms)
✔ openTasks returns unfinished tasks without changing input or objects (0.963875ms)
ℹ tests 4
ℹ suites 0
ℹ pass 4
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 61.445542
Exit code: 0
Working directory: ~/ait-first-task
$ node checks/first-task.mjs
FIRST_TASK_ACCEPTED
Exit code: 0
Working directory: ~/ait-first-task
$ ait blame src/tasks.mjs --line 7
target: current line main
resolved snapshot: SNP-0B558114ECDB
path: src/tasks.mjs
blame parent: SNP-2B43A5F97E11
range: 7-7
7 SNP-0B558114ECDB task=LT-0001 confidence=durable_snapshot_binding
Exit code: 0
Implementation recorded in the completed Task:
// Small, existing behavior to preserve while adding your first feature.
export function taskTitles(tasks) {
return tasks.map((task) => task.title);
}
export function openTasks(tasks) {
return tasks.filter((task) => task.done !== true);
}
Bound sprint after Task finish:
# Open tasks [plan-ref: example/open-tasks]
## Intent
Add openTasks(tasks) to src/tasks.mjs. Return a new array of tasks whose done property is not true, preserving order and object references without mutating the input. Keep taskTitles unchanged.
## Constraints
Only edit this Task worktree. Do not edit checks/, remove tests, or add packages. The root agent executes this task without subagents.
## Acceptance
Add a focused regression test for done true, false, missing, empty input, preserved order and identity. Run node --test tests/*.test.mjs and node checks/first-task.mjs before Task finish; verify acceptance again in the original directory afterward.
- [x] Add non-mutating openTasks and focused tests. [ref: open-tasks]
Two separate 200-session GPT-5.6 Sol campaigns · 100/100 accepted in each treatment · Read the scope and evidence
Why not just use a worktree?
Parallel execution is already common. The missing layer is a durable definition of what each agent was asked to do, which result passed, and how it joined newer work.
Worktree alone
AIT Task
ait blame connects a regressed line to its revision and recorded intent.One request. One governed result.
State the outcome and constraints in plain language.
The Task receives one dedicated writable worktree.
Your checks stay attached to the exact revision that passed.
AIT updates clean work or stops without hiding a conflict.
The responsible revision and recorded intent remain connected.
Start with one repository
ait init, then ask your agent normally.The default workflow stays local and starts no server.
Each Task keeps its own intent, worktree and checks. Compatible work can finish; a conflicting change stops with its work retained. Recorded versions make later investigation possible.