@rasensio/aidlc 1.27.1 โ 1.28.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.
- package/README.md +334 -54
- package/dist/commands/cost.d.ts +4 -0
- package/dist/commands/cost.d.ts.map +1 -1
- package/dist/commands/cost.js +99 -26
- package/dist/commands/cost.js.map +1 -1
- package/dist/cost/providers/claude-code.d.ts.map +1 -1
- package/dist/cost/providers/claude-code.js +4 -1
- package/dist/cost/providers/claude-code.js.map +1 -1
- package/dist/cost/recorder.d.ts.map +1 -1
- package/dist/cost/recorder.js +7 -3
- package/dist/cost/recorder.js.map +1 -1
- package/dist/cost/report.d.ts +36 -0
- package/dist/cost/report.d.ts.map +1 -1
- package/dist/cost/report.js +112 -47
- package/dist/cost/report.js.map +1 -1
- package/dist/cost/sync.d.ts.map +1 -1
- package/dist/cost/sync.js +6 -0
- package/dist/cost/sync.js.map +1 -1
- package/dist/cost/types.d.ts +8 -0
- package/dist/cost/types.d.ts.map +1 -1
- package/dist/cost/types.js.map +1 -1
- package/package.json +9 -2
package/README.md
CHANGED
|
@@ -1,25 +1,55 @@
|
|
|
1
|
-
|
|
1
|
+
<!-- Generated from the repo-root README.md by packages/cli/scripts/sync-readme.mjs.
|
|
2
|
+
Edit that file, not this one. npm renders this copy; GitHub renders the root. -->
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
<div align="center">
|
|
4
5
|
|
|
6
|
+
# `$ aidlc_`
|
|
7
|
+
|
|
8
|
+
## AI codes fast. AIDLC makes it ship right.
|
|
9
|
+
|
|
10
|
+
A real software lifecycle for AI coding agents: **phases, gates, state, and traceability** โ from idea to maintenance, on any agent platform.
|
|
11
|
+
|
|
12
|
+
[](https://www.npmjs.com/package/@rasensio/aidlc)
|
|
13
|
+
[](https://www.npmjs.com/package/@rasensio/aidlc)
|
|
14
|
+
[](https://nodejs.org)
|
|
5
15
|
[](https://github.com/rasensio/aidlc/blob/main/LICENSE)
|
|
16
|
+
[](https://aidlc.rodrigoasensio.com)
|
|
17
|
+
|
|
18
|
+
**[๐ Homepage](https://aidlc.rodrigoasensio.com)** ยท [๐ Docs](https://aidlc.rodrigoasensio.com/docs/) ยท [๐ Tutorials](https://aidlc.rodrigoasensio.com/tutorials/) ยท [๐ Blog](https://aidlc.rodrigoasensio.com/blog/) ยท [๐ฆ npm](https://www.npmjs.com/package/@rasensio/aidlc)
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx @rasensio/aidlc init
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**One command. Any agent.**
|
|
6
25
|
|
|
7
|
-
|
|
26
|
+
</div>
|
|
8
27
|
|
|
9
|
-
|
|
28
|
+
---
|
|
10
29
|
|
|
11
|
-
|
|
30
|
+
## The problem isn't speed
|
|
12
31
|
|
|
13
|
-
|
|
32
|
+
Agents outpace the capacity to review what they produce. What's missing isn't throughput โ it's the lifecycle around it:
|
|
14
33
|
|
|
15
|
-
|
|
34
|
+
- requirements anyone actually agreed to
|
|
35
|
+
- designs anyone actually challenged
|
|
36
|
+
- tests mapped to the criteria they're supposed to prove
|
|
37
|
+
- a record of why decisions were made
|
|
16
38
|
|
|
17
|
-
|
|
39
|
+
AIDLC adds that missing lifecycle **without slowing the agent down**. It works with **Claude Code**, **Kiro**, **Cursor**, **Windsurf**, **Codex**, **GitHub Copilot** โ and any platform that reads skills. State lives as plain YAML in your repo: no server, no lock-in.
|
|
40
|
+
|
|
41
|
+
## The loop
|
|
42
|
+
|
|
43
|
+
An idea arrives mid-task, gets captured in five seconds, and comes back out the far end with a number attached to it.
|
|
44
|
+
|
|
45
|
+
> **[View this diagram on GitHub](https://github.com/rasensio/aidlc/blob/main/README.md#the-loop)** โ npm does not render Mermaid.
|
|
46
|
+
|
|
47
|
+
Nothing in that picture lives in a database. Every box is a file in your repository, readable by the next agent, the next session, and you.
|
|
18
48
|
|
|
19
49
|
## Quick Start
|
|
20
50
|
|
|
21
51
|
```bash
|
|
22
|
-
# Set up
|
|
52
|
+
# 1 โ Set up once (interactive wizard, or pass --platform to skip prompts)
|
|
23
53
|
npx @rasensio/aidlc init --platform claude-code
|
|
24
54
|
```
|
|
25
55
|
|
|
@@ -31,71 +61,168 @@ Then work from your AI coding tool. In Claude Code, invoke the entry point:
|
|
|
31
61
|
|
|
32
62
|
It reads your lifecycle state and offers the next actions โ continue an in-progress instance, start something new, check status, or review an artifact. You can also just describe what you want ("help me fix a bug") and the matching skill activates on its own.
|
|
33
63
|
|
|
34
|
-
|
|
64
|
+
Prefer the terminal? The same state protocol is addressable directly:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
aidlc start full-feature --name dark-mode
|
|
68
|
+
aidlc status
|
|
69
|
+
```
|
|
35
70
|
|
|
36
|
-
|
|
71
|
+
```text
|
|
72
|
+
Name Template Phase Completion Owner Stalled Cost Coverage Tasks
|
|
73
|
+
------------------ ------------ -------------- ---------- ---------- ------- ----- -------- -------
|
|
74
|
+
20260821-dark-mode full-feature implementation 57% session-a1 no $4.18 12/14 9/12 โธ1
|
|
75
|
+
20260824-login-500 bugfix testing 80% - no $0.92 3/3 4/4
|
|
76
|
+
```
|
|
37
77
|
|
|
38
|
-
|
|
39
|
-
|---------|---------|
|
|
40
|
-
| `aidlc` (no arguments) | Interactive menu of common commands; each entry shows the command it runs |
|
|
41
|
-
| `aidlc menu` | The same menu, addressable by name |
|
|
42
|
-
| `aidlc init [--platform <id>]` | Set up AIDLC: interactive wizard, or non-interactive with `--platform` |
|
|
43
|
-
| `aidlc update` | Update CLI and refresh project skills |
|
|
44
|
-
| `aidlc gate <phase>` | CI gate check (exit 0 = pass, 1 = fail) |
|
|
45
|
-
| `aidlc start [template]` | Begin a new lifecycle instance |
|
|
46
|
-
| `aidlc continue [instance]` | Resume the active instance |
|
|
47
|
-
| `aidlc status [--json]` | Show progress across active instances |
|
|
48
|
-
| `aidlc transition <instance>` | Evaluate gates and advance phase |
|
|
49
|
-
| `aidlc review <artifact>` | Adversarial review of an artifact |
|
|
50
|
-
| `aidlc discover [--no-knowledge]` | Scan codebase, generate context docs, seed the knowledge graph |
|
|
51
|
-
| `aidlc docs` | Generate onboarding documentation |
|
|
52
|
-
| `aidlc knowledge <subcommand>` | Query and update the local knowledge graph (see below) |
|
|
53
|
-
| `aidlc add action <description>` | Create lifecycle automation from a natural language description |
|
|
54
|
-
| `aidlc compliance <subcommand>` | Install compliance packs and report evidence per control (`list`, `add`, `remove`, `check`, `report`) |
|
|
78
|
+
Or run `aidlc` with no arguments for an interactive menu of the common commands.
|
|
55
79
|
|
|
56
|
-
##
|
|
80
|
+
## The gate is the whole idea
|
|
57
81
|
|
|
58
|
-
|
|
82
|
+
A phase doesn't end because an agent says it did. It ends when the gate lets it.
|
|
59
83
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
aidlc
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
aidlc
|
|
68
|
-
|
|
84
|
+
> **[View this diagram on GitHub](https://github.com/rasensio/aidlc/blob/main/README.md#the-gate-is-the-whole-idea)** โ npm does not render Mermaid.
|
|
85
|
+
|
|
86
|
+
The same binary runs in CI. `aidlc gate <instance> <phase>` exits 0 when the phase is complete and 1 when it isn't, so a pull request can be blocked by the identical check the agent just faced โ see [`ci/aidlc-gate.yml`](https://github.com/rasensio/aidlc/blob/main/ci/aidlc-gate.yml).
|
|
87
|
+
|
|
88
|
+
| | |
|
|
89
|
+
|---|---|
|
|
90
|
+
| **๐ฆ Phases with gates** | Each phase exits through a gate that requires artifacts, adversarial review, and a test per criterion. Agents cannot skip ahead. |
|
|
91
|
+
| **๐พ State on disk** | Lifecycle state is YAML under `.aidlc/` โ readable across agents, sessions, and git worktrees. Claims stop concurrent sessions from colliding. |
|
|
92
|
+
| **๐ Traceability built in** | Every acceptance criterion gets an ID. Tasks reference criteria; tests reference both. The gate fails on any criterion without a test. |
|
|
69
93
|
|
|
70
|
-
|
|
94
|
+
## How much process? Pick a template
|
|
95
|
+
|
|
96
|
+
Ceremony that fits a new subsystem will make people route around a typo fix. So the amount of lifecycle is a choice you make per piece of work, and it is the choice worth getting right.
|
|
97
|
+
|
|
98
|
+
> **[View this diagram on GitHub](https://github.com/rasensio/aidlc/blob/main/README.md#how-much-process-pick-a-template)** โ npm does not render Mermaid.
|
|
99
|
+
|
|
100
|
+
| Template | Scope | Description |
|
|
101
|
+
|----------|-------|-------------|
|
|
102
|
+
| `full-feature` | full | Full lifecycle from ideation through maintenance with adversarial review gates |
|
|
103
|
+
| `quick-feature` | standard | Standard feature workflow from requirements through deployment |
|
|
104
|
+
| `bugfix` | standard | Bug fix workflow with reproduction steps, no design phase |
|
|
105
|
+
| `spike` | standard | Spike or research workflow for exploration and findings documentation |
|
|
106
|
+
| `micro-task` | micro | Minimal workflow for small tasks requiring only implementation and testing |
|
|
107
|
+
|
|
108
|
+
**Scope** is the second dial, and the one people get wrong: it is not how big or ambitious the work is, it is which phases run. **Full** (all phases), **Standard** (Requirements โ Deployment), **Micro** (Implementation + Testing only). A large change with a settled design is standard; a small change nobody has thought about is full.
|
|
109
|
+
|
|
110
|
+
## Lifecycle Phases
|
|
111
|
+
|
|
112
|
+
| Phase | Purpose |
|
|
113
|
+
|-------|---------|
|
|
114
|
+
| Ideation | Explore and validate ideas, identify alternatives |
|
|
115
|
+
| Requirements | Define acceptance criteria, scope, and constraints |
|
|
116
|
+
| Design | Produce architecture and technical design documents |
|
|
117
|
+
| Implementation | Write code following established conventions |
|
|
118
|
+
| Testing | Validate correctness and coverage |
|
|
119
|
+
| Deployment | Release to target environment |
|
|
120
|
+
| Maintenance | Monitor, patch, and evolve |
|
|
121
|
+
|
|
122
|
+
When requirements move after their phase closed, `aidlc amend <instance>` retires the old criterion, issues a replacement, and reopens exactly the phases that assumption invalidated โ so drift shows up in history instead of hiding behind gates that all still pass.
|
|
123
|
+
|
|
124
|
+
## Two people, one repo
|
|
125
|
+
|
|
126
|
+
Claims are a lease on an instance, not a lock on the filesystem. They are what keeps two sessions from silently overwriting each other's phase.
|
|
127
|
+
|
|
128
|
+
> **[View this diagram on GitHub](https://github.com/rasensio/aidlc/blob/main/README.md#two-people-one-repo)** โ npm does not render Mermaid.
|
|
129
|
+
|
|
130
|
+
For genuinely concurrent work, use a worktree: `aidlc start --worktree` puts the second instance in its own checkout, because two sessions in one checkout collide on git long before they collide on state.
|
|
71
131
|
|
|
72
132
|
## Supported Platforms
|
|
73
133
|
|
|
134
|
+
One canonical skill body is written once and packaged into whatever each tool reads natively.
|
|
135
|
+
|
|
136
|
+
> **[View this diagram on GitHub](https://github.com/rasensio/aidlc/blob/main/README.md#supported-platforms)** โ npm does not render Mermaid.
|
|
137
|
+
|
|
74
138
|
| Platform | Config Location | Strategy |
|
|
75
139
|
|----------|----------------|----------|
|
|
76
140
|
| Claude Code | `.claude/skills/aidlc-*/SKILL.md` | Thin activation shims |
|
|
77
141
|
| Kiro | `.kiro/skills/aidlc-*/SKILL.md` + steering | Shims + steering file |
|
|
78
142
|
| Cursor | `.cursor/rules/aidlc-*.mdc` | Description-based rules |
|
|
79
143
|
| Windsurf | `.windsurf/rules/aidlc-*.md` | Size-constrained pointer shims |
|
|
80
|
-
| Codex |
|
|
81
|
-
| GitHub Copilot | `.github/skills/aidlc-*/SKILL.md` + `.github/copilot-instructions.md` | Full
|
|
144
|
+
| Codex | `AGENTS.md` | Managed delimiter block |
|
|
145
|
+
| GitHub Copilot | `.github/skills/aidlc-*/SKILL.md` + `.github/copilot-instructions.md` | Full bodies + instructions block |
|
|
146
|
+
|
|
147
|
+
Switching assistants, or having two people on different ones, doesn't fork your process: the rules are in your repository, the packaging is per-tool.
|
|
148
|
+
|
|
149
|
+
## It Closes the Loop
|
|
150
|
+
|
|
151
|
+
Most tooling stops at "the feature shipped." AIDLC keeps measuring after that, from state you already have:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
aidlc metrics
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
```text
|
|
158
|
+
Feedback-loop metrics (attribution: full-count-per-cause)
|
|
159
|
+
Coverage: 14 instances, 5 with defect linkage, 12 with cost data
|
|
160
|
+
|
|
161
|
+
By template:
|
|
162
|
+
full-feature: 6 completed, change failure rate 33%, avg lead time 2.4d
|
|
163
|
+
phases: ideation 3.1h, requirements 5.8h, design 7.2h, implementation 1.4d
|
|
164
|
+
bugfix: 5 completed, change failure rate 0%, avg lead time 4.6h
|
|
165
|
+
|
|
166
|
+
By instance:
|
|
167
|
+
20260821-dark-mode (full-feature): complete, lead 2.1d, cost $4.18, caused 1 bugfix(es), true cost $5.10
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
- **`aidlc metrics`** โ DORA-style roll-ups: change failure rate per template, lead time per phase, and true feature cost including the bugfixes it caused
|
|
171
|
+
- **`aidlc cost`** โ per-instance cost tracking with metered capture across every session that touched the instance
|
|
172
|
+
- **`caused_by`** โ links a bugfix back to the feature that produced it, so quality leaks become measurable instead of anecdotal
|
|
173
|
+
|
|
174
|
+
## Learn it
|
|
175
|
+
|
|
176
|
+
The tutorials are on the website, where the terminal transcripts are interactive.
|
|
177
|
+
|
|
178
|
+
**[๐ Getting Started](https://aidlc.rodrigoasensio.com/tutorials/getting-started/)** โ five steps: install, pick a template, run one instance end to end, enforce the gate in CI.
|
|
179
|
+
|
|
180
|
+
**[๐ The deep dive](https://aidlc.rodrigoasensio.com/tutorials/deep-dive/)** โ eight short chapters covering everything past that first session:
|
|
181
|
+
|
|
182
|
+
1. [Why the work lives in files](https://aidlc.rodrigoasensio.com/tutorials/deep-dive-why-files/)
|
|
183
|
+
2. [How much process is enough](https://aidlc.rodrigoasensio.com/tutorials/deep-dive-how-much-process/)
|
|
184
|
+
3. [The check that says no](https://aidlc.rodrigoasensio.com/tutorials/deep-dive-gates-that-say-no/)
|
|
185
|
+
4. [Notes about your code, kept once](https://aidlc.rodrigoasensio.com/tutorials/deep-dive-memory/)
|
|
186
|
+
5. [What it cost, and what it really cost](https://aidlc.rodrigoasensio.com/tutorials/deep-dive-what-it-cost/)
|
|
187
|
+
6. [Ideas that don't evaporate](https://aidlc.rodrigoasensio.com/tutorials/deep-dive-ideas-you-keep/)
|
|
188
|
+
7. [Two people, one checkout](https://aidlc.rodrigoasensio.com/tutorials/deep-dive-two-people/)
|
|
189
|
+
8. [Making it yours](https://aidlc.rodrigoasensio.com/tutorials/deep-dive-making-it-yours/)
|
|
82
190
|
|
|
83
|
-
|
|
84
|
-
activates on its own description and `/aidlc` works as a slash command. The instruction
|
|
85
|
-
block goes in `.github/copilot-instructions.md` because that is the one customization file
|
|
86
|
-
every Copilot surface reads โ editor chat, the cloud agent, code review and the CLI. It
|
|
87
|
-
writes nothing under `.claude/`, `.agents/` or any other vendor's directory.
|
|
191
|
+
Reference material is generated from the shipped packages, so it cannot drift from what you install: **[CLI reference](https://aidlc.rodrigoasensio.com/docs/cli/)** ยท **[phases](https://aidlc.rodrigoasensio.com/docs/phases/ideation/)** ยท **[skills](https://aidlc.rodrigoasensio.com/docs/skills/overview/)** ยท **[templates](https://aidlc.rodrigoasensio.com/docs/templates/bugfix/)** ยท **[guidance layers](https://aidlc.rodrigoasensio.com/docs/guidance/secure-defaults/)** ยท **[glossary](https://aidlc.rodrigoasensio.com/docs/glossary/)**.
|
|
88
192
|
|
|
89
|
-
|
|
193
|
+
And [๐ the blog](https://aidlc.rodrigoasensio.com/blog/) has a post per release, written the moment the work landed โ including the ones where it went wrong.
|
|
90
194
|
|
|
91
|
-
|
|
92
|
-
2. **Pick a template** โ full features, quick tasks, bug fixes, or spikes
|
|
93
|
-
3. **Your AI follows the lifecycle** โ skills activate in each phase, and the agent manages state directly in `.aidlc/state/` (plain YAML)
|
|
94
|
-
4. **Gates enforce quality** โ phase transitions require artifacts to be complete; `aidlc gate` gives CI the same check
|
|
195
|
+
## CLI Commands
|
|
95
196
|
|
|
96
|
-
|
|
197
|
+
The CLI has two core jobs: **bootstrap** (installing and refreshing skills โ the step that can't be a skill) and **CI enforcement** (`aidlc gate`, which runs where no agent does). Lifecycle work itself happens inside your AI tool via skills; the runtime commands below remain available as terminal shortcuts for the same state protocol.
|
|
97
198
|
|
|
98
|
-
|
|
199
|
+
| Command | Purpose |
|
|
200
|
+
|---------|---------|
|
|
201
|
+
| `aidlc` (no arguments) | Interactive menu of common commands; each entry shows the command it runs |
|
|
202
|
+
| `aidlc menu` | The same menu, addressable by name |
|
|
203
|
+
| `aidlc init [--platform <id>]` | Set up AIDLC: interactive wizard, or non-interactive with `--platform` |
|
|
204
|
+
| `aidlc update` | Update CLI and refresh project skills |
|
|
205
|
+
| `aidlc gate <instance> [phase]` | CI gate check (exit 0 = pass, 1 = fail) |
|
|
206
|
+
| `aidlc start [template]` | Begin a new lifecycle instance (`--name`, `--scope`, `--worktree`) |
|
|
207
|
+
| `aidlc continue [instance]` | Resume the active instance |
|
|
208
|
+
| `aidlc status [--json]` | Show progress across active instances (`--all`, `--prune`) |
|
|
209
|
+
| `aidlc transition <instance>` | Evaluate gates and advance phase |
|
|
210
|
+
| `aidlc amend <instance>` | Record a requirements amendment and reopen the phases it invalidated (`--impact` is read-only) |
|
|
211
|
+
| `aidlc review <instance> <artifact>` | Adversarial review of a lifecycle artifact |
|
|
212
|
+
| `aidlc metrics [--json]` | DORA-style metrics: change failure rate, lead times, true cost |
|
|
213
|
+
| `aidlc cost` | Per-instance cost tracking: reports, capture, rates, hooks |
|
|
214
|
+
| `aidlc claim` / `release` | Claim or release an instance for this session |
|
|
215
|
+
| `aidlc knowledge` | Local knowledge graph โ persistent codebase memory for agents |
|
|
216
|
+
| `aidlc discover` | Scan codebase, generate context docs |
|
|
217
|
+
| `aidlc docs` | Generate onboarding documentation |
|
|
218
|
+
| `aidlc doctor` | Check and repair repo hygiene |
|
|
219
|
+
| `aidlc constitution` | Import a product vision document and track the repo scope derived from it |
|
|
220
|
+
| `aidlc compliance` | Install compliance packs and report evidence per control (`list`, `add`, `remove`, `check`, `report`) |
|
|
221
|
+
| `aidlc roadmap` | Project the roadmap onto GitHub Issues (`sync`), or seed an item from one (`import`) |
|
|
222
|
+
| `aidlc add` | Add framework components: an `action` on a lifecycle event, or an app-owned `skill` |
|
|
223
|
+
|
|
224
|
+
<details>
|
|
225
|
+
<summary><b>Non-interactive setup (CI or agent-driven)</b></summary>
|
|
99
226
|
|
|
100
227
|
```bash
|
|
101
228
|
# Apply defaults (or keep the existing config) without prompts
|
|
@@ -105,6 +232,8 @@ npx @rasensio/aidlc init --non-interactive
|
|
|
105
232
|
npx @rasensio/aidlc init --platform claude-code
|
|
106
233
|
```
|
|
107
234
|
|
|
235
|
+
</details>
|
|
236
|
+
|
|
108
237
|
## Configuration
|
|
109
238
|
|
|
110
239
|
Project configuration lives in `.aidlc/config.yaml`:
|
|
@@ -118,6 +247,157 @@ claim_timeout_minutes: 60
|
|
|
118
247
|
|
|
119
248
|
Without this file, AIDLC defaults to Micro scope (Implementation + Testing only).
|
|
120
249
|
|
|
250
|
+
## Compliance packs
|
|
251
|
+
|
|
252
|
+
A compliance pack applies a regime's controls while code is written and reports the
|
|
253
|
+
evidence the lifecycle already produces. Packs are opt-in: with none installed,
|
|
254
|
+
nothing changes. Install one with `aidlc compliance add <pack>`, and it applies from
|
|
255
|
+
the next phase โ advisory by default, so findings are recorded and reported without
|
|
256
|
+
blocking. Set `compliance.enforce: true` in `.aidlc/config.yaml` to make a critical
|
|
257
|
+
control finding block a phase transition.
|
|
258
|
+
|
|
259
|
+
Packs describe themselves as guidance toward a regime. Nothing a pack emits states or
|
|
260
|
+
implies that a project is compliant, certified, or audit-ready.
|
|
261
|
+
|
|
262
|
+
`aidlc compliance check` assesses a change against the installed controls, for use in
|
|
263
|
+
continuous integration. Its exit codes:
|
|
264
|
+
|
|
265
|
+
| Exit | Meaning |
|
|
266
|
+
|------|---------|
|
|
267
|
+
| 0 | No failing control, or failures present in advisory mode |
|
|
268
|
+
| 1 | A failing critical control, with `--enforce` |
|
|
269
|
+
| 2 | Usage or pack-load error, or a control left unassessed with `--enforce` |
|
|
270
|
+
|
|
271
|
+
`--enforce` raises the exit code for that one invocation and reads no config, so a
|
|
272
|
+
failing pull-request check does not require blocking every local phase transition. An
|
|
273
|
+
unassessed control exits non-zero under `--enforce` rather than passing silently: a
|
|
274
|
+
control nothing looked at is never a pass.
|
|
275
|
+
|
|
276
|
+
## Architecture
|
|
277
|
+
|
|
278
|
+
Three packages, one direction of dependency.
|
|
279
|
+
|
|
280
|
+
> **[View this diagram on GitHub](https://github.com/rasensio/aidlc/blob/main/README.md#architecture)** โ npm does not render Mermaid.
|
|
281
|
+
|
|
282
|
+
- **`@rasensio/aidlc-content`** โ Knowledge layer. Skills, templates, guidance documents, capability maps, and phase definitions. The single source of truth for what AIDLC knows about lifecycle phases.
|
|
283
|
+
- **`@rasensio/aidlc`** (CLI) โ Engine. Orchestrates lifecycle state, compiles skills into platform-native formats, evaluates transition gates, and manages instance sessions.
|
|
284
|
+
- **`@rasensio/aidlc-website`** โ Documentation and marketing site at [aidlc.rodrigoasensio.com](https://aidlc.rodrigoasensio.com).
|
|
285
|
+
|
|
286
|
+
Content is the shared dependency. The CLI reads it at compile time to produce installable artifacts. The website reads it at build time to generate documentation pages โ which is why the reference docs cannot describe a command the binary doesn't have.
|
|
287
|
+
|
|
288
|
+
<details>
|
|
289
|
+
<summary><b>Monorepo structure</b></summary>
|
|
290
|
+
|
|
291
|
+
This repository is a pnpm workspace:
|
|
292
|
+
|
|
293
|
+
```
|
|
294
|
+
aidlc/
|
|
295
|
+
โโโ docs/ # How AIDLC works โ nine prose pages on why each subsystem exists
|
|
296
|
+
โโโ packages/
|
|
297
|
+
โ โโโ content/ # @rasensio/aidlc-content โ skills, templates, guidance, capabilities
|
|
298
|
+
โ โโโ cli/ # @rasensio/aidlc โ CLI tool (npm package)
|
|
299
|
+
โ โโโ website/ # @rasensio/aidlc-website โ documentation website (Next.js)
|
|
300
|
+
โโโ ci/ # CI pipeline configuration
|
|
301
|
+
โโโ pnpm-workspace.yaml
|
|
302
|
+
โโโ tsconfig.json # Shared compiler options + project references
|
|
303
|
+
โโโ package.json # Workspace-level scripts
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
| Package | Description | Published |
|
|
307
|
+
|---------|-------------|-----------|
|
|
308
|
+
| `@rasensio/aidlc-content` | Shared content (skills, templates, guidance layers, capability maps) | npm |
|
|
309
|
+
| `@rasensio/aidlc` | CLI tool โ lifecycle engine, platform adapters, state management | npm |
|
|
310
|
+
| `@rasensio/aidlc-website` | Marketing site + documentation (Next.js, Tailwind, static export) | AWS Amplify โ [aidlc.rodrigoasensio.com](https://aidlc.rodrigoasensio.com) |
|
|
311
|
+
|
|
312
|
+
</details>
|
|
313
|
+
|
|
314
|
+
## How this repo works
|
|
315
|
+
|
|
316
|
+
Reference docs tell you *what* a command does. [**`docs/`**](https://github.com/rasensio/aidlc/blob/main/docs/README.md) tells you *why the subsystem exists and what breaks without it* โ nine pages, written for a person trying to understand the system and for an agent about to change it. Read the relevant page before modifying a subsystem: several of these designs look arbitrary until you know which bug bought them.
|
|
317
|
+
|
|
318
|
+
| Page | What it covers |
|
|
319
|
+
|---|---|
|
|
320
|
+
| [lifecycle.md](https://github.com/rasensio/aidlc/blob/main/docs/lifecycle.md) | Instances, templates, scope, phases, gates, amendments |
|
|
321
|
+
| [state-and-concurrency.md](https://github.com/rasensio/aidlc/blob/main/docs/state-and-concurrency.md) | State files, claims, the registry, worktrees |
|
|
322
|
+
| [roadmap.md](https://github.com/rasensio/aidlc/blob/main/docs/roadmap.md) | Capture, triage, promote, and the GitHub Issues projection |
|
|
323
|
+
| [reviews-and-guidance.md](https://github.com/rasensio/aidlc/blob/main/docs/reviews-and-guidance.md) | Adversarial review, guidance layers, context docs, the constitution |
|
|
324
|
+
| [cost-tracking.md](https://github.com/rasensio/aidlc/blob/main/docs/cost-tracking.md) | What a feature cost, and how the number is attributed |
|
|
325
|
+
| [metrics.md](https://github.com/rasensio/aidlc/blob/main/docs/metrics.md) | Change failure rate, lead times, true cost |
|
|
326
|
+
| [knowledge-graph.md](https://github.com/rasensio/aidlc/blob/main/docs/knowledge-graph.md) | Persistent codebase memory for agents |
|
|
327
|
+
| [skills-and-platforms.md](https://github.com/rasensio/aidlc/blob/main/docs/skills-and-platforms.md) | One canonical skill body, six platform packagings |
|
|
328
|
+
| [hygiene-and-compliance.md](https://github.com/rasensio/aidlc/blob/main/docs/hygiene-and-compliance.md) | `aidlc doctor`, compliance packs |
|
|
329
|
+
|
|
330
|
+
## Development
|
|
331
|
+
|
|
332
|
+
**Prerequisites:** Node.js >= 22.13 (the CLI's knowledge graph uses the built-in `node:sqlite` module, unflagged since 22.13) and pnpm >= 9.
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
pnpm install
|
|
336
|
+
pnpm build # content first, then CLI + website in parallel
|
|
337
|
+
pnpm test # all tests, one package at a time (see note below)
|
|
338
|
+
pnpm lint # type-check all packages
|
|
339
|
+
|
|
340
|
+
pnpm --filter @rasensio/aidlc-website dev # work on the site locally
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
Tests use **vitest** (unit + integration) and **fast-check** (property-based testing):
|
|
344
|
+
|
|
345
|
+
```bash
|
|
346
|
+
pnpm --filter @rasensio/aidlc test
|
|
347
|
+
pnpm --filter @rasensio/aidlc-content test
|
|
348
|
+
pnpm --filter @rasensio/aidlc-website test
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
`pnpm test` is `pnpm -r --workspace-concurrency=1 test` โ the packages run one at a
|
|
352
|
+
time, deliberately. vitest already parallelises test files across workers, so a
|
|
353
|
+
second axis of parallelism oversubscribes the CPU and pushes subprocess-spawning
|
|
354
|
+
tests past their timeout. Measured on an idle machine: 263s for `packages/cli` with
|
|
355
|
+
two 30-second timeouts when the packages run concurrently, against 71s and 75s for
|
|
356
|
+
the whole workspace when they do not. Serialising is both faster and greener โ
|
|
357
|
+
please don't change it back.
|
|
358
|
+
|
|
359
|
+
Every push to `main` and every pull request runs the same gate as a release โ
|
|
360
|
+
`pnpm build`, `pnpm lint`, `pnpm test` โ via [`.github/workflows/ci.yml`](https://github.com/rasensio/aidlc/blob/main/.github/workflows/ci.yml).
|
|
361
|
+
|
|
362
|
+
**One caution, learned the hard way:** during development invoke the workspace build,
|
|
363
|
+
`node packages/cli/dist/cli.js`, never `npx aidlc`. `npx` prefers a globally installed
|
|
364
|
+
binary, and it once reported "0 files updated, 35 unchanged" while the edited files sat
|
|
365
|
+
changed on disk.
|
|
366
|
+
|
|
367
|
+
<details>
|
|
368
|
+
<summary><b>Project conventions & migration notes</b></summary>
|
|
369
|
+
|
|
370
|
+
- TypeScript, ES modules, Node >= 22.13
|
|
371
|
+
- Pure-function core (no I/O) with I/O pushed to edges
|
|
372
|
+
- Pinned dependencies
|
|
373
|
+
- Property-based tests for core logic
|
|
374
|
+
- Content package uses `import.meta.url` for path resolution
|
|
375
|
+
|
|
376
|
+
> **Migration note (v1.0):** the CLI previously ran on Node >= 18. The local
|
|
377
|
+
> knowledge graph feature raised the floor to Node 22.13+ to use `node:sqlite`
|
|
378
|
+
> with zero native dependencies. Users on Node 18/20 must upgrade their Node
|
|
379
|
+
> runtime (e.g. `nvm install 22`); no other migration steps are required.
|
|
380
|
+
|
|
381
|
+
</details>
|
|
382
|
+
|
|
383
|
+
## Contributing
|
|
384
|
+
|
|
385
|
+
Contributions welcome. Please open an issue first for significant changes.
|
|
386
|
+
|
|
387
|
+
```bash
|
|
388
|
+
pnpm install
|
|
389
|
+
pnpm build
|
|
390
|
+
pnpm test
|
|
391
|
+
```
|
|
392
|
+
|
|
121
393
|
## License
|
|
122
394
|
|
|
123
395
|
[MIT](https://github.com/rasensio/aidlc/blob/main/LICENSE)
|
|
396
|
+
|
|
397
|
+
---
|
|
398
|
+
|
|
399
|
+
<div align="center">
|
|
400
|
+
|
|
401
|
+
**[aidlc.rodrigoasensio.com](https://aidlc.rodrigoasensio.com)** โ docs, tutorials, and the build log
|
|
402
|
+
|
|
403
|
+
</div>
|
package/dist/commands/cost.d.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* Design: design.md ยง1 (command surface)
|
|
9
9
|
*/
|
|
10
10
|
import { Command } from 'commander';
|
|
11
|
+
import type { CostDrivers, UnattributedSummary } from '../cost/report.js';
|
|
11
12
|
/**
|
|
12
13
|
* Token counts at the magnitude they actually occur: `245k`, `1.2M`.
|
|
13
14
|
*
|
|
@@ -17,5 +18,8 @@ import { Command } from 'commander';
|
|
|
17
18
|
export declare function fmtTokens(tokens: number): string;
|
|
18
19
|
/** Human age of an ISO timestamp, for the capture-error note (AC-11). */
|
|
19
20
|
export declare function fmtAge(timestamp: string, now?: Date): string;
|
|
21
|
+
export declare function fmtDriverLine(d: CostDrivers): string | null;
|
|
22
|
+
/** One whole-project line pricing the pool no instance owns (AC-8). */
|
|
23
|
+
export declare function fmtUnattributedLine(u: UnattributedSummary): string;
|
|
20
24
|
export declare function registerCost(program: Command): void;
|
|
21
25
|
//# sourceMappingURL=cost.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cost.d.ts","sourceRoot":"","sources":["../../src/commands/cost.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"cost.d.ts","sourceRoot":"","sources":["../../src/commands/cost.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAgF1E;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAIhD;AAED,yEAAyE;AACzE,wBAAgB,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,GAAE,IAAiB,GAAG,MAAM,CASxE;AA4LD,wBAAgB,aAAa,CAAC,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAwB3D;AAgBD,uEAAuE;AACvE,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,mBAAmB,GAAG,MAAM,CAMlE;AAoaD,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAiGnD"}
|
package/dist/commands/cost.js
CHANGED
|
@@ -17,7 +17,7 @@ import { registerBuiltinProviders } from '../cost/providers/index.js';
|
|
|
17
17
|
import { recordUsage, lastCaptureError, logCapture, captureLiveness } from '../cost/recorder.js';
|
|
18
18
|
import { stashSession, unstashSession } from '../cost/sessions.js';
|
|
19
19
|
import { appendEntry, ledgerPath } from '../cost/ledger.js';
|
|
20
|
-
import { instanceCost, listInstances, byTemplate, unattributedEntries } from '../cost/report.js';
|
|
20
|
+
import { instanceCost, listInstances, byTemplate, unattributedEntries, unattributedSummary } from '../cost/report.js';
|
|
21
21
|
import { effectiveRates, updateRates, microToUsd, NORMALIZATION_RULES } from '../cost/rates.js';
|
|
22
22
|
import { loadCostConfig, loadClaimTimeoutMinutes } from '../cost/config.js';
|
|
23
23
|
import { resolvePin, skipReason, pinLabel } from '../cost/pin.js';
|
|
@@ -270,17 +270,98 @@ async function runSessionStart(opts) {
|
|
|
270
270
|
logCapture(root, 'session-start', 'stash-failed');
|
|
271
271
|
}
|
|
272
272
|
}
|
|
273
|
+
/*
|
|
274
|
+
* Where the money went, not just how much. `$578.45` alone gives a reader
|
|
275
|
+
* nothing to act on: on this project's ledger 59.6% of dollars is cache read โ
|
|
276
|
+
* re-reading the conversation prefix, not producing anything โ so the lever is
|
|
277
|
+
* context size, and that is invisible from a total.
|
|
278
|
+
*
|
|
279
|
+
* Every figure is a word or a number, never a colour or a bare symbol, so the
|
|
280
|
+
* line reads the same piped, in a monochrome terminal, and to a screen reader.
|
|
281
|
+
* `unmeasured` is printed rather than omitted: a missing figure and a zero one
|
|
282
|
+
* mean different things, which is the rule the rest of this report already
|
|
283
|
+
* follows.
|
|
284
|
+
*/
|
|
285
|
+
export function fmtDriverLine(d) {
|
|
286
|
+
if (d.responses === null && d.cacheReadShare === null)
|
|
287
|
+
return null;
|
|
288
|
+
const parts = [];
|
|
289
|
+
if (d.cacheReadShare !== null) {
|
|
290
|
+
parts.push(`context re-read: ${(d.cacheReadShare * 100).toFixed(1)}% of spend`);
|
|
291
|
+
}
|
|
292
|
+
// The same `~` the response count carries: the averages are derived from the
|
|
293
|
+
// counted subset, so when the count is a floor they are estimates over part of
|
|
294
|
+
// the ledger, not measurements of all of it (cost-driver-integrity/AC-2).
|
|
295
|
+
const approx = d.responsesPartial ? '~' : '';
|
|
296
|
+
if (d.avgContextTokens !== null) {
|
|
297
|
+
parts.push(`avg context: ${approx}${fmtTokens(d.avgContextTokens)}`);
|
|
298
|
+
}
|
|
299
|
+
if (d.microUsdPerResponse !== null) {
|
|
300
|
+
parts.push(`per response: ${approx}${microToUsd(d.microUsdPerResponse)}`);
|
|
301
|
+
}
|
|
302
|
+
if (d.responses !== null) {
|
|
303
|
+
// `~` marks a floor, matching how activePartial is already marked: some
|
|
304
|
+
// entries predate response counting, so the total understates the truth.
|
|
305
|
+
parts.push(`responses: ${d.responsesPartial ? '~' : ''}${d.responses}`);
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
parts.push('responses: unmeasured');
|
|
309
|
+
}
|
|
310
|
+
return parts.join(' ');
|
|
311
|
+
}
|
|
312
|
+
/*
|
|
313
|
+
* The pool's headline figure, in the most honest unit available.
|
|
314
|
+
*
|
|
315
|
+
* Dollars when anything priced; otherwise tokens, or credits for a kiro-only
|
|
316
|
+
* pool; and `unmeasured` when there is no quantity of any kind โ never the bare
|
|
317
|
+
* `0` that `fmtTokens(0)` would produce for entries that carry real usage.
|
|
318
|
+
*/
|
|
319
|
+
function fmtUnattributedTotal(u) {
|
|
320
|
+
if (u.microUsd !== null)
|
|
321
|
+
return microToUsd(u.microUsd);
|
|
322
|
+
if (u.tokens > 0)
|
|
323
|
+
return `${fmtTokens(u.tokens)} tok`;
|
|
324
|
+
if (u.credits > 0)
|
|
325
|
+
return `${u.credits} credits`;
|
|
326
|
+
return 'unmeasured';
|
|
327
|
+
}
|
|
328
|
+
/** One whole-project line pricing the pool no instance owns (AC-8). */
|
|
329
|
+
export function fmtUnattributedLine(u) {
|
|
330
|
+
return (`unattributed: ${fmtUnattributedTotal(u)} across ${u.entries} entries` +
|
|
331
|
+
(u.unpricedModels.length > 0 ? ` (unpriced: ${u.unpricedModels.join(', ')})` : '') +
|
|
332
|
+
' โ `aidlc cost sync` attributes what claim windows cover');
|
|
333
|
+
}
|
|
273
334
|
function runReport(instance, opts) {
|
|
274
335
|
const root = projectRoot();
|
|
275
336
|
const config = loadCostConfig(root);
|
|
276
337
|
if (opts.unattributed) {
|
|
277
|
-
const entries = unattributedEntries(root);
|
|
278
338
|
if (opts.json) {
|
|
279
|
-
process.stdout.write(JSON.stringify(
|
|
339
|
+
process.stdout.write(JSON.stringify(unattributedEntries(root), null, 2) + '\n');
|
|
340
|
+
return;
|
|
280
341
|
}
|
|
281
|
-
|
|
282
|
-
|
|
342
|
+
const u = unattributedSummary(root, config);
|
|
343
|
+
if (u === null) {
|
|
344
|
+
process.stdout.write('0 unattributed entries\n');
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
// Dollars first: a count alone let ~44% of this repo's spend hide here
|
|
348
|
+
// (cost-driver-integrity/AC-9).
|
|
349
|
+
process.stdout.write(`${u.entries} unattributed entries total: ${fmtUnattributedTotal(u)}` +
|
|
350
|
+
(u.unpricedModels.length > 0 ? ` (unpriced: ${u.unpricedModels.join(', ')})` : '') +
|
|
351
|
+
'\n');
|
|
352
|
+
const fid = Object.entries(u.fidelity)
|
|
353
|
+
.filter(([, n]) => n > 0)
|
|
354
|
+
.map(([k, n]) => `${k} ${n}`)
|
|
355
|
+
.join(', ');
|
|
356
|
+
process.stdout.write(` fidelity: ${fid}\n`);
|
|
357
|
+
for (const [model, tokens] of Object.entries(u.modelTokens).sort((a, b) => b[1] - a[1])) {
|
|
358
|
+
process.stdout.write(` ${model.padEnd(24)} ${fmtTokens(tokens)} tok (raw)\n`);
|
|
359
|
+
}
|
|
360
|
+
// Credits are a separate unit and are never printed as tokens.
|
|
361
|
+
for (const [model, credits] of Object.entries(u.modelCredits).sort((a, b) => b[1] - a[1])) {
|
|
362
|
+
process.stdout.write(` ${model.padEnd(24)} ${credits} credits (raw)\n`);
|
|
283
363
|
}
|
|
364
|
+
process.stdout.write(' `aidlc cost sync` attributes what claim windows cover\n');
|
|
284
365
|
return;
|
|
285
366
|
}
|
|
286
367
|
if (opts.byTemplate) {
|
|
@@ -355,30 +436,22 @@ function runReport(instance, opts) {
|
|
|
355
436
|
* mean different things, which is the rule the rest of this report already
|
|
356
437
|
* follows.
|
|
357
438
|
*/
|
|
358
|
-
const
|
|
359
|
-
if (
|
|
360
|
-
|
|
361
|
-
if (d.cacheReadShare !== null) {
|
|
362
|
-
parts.push(`context re-read: ${(d.cacheReadShare * 100).toFixed(1)}% of spend`);
|
|
363
|
-
}
|
|
364
|
-
if (d.avgContextTokens !== null) {
|
|
365
|
-
parts.push(`avg context: ${fmtTokens(d.avgContextTokens)}`);
|
|
366
|
-
}
|
|
367
|
-
if (d.microUsdPerResponse !== null) {
|
|
368
|
-
parts.push(`per response: ${microToUsd(d.microUsdPerResponse)}`);
|
|
369
|
-
}
|
|
370
|
-
if (d.responses !== null) {
|
|
371
|
-
// `~` marks a floor, matching how activePartial is already marked: some
|
|
372
|
-
// entries predate response counting, so the total understates the truth.
|
|
373
|
-
parts.push(`responses: ${d.responsesPartial ? '~' : ''}${d.responses}`);
|
|
374
|
-
}
|
|
375
|
-
else {
|
|
376
|
-
parts.push('responses: unmeasured');
|
|
377
|
-
}
|
|
378
|
-
process.stdout.write(` ${parts.join(' ')}\n`);
|
|
439
|
+
const driverLine = fmtDriverLine(c.drivers);
|
|
440
|
+
if (driverLine !== null) {
|
|
441
|
+
process.stdout.write(` ${driverLine}\n`);
|
|
379
442
|
}
|
|
380
443
|
process.stdout.write(` rates: ${c.snapshot}\n`);
|
|
381
444
|
}
|
|
445
|
+
// The pool of spend no instance owns, priced โ on this repo it was ~44% of the
|
|
446
|
+
// total while the report said nothing. Whole-project view only: beside a single
|
|
447
|
+
// instance it would read as that instance's number (AC-8). Empty pool prints
|
|
448
|
+
// nothing โ silence, never `$0.00` (AC-10).
|
|
449
|
+
if (instance === undefined) {
|
|
450
|
+
const u = unattributedSummary(root, config);
|
|
451
|
+
if (u !== null) {
|
|
452
|
+
process.stdout.write(`${fmtUnattributedLine(u)}\n`);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
382
455
|
const err = lastCaptureError(root);
|
|
383
456
|
if (err) {
|
|
384
457
|
process.stderr.write(`note: last capture error ${err.error_code} at ${err.stage} (${fmtAge(err.timestamp)}) โ see .aidlc/cost/capture.log\n`);
|