@rasensio/aidlc-content 1.49.0 → 1.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,347 @@
1
+ # The roadmap
2
+
3
+ ## Why this exists
4
+
5
+ An idea arrives while you are mid-implementation on something else. You have three options: derail
6
+ what you are doing, write it on a sticky note, or lose it. The roadmap is a fourth — capture it in
7
+ five seconds and get back to work.
8
+
9
+ The design decision that matters is that **capture is legal at any moment**. No instance, no claim, no
10
+ phase. Capture never reads or writes anything under `.aidlc/state/`, so two sessions capturing
11
+ simultaneously just produce two files and no locking is needed or exists.
12
+
13
+ The second reason is social. Projects have more than one person proposing work, with mixed technical
14
+ depth, so the roadmap distinguishes *submitted* from *agreed*. An item in `inbox/` is somebody waiting
15
+ on a decision; an item in `backlog/` is a decision already made. Collapsing those two into one list is
16
+ how a backlog becomes a place ideas go to die.
17
+
18
+ **What breaks without it:** the thing this project measured — a backlog that only grows is the same as
19
+ no backlog. Over eleven days the product backlog moved zero items while self-repair items were
20
+ promoted within one to three days. The roadmap did not cause that, but it is what made it visible.
21
+
22
+ ## How to use it
23
+
24
+ **Capture is not a CLI command.** The roadmap is files plus a skill, on purpose — capture friction
25
+ kills inboxes, and shelling out to a CLI mid-thought is friction. Ask the agent to capture an item,
26
+ and it writes one. `aidlc roadmap` does exist, but only for the GitHub Issues projection described
27
+ below; it never captures, triages or promotes.
28
+
29
+ **The directory an item sits in is its status.** There is no `status:` field, and you must never add
30
+ one:
31
+
32
+ ```
33
+ .aidlc/roadmap/
34
+ inbox/ submitted, nobody has triaged it
35
+ backlog/ accepted, will do, not started
36
+ in-progress/ an instance exists
37
+ done/ shipped
38
+ hold/ parked or declined
39
+ ```
40
+
41
+ Changing status means moving the file. Two representations of one fact drift apart, and a wrong status
42
+ is indistinguishable from a right one.
43
+
44
+ One item per file, `YYYYMMDD-<slug>.md`, with frontmatter carrying `id`, `title`, `created_at`,
45
+ `source`, `promoted_to`, `depends_on` and an append-only `history`.
46
+
47
+ **Always quote the title.** `title: "..."` with double quotes, every time, with no judgement call
48
+ about whether this one needs it. An unquoted YAML plain scalar may not begin with a reserved
49
+ character, so the single most natural way to name a code defect — a title starting with a backtick —
50
+ does not parse. Nothing reports it: the item vanishes from browse, from promotion lookup, from the
51
+ completion action and from `aidlc doctor`, because an item that will not parse and an item that was
52
+ never written look identical. Five of this project's first 49 items were lost this way for up to ten
53
+ days.
54
+
55
+ **Every item opens with a six-line executive summary** — what it is, who benefits, customer value,
56
+ revenue, cost and risk, recommendation. This exists so triage can happen from the top of the file.
57
+ `None` is a real answer for revenue and usually the correct one; writing `Indirect` for everything
58
+ makes the field useless. It is also the cheapest check against building things that only watch the
59
+ lifecycle: a feature that has to write *"Revenue — None"* and *"Customer value — none, it observes the
60
+ lifecycle"* has declared itself.
61
+
62
+ The rule binds **every** path into `inbox/`, including an item written by an instance mid-phase.
63
+ `Not yet decided.` is a valid value for any label; an absent section is not a valid item.
64
+ `aidlc doctor` reports inbox items missing one, by name, and never writes one — see
65
+ [Hygiene and compliance](hygiene-and-compliance.md).
66
+
67
+ **A `hold/` entry says whether it is parked or declined.** One directory holds both, and the
68
+ `history` entry carries the reason: `{ status: hold, at: 2026-09-23, reason: "parked — gated on the
69
+ accounts table" }`, prefixed `parked — ` or `declined — `. Because `history` is frontmatter, browse
70
+ reads it without opening the body. The consequence worth knowing: agreed work waiting on a trigger
71
+ belongs in `hold/`, parked, not in `backlog/` — `backlog/` means "could start now", and an item gated
72
+ on something that does not exist yet makes every count of what is ready wrong.
73
+
74
+ Three flows: **capture** writes to `inbox/`, after checking whether an open item already owns the area
75
+ — if one does, the finding is appended there as a dated `## Received from <source>` section instead of
76
+ becoming a new file. **Triage** moves to `backlog/` or `hold/`, and is the one flow allowed to read
77
+ into an item's body — as far as the executive summary and no further. **Promote** creates an instance,
78
+ sets `promoted_to`, and moves the file to `in-progress/`. When the instance completes, the
79
+ `roadmap-done` action moves every item whose `promoted_to` names it to `done/` by itself; do not do
80
+ that by hand.
81
+
82
+ **Promotion is one command, not a checklist.** `aidlc start <template> --name <name> --roadmap-item
83
+ <item>` finds the item in `backlog/` or `inbox/` by file name or id, sets `promoted_to`, moves it to
84
+ `in-progress/` in the primary checkout, and copies it into the instance as `roadmap-item.md`. It works
85
+ with `--worktree`. Why a flag rather than prose: on 2026-10-02 two unattended runs of the same
86
+ worktree flow disagreed — one linked the item by hand, the other left it in `backlog/` with
87
+ `promoted_to: null`, so `roadmap-done` would never have found it. The reference is matched against
88
+ listed items and never opened as a path, and an item that already has a `promoted_to` is refused before
89
+ anything is created. The move is left uncommitted; committing it is the caller's.
90
+
91
+ **Picking the next item** is `aidlc roadmap next`: the `backlog/` item with the lowest `priority`
92
+ among those whose `depends_on` are all done, unranked items last, ties by file name. `--explain` shows
93
+ the whole order and why anything was skipped; `--json` is for scripts. It only reads. A script that
94
+ works the backlog may ask it what is next, but promoting stays a person's decision, so the command
95
+ that picks has no way to write. `priority` is an ordinary extension field (a rank, 1 first) that a
96
+ project declares in `roadmap.item_fields`.
97
+
98
+ **Ranking the backlog** is `aidlc roadmap rank <item> <n>`: it puts a `backlog/` item at rank `n` and
99
+ renumbers every ranked backlog item 1…k in their existing order, so ranks stay unique and gap-free —
100
+ hand-typed ranks drift, because an item leaving the backlog leaves a hole and two items typed at one
101
+ number tie. `--dry-run` prints the resulting order and writes nothing; the roadmap skill shows it at
102
+ triage, proposes a rank, and runs the command only after the person answers. Only the `priority:`
103
+ lines that change are rewritten, unranked items stay unranked, and the command refuses — writing
104
+ nothing — when the project does not declare `priority`, when the item is not in `backlog/`, or when
105
+ any backlog item carries a malformed rank. Where `priority` is declared, `roadmap next --explain`
106
+ also lists every unranked backlog item, so one sitting last is visible rather than silently last.
107
+
108
+ **Parking from an instance** is `aidlc roadmap park <instance> --reason "<why>"`: it moves the item
109
+ promoted to that instance into `hold/` with a `parked — ` reason. It exists for unattended mode's hard
110
+ stops — see [Skills and platforms](skills-and-platforms.md) — where the agent works in a worktree but
111
+ the item's status lives in the primary checkout.
112
+
113
+ Keep the raw idea count around a dozen. At the cap, promote or drop before capturing anything new. A
114
+ completed instance queues **at most two** follow-up items and records the rest in its own
115
+ `retrospective.md` as observed, not queued — the same cap, in the same shape, as the one on lessons.
116
+ Without it, closing an instance reliably grew the backlog: one project emitted five to nine items per
117
+ close and triage kept three of eighteen.
118
+
119
+ ## Working the backlog unattended
120
+
121
+ Ask your agent to "do the next 3 items" (or "do all the items"), or run it yourself:
122
+
123
+ ```
124
+ aidlc autopilot run --items 3
125
+ aidlc autopilot run --all
126
+ ```
127
+
128
+ It starts one background process and returns at once, printing its process id, its log file, and the
129
+ commands to watch and stop it. There is nothing to schedule. The run passes over the backlog every
130
+ minute (`--interval` to change it) and ends when the items it started are each released or parked —
131
+ or, with `--all`, when nothing is ready and nothing is in flight. A restart ends it; asking again
132
+ resumes.
133
+
134
+ Each item goes through these steps:
135
+
136
+ 1. **Pick.** `aidlc roadmap next` names the next ready backlog item.
137
+ 2. **Build.** `aidlc start … --worktree --roadmap-item <item>` creates the instance in its own
138
+ worktree, then the configured agent runs there with `AIDLC_UNATTENDED=1`. The agent follows the
139
+ unattended rule and stops at the release boundary, or parks the item on a hard stop.
140
+ 3. **PR and CI.** Autopilot pushes the branch and opens the pull request. Green checks queue it;
141
+ a failure relaunches the agent once with the failing checks, and a second failure parks the item.
142
+ 4. **Up to date with main.** Before merging, autopilot merges `origin/main` into the branch in the
143
+ item's worktree — locally, so the repository's `merge=union` rules apply — pushes, and waits for
144
+ CI on the new head. A conflict goes back to the item's agent to resolve, twice at most, then the
145
+ item is parked. A pull request with no checks that GitHub reports as conflicting is handled the
146
+ same way: GitHub runs no checks on a conflicting PR, so waiting for them would wait forever.
147
+ 5. **Merge and release**, one at a time, never while a release workflow is running: merge the exact
148
+ commit CI passed (`--match-head-commit`), pull `main`, run the release step, then
149
+ `aidlc transition` to close the instance. A failure halts the queue. Running
150
+ `aidlc autopilot run` again retries a failure that came before the merge; from the pull onward
151
+ nothing is retried — a half-finished release is for a person.
152
+
153
+ At most two items build at once, and never more than you asked for. Autopilot never moves anything
154
+ between `inbox/`, `backlog/` and `hold/` except to park what it is building, and never edits a rank or
155
+ a dependency: deciding what is agreed work stays a person's job.
156
+
157
+ **Setup** comes first, once per machine: `aidlc autopilot setup` (or `aidlc init --autopilot`). It
158
+ asks four questions, each a list with one choice marked recommended:
159
+
160
+ - **The agent, and what it may do.** Claude Code limited to editing files and running git, pnpm,
161
+ node and read-only shell tools (recommended); Claude Code with full access; Codex in full-auto
162
+ mode; or a command you type. This decides what an unattended agent may do on your machine, so
163
+ it is never picked for you: with no terminal, setup needs `--agent <preset>` or
164
+ `--non-interactive`.
165
+ - **How many items build at once** — two (recommended) or one.
166
+ - **A cost cap per item** — an item past it is stopped and parked.
167
+ - **The release step.** In a project with `scripts/autopilot-release.sh`, running it after each
168
+ merge (recommended); otherwise merge only, and you release when you choose. This repository's
169
+ script runs `release-bookkeeping --write`, commits the manifest and `.aidlc`, and runs
170
+ `scripts/release.sh` with the bump bookkeeping printed.
171
+
172
+ Flags skip the questions: `--agent`, `--parallel`, `--cost-cap <usd|none>`, `--release
173
+ <repo-script|merge-only>`. The answers go to `<git-common-dir>/aidlc/autopilot/config.json`, per
174
+ machine and never committed, beside autopilot's `state.json`, `run.json`, `logs/` and `STOP` file.
175
+
176
+ **Watching and stopping.** `aidlc autopilot status` shows the active run and each item's step, pull
177
+ request, CI failure count and last error. `aidlc autopilot stop` (or `/aidlc-autopilot-stop`) ends the
178
+ run at its next step: nothing further is started, merged or released, and agents already running
179
+ finish their item. `aidlc autopilot forget <instance>` stops tracking an item you finished or
180
+ abandoned by hand; a pull request merged by hand is noticed and dropped on its own. A rate limit
181
+ from `gh` or the agent backs off five minutes, doubling to at most
182
+ two hours. `aidlc autopilot tick --dry-run` prints every command one pass would run and runs only the
183
+ reads.
184
+
185
+ ## Projecting the roadmap onto GitHub Issues
186
+
187
+ Opt-in, and off until the config block exists. `aidlc roadmap sync` renders eligible items as
188
+ GitHub issues; `aidlc roadmap import <issue-url>` seeds one `inbox/` item from an existing issue.
189
+
190
+ `aidlc init` offers to write the block for you — it is the last question in the wizard, and it
191
+ defaults to no. Say yes and it lists all five statuses with every one checked, so unchecking
192
+ `inbox` and `hold` is a choice you make with the list in front of you rather than one made on your
193
+ behalf. `done` cannot be turned off; without it the close path never runs and the projection never
194
+ converges. Then it prints `aidlc roadmap sync --dry-run` and stops — nothing is published by
195
+ answering a setup question.
196
+
197
+ ```yaml
198
+ # .aidlc/config.yaml, in the PRIMARY checkout
199
+ roadmap:
200
+ sync:
201
+ provider: github # the only value in this version
202
+ repo: owner/name # optional; gh resolves the current repo when absent
203
+ statuses: [backlog, in-progress, done] # the default; must include done
204
+ label: aidlc # optional; the discovery label
205
+ ```
206
+
207
+ Writing it by hand stays supported, and re-running `aidlc init` never destroys it: the offer arrives
208
+ pre-answered *yes* when a section already exists, `repo` and `label` are preserved, and a section
209
+ that omits `statuses` pre-checks the three defaults rather than all five — so pressing Enter through
210
+ an update cannot start publishing your `inbox/`. Answering an explicit no removes the section and
211
+ says which keys went with it.
212
+
213
+ Two things `init` deliberately does not do. It does not hide the question when the GitHub CLI is
214
+ missing — that would make the wizard's contents depend on the machine it ran on, and initializing on
215
+ a laptop while syncing from CI is normal. It probes `gh` only after you say yes, warns with the
216
+ remedy, writes the section anyway, and exits 0. And it never runs the projection, not even
217
+ `--dry-run`: a fresh project has an empty roadmap, so the run would say nothing, and on a machine
218
+ with no `gh` it could not run at all.
219
+
220
+ `aidlc doctor` reports the matching condition — `roadmap.sync` configured and `gh` not on `PATH` —
221
+ and applies nothing. It probes presence only, never `gh auth status`, so an offline run reports
222
+ only what is true, and it is `report` tier rather than `confirm` for a specific reason: a confirm-tier
223
+ remover applies unprompted under `--yes`, and CI is exactly where `gh` is legitimately absent.
224
+
225
+ It is a **projection, not sync**. Disk stays the source of truth and the tracker is a rendering of
226
+ it, which buys four properties worth knowing about:
227
+
228
+ - **Nothing is written to disk.** There is no `remote:` field and no cache. Creating an issue and
229
+ writing a local link would be two writes to two systems, and every failure of the second leaves an
230
+ issue with no link that the next run turns into a duplicate. Instead the item `id` lives on the
231
+ issue, in an HTML-comment marker, so the projection can be thrown away and rebuilt.
232
+ - **`inbox/` and `hold/` are not projected by default.** The line falls between thinking and work,
233
+ which happens to be the same line that keeps parked pricing thinking and a competitor teardown off
234
+ a public, indexed, notification-generating board.
235
+ - **`done/` is never backfilled.** A shipped item gets an issue only if it already had one, so
236
+ turning this on does not create fifty closed issues nobody will read.
237
+ - **A closed issue is never reopened, and titles you improve on GitHub are overwritten.** Closing an
238
+ issue is the primary triage act of the person this feature is for, so `sync` reports the divergence
239
+ and leaves it alone. Titles follow disk.
240
+
241
+ ### What the issue body contains
242
+
243
+ The body carries the item: its frontmatter facts, its whole prose, and links. Specifically a facts
244
+ block (status, created date, author, source, dependencies, promoted-to instance), a permalink to the
245
+ roadmap file, the item's body text, and the `aidlc-item` marker. So a reader with no checkout can
246
+ decide from the issue instead of being redirected to a file they cannot open.
247
+
248
+ Three things about it are worth knowing:
249
+
250
+ - **The projection owns one region, and only that region.** Everything between
251
+ `<!-- aidlc-body:begin -->` and `<!-- aidlc-body:end -->` is regenerated on every sync. Anything you
252
+ write above or below those markers is preserved, so an issue description stays usable as a place to
253
+ add a note. Comments are separate from the body and are never touched.
254
+ - **Editing the item on disk updates the issue on the next sync**, as an `update-body` write. Bodies
255
+ used to be written once at creation, which left every issue quietly contradicting its item as soon
256
+ as the item changed. Issues created before v1.22.0 get the new body on the next run.
257
+ - **Item prose is sanitized before publication, and the sanitizer is code-aware.** HTML comments are
258
+ stripped from prose (so an item that quotes a marker cannot hijack another issue), and `@name` and
259
+ `#123` spans in prose are wrapped in backticks so a sync notifies nobody and cross-links nothing.
260
+ Anything inside a fence or an inline code span is left byte-identical — measured over this
261
+ project's own roadmap, 40 of the 41 hazard-shaped spans are in code (`@clack/prompts`,
262
+ `actions/checkout@v4`, colour hexes such as `#0891b2`), so a code-unaware sanitizer would corrupt
263
+ forty spans to defuse one. Item ids in the prose become links to their item files; they are
264
+ deliberately *not* linked as `#N`, because that is the cross-reference being defused and it would
265
+ make the body depend on remote issue numbers.
266
+
267
+ Nothing volatile ever enters the body — no timestamp, no commit sha, no metrics. A body containing
268
+ the current time would differ from the stored copy on every run, so every item would plan a write
269
+ forever and the projection would never converge.
270
+
271
+ Writes always need consent: `--dry-run` prints the plan and touches nothing, an interactive run asks,
272
+ and a non-interactive run without `--yes` prints the plan and exits **non-zero** — a green run that
273
+ wrote nothing is how an automation comes to believe it is syncing when it never was. The plan names
274
+ the resolved repository before the first write, which is the only moment a projection aimed at the
275
+ wrong repo is still reversible.
276
+
277
+ An item that has left a projected status keeps its open issue and is reported every run;
278
+ `--retire-ineligible` closes those. Nothing here installs a lifecycle action: wrapping `sync` in CI is
279
+ a user-side step, and a shipped action would start firing in every project on the next
280
+ `aidlc update`.
281
+
282
+ ### Moving a Project board
283
+
284
+ Put the issues on a GitHub Project and they all land in one column. That is the projection stopping
285
+ where it should: setting a Project's Status field needs a token with `project: write`, and the
286
+ workflow-provided `GITHUB_TOKEN` cannot do it at any permission level. The tool would need every
287
+ project to create and store a token before it could move a board, so it does not try.
288
+
289
+ The other half ships as a file:
290
+
291
+ ```bash
292
+ aidlc roadmap board-workflow > .github/workflows/aidlc-project-status.yml
293
+ ```
294
+
295
+ The five setup steps print to the terminal as it runs; only the workflow goes into the file.
296
+ Do them in the order shown: label changes made before the token and project number exist are
297
+ skipped and never replayed.
298
+
299
+ That prints a GitHub Actions workflow which, on every issue event, reads the issue's current
300
+ `aidlc:<status>` label and sets the Status field to match. Its header has the setup: create the
301
+ Status columns (or edit its `STATUS_MAP` to name the ones you have), store a classic token with the
302
+ `project` and `read:org` scopes — plus `repo` for a private repository — as the secret
303
+ `AIDLC_PROJECT_TOKEN`, and set the variable `AIDLC_PROJECT_NUMBER`. A renamed discovery
304
+ label goes in `AIDLC_DISCOVERY_LABEL`. It needs `gh` 2.97.0 or later on the runner and checks for it.
305
+
306
+ The tool prints the file and never writes it into `.github/workflows/`. The token is the real setup
307
+ cost, not the paste, and CI running in your repository with your token is yours to own.
308
+
309
+ **The labels are a supported interface.** The discovery label (`aidlc` unless `label` renames it)
310
+ and the five `aidlc:<status>` labels — `aidlc:inbox`, `aidlc:backlog`, `aidlc:in-progress`,
311
+ `aidlc:done`, `aidlc:hold` — may be bound to by automation. Renaming or removing one is a breaking
312
+ change and will be released as one. Each issue carries exactly one status label; the workflow refuses
313
+ an issue with two rather than guess which is right.
314
+
315
+ This repository runs the same file from `.github/workflows/project-status.yml`, and a test fails if
316
+ the two differ.
317
+
318
+ ## Where the code lives
319
+
320
+ - `packages/content/skills/04-roadmap.md` — the capture, triage and promote protocol. This is the
321
+ authority for the item format and the three flows.
322
+ - `packages/cli/src/roadmap/sync` — the GitHub projection: `plan.ts` is pure and imports no
323
+ filesystem, no subprocess and not the `gh` seam, so planning is testable with no network at all;
324
+ `execute.ts` is the only writer and imports no `node:fs`; `gh.ts` is the single subprocess boundary,
325
+ argument-array only. `body.ts` renders the projection-owned region and merges it into an existing
326
+ issue; `sanitize.ts` defuses item prose; `markdown.ts` is the one place that decides what counts as
327
+ code, shared by the sanitizer and the marker scanner so the two cannot disagree.
328
+ - `packages/cli/src/commands/roadmap.ts` — the `sync`, `import` and `board-workflow` commands,
329
+ consent, and exit codes.
330
+ - `packages/content/resources/recipes/project-status.yml` — the board workflow, loaded by
331
+ `loadBoardWorkflow()` in `packages/content/src/recipes.ts`.
332
+ - `packages/cli/src/commands/init.ts` — the wizard step that offers the projection, plus the
333
+ `gh` warning and the removal notice. `packages/cli/src/setup/setup-compute.ts` owns the merge:
334
+ not-asked, yes, and an explicit no are three different answers, and collapsing any two of them
335
+ makes a re-run of `init` delete somebody's configuration.
336
+ - `packages/cli/src/doctor/migrations/roadmap-sync-gh-missing.ts` — the report-tier check. It
337
+ spawns nothing at all: the primary checkout comes from `ctx.gitCommonDir`, already resolved, not
338
+ from `primaryCheckout()`, which shells out to `git rev-parse`.
339
+ - `packages/content/resources` — a portable version of the item-authoring skill, loadable into any
340
+ agent, so a contributor with no checkout can write an item and commit it to `inbox/`.
341
+ - `packages/cli/src/operational` — the `roadmap-done` completion action. Its history is instructive:
342
+ it resolved the roadmap root to the primary checkout, so an instance finishing on a worktree branch
343
+ stranded its item, found nothing, printed nothing, and the transition reported success over it. An
344
+ action that can legitimately find nothing has to say so. Later it filed only the first of two items
345
+ promoted to one instance; it now files all of them and prints how many it moved.
346
+ - `.aidlc/roadmap` — this project's own items, including the ones that became the features documented
347
+ elsewhere in this folder.
@@ -0,0 +1,126 @@
1
+ # Skills and platforms
2
+
3
+ ## Why this exists
4
+
5
+ The lifecycle is not code that runs — it is instructions an AI agent follows. So the framework's real
6
+ payload is prose, and the problem is that every agent platform wants that prose in a different place and
7
+ a different shape. Claude Code wants `.claude/skills/<name>/SKILL.md`. Cursor wants
8
+ `.cursor/rules/<name>.mdc`. Codex wants one `AGENTS.md`. Kiro wants skills plus a steering file.
9
+
10
+ The naive answer is to write the instructions once per platform. That answer fails on the second edit:
11
+ five copies of "how the design phase works" become five slightly different phases, and nobody can tell
12
+ which one is right.
13
+
14
+ So there is exactly one canonical body per skill, and a **platform adapter** that packages it. The seam
15
+ is *platform-neutral content, platform-specific packaging*. Content never knows which platform it is
16
+ going to; adapters never contain instructions.
17
+
18
+ **What breaks without it:** the same instruction drifts across five files, and a fix applied to one
19
+ platform silently leaves the other four wrong. This is the same single-source argument as the glossary
20
+ and the guidance layers, and it is the reason guidance is referenced by skills rather than pasted into
21
+ them.
22
+
23
+ ## How to use it
24
+
25
+ ```
26
+ aidlc init
27
+ aidlc update
28
+ aidlc add
29
+ aidlc docs
30
+ aidlc explain [topic]
31
+ ```
32
+
33
+ `explain` prints these pages from the installed package: bare, it lists the topics; with a topic id, or
34
+ a command a page covers (`aidlc explain claim`), it prints that page. Nothing is copied into your
35
+ project, so there is no second version to drift.
36
+
37
+ `init` installs skills for the platforms listed in `.aidlc/config.yaml`. `update` refreshes them after
38
+ the framework changes, and also rewrites the managed block in `CLAUDE.md`.
39
+
40
+ **Anything you write inside that managed block is lost on the next update.** Put project instructions
41
+ above the start marker or below the end marker. This repo's own `CLAUDE.md` says so at the top, and the
42
+ "Lessons That Keep Costing Us" section sits deliberately outside the block for exactly that reason.
43
+
44
+ **Run the workspace build, not the installed one.** During development, invoke
45
+ `node packages/cli/dist/cli.js update`, never `npx aidlc update`. `npx` prefers a globally installed
46
+ binary, and it once reported "0 files updated, 35 unchanged" while the edited files sat changed on disk;
47
+ the same command through the built path reported 7. A verification step that reads a different artifact
48
+ than the one you changed fails green.
49
+
50
+ Six adapters ship today — Claude Code, Kiro, Cursor, Codex, Windsurf and GitHub Copilot. Each
51
+ implements one method, `plan(skills, caps, ctx)`, returning an install plan. All of them also
52
+ copy the canonical bodies to `.aidlc/skills/`, which is what lets the framework work with no CLI present
53
+ at runtime: the skill files on disk are self-sufficient.
54
+
55
+ Platform **capabilities** are a separate axis, declared in `packages/content/capabilities`. These are
56
+ per-platform features a phase can opt into — plan mode during ideation, for instance — keyed by platform
57
+ and phase. Note the vocabulary collision: "capability" in that directory means a platform feature, not a
58
+ subsystem of this repo. These pages are organised by **topic** for that reason.
59
+
60
+ Those files also carry a **top-level `questions:` key**, outside the phase-keyed `capabilities:` map, and
61
+ the reason it sits outside is not cosmetic. Capability resolution returns exactly one activation string
62
+ per phase, and three platforms already occupy `requirements` and `design` — the two phases questions
63
+ actually get asked in. A second entry for those phases would silently lose to the first, so question
64
+ rendering could not live there at all.
65
+
66
+ Every question opens with **what it is**: the thing being decided, in plain words, on one concrete
67
+ example. The emitted rendering file states this once, under `## Every platform`, and every directive
68
+ names the line again where it lists what a prompt contains. That looks like duplication and is not. An
69
+ agent follows the most specific list it has, and five directives spell out the prompt's contents in
70
+ order, so a rule stated only in the shared section would be dropped exactly where it is needed. The
71
+ option half of the rule exists because Claude Code shows an option's consequence as its whole
72
+ description: written in schema terms, the prompt was unreadable even when the question file was fine.
73
+ The first real test (fieldmodel-apps, 2026-09-26) had all four questions declined as incomprehensible;
74
+ rewritten with a primer and one running example, all four were answered, three against the
75
+ recommendation.
76
+
77
+ **Not everything that emits a file is an adapter.** Two emitters sit beside the adapter pass rather than
78
+ inside it — the roadmap authoring skill and the per-platform question rendering. Both are excluded for the
79
+ same two reasons. Adapters re-serialize frontmatter from a fixed key whitelist, so any key they do not
80
+ already know about is dropped on round-trip; and an adapter packages one body for one platform, whereas
81
+ these write one file carrying every configured platform's section, so a developer running two agents
82
+ against one checkout reads one file instead of guessing which of two applies. If you are tempted to add
83
+ an adapter to emit a file, check which of those two shapes you have first.
84
+
85
+ If you are adding an operational skill of your own, reuse this seam rather than writing platform files
86
+ directly.
87
+
88
+ **Unattended mode.** Every skill assumes a person is there to answer. With `AIDLC_UNATTENDED=1`, an
89
+ agent follows `.aidlc/resources/rules/unattended.md` instead: each place a skill would ask, wait or
90
+ confirm has one written outcome — take the named default and log it to the instance's
91
+ `unattended-stops.md`, or hard-stop (constitution, deleting data the session did not create,
92
+ credentials and permissions, scope beyond the roadmap item), which parks the item and ends the session.
93
+ Completing testing is the normal end: the agent writes the release plan and stops, and whatever runs
94
+ it owns the push, merge and release. The list of stops came from two dry runs on 2026-10-02 that
95
+ logged the same thirteen on two machines. The mode is a rule the agent reads, not a switch the CLI
96
+ reads — no command behaves differently when the variable is set, because a branch in every command
97
+ would be a cost every future change pays.
98
+
99
+ ## Where the code lives
100
+
101
+ - `packages/cli/src/compile` — the compiler and the adapters. `adapters/index.ts` is the registry; each
102
+ adapter file maps one canonical body to one platform's packaging.
103
+ - `packages/content/skills` — the canonical bodies, numbered by lifecycle order (`00-overview.md`
104
+ through `90-retrospective.md`). This is the only place instructions are authored.
105
+ - `packages/content/capabilities` — per-platform capability declarations, plus each platform's
106
+ `questions:` rendering.
107
+ - `packages/cli/src/compile/question-rendering.ts` — emits `.aidlc/resources/questions/rendering.md`, the
108
+ one file holding how each configured platform puts a question in front of the user. The protocol it
109
+ serves is in `packages/content/resources/rules/question-protocol.md` and names no platform tool
110
+ anywhere; that split is what stops the question shape from being written for one platform's UI.
111
+ - `packages/content/resources/rules` — the six rules skills send readers to (the context rule, the
112
+ always-read rule, the constitution rule, the Question Protocol, Creating an Instance, Lifecycle or
113
+ Skill?), one file each. `packages/cli/src/compile/rules.ts` emits them to `.aidlc/resources/rules/`
114
+ on `init` and `update`. They used to be sections of the overview, and following one cross-reference
115
+ cost the reader the whole 24KB file; now it costs the rule. The overview keeps a one-line pointer per
116
+ rule and states none of them. On Cursor the overview is always applied, so its size is also what every
117
+ turn carries.
118
+ - `packages/content/glossary.yaml` — canonical vocabulary, resolved into skill bodies where they write
119
+ `{{glossary:<term>}}`. Deliberately not installable into a project: guidance is yours to edit,
120
+ framework vocabulary is not, and a second copy drifts.
121
+ - `packages/cli/test/skill-code-contract.test.ts` — the guard that keeps prose and code honest. It
122
+ asserts that every artifact filename a skill mentions is one some template actually requires, and that
123
+ every `aidlc <cmd>` a skill mentions resolves on the real command tree. Skills claiming commands that
124
+ do not exist is a class of defect this closed.
125
+ - `packages/content/test/skill-prose.test.ts` — forbids internal type names standing in for English in
126
+ text a user reads.
@@ -0,0 +1,75 @@
1
+ # State, claims and concurrent work
2
+
3
+ ## Why this exists
4
+
5
+ Two agent sessions in one checkout do not collide on state. They collide on **git**.
6
+
7
+ That sentence cost this project real money to learn. The intuition is that the danger is two sessions
8
+ writing the same YAML file, so the obvious fix is a lock on the state. It is the wrong fix, because
9
+ the actual damage happens elsewhere: one session runs `git add -A` and stages whatever the other
10
+ session left on disk. Creating a branch in place yanks the other session off its branch. And on
11
+ 2026-08-26 both live instances lost their cost data entirely — the recorder saw overlapping claims,
12
+ found `6 candidate records — ambiguous`, and attributed nothing to either.
13
+
14
+ So there are two mechanisms here, and they answer different questions.
15
+
16
+ A **claim** is a lock saying which session is currently working on an instance. It is not an
17
+ assertion, a ticket, or an expense claim. It exists so that the ownership gate can tell "the session
18
+ entitled to advance this phase" from "some other session", and so the cost recorder knows whose
19
+ tokens these were.
20
+
21
+ A **worktree** is the answer to the git problem. Two sessions get two checkouts of one repository,
22
+ each on its own branch, sharing one `.git`. Nothing either one stages can surprise the other.
23
+
24
+ **What breaks without them:** cost becomes unattributable, and one session's `git add -A` commits the
25
+ other's half-finished work. Neither failure announces itself — you find out at the retrospective when
26
+ the numbers are null.
27
+
28
+ ## How to use it
29
+
30
+ ```
31
+ aidlc claim my-thing
32
+ aidlc release my-thing
33
+ ```
34
+
35
+ Claims live in `<git-common-dir>/aidlc/claims/`, not in the instance folder, so they are shared
36
+ across worktrees of the same repository. A claim carries `claimed_at`, `renewed_at`, the session id,
37
+ and the `worktree_path` it was taken from. It goes **stale** after `claim_timeout_minutes` (default
38
+ 60, set in `.aidlc/config.yaml`) — a long conversation will outlive its own claim, and re-claiming
39
+ renews it.
40
+
41
+ Note the wrinkle, because it will bite you: `owner` in a phase file is a *label*, not a lock. Nothing
42
+ in the CLI writes it. The ownership gate resolves the current actor from the live claim, falling back
43
+ to `$USER` when no claim is live. So a phase file whose `owner` was hand-written to one identity,
44
+ plus a claim that has since gone stale, produces a gate failure that names two identities and blames
45
+ the wrong one. Re-claim rather than reaching for `--override`.
46
+
47
+ For concurrent work, use a worktree:
48
+
49
+ ```
50
+ git worktree add -b feat/20260907-my-thing ../aidlc-my-thing main
51
+ aidlc start quick-feature --name my-thing --worktree
52
+ ```
53
+
54
+ The `--worktree` flag does this for you, including the branch-prefix convention (`fix/` for bugfix,
55
+ `chore/` for micro-task and spike, `feat/` otherwise). When another live session holds a claim, the
56
+ entry-point skill offers exactly three options — separate worktree, stop, or continue with no code
57
+ changes — and takes none of them without being told.
58
+
59
+ The hook declarations are tracked, but their capture-shim target is machine-local and gitignored.
60
+ `aidlc start --worktree` now regenerates that shim in the new checkout before returning,
61
+ using the same helper as `aidlc doctor`; a real worktree test keeps the raw, unarmed Git path as its
62
+ negative control. If you create the worktree with `git worktree add` yourself, run `aidlc doctor`
63
+ inside it before starting the agent session.
64
+
65
+ ## Where the code lives
66
+
67
+ - `packages/cli/src/concurrency` — the claim store, staleness logic, and worktree helpers.
68
+ `claim-store.ts` is the single place a claim is written or read.
69
+ - `packages/cli/src/state` — instance folders, `phase-<name>.yaml`, and the append-only
70
+ `transitions.log`.
71
+ - `packages/cli/src/commands/claim.ts` — the `claim` and `release` commands, which also write the
72
+ session intervals that cost attribution later reads.
73
+ - `packages/cli/src/commands/transition.ts` — `getActorIdentity`, the function that decides whose
74
+ turn it is. Its docblock records both 2026-09-01 reproductions where comparing a Unix username
75
+ against an `agent-<uuid>` session id blocked the one session entitled to proceed.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rasensio/aidlc-content",
3
- "version": "1.49.0",
3
+ "version": "1.51.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -22,6 +22,7 @@
22
22
  "tutorials/",
