tracerkit 1.4.7 → 1.6.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 +11 -19
- package/dist/bin.js +104 -20
- package/dist/index.js +2 -2
- package/dist/{uninstall-C6vhDv_T.js → uninstall-Dri3LFXP.js} +40 -35
- package/package.json +2 -3
- package/templates/.claude/skills/tk:check/SKILL.md +141 -0
- package/templates/.claude/skills/tk:plan/SKILL.md +8 -2
- package/templates/.claude/skills/tk:prd/SKILL.md +22 -0
- package/templates/.claude/skills/tk:status/SKILL.md +0 -64
- package/templates/.claude/skills/tk:verify/SKILL.md +0 -130
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
[](https://www.npmjs.com/package/tracerkit)
|
|
9
9
|
[](https://opensource.org/licenses/MIT)
|
|
10
10
|
|
|
11
|
-
Replace ad-hoc AI prompts with a repeatable
|
|
11
|
+
Replace ad-hoc AI prompts with a repeatable spec-driven workflow: from idea to verified, archived code.
|
|
12
12
|
|
|
13
13
|
Named after the tracer-bullet technique from _The Pragmatic Programmer_ — **Tracer** + **Kit**.
|
|
14
14
|
|
|
@@ -43,9 +43,11 @@ AI: ✓ Phase 1 — CSS variables + ThemeProvider
|
|
|
43
43
|
✓ Phase 2 — Toggle component + localStorage
|
|
44
44
|
✓ Written .tracerkit/plans/dark-mode-support.md
|
|
45
45
|
|
|
46
|
-
You:
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
You: # implement each phase...
|
|
47
|
+
|
|
48
|
+
You: /tk:check dark-mode-support
|
|
49
|
+
AI: ✓ All checks verified — status: done
|
|
50
|
+
Archived to .tracerkit/archives/dark-mode-support/
|
|
49
51
|
```
|
|
50
52
|
|
|
51
53
|
See [Examples](docs/examples.md) for full walkthroughs.
|
|
@@ -65,11 +67,7 @@ npx tracerkit uninstall . # remove project-scoped skills
|
|
|
65
67
|
|
|
66
68
|
## Skills
|
|
67
69
|
|
|
68
|
-
TracerKit ships
|
|
69
|
-
|
|
70
|
-
### Core skills
|
|
71
|
-
|
|
72
|
-
Three steps that take a feature from idea to verified archive.
|
|
70
|
+
TracerKit ships three skills that take a feature from idea to verified archive.
|
|
73
71
|
|
|
74
72
|
#### `/tk:prd <idea>`: Write a PRD
|
|
75
73
|
|
|
@@ -83,19 +81,13 @@ Reads a PRD and breaks it into phased **tracer-bullet vertical slices**. Each ph
|
|
|
83
81
|
|
|
84
82
|
**Output:** `.tracerkit/plans/<slug>.md`
|
|
85
83
|
|
|
86
|
-
#### `/tk:
|
|
87
|
-
|
|
88
|
-
Read-only review that checks the codebase against the plan's done-when conditions. Runs tests, validates user stories, and stamps a **✅ PASS** or **🚧 NEEDS_WORK** verdict. On ✅ PASS, archives the PRD and plan to `.tracerkit/archives/<slug>/` automatically.
|
|
89
|
-
|
|
90
|
-
**Output:** Verdict block in `.tracerkit/plans/<slug>.md`. On ✅ PASS: `.tracerkit/archives/<slug>/prd.md` + `.tracerkit/archives/<slug>/plan.md`
|
|
91
|
-
|
|
92
|
-
### Helper skills
|
|
84
|
+
#### `/tk:check [slug]`: Check and archive
|
|
93
85
|
|
|
94
|
-
|
|
86
|
+
Checks the codebase against the plan's done-when checkboxes. Runs tests, validates user stories, updates check progress, and transitions the PRD status. On `done`, archives the PRD and plan to `.tracerkit/archives/<slug>/` automatically.
|
|
95
87
|
|
|
96
|
-
|
|
88
|
+
Without arguments, shows a feature dashboard with status and progress before asking which feature to check.
|
|
97
89
|
|
|
98
|
-
|
|
90
|
+
**Output:** Verdict block in `.tracerkit/plans/<slug>.md`. On `done`: `.tracerkit/archives/<slug>/prd.md` + `.tracerkit/archives/<slug>/plan.md`
|
|
99
91
|
|
|
100
92
|
## Docs
|
|
101
93
|
|
package/dist/bin.js
CHANGED
|
@@ -1,17 +1,85 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { n as e,
|
|
3
|
-
import { readFileSync as
|
|
4
|
-
import { dirname as
|
|
5
|
-
import { fileURLToPath as
|
|
6
|
-
import { homedir as
|
|
2
|
+
import { n as e, o as t, r as n, t as r } from "./uninstall-Dri3LFXP.js";
|
|
3
|
+
import { existsSync as i, mkdirSync as a, readFileSync as o, rmSync as s, unlinkSync as c, writeFileSync as l } from "node:fs";
|
|
4
|
+
import { dirname as u, join as d, resolve as f } from "node:path";
|
|
5
|
+
import { fileURLToPath as p } from "node:url";
|
|
6
|
+
import { homedir as m } from "node:os";
|
|
7
|
+
//#region src/frontmatter.ts
|
|
8
|
+
var h = /^---\n([\s\S]*?)\n---(?:\n|$)/;
|
|
9
|
+
function g(e) {
|
|
10
|
+
return e.replace(/\r\n/g, "\n");
|
|
11
|
+
}
|
|
12
|
+
function _(e, t, n) {
|
|
13
|
+
let r = g(e), i = r.match(h);
|
|
14
|
+
if (!i) return `---\n${t}: ${n}\n---\n${r}`;
|
|
15
|
+
let a = i[1].split("\n"), o = RegExp(`^${t}\\s*:`), s = a.findIndex((e) => o.test(e));
|
|
16
|
+
s === -1 ? a.push(`${t}: ${n}`) : a[s] = `${t}: ${n}`;
|
|
17
|
+
let c = r.slice(i[0].length);
|
|
18
|
+
return `---\n${a.join("\n")}\n---\n${c}`;
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/commands/archive.ts
|
|
22
|
+
function v(e, n) {
|
|
23
|
+
let r = t(e), u = d(e, r.paths.prds, `${n}.md`), f = d(e, r.paths.plans, `${n}.md`), p = d(e, r.paths.archives, n), m = i(u);
|
|
24
|
+
if (!i(f)) throw Error(`Plan "${n}" not found at ${f}`);
|
|
25
|
+
if (i(p)) throw Error(`Archive "${n}" already exists at ${p}`);
|
|
26
|
+
a(p, { recursive: !0 });
|
|
27
|
+
try {
|
|
28
|
+
let e = (/* @__PURE__ */ new Date()).toISOString(), t = [];
|
|
29
|
+
if (m) {
|
|
30
|
+
let t = o(u, "utf8");
|
|
31
|
+
t = _(t, "status", "done"), t = _(t, "completed", e), l(d(p, "prd.md"), t);
|
|
32
|
+
} else t.push(`Warning: PRD "${n}" missing, archiving plan only`);
|
|
33
|
+
let i = o(f, "utf8");
|
|
34
|
+
return i += `\n## Archived\n\nArchived on ${e.slice(0, 10)}.\n`, l(d(p, "plan.md"), i), m && c(u), c(f), t.push(`Archived "${n}" to ${r.paths.archives}/${n}/`), m && t.push(` prd.md — status: done, completed: ${e}`), t.push(" plan.md — archived block appended"), t;
|
|
35
|
+
} catch (e) {
|
|
36
|
+
throw s(p, {
|
|
37
|
+
recursive: !0,
|
|
38
|
+
force: !0
|
|
39
|
+
}), e;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region src/plan.ts
|
|
44
|
+
var y = /^## (Phase \d+\s*.*)$/, b = /^- \[x\] /i, x = /^- \[ \] /;
|
|
45
|
+
function S(e) {
|
|
46
|
+
let t = e.replace(/\r\n/g, "\n").split("\n"), n = [], r = null;
|
|
47
|
+
for (let e of t) {
|
|
48
|
+
let t = e.trimStart(), i = t.match(y);
|
|
49
|
+
if (t.startsWith("## ")) {
|
|
50
|
+
i ? (r = {
|
|
51
|
+
title: i[1].trim(),
|
|
52
|
+
checked: 0,
|
|
53
|
+
total: 0
|
|
54
|
+
}, n.push(r)) : r = null;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
r && (b.test(t) ? (r.checked++, r.total++) : x.test(t) && r.total++);
|
|
58
|
+
}
|
|
59
|
+
return { phases: n };
|
|
60
|
+
}
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region src/commands/progress.ts
|
|
63
|
+
function C(e, n) {
|
|
64
|
+
let r = d(e, t(e).paths.plans, `${n}.md`);
|
|
65
|
+
if (!i(r)) throw Error(`Plan "${n}" not found at ${r}`);
|
|
66
|
+
let { phases: a } = S(o(r, "utf8"));
|
|
67
|
+
if (a.length === 0) return ["No phases found in plan.", "Total: 0/0"];
|
|
68
|
+
let s = [], c = 0, l = 0;
|
|
69
|
+
for (let e of a) c += e.checked, l += e.total, s.push(` ${e.title}: ${e.checked}/${e.total}`);
|
|
70
|
+
return s.push(""), s.push(`Total: ${c}/${l}`), s;
|
|
71
|
+
}
|
|
72
|
+
//#endregion
|
|
7
73
|
//#region src/cli.ts
|
|
8
|
-
var { version:
|
|
74
|
+
var { version: w } = JSON.parse(o(f(u(p(import.meta.url)), "..", "package.json"), "utf8")), T = [
|
|
9
75
|
"Usage: tracerkit <command> [path]",
|
|
10
76
|
"",
|
|
11
77
|
"Commands:",
|
|
12
78
|
" init [path] Install skills to ~/.claude/skills/ (or [path] if given)",
|
|
13
79
|
" update [path] Refresh unchanged files from latest version, skip modified",
|
|
14
80
|
" uninstall [path] Remove TracerKit skill directories, keep .tracerkit/ artifacts",
|
|
81
|
+
" progress <slug> Show per-phase checkbox progress for a plan",
|
|
82
|
+
" archive <slug> Archive a completed feature (PRD + plan)",
|
|
15
83
|
"",
|
|
16
84
|
"Options:",
|
|
17
85
|
" --force Overwrite modified files during update",
|
|
@@ -20,26 +88,42 @@ var { version: c } = JSON.parse(r(a(i(o(import.meta.url)), "..", "package.json")
|
|
|
20
88
|
"",
|
|
21
89
|
"All commands default to the home directory when no path is given."
|
|
22
90
|
];
|
|
23
|
-
function
|
|
24
|
-
let
|
|
25
|
-
return
|
|
26
|
-
}
|
|
27
|
-
function
|
|
28
|
-
|
|
29
|
-
if (
|
|
30
|
-
|
|
91
|
+
function E(e, t = m()) {
|
|
92
|
+
let n = e.find((e) => !e.startsWith("-"));
|
|
93
|
+
return n ? f(n) : t;
|
|
94
|
+
}
|
|
95
|
+
function D(e, t) {
|
|
96
|
+
let n = e.findIndex((e) => !e.startsWith("-"));
|
|
97
|
+
if (n === -1) return [
|
|
98
|
+
"Error: missing <slug> argument",
|
|
99
|
+
"",
|
|
100
|
+
...T
|
|
101
|
+
];
|
|
102
|
+
let r = e[n], i = e.filter((e, t) => t !== n);
|
|
103
|
+
try {
|
|
104
|
+
return t(E(i, process.cwd()), r);
|
|
105
|
+
} catch (e) {
|
|
106
|
+
return [`Error: ${e instanceof Error ? e.message : String(e)}`];
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function O(t) {
|
|
110
|
+
if (t.includes("--help") || t.includes("-h")) return T;
|
|
111
|
+
if (t.includes("--version") || t.includes("-v")) return [`tracerkit/${w}`];
|
|
112
|
+
let i = t[0], a = t.slice(1);
|
|
31
113
|
switch (i) {
|
|
32
|
-
case "init": return
|
|
114
|
+
case "init": return n(E(a));
|
|
33
115
|
case "update": {
|
|
34
|
-
let t = a.includes("--force"), n = e(
|
|
116
|
+
let t = a.includes("--force"), n = e(E(a.filter((e) => e !== "--force")), { force: t });
|
|
35
117
|
return n.push("", "Updated to the latest TracerKit."), n.push("If using Claude Code, restart your session to load changes."), n;
|
|
36
118
|
}
|
|
37
|
-
case "uninstall": return
|
|
38
|
-
|
|
119
|
+
case "uninstall": return r(E(a));
|
|
120
|
+
case "progress": return D(a, C);
|
|
121
|
+
case "archive": return D(a, v);
|
|
122
|
+
default: return T;
|
|
39
123
|
}
|
|
40
124
|
}
|
|
41
125
|
//#endregion
|
|
42
126
|
//#region src/bin.ts
|
|
43
|
-
var
|
|
44
|
-
for (let e of
|
|
127
|
+
var k = O(process.argv.slice(2));
|
|
128
|
+
for (let e of k) console.log(e);
|
|
45
129
|
//#endregion
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { e as SKILL_NAMES,
|
|
1
|
+
import { a as e, i as t, n, r, t as i } from "./uninstall-Dri3LFXP.js";
|
|
2
|
+
export { t as DEPRECATED_SKILLS, e as SKILL_NAMES, r as init, i as uninstall, n as update };
|
|
@@ -24,44 +24,41 @@ function d(t) {
|
|
|
24
24
|
archives: typeof o.archives == "string" ? o.archives : u.archives
|
|
25
25
|
} };
|
|
26
26
|
}
|
|
27
|
-
//#endregion
|
|
28
|
-
//#region src/templates.ts
|
|
29
27
|
var f = [
|
|
30
28
|
"tk:prd",
|
|
31
29
|
"tk:plan",
|
|
32
|
-
"tk:
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
function m(e, t = "") {
|
|
30
|
+
"tk:check"
|
|
31
|
+
], p = ["tk:verify"], m = s(o(l(import.meta.url)), "..", "templates");
|
|
32
|
+
function h(e, t = "") {
|
|
36
33
|
let n = r(e, { withFileTypes: !0 }), i = [];
|
|
37
34
|
for (let r of n) {
|
|
38
35
|
let n = t ? `${t}/${r.name}` : r.name;
|
|
39
|
-
r.isDirectory() ? i.push(...
|
|
36
|
+
r.isDirectory() ? i.push(...h(s(e, r.name), n)) : i.push(n);
|
|
40
37
|
}
|
|
41
38
|
return i.sort();
|
|
42
39
|
}
|
|
43
|
-
function
|
|
40
|
+
function g(e, t) {
|
|
44
41
|
return e.replaceAll("{{paths.prds}}", t.paths.prds).replaceAll("{{paths.plans}}", t.paths.plans).replaceAll("{{paths.archives}}", t.paths.archives);
|
|
45
42
|
}
|
|
46
|
-
function
|
|
47
|
-
let c = i ?? m
|
|
43
|
+
function _(e, r, i) {
|
|
44
|
+
let c = i ?? h(m);
|
|
48
45
|
for (let i of c) {
|
|
49
|
-
let c = s(
|
|
50
|
-
t(o(l), { recursive: !0 }), a(l,
|
|
46
|
+
let c = s(m, i), l = s(e, i);
|
|
47
|
+
t(o(l), { recursive: !0 }), a(l, g(n(c, "utf8"), r));
|
|
51
48
|
}
|
|
52
49
|
return { copied: c };
|
|
53
50
|
}
|
|
54
|
-
function
|
|
51
|
+
function v(e) {
|
|
55
52
|
return c("sha256").update(e).digest("hex");
|
|
56
53
|
}
|
|
57
|
-
function
|
|
58
|
-
let i = m
|
|
54
|
+
function y(t, r) {
|
|
55
|
+
let i = h(m), a = [], o = [], c = [];
|
|
59
56
|
for (let l of i) {
|
|
60
57
|
let i = s(t, l);
|
|
61
58
|
if (!e(i)) c.push(l);
|
|
62
59
|
else {
|
|
63
|
-
let e =
|
|
64
|
-
|
|
60
|
+
let e = g(n(s(m, l), "utf8"), r);
|
|
61
|
+
v(Buffer.from(e)) === v(n(i)) ? a.push(l) : o.push(l);
|
|
65
62
|
}
|
|
66
63
|
}
|
|
67
64
|
return {
|
|
@@ -72,35 +69,43 @@ function v(t, r) {
|
|
|
72
69
|
}
|
|
73
70
|
//#endregion
|
|
74
71
|
//#region src/commands/init.ts
|
|
75
|
-
function
|
|
72
|
+
function b(t) {
|
|
76
73
|
for (let n of f) if (e(s(t, ".claude", "skills", n))) throw Error(`.claude/skills/${n}/ already exists — aborting`);
|
|
77
|
-
let { copied: n } =
|
|
74
|
+
let { copied: n } = _(t, d(t));
|
|
78
75
|
return n.map((e) => `✓ ${e}`);
|
|
79
76
|
}
|
|
80
77
|
//#endregion
|
|
81
78
|
//#region src/commands/update.ts
|
|
82
|
-
function
|
|
79
|
+
function x(t, n) {
|
|
83
80
|
if (!f.some((n) => e(s(t, ".claude", "skills", n)))) throw Error("TracerKit not initialized — run `tracerkit init` first");
|
|
84
|
-
let r = d(t), { unchanged:
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
81
|
+
let r = d(t), { unchanged: a, modified: o, missing: c } = y(t, r), l = [];
|
|
82
|
+
for (let n of p) {
|
|
83
|
+
let r = s(t, ".claude", "skills", n);
|
|
84
|
+
e(r) && (i(r, {
|
|
85
|
+
recursive: !0,
|
|
86
|
+
force: !0
|
|
87
|
+
}), l.push(`✗ .claude/skills/${n}/ removed (deprecated)`));
|
|
88
|
+
}
|
|
89
|
+
let u = n?.force ?? !1, m = [
|
|
90
|
+
...a,
|
|
91
|
+
...c,
|
|
92
|
+
...u ? o : []
|
|
88
93
|
];
|
|
89
|
-
if (
|
|
90
|
-
|
|
91
|
-
for (let e of
|
|
92
|
-
for (let e of
|
|
93
|
-
if (
|
|
94
|
+
if (m.length > 0) {
|
|
95
|
+
_(t, r, m);
|
|
96
|
+
for (let e of a) l.push(`✓ ${e}`);
|
|
97
|
+
for (let e of c) l.push(`✓ ${e} (added)`);
|
|
98
|
+
if (u) for (let e of o) l.push(`✓ ${e} (replaced)`);
|
|
94
99
|
}
|
|
95
|
-
if (!
|
|
96
|
-
for (let e of
|
|
97
|
-
|
|
100
|
+
if (!u && o.length > 0) {
|
|
101
|
+
for (let e of o) l.push(`⚠ ${e} (skipped — modified)`);
|
|
102
|
+
l.push("", "Run `tracerkit update --force` to replace modified files with latest versions.");
|
|
98
103
|
}
|
|
99
|
-
return
|
|
104
|
+
return l;
|
|
100
105
|
}
|
|
101
106
|
//#endregion
|
|
102
107
|
//#region src/commands/uninstall.ts
|
|
103
|
-
function
|
|
108
|
+
function S(t) {
|
|
104
109
|
if (!f.some((n) => e(s(t, ".claude", "skills", n)))) throw Error("TracerKit not initialized — nothing to uninstall");
|
|
105
110
|
let n = [];
|
|
106
111
|
for (let r of f) {
|
|
@@ -113,4 +118,4 @@ function x(t) {
|
|
|
113
118
|
return n;
|
|
114
119
|
}
|
|
115
120
|
//#endregion
|
|
116
|
-
export { f as i,
|
|
121
|
+
export { f as a, p as i, x as n, d as o, b as r, S as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tracerkit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Spec-driven workflow for Claude Code: replace ad-hoc prompts with PRD → plan → verify.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -50,8 +50,7 @@
|
|
|
50
50
|
"format": "prettier --write .",
|
|
51
51
|
"format:check": "prettier --check .",
|
|
52
52
|
"typecheck": "tsc --noEmit",
|
|
53
|
-
"prepare": "husky",
|
|
54
|
-
"prepublishOnly": "npm run build",
|
|
53
|
+
"prepare": "husky || true && npm run build",
|
|
55
54
|
"release": "semantic-release"
|
|
56
55
|
},
|
|
57
56
|
"lint-staged": {
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Verify implementation against plan. Shows progress, finds blockers, and archives when done. Use after implementing a plan, or without arguments to see a feature dashboard.
|
|
3
|
+
argument-hint: '[slug]'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Check Implementation
|
|
7
|
+
|
|
8
|
+
Check implementation against a plan. Update checks, stamp findings, transition status, and archive when done.
|
|
9
|
+
|
|
10
|
+
## Pre-loaded context
|
|
11
|
+
|
|
12
|
+
- Available plans: !`ls {{paths.plans}}/ 2>/dev/null || echo "no {{paths.plans}}/ directory found"`
|
|
13
|
+
|
|
14
|
+
## Input
|
|
15
|
+
|
|
16
|
+
The argument (if provided) is: $ARGUMENTS
|
|
17
|
+
|
|
18
|
+
Use the argument as `<slug>` if given.
|
|
19
|
+
|
|
20
|
+
If no argument is provided, scan `{{paths.prds}}/` and `{{paths.plans}}/` and show a summary table before asking which one to check:
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
| Feature | Status | Progress |
|
|
24
|
+
|---------|--------|----------|
|
|
25
|
+
| <slug> | ... | 3/7 |
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
- **Feature**: slug (filename without `.md`)
|
|
29
|
+
- **Status**: from PRD frontmatter (`created`, `in_progress`, `done`) — `unknown` if no frontmatter
|
|
30
|
+
- **Progress**: run `npx tracerkit progress <slug>` for each feature with a plan — use the Total line (e.g. "3/7"). Show `—` if no plan.
|
|
31
|
+
|
|
32
|
+
After the table, ask which feature to verify.
|
|
33
|
+
|
|
34
|
+
## Workflow
|
|
35
|
+
|
|
36
|
+
### 1. Load the plan
|
|
37
|
+
|
|
38
|
+
Read `{{paths.plans}}/<slug>.md`. If it does not exist, list available plans and ask.
|
|
39
|
+
|
|
40
|
+
### 2. Load the PRD
|
|
41
|
+
|
|
42
|
+
Read the source PRD referenced in the plan header (`> Source PRD: ...`).
|
|
43
|
+
|
|
44
|
+
### 3. Launch read-only review
|
|
45
|
+
|
|
46
|
+
Use a **read-only subagent** (no file writes, no edits) to:
|
|
47
|
+
|
|
48
|
+
1. Read every section of the plan — architectural decisions, each phase, done-when checkboxes
|
|
49
|
+
2. For each phase, check every `- [ ]` / `- [x]` item against the codebase
|
|
50
|
+
3. Run any test commands referenced in the plan or discoverable via project conventions
|
|
51
|
+
4. Compare user stories from the PRD against actual behavior
|
|
52
|
+
|
|
53
|
+
For each checkbox, determine whether it should be verified (`[x]`) or not (`[ ]`) and report this — do not edit any files.
|
|
54
|
+
|
|
55
|
+
Collect findings into two categories:
|
|
56
|
+
|
|
57
|
+
- **BLOCKERS** — checked items that don't hold up, failing tests, broken contracts. These prevent transitioning to `done`.
|
|
58
|
+
- **SUGGESTIONS** — improvements, minor gaps, style issues. These do not prevent `done`.
|
|
59
|
+
|
|
60
|
+
### 3b. Update checkboxes
|
|
61
|
+
|
|
62
|
+
Using the subagent's report, update each checkbox in `{{paths.plans}}/<slug>.md` to `[x]` or `[ ]`.
|
|
63
|
+
|
|
64
|
+
### 4. Determine outcome
|
|
65
|
+
|
|
66
|
+
Based on checks and findings, decide the status transition:
|
|
67
|
+
|
|
68
|
+
- All checks verified + zero BLOCKERS → transition PRD to `done`
|
|
69
|
+
- Some checks verified + zero BLOCKERS → keep PRD as `in_progress`
|
|
70
|
+
- BLOCKERS found → keep PRD as `in_progress`
|
|
71
|
+
|
|
72
|
+
### 5. Report to user
|
|
73
|
+
|
|
74
|
+
Run `npx tracerkit progress <slug>` to get exact per-phase progress, then print the verdict report:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
## Verification: <slug>
|
|
78
|
+
|
|
79
|
+
### Status: created | in_progress | done
|
|
80
|
+
|
|
81
|
+
### Progress
|
|
82
|
+
<output from tracerkit progress>
|
|
83
|
+
|
|
84
|
+
### BLOCKERS
|
|
85
|
+
- (list or "None")
|
|
86
|
+
|
|
87
|
+
### SUGGESTIONS
|
|
88
|
+
- (list or "None")
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 6. Stamp the plan
|
|
92
|
+
|
|
93
|
+
Append a verdict block at the bottom of `{{paths.plans}}/<slug>.md`:
|
|
94
|
+
|
|
95
|
+
```markdown
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Verdict
|
|
99
|
+
|
|
100
|
+
- **Date**: YYYY-MM-DD
|
|
101
|
+
- **Checks**: (checked/total)
|
|
102
|
+
- **BLOCKERS**: (count)
|
|
103
|
+
- **SUGGESTIONS**: (count)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
If a previous verdict block exists, replace it with the new one.
|
|
107
|
+
|
|
108
|
+
### 7. On `done` — archive
|
|
109
|
+
|
|
110
|
+
If all checks pass and zero BLOCKERS, run:
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
npx tracerkit archive <slug>
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
This handles: PRD frontmatter update (`status: done`, `completed` timestamp), file moves to `{{paths.archives}}/<slug>/`, and archived block on the plan.
|
|
117
|
+
|
|
118
|
+
Tell the user: archived to `{{paths.archives}}/<slug>/`, one-line summary of the feature.
|
|
119
|
+
|
|
120
|
+
### 8. On `in_progress` (no blockers)
|
|
121
|
+
|
|
122
|
+
Show progress summary (checked/total per phase), list the next unchecked items to implement. Keep going.
|
|
123
|
+
|
|
124
|
+
### 9. On `in_progress` (with blockers)
|
|
125
|
+
|
|
126
|
+
List the blockers to fix, then re-run `/tk:check <slug>`.
|
|
127
|
+
|
|
128
|
+
## Rules
|
|
129
|
+
|
|
130
|
+
- The review subagent must be **read-only** — it must not create, edit, or delete any files
|
|
131
|
+
- The only file writes this skill makes are: checkboxes + verdict block in the plan, and the archive command on `done`
|
|
132
|
+
- Never modify the source PRD manually — `tracerkit archive` handles frontmatter updates
|
|
133
|
+
- Never modify implementation code — only observe and report
|
|
134
|
+
- If the PRD file is missing but all checks pass, warn and proceed — `tracerkit archive` supports plan-only archiving
|
|
135
|
+
|
|
136
|
+
## Error Handling
|
|
137
|
+
|
|
138
|
+
- Plan not found — list available plans and ask
|
|
139
|
+
- PRD referenced in plan not found — warn and continue with plan checks only
|
|
140
|
+
- `{{paths.plans}}/` missing — tell user to run `/tk:plan` first
|
|
141
|
+
- `{{paths.archives}}/<slug>/` already exists — `tracerkit archive` will error; warn and ask whether to remove it first
|
|
@@ -35,6 +35,8 @@ If the PRD has no frontmatter, skip this step silently.
|
|
|
35
35
|
|
|
36
36
|
Understand current architecture, existing patterns, and integration points.
|
|
37
37
|
|
|
38
|
+
**Research protocol**: codebase first, then project docs. If you cannot verify a technical claim from these sources, flag it as uncertain — never fabricate.
|
|
39
|
+
|
|
38
40
|
### 3. Identify durable architectural decisions
|
|
39
41
|
|
|
40
42
|
Before slicing, extract decisions that hold across all phases:
|
|
@@ -65,6 +67,8 @@ Each phase is a thin **tracer bullet** — a narrow but complete path through ev
|
|
|
65
67
|
|
|
66
68
|
**Phase naming:** use a goal phrase answering "what can we demo when this is done?" (e.g., "Phase 1 — Revenue visible end-to-end"), not a layer name.
|
|
67
69
|
|
|
70
|
+
**Done when:** write as a checkbox list of atomic, testable conditions — not prose. Each item should be independently verifiable. The agent marks `[x]` during implementation to track progress.
|
|
71
|
+
|
|
68
72
|
**When to use layer-by-layer instead:** If the PRD has complex schema changes that all modules depend on and no single user story can stand alone without the full schema, build the data foundation first, then slice the rest vertically.
|
|
69
73
|
|
|
70
74
|
**Phase count:** 2–3 for single-module, 3–5 for multi-module, 5+ means consider splitting the PRD.
|
|
@@ -112,7 +116,8 @@ Concise description of this vertical slice — end-to-end behavior, not layer-by
|
|
|
112
116
|
|
|
113
117
|
### Done when
|
|
114
118
|
|
|
115
|
-
|
|
119
|
+
- [ ] Atomic, testable condition
|
|
120
|
+
- [ ] Another testable condition
|
|
116
121
|
|
|
117
122
|
---
|
|
118
123
|
|
|
@@ -133,7 +138,8 @@ Print saved path and one line per phase: `Phase N — <title> (<condition summar
|
|
|
133
138
|
|
|
134
139
|
- Phases derive from PRD user stories — never invented
|
|
135
140
|
- Each phase must be demoable end-to-end on its own
|
|
136
|
-
- "Done when" must be testable, not
|
|
141
|
+
- "Done when" must be a checkbox list of testable conditions, not prose
|
|
142
|
+
- **Safety valve**: if a phase has >5 "Done when" items, stop and split it into smaller phases before continuing
|
|
137
143
|
- Never modify the source PRD
|
|
138
144
|
- Carry PRD's Out of Scope forward verbatim
|
|
139
145
|
|
|
@@ -27,6 +27,8 @@ Ask the user for a detailed description of the problem and any solution ideas.
|
|
|
27
27
|
|
|
28
28
|
Verify assertions and map current state: data models, services, API routes, frontend structure, and test patterns. Note what exists vs. what must be built.
|
|
29
29
|
|
|
30
|
+
**Research protocol**: codebase first, then project docs. If you cannot verify a technical claim from these sources, flag it as uncertain — never fabricate.
|
|
31
|
+
|
|
30
32
|
### 3. Interview
|
|
31
33
|
|
|
32
34
|
Interview relentlessly, one question at a time. Lead with your recommended answer; let the user confirm or correct. If a question can be answered by exploring code, explore instead of asking. For terse answers, offer concrete options (A/B/C).
|
|
@@ -41,6 +43,18 @@ Walk these branches (skip any already resolved):
|
|
|
41
43
|
- **Boundaries** — What is explicitly out of scope? Adjacent features to defer?
|
|
42
44
|
- **Integration** — Schema changes? New or extended services? External dependencies?
|
|
43
45
|
|
|
46
|
+
### 3b. Gray area checkpoint
|
|
47
|
+
|
|
48
|
+
Before continuing, list any unresolved ambiguities from the interview — vague answers, contradictions, assumptions you made without confirmation. Present them as a numbered list:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
Gray areas found:
|
|
52
|
+
1. <ambiguity> — assumed <X>, confirm?
|
|
53
|
+
2. <ambiguity> — two options: A or B
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
If the list is empty, say so and move on. Otherwise, resolve each item with the user before proceeding.
|
|
57
|
+
|
|
44
58
|
### 4. Design modules
|
|
45
59
|
|
|
46
60
|
Sketch major modules to build or modify. Favor **deep modules** — a simple interface (1–3 entry points) hiding a large implementation that rarely changes, over shallow modules where the interface is nearly as complex as the implementation.
|
|
@@ -65,6 +79,14 @@ status: created
|
|
|
65
79
|
|
|
66
80
|
The problem from the user's perspective. Focus on pain and impact.
|
|
67
81
|
|
|
82
|
+
## Current State
|
|
83
|
+
|
|
84
|
+
What exists today that this feature changes or builds on. Skip for greenfield.
|
|
85
|
+
|
|
86
|
+
- Relevant modules, services, or UI surfaces already in place
|
|
87
|
+
- Current behavior the user experiences
|
|
88
|
+
- Known limitations or workarounds
|
|
89
|
+
|
|
68
90
|
## Solution
|
|
69
91
|
|
|
70
92
|
The solution from the user's perspective. Describe the experience, not the architecture.
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Show a dashboard of all features and their workflow status. Use any time to check progress.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Workflow Dashboard
|
|
6
|
-
|
|
7
|
-
Scan all PRDs and display a status overview of every feature in the workflow.
|
|
8
|
-
|
|
9
|
-
## Workflow
|
|
10
|
-
|
|
11
|
-
### 1. Scan PRDs
|
|
12
|
-
|
|
13
|
-
List all `.md` files in `{{paths.prds}}/`. If the directory is missing or empty, print "No features found — run `/tk:prd` to start one." and stop.
|
|
14
|
-
|
|
15
|
-
### 2. Parse each PRD
|
|
16
|
-
|
|
17
|
-
For each file `{{paths.prds}}/<slug>.md`:
|
|
18
|
-
|
|
19
|
-
1. Read YAML frontmatter (between opening and closing `---` delimiters)
|
|
20
|
-
2. Extract fields: `created`, `status`, `completed`
|
|
21
|
-
3. If no frontmatter exists, treat as `status: unknown` with no age
|
|
22
|
-
|
|
23
|
-
### 3. Read verdict data
|
|
24
|
-
|
|
25
|
-
For each slug, check if `{{paths.plans}}/<slug>.md` exists. If it does, find the last `## Verdict` block and extract:
|
|
26
|
-
|
|
27
|
-
- **Result**: ✅ PASS or 🚧 NEEDS_WORK
|
|
28
|
-
- **BLOCKERS**: count
|
|
29
|
-
- **SUGGESTIONS**: count
|
|
30
|
-
|
|
31
|
-
If no plan or no verdict block exists, leave verdict columns blank.
|
|
32
|
-
|
|
33
|
-
### 4. Print the table
|
|
34
|
-
|
|
35
|
-
Group features by status in this order: `in_progress`, `created`, `done`, `unknown`.
|
|
36
|
-
|
|
37
|
-
Within each group, sort by `created` date (oldest first). Features without a `created` date sort last.
|
|
38
|
-
|
|
39
|
-
Print a markdown table:
|
|
40
|
-
|
|
41
|
-
```
|
|
42
|
-
## Workflow Dashboard
|
|
43
|
-
|
|
44
|
-
| Feature | Status | Age | Verdict | Blockers | Suggestions |
|
|
45
|
-
|---------|--------|-----|---------|----------|-------------|
|
|
46
|
-
| <slug> | ... | ... | ... | ... | ... |
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
Column definitions:
|
|
50
|
-
|
|
51
|
-
- **Feature**: the slug (filename without `.md`)
|
|
52
|
-
- **Status**: `created`, `in_progress`, `done`, or `unknown`
|
|
53
|
-
- **Age**: human-readable duration since `created` (e.g. "3d", "2w", "1mo") — blank if no `created`
|
|
54
|
-
- **Verdict**: latest verdict result or blank
|
|
55
|
-
- **Blockers**: blocker count from latest verdict or blank
|
|
56
|
-
- **Suggestions**: suggestion count from latest verdict or blank
|
|
57
|
-
|
|
58
|
-
After the table, print a one-line summary: `N features: X in progress, Y created, Z done`.
|
|
59
|
-
|
|
60
|
-
## Rules
|
|
61
|
-
|
|
62
|
-
- Read-only — this skill must not create, edit, or delete any files
|
|
63
|
-
- Graceful degradation for missing frontmatter, missing plans, or missing verdicts
|
|
64
|
-
- No arguments accepted — always scans all PRDs
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Compare implementation against plan, emit BLOCKERS/SUGGESTIONS and a ✅ PASS or 🚧 NEEDS_WORK verdict. Auto-archives on ✅ PASS. Use after implementing a plan.
|
|
3
|
-
argument-hint: '[slug]'
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Verify Implementation
|
|
7
|
-
|
|
8
|
-
Compare current implementation against a plan, stamp a verdict, and archive on ✅ PASS.
|
|
9
|
-
|
|
10
|
-
## Pre-loaded context
|
|
11
|
-
|
|
12
|
-
- Available plans: !`ls {{paths.plans}}/ 2>/dev/null || echo "no {{paths.plans}}/ directory found"`
|
|
13
|
-
|
|
14
|
-
## Input
|
|
15
|
-
|
|
16
|
-
The argument (if provided) is: $ARGUMENTS
|
|
17
|
-
|
|
18
|
-
Use the argument as `<slug>` if given. If no argument is provided, list available plans and ask which one to verify.
|
|
19
|
-
|
|
20
|
-
## Workflow
|
|
21
|
-
|
|
22
|
-
### 1. Load the plan
|
|
23
|
-
|
|
24
|
-
Read `{{paths.plans}}/<slug>.md`. If it does not exist, list available plans and ask.
|
|
25
|
-
|
|
26
|
-
### 2. Load the PRD
|
|
27
|
-
|
|
28
|
-
Read the source PRD referenced in the plan header (`> Source PRD: ...`).
|
|
29
|
-
|
|
30
|
-
### 3. Launch read-only review
|
|
31
|
-
|
|
32
|
-
Use a **read-only subagent** (no file writes, no edits) to:
|
|
33
|
-
|
|
34
|
-
1. Read every section of the plan — architectural decisions, each phase, done-when conditions
|
|
35
|
-
2. For each phase, explore the codebase to verify the done-when condition is satisfied
|
|
36
|
-
3. Run any test commands referenced in the plan or discoverable via project conventions
|
|
37
|
-
4. Compare user stories from the PRD against actual behavior
|
|
38
|
-
|
|
39
|
-
Collect findings into two categories:
|
|
40
|
-
|
|
41
|
-
- **BLOCKERS** — done-when conditions not met, missing functionality, failing tests, broken contracts. These prevent a ✅ PASS.
|
|
42
|
-
- **SUGGESTIONS** — improvements, minor gaps, style issues. These do not prevent a ✅ PASS.
|
|
43
|
-
|
|
44
|
-
### 4. Determine verdict
|
|
45
|
-
|
|
46
|
-
- **✅ PASS** — zero BLOCKERS
|
|
47
|
-
- **🚧 NEEDS_WORK** — one or more BLOCKERS
|
|
48
|
-
|
|
49
|
-
### 5. Report to user
|
|
50
|
-
|
|
51
|
-
Print the verdict report:
|
|
52
|
-
|
|
53
|
-
```
|
|
54
|
-
## Verification: <slug>
|
|
55
|
-
|
|
56
|
-
### Verdict: ✅ PASS | 🚧 NEEDS_WORK
|
|
57
|
-
|
|
58
|
-
### BLOCKERS
|
|
59
|
-
- (list or "None")
|
|
60
|
-
|
|
61
|
-
### SUGGESTIONS
|
|
62
|
-
- (list or "None")
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
### 6. Stamp the plan
|
|
66
|
-
|
|
67
|
-
Append a verdict block at the bottom of `{{paths.plans}}/<slug>.md`:
|
|
68
|
-
|
|
69
|
-
```markdown
|
|
70
|
-
---
|
|
71
|
-
|
|
72
|
-
## Verdict
|
|
73
|
-
|
|
74
|
-
- **Result**: ✅ PASS | 🚧 NEEDS_WORK
|
|
75
|
-
- **Date**: YYYY-MM-DD
|
|
76
|
-
- **BLOCKERS**: (count)
|
|
77
|
-
- **SUGGESTIONS**: (count)
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
If a previous verdict block exists, replace it with the new one.
|
|
81
|
-
|
|
82
|
-
### 7. On ✅ PASS — update PRD status and archive
|
|
83
|
-
|
|
84
|
-
If the verdict is **✅ PASS**:
|
|
85
|
-
|
|
86
|
-
**First**, update the YAML frontmatter in `{{paths.prds}}/<slug>.md`:
|
|
87
|
-
|
|
88
|
-
- Set `status: done`
|
|
89
|
-
- Add `completed: <current UTC timestamp, ISO 8601, e.g. 2025-06-15T14:30:00Z>`
|
|
90
|
-
- Do not touch any other frontmatter fields or the markdown content below the closing `---`
|
|
91
|
-
- If the PRD has no frontmatter, skip frontmatter update silently
|
|
92
|
-
|
|
93
|
-
**Then**, automatically archive:
|
|
94
|
-
|
|
95
|
-
1. Create `{{paths.archives}}/<slug>/` directory (and `{{paths.archives}}/` if missing)
|
|
96
|
-
2. Move `{{paths.prds}}/<slug>.md` → `{{paths.archives}}/<slug>/prd.md`
|
|
97
|
-
3. Move `{{paths.plans}}/<slug>.md` → `{{paths.archives}}/<slug>/plan.md`
|
|
98
|
-
4. Append closing timestamp to `{{paths.archives}}/<slug>/plan.md`:
|
|
99
|
-
|
|
100
|
-
```markdown
|
|
101
|
-
---
|
|
102
|
-
|
|
103
|
-
## Archived
|
|
104
|
-
|
|
105
|
-
- **Status**: closed
|
|
106
|
-
- **Closed**: YYYY-MM-DD HH:MM (UTC)
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
5. Tell the user: archived to `{{paths.archives}}/<slug>/`, one-line summary of the feature.
|
|
110
|
-
|
|
111
|
-
If `{{paths.archives}}/<slug>/` already exists, warn and ask whether to overwrite.
|
|
112
|
-
|
|
113
|
-
### 8. On 🚧 NEEDS_WORK
|
|
114
|
-
|
|
115
|
-
Tell the user: fix the listed blockers, then re-run `/tk:verify <slug>`.
|
|
116
|
-
|
|
117
|
-
## Rules
|
|
118
|
-
|
|
119
|
-
- The review subagent must be **read-only** — it must not create, edit, or delete any files
|
|
120
|
-
- The only file writes this skill makes are: the verdict block in the plan, and the archive move on ✅ PASS
|
|
121
|
-
- Never modify the source PRD (except moving it to archive)
|
|
122
|
-
- Never modify implementation code — only observe and report
|
|
123
|
-
- If the PRD file is missing but the plan has a ✅ PASS verdict, warn but proceed with archiving the plan only
|
|
124
|
-
|
|
125
|
-
## Error Handling
|
|
126
|
-
|
|
127
|
-
- Plan not found — list available plans and ask
|
|
128
|
-
- PRD referenced in plan not found — warn and continue with plan only
|
|
129
|
-
- `{{paths.plans}}/` missing — tell user to run `/tk:plan` first
|
|
130
|
-
- `{{paths.archives}}/<slug>/` already exists — warn and ask whether to overwrite
|