claudify-agent 1.0.9 → 1.0.11
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/.claude/commands/backbone-init.md +1 -0
- package/.claude/commands/spec-apply.md +4 -2
- package/.claude/commands/spec-archive.md +2 -1
- package/.claude/commands/spec-new.md +9 -6
- package/.claude/scripts/spec-check.mjs +96 -0
- package/CLAUDE.md +2 -0
- package/README.md +7 -0
- package/README.vi.md +7 -0
- package/package.json +1 -1
- package/templates/BACKBONE.md +6 -0
- package/templates/spec/config.md +2 -1
|
@@ -12,6 +12,7 @@ Draft or refresh `BACKBONE.md` at the project root. Notes from me: $ARGUMENTS
|
|
|
12
12
|
- CI workflows for the real lint/test/build commands.
|
|
13
13
|
2. Fill every section of the existing `BACKBONE.md` (or the template if missing):
|
|
14
14
|
- Docs index: one line per doc, with status. Mark a doc outdated only with evidence (superseded note, archive folder, version mismatch); otherwise ask.
|
|
15
|
+
- Domain glossary: the main business nouns from models/entities/DB schema/status enums, with meaning and states. Ask me when a name is cryptic (e.g. `tbl_sub_v3`, `flag_v2`) instead of guessing. Keep it to the terms that matter (~15).
|
|
15
16
|
- Capabilities: one line per `spec/specs/*.md` (or `openspec/specs/*/` if migrating from OpenSpec).
|
|
16
17
|
- Invariants: only rules found in docs or that I confirm. Never invent business rules.
|
|
17
18
|
3. Keep it under ~80 lines. Link, never copy.
|
|
@@ -7,8 +7,10 @@ Implement spec change: $ARGUMENTS
|
|
|
7
7
|
|
|
8
8
|
1. Read `spec/changes/<change-name>.md`; respect the Invariants in `BACKBONE.md`. Nothing else up front; read code only as each task needs it.
|
|
9
9
|
2. Take the requested task, or the first unchecked `- [ ]` task. Work one task at a time.
|
|
10
|
-
|
|
10
|
+
Business-rule guard: money amounts, limits, fees, refunds, permissions, status transitions, legal/compliance rules MUST come from an AC, the Invariants or a linked doc. If the task needs one that is not written down, stop and ask me; never pick a "reasonable" value. Add my answer to the spec before coding it.
|
|
11
|
+
3. Implement it with tests for the ACs it covers. Each test name contains the full AC ID, e.g. `describe("refund/AC-2: expired QR is refunded", ...)` or `func TestRefund_AC2` with a `// refund/AC-2` comment. Use the Domain glossary terms for names. Then run its DoD. Fix until it passes (max 5 attempts, then stop and report).
|
|
11
12
|
4. Tick it `- [x]` in the change file. If reality differs from the spec, update the spec (Requirements/Design) in the same step and tell me.
|
|
12
|
-
5.
|
|
13
|
+
5. If I ask you to commit: `feat(<change-name>): <what>` and list the AC IDs covered in the body.
|
|
14
|
+
6. Report in 2-3 lines: task done, proof run, next task. Continue to the next task only if I asked for more than one.
|
|
13
15
|
|
|
14
16
|
When every task is ticked, set `Status: done` and suggest `/spec-archive <change-name>`.
|
|
@@ -6,8 +6,9 @@ argument-hint: <change-name>
|
|
|
6
6
|
Archive spec change: $ARGUMENTS
|
|
7
7
|
|
|
8
8
|
1. Read `spec/changes/<change-name>.md`. Refuse if any task is unchecked; list them.
|
|
9
|
+
Run `node .claude/scripts/spec-check.mjs spec/changes/<change-name>.md`. If an AC has no test, list it and ask me: add the test, or archive anyway (I accept the gap).
|
|
9
10
|
2. For each `### <capability>` block under Requirements, update `spec/specs/<capability>.md` (create if new):
|
|
10
|
-
- Keep only Requirements and
|
|
11
|
+
- Keep only Requirements and their ACs (with IDs unchanged): the current truth of the system, no history, no tasks.
|
|
11
12
|
- ADDED → append. MODIFIED → replace the requirement of the same name in full. REMOVED → delete it.
|
|
12
13
|
- If a MODIFIED/REMOVED name does not exist in the backbone, stop and ask instead of guessing.
|
|
13
14
|
3. Move the change file to `spec/changes/archive/YYYY-MM-DD-<change-name>.md`.
|
|
@@ -22,19 +22,22 @@ Status: draft | Depends on: <change or none>
|
|
|
22
22
|
### <capability> (new | modified)
|
|
23
23
|
#### ADDED Requirement: <name>
|
|
24
24
|
<statement with SHALL/MUST>
|
|
25
|
-
-
|
|
25
|
+
- AC-1 <name>: GIVEN ... WHEN ... THEN ...
|
|
26
|
+
- AC-2 <name>: GIVEN ... WHEN ... THEN ...
|
|
26
27
|
#### MODIFIED Requirement: <existing name>
|
|
27
|
-
<full new text, not just the diff>
|
|
28
|
+
<full new text and its ACs, not just the diff>
|
|
28
29
|
#### REMOVED Requirement: <existing name>
|
|
29
30
|
<reason>
|
|
30
31
|
## Design
|
|
31
32
|
<only decisions not obvious from the code: data flow, schema, API, edge cases. Omit section if trivial.>
|
|
32
33
|
## Risks
|
|
33
34
|
## Tasks
|
|
34
|
-
- [ ] 1. <task> — files: ... — DoD: ...
|
|
35
|
+
- [ ] 1. <task> — files: ... — covers: <capability>/AC-1, AC-2 — DoD: ...
|
|
35
36
|
```
|
|
36
37
|
|
|
37
|
-
4.
|
|
38
|
+
4. AC IDs: numbered per capability and never reused. New ACs continue after the highest `AC-<n>` in `spec/specs/<capability>.md`; a MODIFIED requirement keeps its existing AC IDs. The full ID is `<capability>/AC-<n>`.
|
|
39
|
+
5. Use the terms from the Domain glossary in `BACKBONE.md`. A new domain term → add it to the glossary in the same step.
|
|
40
|
+
6. Keep the whole file under ~800 words, plus ~300 per extra capability. No restating config, docs or code; link them.
|
|
38
41
|
If it still does not fit (e.g. more than 4 capabilities), propose splitting into smaller changes with `Depends on:` instead of one giant spec.
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
7. Add the change as one line under "Open changes" in `BACKBONE.md`.
|
|
43
|
+
8. Do not write code. Finish by showing the task list and asking me to approve before `/spec-apply`.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Spec ↔ Test Traceability Check
|
|
5
|
+
* Every acceptance criterion `<capability>/AC-<n>` must be named by at least one test.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* node .claude/scripts/spec-check.mjs # all of spec/specs/
|
|
9
|
+
* node .claude/scripts/spec-check.mjs spec/changes/x.md # one change (before archive)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { execSync } from 'child_process';
|
|
13
|
+
import { readFileSync, readdirSync, existsSync } from 'fs';
|
|
14
|
+
import { join, basename } from 'path';
|
|
15
|
+
|
|
16
|
+
const AC_LINE = /\bAC-(\d+)\b/g;
|
|
17
|
+
const TEST_REF = /([\w-]+)\/AC-(\d+)(?!\d)/g;
|
|
18
|
+
|
|
19
|
+
// Acceptance criteria declared in a spec file. In a change file the capability
|
|
20
|
+
// comes from the enclosing `### <capability> (new|modified)` heading.
|
|
21
|
+
function declaredAcs(file, capability) {
|
|
22
|
+
const ids = new Set();
|
|
23
|
+
let current = capability;
|
|
24
|
+
let removed = false;
|
|
25
|
+
for (const line of readFileSync(file, 'utf-8').split('\n')) {
|
|
26
|
+
const cap = line.match(/^###\s+([\w-]+)\s+\((new|modified)\)/);
|
|
27
|
+
if (cap) current = cap[1];
|
|
28
|
+
if (/^####\s/.test(line)) removed = /^####\s+REMOVED\b/.test(line);
|
|
29
|
+
if (!current || removed || !/^\s*[-*]\s*AC-\d+/.test(line)) continue;
|
|
30
|
+
for (const m of line.matchAll(AC_LINE)) ids.add(`${current}/AC-${m[1]}`);
|
|
31
|
+
}
|
|
32
|
+
return ids;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const SKIP_DIRS = new Set(['.git', 'node_modules', 'dist', 'build', 'coverage', 'vendor', 'target', '.next']);
|
|
36
|
+
|
|
37
|
+
// Multi-repo workspaces have no git repo at the root: walk the tree instead
|
|
38
|
+
function walk(dir, out = []) {
|
|
39
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
40
|
+
if (entry.isDirectory()) {
|
|
41
|
+
if (!SKIP_DIRS.has(entry.name)) walk(join(dir, entry.name), out);
|
|
42
|
+
} else {
|
|
43
|
+
out.push(dir === '.' ? entry.name : join(dir, entry.name));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// AC references found in code/test files (everything except specs and docs)
|
|
50
|
+
function referencedAcs() {
|
|
51
|
+
let files;
|
|
52
|
+
try {
|
|
53
|
+
files = execSync('git ls-files --cached --others --exclude-standard', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'ignore'] }).split('\n');
|
|
54
|
+
} catch {
|
|
55
|
+
files = walk('.');
|
|
56
|
+
}
|
|
57
|
+
const refs = new Set();
|
|
58
|
+
for (const file of files) {
|
|
59
|
+
if (!file || file.startsWith('spec/') || /\.(md|lock)$/.test(file) || !existsSync(file)) continue;
|
|
60
|
+
let text;
|
|
61
|
+
try {
|
|
62
|
+
text = readFileSync(file, 'utf-8');
|
|
63
|
+
} catch {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
for (const m of text.matchAll(TEST_REF)) refs.add(`${m[1]}/AC-${m[2]}`);
|
|
67
|
+
}
|
|
68
|
+
return refs;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const target = process.argv[2];
|
|
72
|
+
const declared = new Set();
|
|
73
|
+
if (target) {
|
|
74
|
+
for (const id of declaredAcs(target)) declared.add(id);
|
|
75
|
+
} else if (existsSync('spec/specs')) {
|
|
76
|
+
for (const f of readdirSync('spec/specs').filter((f) => f.endsWith('.md'))) {
|
|
77
|
+
for (const id of declaredAcs(join('spec/specs', f), basename(f, '.md'))) declared.add(id);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (declared.size === 0) {
|
|
82
|
+
console.log('ℹ️ No acceptance criteria (AC-<n>) found.');
|
|
83
|
+
process.exit(0);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const refs = referencedAcs();
|
|
87
|
+
const missing = [...declared].filter((id) => !refs.has(id)).sort();
|
|
88
|
+
const covered = declared.size - missing.length;
|
|
89
|
+
|
|
90
|
+
console.log(`📋 AC coverage: ${covered}/${declared.size}`);
|
|
91
|
+
if (missing.length) {
|
|
92
|
+
console.log('❌ No test references:');
|
|
93
|
+
for (const id of missing) console.log(` - ${id}`);
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
console.log('✅ Every AC is covered by a test.');
|
package/CLAUDE.md
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
If it still holds `<placeholders>`, suggest `/backbone-init`. Follow its Invariants on every task.
|
|
11
11
|
If you finish work without a spec that changes structure, docs, commands or capabilities, suggest `/backbone-sync`.
|
|
12
|
+
Never invent business rules (money, limits, refunds, permissions, status transitions, legal): if no spec, invariant or doc states it, ask.
|
|
12
13
|
|
|
13
14
|
## 1. 🛑 Context & Token Preservation (Sub-20 Line Core)
|
|
14
15
|
- Keep responses concise and targeted. Never dump entire files when diffs suffice.
|
|
@@ -21,6 +22,7 @@ If you finish work without a spec that changes structure, docs, commands or capa
|
|
|
21
22
|
## 2. 📋 Plan First Protocol (Anti-Drift)
|
|
22
23
|
- For tasks touching **>= 2 files** or core architecture:
|
|
23
24
|
- Generate a concise Plan before modifying files.
|
|
25
|
+
- Inside `/spec-apply`, the approved spec Tasks are the plan; do not write another one.
|
|
24
26
|
- Research protocol: `.claude/rules/plan-mode-research.md`
|
|
25
27
|
- Execution checklist: `.claude/rules/plan-mode-execution.md`
|
|
26
28
|
- Validation steps: `.claude/rules/plan-mode-validation.md`
|
package/README.md
CHANGED
|
@@ -96,6 +96,13 @@ spec/
|
|
|
96
96
|
└── data-export.md ← current truth, merged on archive
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
+
### Traceability (spec ↔ test)
|
|
100
|
+
|
|
101
|
+
- Every acceptance criterion has an ID per capability: `- AC-2 expired QR: GIVEN ... WHEN ... THEN ...` in `spec/specs/refund.md` is `refund/AC-2`.
|
|
102
|
+
- `/spec-apply` names tests with that ID: `describe("refund/AC-2: expired QR is refunded", ...)`.
|
|
103
|
+
- `node .claude/scripts/spec-check.mjs [spec/changes/<name>.md]` lists ACs with no test (zero tokens, works in multi-repo workspaces). `/spec-archive` runs it before merging.
|
|
104
|
+
- `BACKBONE.md` has a **Domain glossary** (Order, Payment, states...) so specs, code and tests use the same names.
|
|
105
|
+
|
|
99
106
|
### Example: a feature, end to end
|
|
100
107
|
|
|
101
108
|
```text
|
package/README.vi.md
CHANGED
|
@@ -96,6 +96,13 @@ spec/
|
|
|
96
96
|
└── data-export.md ← sự thật hiện tại, gộp vào khi archive
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
+
### Truy vết (spec ↔ test)
|
|
100
|
+
|
|
101
|
+
- Mỗi acceptance criterion có ID theo capability: dòng `- AC-2 QR hết hạn: GIVEN ... WHEN ... THEN ...` trong `spec/specs/refund.md` là `refund/AC-2`.
|
|
102
|
+
- `/spec-apply` đặt tên test chứa ID đó: `describe("refund/AC-2: QR hết hạn thì hoàn tiền", ...)`.
|
|
103
|
+
- `node .claude/scripts/spec-check.mjs [spec/changes/<tên>.md]` liệt kê AC chưa có test (không tốn token, chạy được cả workspace nhiều repo). `/spec-archive` tự chạy trước khi gộp.
|
|
104
|
+
- `BACKBONE.md` có **Domain glossary** (Order, Payment, các trạng thái...) để spec, code và test dùng cùng một tên.
|
|
105
|
+
|
|
99
106
|
### Ví dụ: một feature từ đầu tới cuối
|
|
100
107
|
|
|
101
108
|
```text
|
package/package.json
CHANGED
package/templates/BACKBONE.md
CHANGED
|
@@ -14,6 +14,12 @@ Last synced: <commit> (<date>)
|
|
|
14
14
|
|---|---|
|
|
15
15
|
| <path> | <what lives there> |
|
|
16
16
|
|
|
17
|
+
## Domain glossary
|
|
18
|
+
<!-- The nouns of the business, as the team says them. Code, specs and tests use these names. -->
|
|
19
|
+
| Term | Meaning | States / relations |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| <Order> | <one customer purchase> | <draft → paid → cancelled; has many OrderItem> |
|
|
22
|
+
|
|
17
23
|
## Docs index
|
|
18
24
|
| Doc | About | Status |
|
|
19
25
|
|---|---|---|
|
package/templates/spec/config.md
CHANGED
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
## Requirements
|
|
10
10
|
- `#### ADDED|MODIFIED|REMOVED Requirement: <name>` containing SHALL or MUST.
|
|
11
|
-
- Each has
|
|
11
|
+
- Each has ACs `- AC-<n> <name>: GIVEN / WHEN / THEN` with concrete values: at least one happy path and one failure.
|
|
12
|
+
- AC IDs are per capability, never reused; tests name them as `<capability>/AC-<n>` (checked by `node .claude/scripts/spec-check.mjs`).
|
|
12
13
|
|
|
13
14
|
## Tasks
|
|
14
15
|
- Each task fits in 2-4 hours, lists files/packages touched and its DoD.
|