23
23
  "howto/",
24
24
  "resources/",
25
+ "docs/",
25
26
  "glossary.yaml"
26
27
  ],
27
28
  "engines": {
@@ -133,7 +133,7 @@ An instance's **completion moment** is when the last applicable phase (template
133
133
 
134
134
  - Project context lives in `.aidlc/context/` (style-guide.md, architecture.md)
135
135
  - Guidance layers live in `.aidlc/guidance/` — load only those listed in `index.yaml`
136
- - Load context relevant to the current phase; avoid re-reading unchanged files
136
+ - Why AIDLC works as it does: `aidlc explain` lists topics, `aidlc explain <topic>` prints one
137
137
 
138
138
  ### The always-read rule
139
139
 
@@ -197,7 +197,7 @@ When the user asks for a worktree ("create a new worktree for roadmap `<file>`")
197
197
  ```
198
198
  For Codex, swap `claude` for `codex`. If the user names a session manager, give them the worktree path to point it at.
199
199
 
200
- When the instance completes, the `roadmap-done` lifecycle action moves the item to `done/` on its own — do not do it by hand, and do not remove that action to do it manually.
200
+ When the instance completes, the `roadmap-done` lifecycle action moves every item whose `promoted_to` names it to `done/` on its own, and says how many it moved — do not do it by hand, and do not remove that action to do it manually.
201
201
 
202
202
  ## Drop
203
203
 
@@ -42,16 +42,17 @@ Then the source files that task touches. See **The context rule** (`.aidlc/resou
42
42
 
43
43
  1. **Load context.** Read `.aidlc/context/style-guide.md` and `.aidlc/context/architecture.md` if they exist. Match the project's established patterns. If the project has a knowledge graph (`.aidlc/knowledge/` exists), also run `aidlc knowledge context --scope phase --phase implementation` and query it (`aidlc knowledge query <term>`) before re-exploring code it already describes — as an index into the source, never a substitute for reading it. Open the file before calling anything the graph names; an entry can outlive the symbol it describes.
44
44
  2. **Load guidance.** Read the always-read guidance layers from `.aidlc/guidance/index.yaml` — see **The always-read rule** (`.aidlc/resources/rules/always-read.md`) for which layers those are and when to reach for the full `lessons.md`. Apply their rules during implementation.
45
- 3. **Execute the task breakdown.** When the instance has a `tasks.md` (produced in Design for full/quick-feature scope), read it and execute tasks in order: complete a task, then mark its checkbox `[x]` as part of the same work unit — never batch checkbox updates for later. A task that should not be done is deferred in place (`- [>] T<n>: <title> (deferred YYYY-MM-DD: <reason>)`) with a dated reason, never skipped silently or deleted; the implementation→testing gate blocks on open tasks. For bugfix scope, create the optional `tasks.md` at implementation start when the fix spans more than one commit-sized unit. For Micro scope, reference the task description and acceptance criteria directly — no task file.
46
- 4. **Write code.** Follow the design interfaces. Match existing code style (naming, formatting, error handling patterns).
47
- 5. **Handle sensitive operations.** Before executing any of the following, describe the action and wait for explicit user confirmation (unattended, `AIDLC_UNATTENDED=1`: each is a hard stop except reverting this session's own changes, per `.aidlc/resources/rules/unattended.md`):
45
+ 3. **Check that the planning artifacts agree.** Before the first task, run `aidlc cross-check <instance>` and show the user the list. It reads `requirements.md`, `design.md` and `tasks.md` side by side and prints one line per gap — a criterion no task cites, a task citing no criterion, a criterion design never mentions — each naming both artifacts and the ID. It is a report: it writes nothing and never blocks, and acting on a gap is the user's call. A gap in `tasks.md` is fixed in place, since its phase is still open here; a gap in a completed `requirements.md` or `design.md` is fixed through an amendment (**Amending a Completed Phase**, in the requirements skill), never by editing it silently. Unattended (`AIDLC_UNATTENDED=1`): record the list in `code-complete.md` and carry on.
46
+ 4. **Execute the task breakdown.** When the instance has a `tasks.md` (produced in Design for full/quick-feature scope), read it and execute tasks in order: complete a task, then mark its checkbox `[x]` as part of the same work unit — never batch checkbox updates for later. A task that should not be done is deferred in place (`- [>] T<n>: <title> (deferred YYYY-MM-DD: <reason>)`) with a dated reason, never skipped silently or deleted; the implementation→testing gate blocks on open tasks. For bugfix scope, create the optional `tasks.md` at implementation start when the fix spans more than one commit-sized unit. For Micro scope, reference the task description and acceptance criteria directly — no task file.
47
+ 5. **Write code.** Follow the design interfaces. Match existing code style (naming, formatting, error handling patterns).
48
+ 6. **Handle sensitive operations.** Before executing any of the following, describe the action and wait for explicit user confirmation (unattended, `AIDLC_UNATTENDED=1`: each is a hard stop except reverting this session's own changes, per `.aidlc/resources/rules/unattended.md`):
48
49
  - File deletions or destructive operations
49
50
  - Infrastructure changes (provisioning, configuration)
50
51
  - Permission or access control modifications
51
52
  - Credential or secret handling
52
- 6. **Commit incrementally.** Produce working code at each step; avoid large uncommittable diffs.
53
- 7. **Update the knowledge graph.** After modifying code, record what changed with `aidlc knowledge add` / `relate` / `update`: new or restructured modules, decisions taken, debt introduced or paid down. Keep the graph in sync with the code you just changed.
54
- 8. **Update state.** As implementation artifacts are produced, mark them in `phase-implementation.yaml`.
53
+ 7. **Commit incrementally.** Produce working code at each step; avoid large uncommittable diffs.
54
+ 8. **Update the knowledge graph.** After modifying code, record what changed with `aidlc knowledge add` / `relate` / `update`: new or restructured modules, decisions taken, debt introduced or paid down. Keep the graph in sync with the code you just changed.
55
+ 9. **Update state.** As implementation artifacts are produced, mark them in `phase-implementation.yaml`.
55
56
 
56
57
  ## Exit Criteria
57
58
 
@@ -35,7 +35,8 @@ The CLI does the work. This skill starts it and says how to watch and stop it. D
35
35
 
36
36
  - Takes items in `aidlc roadmap next` order. Builds at most two at once, and never more than the count asked for.
37
37
  - Parks an item (moves it to `hold/` with a reason) when its agent stops short, when CI fails twice, or when it passes the cost cap.
38
- - Halts the merge queue when a merge or release step fails, and never retries it. A half-done release is for a person — `aidlc autopilot status` shows the error.
38
+ - Before each merge, brings the item's branch up to date with main and waits for CI on the new head. A conflict with main goes back to the item's agent, twice at most, then the item is parked. A pull request someone merged by hand is dropped from tracking.
39
+ - Halts the merge queue when a step fails. Running `aidlc autopilot run` again retries a failure that came before the merge; a failed release is for a person — `aidlc autopilot status` shows the error. `aidlc autopilot forget <instance>` stops tracking an item finished by hand.
39
40
  - Ends when the asked-for items are each released or parked, or, with `--all`, when nothing is ready and nothing is in flight.
40
41
 
41
42
  ## Exit Criteria