tracerkit 1.12.0 → 1.13.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 +4 -4
- package/dist/bin.js +6 -9
- package/dist/index.js +1 -1
- package/dist/{uninstall-BkaWoWd0.js → uninstall-9tiXr-15.js} +57 -61
- package/package.json +1 -1
- package/skills/brief/SKILL.md +17 -39
- package/skills/check/SKILL.md +18 -51
- package/skills/plan/SKILL.md +17 -54
- package/skills/prd/SKILL.md +40 -138
package/README.md
CHANGED
|
@@ -94,14 +94,14 @@ See [Examples](docs/examples.md) for full walkthroughs.
|
|
|
94
94
|
<details>
|
|
95
95
|
<summary>GitHub Issues as storage backend</summary>
|
|
96
96
|
|
|
97
|
-
Same skills, same workflow.
|
|
97
|
+
Same skills, same workflow. Storage is configured per-project:
|
|
98
98
|
|
|
99
99
|
```bash
|
|
100
|
-
tracerkit
|
|
100
|
+
tracerkit config storage github # set current project to use GitHub
|
|
101
101
|
tracerkit config github.repo org/repo # set target repo
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
-
PRDs and plans become GitHub Issues with `tk:prd` and `tk:plan` labels. On `/tk:check` pass, issues are closed instead of archived locally. See [Configuration](docs/configuration.md) for details.
|
|
104
|
+
PRDs and plans become GitHub Issues with `tk:prd` and `tk:plan` labels. On `/tk:check` pass, issues are closed instead of archived locally. Each project can use a different backend; local is the default. See [Configuration](docs/configuration.md) for details.
|
|
105
105
|
|
|
106
106
|
</details>
|
|
107
107
|
|
|
@@ -140,7 +140,7 @@ Without arguments, shows a feature dashboard with status and progress before ask
|
|
|
140
140
|
| Document | Description |
|
|
141
141
|
| ------------------------------------------------ | -------------------------------------------------- |
|
|
142
142
|
| [Examples](docs/examples.md) | Walk through end-to-end usage scenarios |
|
|
143
|
-
| [CLI Reference](docs/cli-reference.md) |
|
|
143
|
+
| [CLI Reference](docs/cli-reference.md) | Commands: init, update, config, uninstall |
|
|
144
144
|
| [Configuration](docs/configuration.md) | Storage backends, GitHub options, custom paths |
|
|
145
145
|
| [Metadata Lifecycle](docs/metadata-lifecycle.md) | Understand YAML frontmatter states and transitions |
|
|
146
146
|
| [Comparison](docs/comparison.md) | Compare TracerKit to Spec Kit, Kiro, and OpenSpec |
|
package/dist/bin.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as e, c as t, d as n, f as r, i, l as a, n as o, o as s, r as c, t as l } from "./uninstall-
|
|
2
|
+
import { a as e, c as t, d as n, f as r, i, l as a, n as o, o as s, r as c, t as l } from "./uninstall-9tiXr-15.js";
|
|
3
3
|
import { existsSync as u, readFileSync as d, statSync as f } from "node:fs";
|
|
4
4
|
import { dirname as p, join as m, resolve as h } from "node:path";
|
|
5
5
|
import { fileURLToPath as g } from "node:url";
|
|
@@ -54,11 +54,11 @@ var { version: T } = JSON.parse(d(h(p(g(import.meta.url)), "..", "package.json")
|
|
|
54
54
|
"",
|
|
55
55
|
"Options:",
|
|
56
56
|
" --force Overwrite modified files during update",
|
|
57
|
-
" --storage <type> Set storage (local, github) during init",
|
|
58
57
|
" --help, -h Show this help message",
|
|
59
58
|
" --version, -v Print version",
|
|
60
59
|
"",
|
|
61
|
-
"
|
|
60
|
+
"init/update/uninstall default to the home directory when no path is given.",
|
|
61
|
+
"config defaults to the current working directory."
|
|
62
62
|
];
|
|
63
63
|
function O(e) {
|
|
64
64
|
if (!e) return !1;
|
|
@@ -78,17 +78,14 @@ function A(e) {
|
|
|
78
78
|
let n = e[0], r = e.slice(1);
|
|
79
79
|
if (s.includes(n)) return [`"${n}" has been removed — skills handle this now.`, "Run `tracerkit update` to get the latest skills."];
|
|
80
80
|
switch (n) {
|
|
81
|
-
case "init":
|
|
82
|
-
let e = r.indexOf(t.storage), n = e >= 0 ? r[e + 1] : void 0;
|
|
83
|
-
return o(k(e >= 0 ? r.filter((t, n) => n !== e && n !== e + 1) : r), { storage: n });
|
|
84
|
-
}
|
|
81
|
+
case "init": return o(k(r));
|
|
85
82
|
case "update": {
|
|
86
83
|
let e = r.includes(t.force), n = c(k(r.filter((e) => e !== t.force)), { force: e });
|
|
87
84
|
return n.push("", "Updated to the latest TracerKit."), n.push("If using Claude Code, restart your session to load changes."), n;
|
|
88
85
|
}
|
|
89
86
|
case "config": {
|
|
90
|
-
let e = O(r[0])
|
|
91
|
-
return v(e
|
|
87
|
+
let e = O(r[0]);
|
|
88
|
+
return v(e ? h(r[0]) : process.cwd(), e ? r.slice(1) : r);
|
|
92
89
|
}
|
|
93
90
|
case "uninstall": return l(k(r));
|
|
94
91
|
default: return D;
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as e, l as t, n, r, s as i, t as a } from "./uninstall-
|
|
1
|
+
import { a as e, l as t, n, r, s as i, t as a } from "./uninstall-9tiXr-15.js";
|
|
2
2
|
export { e as COMMANDS, i as DEPRECATED_SKILLS, t as SKILL_NAMES, n as init, a as uninstall, r as update };
|
|
@@ -3,20 +3,20 @@ import { dirname as o, join as s } from "node:path";
|
|
|
3
3
|
import { createHash as c } from "node:crypto";
|
|
4
4
|
import { fileURLToPath as l } from "node:url";
|
|
5
5
|
//#region src/config.ts
|
|
6
|
-
var u = "local", d =
|
|
6
|
+
var u = "local", d = [u, "github"], f = {
|
|
7
7
|
prds: ".tracerkit/prds",
|
|
8
8
|
plans: ".tracerkit/plans",
|
|
9
9
|
archives: ".tracerkit/archives"
|
|
10
|
-
},
|
|
10
|
+
}, p = { labels: {
|
|
11
11
|
prd: "tk:prd",
|
|
12
12
|
plan: "tk:plan"
|
|
13
13
|
} };
|
|
14
|
-
function
|
|
14
|
+
function m(t) {
|
|
15
15
|
let r = s(t, ".tracerkit", "config.json");
|
|
16
16
|
if (!e(r)) return {
|
|
17
17
|
storage: u,
|
|
18
|
-
paths: { ...
|
|
19
|
-
github: { ...
|
|
18
|
+
paths: { ...f },
|
|
19
|
+
github: { ...p }
|
|
20
20
|
};
|
|
21
21
|
let i;
|
|
22
22
|
try {
|
|
@@ -25,33 +25,33 @@ function h(t) {
|
|
|
25
25
|
throw Error("Invalid .tracerkit/config.json — expected valid JSON");
|
|
26
26
|
}
|
|
27
27
|
return {
|
|
28
|
-
storage:
|
|
29
|
-
paths:
|
|
30
|
-
github:
|
|
28
|
+
storage: h(i.storage),
|
|
29
|
+
paths: g(i.paths),
|
|
30
|
+
github: _(i.github)
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
|
-
function
|
|
34
|
-
return typeof e == "string" &&
|
|
33
|
+
function h(e) {
|
|
34
|
+
return typeof e == "string" && d.includes(e) ? e : u;
|
|
35
35
|
}
|
|
36
|
-
function
|
|
37
|
-
let t =
|
|
36
|
+
function g(e) {
|
|
37
|
+
let t = b(e) ? e : {};
|
|
38
38
|
return {
|
|
39
|
-
prds: typeof t.prds == "string" ? t.prds :
|
|
40
|
-
plans: typeof t.plans == "string" ? t.plans :
|
|
41
|
-
archives: typeof t.archives == "string" ? t.archives :
|
|
39
|
+
prds: typeof t.prds == "string" ? t.prds : f.prds,
|
|
40
|
+
plans: typeof t.plans == "string" ? t.plans : f.plans,
|
|
41
|
+
archives: typeof t.archives == "string" ? t.archives : f.archives
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
|
-
function
|
|
45
|
-
let t =
|
|
44
|
+
function _(e) {
|
|
45
|
+
let t = b(e) ? e : {}, n = b(t.labels) ? t.labels : {};
|
|
46
46
|
return {
|
|
47
47
|
...typeof t.repo == "string" ? { repo: t.repo } : {},
|
|
48
48
|
labels: {
|
|
49
|
-
prd: typeof n.prd == "string" ? n.prd :
|
|
50
|
-
plan: typeof n.plan == "string" ? n.plan :
|
|
49
|
+
prd: typeof n.prd == "string" ? n.prd : p.labels.prd,
|
|
50
|
+
plan: typeof n.plan == "string" ? n.plan : p.labels.plan
|
|
51
51
|
}
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
|
-
function
|
|
54
|
+
function v(r, i) {
|
|
55
55
|
let c = s(r, ".tracerkit", "config.json");
|
|
56
56
|
t(o(c), { recursive: !0 });
|
|
57
57
|
let l = {};
|
|
@@ -60,32 +60,31 @@ function y(r, i) {
|
|
|
60
60
|
} catch {
|
|
61
61
|
l = {};
|
|
62
62
|
}
|
|
63
|
-
let u =
|
|
63
|
+
let u = y(l, i);
|
|
64
64
|
a(c, JSON.stringify(u, null, 2) + "\n");
|
|
65
65
|
}
|
|
66
|
-
function
|
|
66
|
+
function y(e, t) {
|
|
67
67
|
let n = { ...e };
|
|
68
|
-
for (let e of Object.keys(t))
|
|
68
|
+
for (let e of Object.keys(t)) b(n[e]) && b(t[e]) ? n[e] = y(n[e], t[e]) : n[e] = t[e];
|
|
69
69
|
return n;
|
|
70
70
|
}
|
|
71
|
-
function
|
|
71
|
+
function b(e) {
|
|
72
72
|
return typeof e == "object" && !!e && !Array.isArray(e);
|
|
73
73
|
}
|
|
74
|
-
var
|
|
74
|
+
var x = [
|
|
75
75
|
"tk:brief",
|
|
76
76
|
"tk:prd",
|
|
77
77
|
"tk:plan",
|
|
78
78
|
"tk:check"
|
|
79
|
-
],
|
|
79
|
+
], S = ["tk:verify"], C = {
|
|
80
80
|
force: "--force",
|
|
81
81
|
help: "--help",
|
|
82
|
-
storage: "--storage",
|
|
83
82
|
version: "--version"
|
|
84
|
-
},
|
|
83
|
+
}, w = [
|
|
85
84
|
"brief",
|
|
86
85
|
"progress",
|
|
87
86
|
"archive"
|
|
88
|
-
],
|
|
87
|
+
], T = [
|
|
89
88
|
{
|
|
90
89
|
name: "init",
|
|
91
90
|
args: "[path]",
|
|
@@ -106,46 +105,44 @@ var S = [
|
|
|
106
105
|
args: "[path]",
|
|
107
106
|
desc: "Remove TracerKit skill directories, keep .tracerkit/ artifacts"
|
|
108
107
|
}
|
|
109
|
-
],
|
|
110
|
-
function
|
|
108
|
+
], E = s(o(l(import.meta.url)), "..", "skills");
|
|
109
|
+
function D(e, t = "") {
|
|
111
110
|
let n = r(e, { withFileTypes: !0 }), i = [];
|
|
112
111
|
for (let r of n) {
|
|
113
112
|
let n = t ? `${t}/${r.name}` : r.name;
|
|
114
|
-
r.isDirectory() ? i.push(...
|
|
113
|
+
r.isDirectory() ? i.push(...D(s(e, r.name), n)) : i.push(n);
|
|
115
114
|
}
|
|
116
115
|
return i.sort();
|
|
117
116
|
}
|
|
118
|
-
function
|
|
117
|
+
function O(e) {
|
|
119
118
|
return `.claude/skills/tk:${e}`;
|
|
120
119
|
}
|
|
121
|
-
function
|
|
120
|
+
function k(e) {
|
|
122
121
|
return e.slice(18);
|
|
123
122
|
}
|
|
124
|
-
function
|
|
123
|
+
function A(e, t) {
|
|
125
124
|
let n = e;
|
|
126
|
-
t.paths.prds !==
|
|
127
|
-
let r = t.storage ?? "local", i = r === "local" ? d : u;
|
|
128
|
-
return n = n.replace(RegExp(`<!-- if:${i} -->[^\\S\\n]*\\n[\\s\\S]*?<!-- end:${i} -->[^\\S\\n]*\\n?`, "g"), ""), n = n.replace(RegExp(`<!-- if:${r} -->[^\\S\\n]*\\n`, "g"), ""), n = n.replace(RegExp(`<!-- end:${r} -->[^\\S\\n]*\\n?`, "g"), ""), t.github?.repo && (n = n.replaceAll("{{github.repo}}", t.github.repo)), t.github?.labels?.prd && (n = n.replaceAll("{{github.labels.prd}}", t.github.labels.prd)), t.github?.labels?.plan && (n = n.replaceAll("{{github.labels.plan}}", t.github.labels.plan)), n;
|
|
125
|
+
return t.paths.prds !== f.prds && (n = n.replaceAll(f.prds, t.paths.prds)), t.paths.plans !== f.plans && (n = n.replaceAll(f.plans, t.paths.plans)), t.paths.archives !== f.archives && (n = n.replaceAll(f.archives, t.paths.archives)), t.github?.repo && (n = n.replaceAll("{{github.repo}}", t.github.repo)), t.github?.labels?.prd && (n = n.replaceAll("{{github.labels.prd}}", t.github.labels.prd)), t.github?.labels?.plan && (n = n.replaceAll("{{github.labels.plan}}", t.github.labels.plan)), n;
|
|
129
126
|
}
|
|
130
|
-
function
|
|
131
|
-
let c = i ??
|
|
127
|
+
function j(e, r, i) {
|
|
128
|
+
let c = i ?? D(E).map(O);
|
|
132
129
|
for (let i of c) {
|
|
133
|
-
let c = s(
|
|
134
|
-
t(o(l), { recursive: !0 }), a(l,
|
|
130
|
+
let c = s(E, k(i)), l = s(e, i);
|
|
131
|
+
t(o(l), { recursive: !0 }), a(l, A(n(c, "utf8"), r));
|
|
135
132
|
}
|
|
136
133
|
return { copied: c };
|
|
137
134
|
}
|
|
138
|
-
function
|
|
135
|
+
function M(e) {
|
|
139
136
|
return c("sha256").update(e).digest("hex");
|
|
140
137
|
}
|
|
141
|
-
function
|
|
142
|
-
let i =
|
|
138
|
+
function N(t, r) {
|
|
139
|
+
let i = D(E).map(O), a = [], o = [], c = [];
|
|
143
140
|
for (let l of i) {
|
|
144
141
|
let i = s(t, l);
|
|
145
142
|
if (!e(i)) c.push(l);
|
|
146
143
|
else {
|
|
147
|
-
let e =
|
|
148
|
-
|
|
144
|
+
let e = A(n(s(E, k(l)), "utf8"), r);
|
|
145
|
+
M(Buffer.from(e)) === M(n(i)) ? a.push(l) : o.push(l);
|
|
149
146
|
}
|
|
150
147
|
}
|
|
151
148
|
return {
|
|
@@ -156,10 +153,10 @@ function P(t, r) {
|
|
|
156
153
|
}
|
|
157
154
|
//#endregion
|
|
158
155
|
//#region src/commands/update.ts
|
|
159
|
-
function
|
|
160
|
-
if (!
|
|
161
|
-
let r =
|
|
162
|
-
for (let n of
|
|
156
|
+
function P(t, n) {
|
|
157
|
+
if (!x.some((n) => e(s(t, ".claude", "skills", n)))) throw Error("TracerKit not initialized — run `tracerkit init` first");
|
|
158
|
+
let r = m(t), { unchanged: a, modified: o, missing: c } = N(t, r), l = [];
|
|
159
|
+
for (let n of S) {
|
|
163
160
|
let r = s(t, ".claude", "skills", n);
|
|
164
161
|
e(r) && (i(r, {
|
|
165
162
|
recursive: !0,
|
|
@@ -172,7 +169,7 @@ function F(t, n) {
|
|
|
172
169
|
...u ? o : []
|
|
173
170
|
];
|
|
174
171
|
if (d.length > 0) {
|
|
175
|
-
|
|
172
|
+
j(t, r, d);
|
|
176
173
|
for (let e of a) l.push(`✓ ${e}`);
|
|
177
174
|
for (let e of c) l.push(`✓ ${e} (added)`);
|
|
178
175
|
if (u) for (let e of o) l.push(`✓ ${e} (replaced)`);
|
|
@@ -185,18 +182,17 @@ function F(t, n) {
|
|
|
185
182
|
}
|
|
186
183
|
//#endregion
|
|
187
184
|
//#region src/commands/init.ts
|
|
188
|
-
function
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
return a.map((e) => `✓ ${e}`);
|
|
185
|
+
function F(t) {
|
|
186
|
+
if (x.some((n) => e(s(t, ".claude", "skills", n)))) return P(t, { force: !1 });
|
|
187
|
+
let { copied: n } = j(t, m(t));
|
|
188
|
+
return n.map((e) => `✓ ${e}`);
|
|
193
189
|
}
|
|
194
190
|
//#endregion
|
|
195
191
|
//#region src/commands/uninstall.ts
|
|
196
|
-
function
|
|
197
|
-
if (!
|
|
192
|
+
function I(t) {
|
|
193
|
+
if (!x.some((n) => e(s(t, ".claude", "skills", n)))) throw Error("TracerKit not initialized — nothing to uninstall");
|
|
198
194
|
let n = [];
|
|
199
|
-
for (let r of
|
|
195
|
+
for (let r of x) {
|
|
200
196
|
let a = s(t, ".claude", "skills", r);
|
|
201
197
|
e(a) && (i(a, {
|
|
202
198
|
recursive: !0,
|
|
@@ -206,4 +202,4 @@ function L(t) {
|
|
|
206
202
|
return n;
|
|
207
203
|
}
|
|
208
204
|
//#endregion
|
|
209
|
-
export {
|
|
205
|
+
export { T as a, C as c, m as d, v as f, j as i, x as l, F as n, w as o, P as r, S as s, I as t, u };
|
package/package.json
CHANGED
package/skills/brief/SKILL.md
CHANGED
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
description: Session briefing — shows active features, progress, and suggested focus. Use at the start of a session to orient.
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
+
**Config**: read `.tracerkit/config.json` (default: `local`). Follow matching `<!-- if:local/github -->` blocks. GitHub: use `github.repo` from config or git remote.
|
|
6
|
+
|
|
5
7
|
# Session Briefing
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
Overview of active features, progress, and suggested focus.
|
|
8
10
|
|
|
9
11
|
## Pre-loaded context
|
|
10
12
|
|
|
@@ -18,23 +20,16 @@ Get a quick overview of all active features, their progress, and what to focus o
|
|
|
18
20
|
|
|
19
21
|
## Algorithm
|
|
20
22
|
|
|
21
|
-
Follow these steps exactly to build the briefing table:
|
|
22
|
-
|
|
23
23
|
### 1. Discover features
|
|
24
24
|
|
|
25
25
|
<!-- if:local -->
|
|
26
26
|
|
|
27
|
-
For each `.md` file in `.tracerkit/prds/`:
|
|
27
|
+
For each `.md` file in `.tracerkit/prds/`: parse frontmatter, extract `status` and `created`. Skip `status: done`. Slug = filename without `.md`.
|
|
28
28
|
|
|
29
|
-
1. Read the file
|
|
30
|
-
2. Parse YAML frontmatter (the block between `---` fences at the top)
|
|
31
|
-
3. Extract `status` and `created` fields
|
|
32
|
-
4. Skip files where `status: done`
|
|
33
|
-
5. The slug is the filename without `.md`
|
|
34
29
|
<!-- end:local -->
|
|
35
30
|
<!-- if:github -->
|
|
36
31
|
|
|
37
|
-
|
|
32
|
+
List open GitHub Issues with label `{{github.labels.prd}}`:
|
|
38
33
|
|
|
39
34
|
6. For each issue, parse the `<!-- tk:metadata -->` comment in the body
|
|
40
35
|
7. Extract `status` and `created` fields from the metadata
|
|
@@ -47,38 +42,22 @@ For each `.md` file in `.tracerkit/prds/`:
|
|
|
47
42
|
|
|
48
43
|
<!-- if:local -->
|
|
49
44
|
|
|
50
|
-
For each slug
|
|
51
|
-
|
|
52
|
-
1. Read the plan file
|
|
53
|
-
2. Find every `## Phase N` heading (regex: `^## Phase \d+`)
|
|
54
|
-
3. Within each phase section (until the next `## ` heading), count:
|
|
55
|
-
- Checked items: lines matching `^- \[x\] ` (case-insensitive)
|
|
56
|
-
- Unchecked items: lines matching `^- \[ \] `
|
|
57
|
-
4. Sum checked and total across all phases → `checked/total`
|
|
58
|
-
5. Find the first unchecked item (`^- \[ \] (.+)`) in the entire plan — that's the "Next" value. Strip any trailing `[tag]` markers.
|
|
45
|
+
For each slug with a plan at `.tracerkit/plans/<slug>.md`:
|
|
59
46
|
|
|
60
|
-
|
|
47
|
+
Count `- [x]` and `- [ ]` lines under each `## Phase N` heading. Sum → `checked/total`. First unchecked item → "Next" (strip trailing `[tag]`). No plan → `—`.
|
|
61
48
|
|
|
62
49
|
<!-- end:local -->
|
|
63
50
|
<!-- if:github -->
|
|
64
51
|
|
|
65
|
-
For each slug,
|
|
52
|
+
For each slug, find plan issue with label `{{github.labels.plan}}` and matching title. If found:
|
|
66
53
|
|
|
67
|
-
|
|
68
|
-
2. Find every `## Phase N` heading (regex: `^## Phase \d+`)
|
|
69
|
-
3. Within each phase section (until the next `## ` heading), count:
|
|
70
|
-
- Checked items: lines matching `^- \[x\] ` (case-insensitive)
|
|
71
|
-
- Unchecked items: lines matching `^- \[ \] `
|
|
72
|
-
4. Sum checked and total across all phases → `checked/total`
|
|
73
|
-
5. Find the first unchecked item (`^- \[ \] (.+)`) in the entire plan — that's the "Next" value. Strip any trailing `[tag]` markers.
|
|
74
|
-
|
|
75
|
-
If no plan issue exists, progress is `—` and next is `—`.
|
|
54
|
+
Count `- [x]` and `- [ ]` lines under each `## Phase N` heading. Sum → `checked/total`. First unchecked item → "Next" (strip trailing `[tag]`). No plan → `—`.
|
|
76
55
|
|
|
77
56
|
<!-- end:github -->
|
|
78
57
|
|
|
79
58
|
### 3. Build the table
|
|
80
59
|
|
|
81
|
-
Sort
|
|
60
|
+
Sort by `created` ascending (no-date last). Age from `created`:
|
|
82
61
|
|
|
83
62
|
- < 7 days → `Nd` (e.g. `3d`)
|
|
84
63
|
- < 30 days → `Nw` (e.g. `2w`)
|
|
@@ -110,14 +89,13 @@ Append below the table:
|
|
|
110
89
|
|
|
111
90
|
### 5. Offer next steps
|
|
112
91
|
|
|
113
|
-
Ask the user what they'd like to do:
|
|
114
|
-
|
|
115
92
|
<!-- if:local -->
|
|
116
93
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
94
|
+
Options: continue focused feature (read plan at `.tracerkit/plans/<slug>.md`), `/tk:prd` for new feature, `/tk:check <slug>` for progress.
|
|
95
|
+
|
|
96
|
+
<!-- end:local -->
|
|
97
|
+
<!-- if:github -->
|
|
98
|
+
|
|
99
|
+
Options: continue focused feature (read plan issue), `/tk:prd` for new feature, `/tk:check <slug>` for progress.
|
|
100
|
+
|
|
121
101
|
<!-- end:github -->
|
|
122
|
-
- Start a new feature with `/tk:prd`
|
|
123
|
-
- Check progress on a feature with `/tk:check <slug>`
|
package/skills/check/SKILL.md
CHANGED
|
@@ -3,6 +3,8 @@ description: Verify implementation against plan. Shows progress, finds blockers,
|
|
|
3
3
|
argument-hint: '[slug]'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
+
**Config**: read `.tracerkit/config.json` (default: `local`). Follow matching `<!-- if:local/github -->` blocks. GitHub: use `github.repo` from config or git remote.
|
|
7
|
+
|
|
6
8
|
# Check Implementation
|
|
7
9
|
|
|
8
10
|
Check implementation against a plan. Update checks, stamp findings, transition status, and archive when done.
|
|
@@ -48,18 +50,11 @@ For each `.md` file in `.tracerkit/prds/`:
|
|
|
48
50
|
6. If plan issue exists, count progress from checkboxes in its body (see Progress Algorithm below). Show `—` if no plan.
|
|
49
51
|
<!-- end:github -->
|
|
50
52
|
|
|
51
|
-
|
|
53
|
+
Ask which feature to verify.
|
|
52
54
|
|
|
53
55
|
## Progress Algorithm
|
|
54
56
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
1. Find every `## Phase N` heading (regex: `^## Phase \d+`)
|
|
58
|
-
2. Within each phase section (until the next `## ` heading), count:
|
|
59
|
-
- Checked: lines matching `^- \[x\] ` (case-insensitive)
|
|
60
|
-
- Unchecked: lines matching `^- \[ \] `
|
|
61
|
-
3. Per-phase output: ` Phase N — title: checked/total`
|
|
62
|
-
4. Sum across all phases → `Total: checked/total`
|
|
57
|
+
Count `- [x]` and `- [ ]` lines under each `## Phase N` heading. Per-phase: `Phase N — title: checked/total`. Sum → `Total: checked/total`.
|
|
63
58
|
|
|
64
59
|
## Workflow
|
|
65
60
|
|
|
@@ -67,12 +62,12 @@ To count progress for a plan file:
|
|
|
67
62
|
|
|
68
63
|
<!-- if:local -->
|
|
69
64
|
|
|
70
|
-
Read `.tracerkit/plans/<slug>.md`. If
|
|
65
|
+
Read `.tracerkit/plans/<slug>.md`. If missing, list plans and ask.
|
|
71
66
|
|
|
72
67
|
<!-- end:local -->
|
|
73
68
|
<!-- if:github -->
|
|
74
69
|
|
|
75
|
-
Find
|
|
70
|
+
Find plan issue: open issue with label `{{github.labels.plan}}`, title matching `[{{github.labels.plan}}] <slug>:`. If missing, list plans and ask.
|
|
76
71
|
|
|
77
72
|
<!-- end:github -->
|
|
78
73
|
|
|
@@ -80,18 +75,18 @@ Find the plan issue: search for an open GitHub Issue with label `{{github.labels
|
|
|
80
75
|
|
|
81
76
|
<!-- if:local -->
|
|
82
77
|
|
|
83
|
-
Read
|
|
78
|
+
Read source PRD referenced in plan header (`> Source PRD: ...`).
|
|
84
79
|
|
|
85
80
|
<!-- end:local -->
|
|
86
81
|
<!-- if:github -->
|
|
87
82
|
|
|
88
|
-
Read
|
|
83
|
+
Read source PRD issue referenced in plan body (`> Source PRD: #<number>`).
|
|
89
84
|
|
|
90
85
|
<!-- end:github -->
|
|
91
86
|
|
|
92
87
|
### 3. Fast-path: check if implementation exists
|
|
93
88
|
|
|
94
|
-
|
|
89
|
+
If primary module file(s) from Phase 1 don't exist, skip subagent — report `0/N — not yet started`, list Phase 1 done-when items, jump to Step 5.
|
|
95
90
|
|
|
96
91
|
### 3b. Launch read-only review
|
|
97
92
|
|
|
@@ -132,7 +127,7 @@ Based on checks and findings, decide the status transition:
|
|
|
132
127
|
|
|
133
128
|
### 5. Report to user
|
|
134
129
|
|
|
135
|
-
Count progress per phase
|
|
130
|
+
Count progress per phase (Progress Algorithm), then print:
|
|
136
131
|
|
|
137
132
|
```markdown
|
|
138
133
|
## Verification: <slug>
|
|
@@ -186,35 +181,19 @@ If all checks pass and zero BLOCKERS:
|
|
|
186
181
|
|
|
187
182
|
<!-- if:local -->
|
|
188
183
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
1. Create directory `.tracerkit/archives/<slug>/`
|
|
192
|
-
2. If `.tracerkit/prds/<slug>.md` exists:
|
|
193
|
-
- Read the PRD file
|
|
194
|
-
- In the YAML frontmatter (between `---` fences), find the `status:` line and replace its value with `done`. If no `status:` line exists, add `status: done` as a new line inside the frontmatter block.
|
|
195
|
-
- Add a `completed: <current UTC ISO 8601 timestamp>` line inside the frontmatter block (e.g. `completed: 2025-06-15T14:30:00Z`)
|
|
196
|
-
- Write the updated content to `.tracerkit/archives/<slug>/prd.md`
|
|
197
|
-
3. Read `.tracerkit/plans/<slug>.md`
|
|
198
|
-
- Append to the end: `\n## Archived\n\nArchived on YYYY-MM-DD.\n`
|
|
199
|
-
- Write the result to `.tracerkit/archives/<slug>/plan.md`
|
|
200
|
-
4. Delete `.tracerkit/prds/<slug>.md` (if it exists)
|
|
201
|
-
5. Delete `.tracerkit/plans/<slug>.md`
|
|
184
|
+
Archive to `.tracerkit/archives/<slug>/`:
|
|
202
185
|
|
|
203
|
-
|
|
186
|
+
1. Copy PRD → `prd.md` (set `status: done`, add `completed` timestamp in frontmatter)
|
|
187
|
+
2. Copy plan → `plan.md` (append `## Archived` with date)
|
|
188
|
+
3. Delete originals
|
|
204
189
|
|
|
205
190
|
<!-- end:local -->
|
|
206
191
|
<!-- if:github -->
|
|
207
192
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
- Update the `<!-- tk:metadata -->` comment: set `status: done`, add `completed: <current UTC ISO 8601 timestamp>`
|
|
213
|
-
2. Close the PRD issue with reason `completed`
|
|
214
|
-
3. Close the plan issue with reason `completed`
|
|
215
|
-
4. If there is a current PR associated with this work, reference it in a closing comment on the PRD issue
|
|
216
|
-
|
|
217
|
-
Tell the user: issues closed (include issue numbers), one-line summary of the feature.
|
|
193
|
+
1. PRD issue: add `tk:done`, remove `tk:in-progress`, set metadata `status: done` + `completed` timestamp
|
|
194
|
+
2. Close PRD issue (reason: `completed`)
|
|
195
|
+
3. Close plan issue (reason: `completed`)
|
|
196
|
+
4. If current PR exists, reference it in closing comment on PRD issue
|
|
218
197
|
|
|
219
198
|
<!-- end:github -->
|
|
220
199
|
|
|
@@ -232,15 +211,3 @@ List the blockers to fix, then re-run `/tk:check <slug>`.
|
|
|
232
211
|
- The only file writes this skill makes are: checkboxes + verdict block in the plan, and the archive steps on `done`
|
|
233
212
|
- Never modify implementation code — only observe and report
|
|
234
213
|
- If the PRD file is missing but all checks pass, warn and proceed — archive the plan only (skip PRD steps in archive)
|
|
235
|
-
|
|
236
|
-
## Error Handling
|
|
237
|
-
|
|
238
|
-
- Plan not found — list available plans and ask
|
|
239
|
-
- PRD referenced in plan not found — warn and continue with plan checks only
|
|
240
|
-
<!-- if:local -->
|
|
241
|
-
- `.tracerkit/plans/` missing — tell user to run `/tk:plan` first
|
|
242
|
-
- `.tracerkit/archives/<slug>/` already exists — warn and ask whether to remove it first
|
|
243
|
-
<!-- end:local -->
|
|
244
|
-
<!-- if:github -->
|
|
245
|
-
- Issue update fails — report the error and suggest checking `gh auth status`
|
|
246
|
-
<!-- end:github -->
|
package/skills/plan/SKILL.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Turn a PRD into a multi-phase implementation plan using tracer-bullet vertical slices
|
|
2
|
+
description: Turn a PRD into a multi-phase implementation plan using tracer-bullet vertical slices. Use after /tk:prd.
|
|
3
3
|
argument-hint: '[slug]'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
+
**Config**: read `.tracerkit/config.json` (default: `local`). Follow matching `<!-- if:local/github -->` blocks. GitHub: use `github.repo` from config or git remote.
|
|
7
|
+
|
|
6
8
|
# PRD to Plan
|
|
7
9
|
|
|
8
10
|
Break a PRD into phased vertical slices (tracer bullets).
|
|
@@ -32,7 +34,7 @@ Output: a GitHub Issue with label `{{github.labels.plan}}`.
|
|
|
32
34
|
|
|
33
35
|
The argument (if provided) is: $ARGUMENTS
|
|
34
36
|
|
|
35
|
-
Use
|
|
37
|
+
Use argument as `<slug>`. If empty, list available PRDs and ask.
|
|
36
38
|
|
|
37
39
|
## Workflow
|
|
38
40
|
|
|
@@ -40,16 +42,12 @@ Use the argument as `<slug>` if given. If no argument is provided, list availabl
|
|
|
40
42
|
|
|
41
43
|
<!-- if:local -->
|
|
42
44
|
|
|
43
|
-
Read `.tracerkit/prds/<slug>.md`. If
|
|
44
|
-
|
|
45
|
-
If `.tracerkit/plans/<slug>.md` already exists, tell the user and ask whether to overwrite or pick a new name.
|
|
45
|
+
Read `.tracerkit/prds/<slug>.md`. If missing, list PRDs and ask. If `.tracerkit/plans/<slug>.md` exists, ask: overwrite or new name?
|
|
46
46
|
|
|
47
47
|
<!-- end:local -->
|
|
48
48
|
<!-- if:github -->
|
|
49
49
|
|
|
50
|
-
Find
|
|
51
|
-
|
|
52
|
-
Search for an existing plan issue with label `{{github.labels.plan}}` and title matching `[{{github.labels.plan}}] <slug>:`. If found, tell the user and ask whether to update it or pick a new name.
|
|
50
|
+
Find PRD issue: open issue with label `{{github.labels.prd}}`, title matching `[{{github.labels.prd}}] <slug>:`. If missing, list PRDs and ask. If plan issue with label `{{github.labels.plan}}` and matching title exists, ask: update or new name?
|
|
53
51
|
|
|
54
52
|
<!-- end:github -->
|
|
55
53
|
|
|
@@ -57,9 +55,7 @@ Search for an existing plan issue with label `{{github.labels.plan}}` and title
|
|
|
57
55
|
|
|
58
56
|
<!-- if:local -->
|
|
59
57
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
If the PRD has no frontmatter, skip this step silently.
|
|
58
|
+
Set `status: in_progress` in `.tracerkit/prds/<slug>.md` frontmatter. Change only `status`.
|
|
63
59
|
|
|
64
60
|
<!-- end:local -->
|
|
65
61
|
<!-- if:github -->
|
|
@@ -72,9 +68,9 @@ Update the PRD issue:
|
|
|
72
68
|
|
|
73
69
|
### 2. Explore the codebase
|
|
74
70
|
|
|
75
|
-
|
|
71
|
+
Map architecture, patterns, integration points. Skip if codebase context exists from prior step.
|
|
76
72
|
|
|
77
|
-
**Research protocol**: codebase first, then
|
|
73
|
+
**Research protocol**: codebase first, then docs. Unverifiable claims → flag as uncertain, never fabricate.
|
|
78
74
|
|
|
79
75
|
### 3. Identify durable architectural decisions
|
|
80
76
|
|
|
@@ -88,7 +84,7 @@ Before slicing, extract decisions that hold across all phases:
|
|
|
88
84
|
|
|
89
85
|
### 4. Draft vertical slices
|
|
90
86
|
|
|
91
|
-
Each phase
|
|
87
|
+
Each phase: thin vertical slice through all layers (schema → service → API → UI → tests). Demoable alone.
|
|
92
88
|
|
|
93
89
|
**Deriving tasks from the PRD:**
|
|
94
90
|
|
|
@@ -106,9 +102,9 @@ Each phase is a thin **tracer bullet** — a narrow but complete path through ev
|
|
|
106
102
|
|
|
107
103
|
**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.
|
|
108
104
|
|
|
109
|
-
**Done when:**
|
|
105
|
+
**Done when:** checkbox list of atomic, verifiable conditions (not prose). Test: "Can an agent verify by reading files, running a command, or checking a test?" Agent marks `[x]` during implementation.
|
|
110
106
|
|
|
111
|
-
**
|
|
107
|
+
**Layer-by-layer exception:** if complex schema changes underpin all modules and no story stands alone, build data foundation first, then slice vertically.
|
|
112
108
|
|
|
113
109
|
**Phase count thresholds:**
|
|
114
110
|
|
|
@@ -126,19 +122,13 @@ Assign an agent tag to tasks where appropriate:
|
|
|
126
122
|
|
|
127
123
|
### 5. Quiz the user
|
|
128
124
|
|
|
129
|
-
Present
|
|
130
|
-
|
|
131
|
-
- **Title**: short goal phrase
|
|
132
|
-
- **User stories covered**: which PRD stories this addresses
|
|
133
|
-
- **Done when**: the testable condition
|
|
134
|
-
|
|
135
|
-
Ask: Does the granularity feel right? Should any phases merge or split? Iterate until approved.
|
|
125
|
+
Present breakdown (title, user stories covered, done-when per phase). Ask: granularity right? Merge or split? Iterate until approved.
|
|
136
126
|
|
|
137
127
|
### 6. Save plan
|
|
138
128
|
|
|
139
129
|
<!-- if:local -->
|
|
140
130
|
|
|
141
|
-
Save to `.tracerkit/plans/<slug>.md` (create
|
|
131
|
+
Save to `.tracerkit/plans/<slug>.md` (create dir if missing).
|
|
142
132
|
|
|
143
133
|
```markdown
|
|
144
134
|
# Plan: <Feature Name>
|
|
@@ -149,16 +139,9 @@ Save to `.tracerkit/plans/<slug>.md` (create `.tracerkit/plans/` if missing).
|
|
|
149
139
|
<!-- end:local -->
|
|
150
140
|
<!-- if:github -->
|
|
151
141
|
|
|
152
|
-
Ensure
|
|
142
|
+
Ensure labels exist: `{{github.labels.plan}}`, `tk:in-progress` (create if missing).
|
|
153
143
|
|
|
154
|
-
|
|
155
|
-
- `tk:in-progress` — Plan generated, implementation underway
|
|
156
|
-
|
|
157
|
-
Create a GitHub Issue with:
|
|
158
|
-
|
|
159
|
-
- **Title**: `[{{github.labels.plan}}] <slug>: Plan: <Feature Title>`
|
|
160
|
-
- **Labels**: `{{github.labels.plan}}`, `tk:in-progress`
|
|
161
|
-
- **Body**: the plan content below, with a source PRD reference by issue number
|
|
144
|
+
Create GitHub Issue — title: `[{{github.labels.plan}}] <slug>: Plan: <Feature Title>`, labels: `{{github.labels.plan}}`, `tk:in-progress`.
|
|
162
145
|
|
|
163
146
|
```markdown
|
|
164
147
|
<!-- tk:metadata
|
|
@@ -210,16 +193,7 @@ Carried forward from PRD verbatim.
|
|
|
210
193
|
Gaps found in the PRD needing resolution. Blank if none.
|
|
211
194
|
```
|
|
212
195
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
Print saved path and one line per phase: `Phase N — <title> (<condition summary>)`. Then ask: "Run `/tk:check <slug>` when ready?"
|
|
216
|
-
|
|
217
|
-
<!-- end:local -->
|
|
218
|
-
<!-- if:github -->
|
|
219
|
-
|
|
220
|
-
Print issue number/URL and one line per phase: `Phase N — <title> (<condition summary>)`. Then ask: "Run `/tk:check <slug>` when ready?"
|
|
221
|
-
|
|
222
|
-
<!-- end:github -->
|
|
196
|
+
Print one line per phase: `Phase N — <title> (<condition summary>)`. Then ask: "Run `/tk:check <slug>` when ready?"
|
|
223
197
|
|
|
224
198
|
## Rules
|
|
225
199
|
|
|
@@ -234,14 +208,3 @@ Print issue number/URL and one line per phase: `Phase N — <title> (<condition
|
|
|
234
208
|
- Never modify the source PRD content — only update metadata and labels
|
|
235
209
|
<!-- end:github -->
|
|
236
210
|
- Carry PRD's Out of Scope forward verbatim
|
|
237
|
-
|
|
238
|
-
## Error Handling
|
|
239
|
-
|
|
240
|
-
- PRD not found — list available PRDs and ask
|
|
241
|
-
- PRD missing sections — note gaps inline and continue
|
|
242
|
-
<!-- if:local -->
|
|
243
|
-
- `.tracerkit/plans/` missing — create it
|
|
244
|
-
<!-- end:local -->
|
|
245
|
-
<!-- if:github -->
|
|
246
|
-
- Issue creation fails — report the error and suggest checking `gh auth status`
|
|
247
|
-
<!-- end:github -->
|
package/skills/prd/SKILL.md
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Create a PRD through user interview, codebase exploration, and module design
|
|
2
|
+
description: Create a PRD through user interview, codebase exploration, and module design. Use when starting a new feature or change.
|
|
3
3
|
argument-hint: <idea>
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
+
**Config**: read `.tracerkit/config.json` (default: `local`). Follow matching `<!-- if:local/github -->` blocks. GitHub: use `github.repo` from config or git remote.
|
|
7
|
+
|
|
6
8
|
# PRD Writing
|
|
7
9
|
|
|
8
|
-
Skip steps
|
|
10
|
+
Skip satisfied steps. If argument provided, skip to Step 2.
|
|
9
11
|
|
|
10
12
|
## Pre-loaded context
|
|
11
13
|
|
|
@@ -21,9 +23,7 @@ Skip steps already satisfied. If user provided a description via arguments, skip
|
|
|
21
23
|
|
|
22
24
|
The argument is: $ARGUMENTS
|
|
23
25
|
|
|
24
|
-
If
|
|
25
|
-
|
|
26
|
-
If the argument is provided, derive a slug using this exact algorithm:
|
|
26
|
+
If empty, go to Step 1; derive slug after gathering the idea. If provided, derive slug:
|
|
27
27
|
|
|
28
28
|
1. Take only the text before the first `—` or `–` (if present)
|
|
29
29
|
2. Lowercase the text
|
|
@@ -33,16 +33,12 @@ If the argument is provided, derive a slug using this exact algorithm:
|
|
|
33
33
|
|
|
34
34
|
<!-- if:local -->
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
If `.tracerkit/prds/<slug>.md` already exists, tell the user and ask whether to overwrite or pick a new name.
|
|
36
|
+
Output: `.tracerkit/prds/<slug>.md`. If exists, ask: overwrite or new name?
|
|
39
37
|
|
|
40
38
|
<!-- end:local -->
|
|
41
39
|
<!-- if:github -->
|
|
42
40
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
Search for an existing open issue with title matching `[{{github.labels.prd}}] <slug>:`. If found, tell the user and ask whether to update it or pick a new slug.
|
|
41
|
+
Output: GitHub Issue with label `{{github.labels.prd}}`, title `[{{github.labels.prd}}] <slug>: <Feature Title>`. If matching issue exists, ask: update or new slug?
|
|
46
42
|
|
|
47
43
|
<!-- end:github -->
|
|
48
44
|
|
|
@@ -54,180 +50,86 @@ Ask the user for a detailed description of the problem and any solution ideas.
|
|
|
54
50
|
|
|
55
51
|
### 2. Explore codebase
|
|
56
52
|
|
|
57
|
-
|
|
53
|
+
Map current state: data models, services, API routes, frontend, tests. Note exists vs. must build.
|
|
58
54
|
|
|
59
|
-
**Research protocol**: codebase first, then
|
|
55
|
+
**Research protocol**: codebase first, then docs. Unverifiable claims → flag as uncertain, never fabricate.
|
|
60
56
|
|
|
61
57
|
### 3. Interview
|
|
62
58
|
|
|
63
|
-
|
|
59
|
+
One question at a time. Lead with your recommended answer. Explore code instead of asking when possible. Offer A/B/C for terse answers.
|
|
64
60
|
|
|
65
|
-
|
|
61
|
+
| Branch | Key questions | Skip when |
|
|
62
|
+
| ---------------- | --------------------------------------- | -------------------------------- |
|
|
63
|
+
| Scope & Surface | Where? New page or integrated? Roles? | CLI/library, no new entry points |
|
|
64
|
+
| Data & Concepts | Definitions, existing vs missing data | Never skip |
|
|
65
|
+
| Behavior | Interaction patterns, filtering, search | No user-facing behavior |
|
|
66
|
+
| Display | Numbers, tables, charts, exports | No UI |
|
|
67
|
+
| Access & Privacy | Who sees what? Sensitive data? | Single-user, no auth |
|
|
68
|
+
| Boundaries | Out of scope, deferred features | Never skip |
|
|
69
|
+
| Integration | Schema, services, external deps | Self-contained change |
|
|
66
70
|
|
|
67
|
-
|
|
68
|
-
- **Data & Concepts** — Precise definitions for each new concept. What data exists, what's missing? _Never skip_ — every feature has data.
|
|
69
|
-
- **Behavior & Interaction** — How does the user interact? Sorting, filtering, search, time ranges? _Skip if_: feature is purely internal/backend with no user-facing behavior change.
|
|
70
|
-
- **Display & Output** — Numbers, tables, charts, forms? Exportable? URL-driven state? _Skip if_: no UI or formatted output involved.
|
|
71
|
-
- **Access & Privacy** — Who sees what? Role-based restrictions? Sensitive data concerns? _Skip if_: single-user project with no auth layer.
|
|
72
|
-
- **Boundaries** — What is explicitly out of scope? Adjacent features to defer? _Never skip_ — scope control prevents creep.
|
|
73
|
-
- **Integration** — Schema changes? New or extended services? External dependencies? _Skip if_: self-contained change touching no external systems or storage.
|
|
71
|
+
### 3b. Gray areas
|
|
74
72
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
Before continuing, scan the interview for gray areas. Something is a gray area if any of these are true:
|
|
78
|
-
|
|
79
|
-
- **Vague answer**: user said "maybe", "probably", "I think", or gave a one-word answer to a multi-part question
|
|
80
|
-
- **Contradiction**: two answers conflict (e.g., "no auth needed" but "only admins can access")
|
|
81
|
-
- **Unstated assumption**: you filled in a detail the user never confirmed
|
|
82
|
-
- **Ambiguous scope**: a feature boundary is unclear (could be in or out of scope)
|
|
83
|
-
|
|
84
|
-
Present as a numbered list:
|
|
85
|
-
|
|
86
|
-
```
|
|
87
|
-
Gray areas found:
|
|
88
|
-
1. <ambiguity> — assumed <X>, confirm?
|
|
89
|
-
2. <ambiguity> — two options: A or B
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
If the list is empty, say "No gray areas found" and move on. Otherwise, resolve each item with the user before proceeding.
|
|
73
|
+
Surface ambiguities, contradictions, unstated assumptions. Present numbered list. Resolve all before continuing.
|
|
93
74
|
|
|
94
75
|
### 4. Design modules
|
|
95
76
|
|
|
96
|
-
Sketch
|
|
77
|
+
Sketch modules. Favor **deep modules** — simple interface (1-3 entry points) hiding large implementation over shallow modules where interface ≈ implementation.
|
|
97
78
|
|
|
98
|
-
|
|
79
|
+
Shallow signals: many small 1:1 functions, callers compose multiple calls, feature changes require interface changes.
|
|
99
80
|
|
|
100
|
-
Present modules
|
|
81
|
+
Present modules. Confirm which need tests.
|
|
101
82
|
|
|
102
83
|
### 5. Write PRD
|
|
103
84
|
|
|
104
85
|
<!-- if:local -->
|
|
105
86
|
|
|
106
|
-
Save to `.tracerkit/prds/<slug>.md` (create
|
|
87
|
+
Save to `.tracerkit/prds/<slug>.md` (create dir if missing).
|
|
107
88
|
|
|
108
89
|
```markdown
|
|
109
90
|
---
|
|
110
|
-
created: <
|
|
91
|
+
created: <UTC ISO 8601>
|
|
111
92
|
status: created
|
|
112
93
|
---
|
|
113
94
|
|
|
114
95
|
# Feature Name
|
|
115
|
-
|
|
116
|
-
...
|
|
117
96
|
```
|
|
118
97
|
|
|
119
98
|
<!-- end:local -->
|
|
120
99
|
<!-- if:github -->
|
|
121
100
|
|
|
122
|
-
Ensure
|
|
101
|
+
Ensure labels exist: `{{github.labels.prd}}`, `tk:created` (create if missing).
|
|
123
102
|
|
|
124
|
-
|
|
125
|
-
- `tk:created` — PRD written, no plan yet
|
|
126
|
-
|
|
127
|
-
Create a GitHub Issue with:
|
|
128
|
-
|
|
129
|
-
- **Title**: `[{{github.labels.prd}}] <slug>: <Feature Title>`
|
|
130
|
-
- **Labels**: `{{github.labels.prd}}`, `tk:created`
|
|
131
|
-
- **Body**: the PRD content below, with metadata in an HTML comment
|
|
103
|
+
Create GitHub Issue — title: `[{{github.labels.prd}}] <slug>: <Feature Title>`, labels: `{{github.labels.prd}}`, `tk:created`.
|
|
132
104
|
|
|
133
105
|
```markdown
|
|
134
106
|
<!-- tk:metadata
|
|
135
|
-
created: <
|
|
107
|
+
created: <UTC ISO 8601>
|
|
136
108
|
status: created
|
|
137
109
|
-->
|
|
138
110
|
|
|
139
111
|
# Feature Name
|
|
140
|
-
|
|
141
|
-
...
|
|
142
112
|
```
|
|
143
113
|
|
|
144
114
|
<!-- end:github -->
|
|
145
115
|
|
|
146
|
-
|
|
116
|
+
PRD body structure (same for local file and issue body). Omit empty sections. No file paths or code snippets.
|
|
147
117
|
|
|
118
|
+
```
|
|
148
119
|
## Problem Statement
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
## Current State
|
|
153
|
-
|
|
154
|
-
What exists today that this feature changes or builds on. Skip for greenfield.
|
|
155
|
-
|
|
156
|
-
- Relevant modules, services, or UI surfaces already in place
|
|
157
|
-
- Current behavior the user experiences
|
|
158
|
-
- Known limitations or workarounds
|
|
159
|
-
|
|
160
|
-
## Solution
|
|
161
|
-
|
|
162
|
-
The solution from the user's perspective. Describe the experience, not the architecture.
|
|
163
|
-
|
|
164
|
-
## User Stories
|
|
165
|
-
|
|
166
|
-
Long numbered list. Cover happy path, edge cases, error states.
|
|
167
|
-
|
|
168
|
-
1. As a <actor>, I want <feature>, so that <benefit>
|
|
169
|
-
|
|
120
|
+
## Current State (skip if greenfield)
|
|
121
|
+
## Solution (user experience, not architecture)
|
|
122
|
+
## User Stories (numbered, cover happy + edge + error)
|
|
170
123
|
## Implementation Decisions
|
|
171
|
-
|
|
172
|
-
###
|
|
173
|
-
|
|
174
|
-
- Module name, purpose, and public interface (function signatures with param types)
|
|
175
|
-
- Why each module exists as a separate unit
|
|
176
|
-
|
|
177
|
-
### Architectural Decisions
|
|
178
|
-
|
|
179
|
-
- Key definitions (precise meaning of domain terms)
|
|
180
|
-
- Data flow from storage to display
|
|
181
|
-
- State management approach
|
|
182
|
-
|
|
124
|
+
### New Modules (name, purpose, interface signatures)
|
|
125
|
+
### Architectural Decisions (definitions, data flow, state)
|
|
183
126
|
### Schema Changes
|
|
184
|
-
|
|
185
|
-
- New tables/columns needed, or "None required"
|
|
186
|
-
|
|
187
127
|
### API Contracts
|
|
188
|
-
|
|
189
|
-
- New routes, request/response shapes
|
|
190
|
-
|
|
191
128
|
### Navigation
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
Do NOT include file paths or code snippets — they go stale.
|
|
196
|
-
|
|
197
|
-
Omit any section whose content would be "None required" — only include sections with actual content.
|
|
198
|
-
|
|
199
|
-
## Testing Decisions
|
|
200
|
-
|
|
201
|
-
- What makes a good test (behavior, not implementation)
|
|
202
|
-
- Which modules need tests
|
|
203
|
-
- Key test cases (empty state, boundaries, isolation)
|
|
204
|
-
- Prior art: similar test patterns in the codebase
|
|
205
|
-
|
|
206
|
-
## Out of Scope
|
|
207
|
-
|
|
208
|
-
Explicit list. Be specific — vague exclusions invite scope creep.
|
|
129
|
+
## Testing Decisions (behavior tests, key cases, prior art)
|
|
130
|
+
## Out of Scope (be specific)
|
|
131
|
+
```
|
|
209
132
|
|
|
210
133
|
---
|
|
211
134
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
Tell the user: file created, one-line summary. Then ask: "Run `/tk:plan <slug>` next?"
|
|
215
|
-
|
|
216
|
-
<!-- end:local -->
|
|
217
|
-
<!-- if:github -->
|
|
218
|
-
|
|
219
|
-
Tell the user: issue created (include issue number and URL), one-line summary. Then ask: "Run `/tk:plan <slug>` next?"
|
|
220
|
-
|
|
221
|
-
<!-- end:github -->
|
|
222
|
-
|
|
223
|
-
## Error Handling
|
|
224
|
-
|
|
225
|
-
<!-- if:local -->
|
|
226
|
-
|
|
227
|
-
- `.tracerkit/prds/` missing — create it
|
|
228
|
-
<!-- end:local -->
|
|
229
|
-
<!-- if:github -->
|
|
230
|
-
- Labels missing — create them before creating the issue
|
|
231
|
-
- Issue creation fails — report the error and suggest checking `gh auth status`
|
|
232
|
-
<!-- end:github -->
|
|
233
|
-
- Scope larger than expected — surface and re-scope with user before continuing
|
|
135
|
+
Then ask: "Run `/tk:plan <slug>` next?"
|