tracerkit 1.11.3 → 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 CHANGED
@@ -19,9 +19,9 @@ Named after the tracer-bullet technique from _The Pragmatic Programmer_: **Trace
19
19
 
20
20
  ## Why TracerKit?
21
21
 
22
- AI assistants work best with small, well-scoped tasks not sprawling layers or flat task lists. TracerKit structures every feature as **tracer-bullet vertical slices**: each phase cuts through every layer (schema → service → API → UI → tests) and is demoable on its own. Integration problems surface early, not at the end.
22
+ AI assistants work best with small, well-scoped tasks, not sprawling layers or flat task lists. TracerKit structures every feature as **tracer-bullet vertical slices**: each phase cuts through every layer (schema → service → API → UI → tests) and is demoable on its own. Integration problems surface early, not at the end.
23
23
 
24
- The workflow is three skills: **define** (`/tk:prd`), **plan** (`/tk:plan`), **verify** (`/tk:check`). Skills are pure Markdown with zero runtime deps the AI reads your specs directly, counts progress, and archives completed work. No build step, no CLI at runtime.
24
+ The workflow is three skills: **define** (`/tk:prd`), **plan** (`/tk:plan`), **verify** (`/tk:check`). Skills are pure Markdown with zero runtime deps. The AI reads your specs directly, counts progress, and archives completed work. No build step, no CLI at runtime.
25
25
 
26
26
  ## Get Started
27
27
 
@@ -32,7 +32,7 @@ npm install -g tracerkit
32
32
  tracerkit init
33
33
  ```
34
34
 
35
- Skills are installed to `~/.claude/skills/`, available in every project. Safe to re-run adds missing skills without overwriting ones you've modified.
35
+ Skills are installed to `~/.claude/skills/`, available in every project. Safe to re-run: adds missing skills without overwriting ones you've modified.
36
36
 
37
37
  <details>
38
38
  <summary>Per-project install (team members get skills via git)</summary>
@@ -54,7 +54,7 @@ Inside Claude Code, run:
54
54
  /plugin install tk@claude-plugins-official
55
55
  ```
56
56
 
57
- Run `/reload-plugins` if needed. Skills are available immediately no build step, no config.
57
+ Run `/reload-plugins` if needed. Skills are available immediately, no build step, no config.
58
58
 
59
59
  </details>
60
60
 
@@ -91,6 +91,20 @@ AI: | Feature | Status | Age | Progress | Next
91
91
 
92
92
  See [Examples](docs/examples.md) for full walkthroughs.
93
93
 
94
+ <details>
95
+ <summary>GitHub Issues as storage backend</summary>
96
+
97
+ Same skills, same workflow. Storage is configured per-project:
98
+
99
+ ```bash
100
+ tracerkit config storage github # set current project to use GitHub
101
+ tracerkit config github.repo org/repo # set target repo
102
+ ```
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. Each project can use a different backend; local is the default. See [Configuration](docs/configuration.md) for details.
105
+
106
+ </details>
107
+
94
108
  ## Skills
95
109
 
96
110
  TracerKit ships skills that take a feature from idea to verified archive.
@@ -99,19 +113,19 @@ TracerKit ships skills that take a feature from idea to verified archive.
99
113
 
100
114
  Interactive interview that explores your codebase, asks scoping questions one at a time, designs deep modules, and writes a structured PRD.
101
115
 
102
- **Output:** `.tracerkit/prds/<slug>.md`
116
+ **Output:** `.tracerkit/prds/<slug>.md` (local) or GitHub Issue with `tk:prd` label
103
117
 
104
118
  ### `/tk:plan <slug>`: Create an implementation plan
105
119
 
106
120
  Reads a PRD and breaks it into phased **tracer-bullet vertical slices**. Each phase is a thin but complete path through every layer (schema, service, API, UI, tests), demoable on its own.
107
121
 
108
- **Output:** `.tracerkit/plans/<slug>.md`
122
+ **Output:** `.tracerkit/plans/<slug>.md` (local) or GitHub Issue with `tk:plan` label
109
123
 
110
124
  ### `/tk:brief`: Session briefing
111
125
 
112
126
  Shows active features, their progress, and suggested focus. Use at the start of a session to orient.
113
127
 
114
- **Output:** Feature dashboard in the terminal no files written.
128
+ **Output:** Feature dashboard in the terminal. No files written.
115
129
 
116
130
  ### `/tk:check [slug]`: Verify and archive
117
131
 
@@ -119,15 +133,15 @@ Verifies the codebase against the plan's done-when checkboxes. Runs tests, valid
119
133
 
120
134
  Without arguments, shows a feature dashboard with status and progress before asking which feature to check.
121
135
 
122
- **Output:** Verdict block in `.tracerkit/plans/<slug>.md`. On `done`: `.tracerkit/archives/<slug>/prd.md` + `.tracerkit/archives/<slug>/plan.md`
136
+ **Output:** Verdict block appended to the plan. On `done`: archives to `.tracerkit/archives/<slug>/` (local) or closes both issues (GitHub).
123
137
 
124
138
  ## Docs
125
139
 
126
140
  | Document | Description |
127
141
  | ------------------------------------------------ | -------------------------------------------------- |
128
142
  | [Examples](docs/examples.md) | Walk through end-to-end usage scenarios |
129
- | [CLI Reference](docs/cli-reference.md) | Lifecycle commands: init, update, uninstall |
130
- | [Configuration](docs/configuration.md) | Configure custom artifact paths via `config.json` |
143
+ | [CLI Reference](docs/cli-reference.md) | Commands: init, update, config, uninstall |
144
+ | [Configuration](docs/configuration.md) | Storage backends, GitHub options, custom paths |
131
145
  | [Metadata Lifecycle](docs/metadata-lifecycle.md) | Understand YAML frontmatter states and transitions |
132
146
  | [Comparison](docs/comparison.md) | Compare TracerKit to Spec Kit, Kiro, and OpenSpec |
133
147
 
package/dist/bin.js CHANGED
@@ -1,44 +1,98 @@
1
1
  #!/usr/bin/env node
2
- import { a as e, i as t, n, r, s as i, t as a } from "./uninstall-BhTMOfMb.js";
3
- import { readFileSync as o } from "node:fs";
4
- import { dirname as s, resolve as c } from "node:path";
5
- import { fileURLToPath as l } from "node:url";
6
- import { homedir as u } from "node:os";
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
+ import { existsSync as u, readFileSync as d, statSync as f } from "node:fs";
4
+ import { dirname as p, join as m, resolve as h } from "node:path";
5
+ import { fileURLToPath as g } from "node:url";
6
+ import { homedir as _ } from "node:os";
7
+ //#region src/commands/config.ts
8
+ function v(e, t) {
9
+ let [n, r] = t;
10
+ return n ? r ? x(e, n, r) : b(e, n) : y(e);
11
+ }
12
+ function y(e) {
13
+ let t = n(e), r = t.storage === "local" ? {
14
+ storage: t.storage,
15
+ paths: t.paths
16
+ } : t;
17
+ return JSON.stringify(r, null, 2).split("\n");
18
+ }
19
+ function b(e, t) {
20
+ let r = C(n(e), t);
21
+ return r === void 0 ? [`Unknown key: ${t}`] : typeof r == "object" ? [JSON.stringify(r, null, 2)] : [String(r)];
22
+ }
23
+ function x(e, t, n) {
24
+ r(e, w(t, n));
25
+ let i = [`✓ Set ${t} = ${n}`];
26
+ return S(e, i), i;
27
+ }
28
+ function S(e, t) {
29
+ a.some((t) => u(m(e, ".claude", "skills", t))) && (i(e, n(e)), t.push("✓ Skills re-rendered"));
30
+ }
31
+ function C(e, t) {
32
+ let n = t.split("."), r = e;
33
+ for (let e of n) {
34
+ if (typeof r != "object" || !r) return;
35
+ r = r[e];
36
+ }
37
+ return r;
38
+ }
39
+ function w(e, t) {
40
+ let n = e.split("."), r = {}, i = r;
41
+ for (let e = 0; e < n.length - 1; e++) {
42
+ let t = {};
43
+ i[n[e]] = t, i = t;
44
+ }
45
+ return i[n[n.length - 1]] = t, r;
46
+ }
47
+ //#endregion
7
48
  //#region src/cli.ts
8
- var { version: d } = JSON.parse(o(c(s(l(import.meta.url)), "..", "package.json"), "utf8")), f = Math.max(...t.map((e) => `${e.name} ${e.args}`.length)), p = [
49
+ var { version: T } = JSON.parse(d(h(p(g(import.meta.url)), "..", "package.json"), "utf8")), E = Math.max(...e.map((e) => `${e.name} ${e.args}`.length)), D = [
9
50
  "Usage: tracerkit <command> [path]",
10
51
  "",
11
52
  "Commands:",
12
- ...t.map((e) => ` ${`${e.name} ${e.args}`.padEnd(f + 2)}${e.desc}`),
53
+ ...e.map((e) => ` ${`${e.name} ${e.args}`.padEnd(E + 2)}${e.desc}`),
13
54
  "",
14
55
  "Options:",
15
56
  " --force Overwrite modified files during update",
16
57
  " --help, -h Show this help message",
17
58
  " --version, -v Print version",
18
59
  "",
19
- "All commands default to the home directory when no path is given."
60
+ "init/update/uninstall default to the home directory when no path is given.",
61
+ "config defaults to the current working directory."
20
62
  ];
21
- function m(e, t = u()) {
63
+ function O(e) {
64
+ if (!e) return !1;
65
+ try {
66
+ return f(h(e)).isDirectory();
67
+ } catch {
68
+ return !1;
69
+ }
70
+ }
71
+ function k(e, t = _()) {
22
72
  let n = e.find((e) => !e.startsWith("-"));
23
- return n ? c(n) : t;
24
- }
25
- function h(t) {
26
- if (t.includes(i.help) || t.includes("-h")) return p;
27
- if (t.includes(i.version) || t.includes("-v")) return [`tracerkit/${d}`];
28
- let o = t[0], s = t.slice(1);
29
- if (e.includes(o)) return [`"${o}" has been removed — skills handle this now.`, "Run `tracerkit update` to get the latest skills."];
30
- switch (o) {
31
- case "init": return n(m(s));
73
+ return n ? h(n) : t;
74
+ }
75
+ function A(e) {
76
+ if (e.includes(t.help) || e.includes("-h")) return D;
77
+ if (e.includes(t.version) || e.includes("-v")) return [`tracerkit/${T}`];
78
+ let n = e[0], r = e.slice(1);
79
+ if (s.includes(n)) return [`"${n}" has been removed — skills handle this now.`, "Run `tracerkit update` to get the latest skills."];
80
+ switch (n) {
81
+ case "init": return o(k(r));
32
82
  case "update": {
33
- let e = s.includes(i.force), t = r(m(s.filter((e) => e !== i.force)), { force: e });
34
- return t.push("", "Updated to the latest TracerKit."), t.push("If using Claude Code, restart your session to load changes."), t;
83
+ let e = r.includes(t.force), n = c(k(r.filter((e) => e !== t.force)), { force: e });
84
+ return n.push("", "Updated to the latest TracerKit."), n.push("If using Claude Code, restart your session to load changes."), n;
85
+ }
86
+ case "config": {
87
+ let e = O(r[0]);
88
+ return v(e ? h(r[0]) : process.cwd(), e ? r.slice(1) : r);
35
89
  }
36
- case "uninstall": return a(m(s));
37
- default: return p;
90
+ case "uninstall": return l(k(r));
91
+ default: return D;
38
92
  }
39
93
  }
40
94
  //#endregion
41
95
  //#region src/bin.ts
42
- var g = h(process.argv.slice(2));
43
- for (let e of g) console.log(e);
96
+ var j = A(process.argv.slice(2));
97
+ for (let e of j) console.log(e);
44
98
  //#endregion
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { c as e, i as t, n, o as r, r as i, t as a } from "./uninstall-BhTMOfMb.js";
2
- export { t as COMMANDS, r as DEPRECATED_SKILLS, e as SKILL_NAMES, n as init, a as uninstall, i as update };
1
+ import { a as e, l as t, n, r, s as i, t as a } from "./uninstall-9tiXr-15.js";
2
+ export { e as COMMANDS, i as DEPRECATED_SKILLS, t as SKILL_NAMES, n as init, a as uninstall, r as update };
@@ -0,0 +1,205 @@
1
+ import { existsSync as e, mkdirSync as t, readFileSync as n, readdirSync as r, rmSync as i, writeFileSync as a } from "node:fs";
2
+ import { dirname as o, join as s } from "node:path";
3
+ import { createHash as c } from "node:crypto";
4
+ import { fileURLToPath as l } from "node:url";
5
+ //#region src/config.ts
6
+ var u = "local", d = [u, "github"], f = {
7
+ prds: ".tracerkit/prds",
8
+ plans: ".tracerkit/plans",
9
+ archives: ".tracerkit/archives"
10
+ }, p = { labels: {
11
+ prd: "tk:prd",
12
+ plan: "tk:plan"
13
+ } };
14
+ function m(t) {
15
+ let r = s(t, ".tracerkit", "config.json");
16
+ if (!e(r)) return {
17
+ storage: u,
18
+ paths: { ...f },
19
+ github: { ...p }
20
+ };
21
+ let i;
22
+ try {
23
+ i = JSON.parse(n(r, "utf8"));
24
+ } catch {
25
+ throw Error("Invalid .tracerkit/config.json — expected valid JSON");
26
+ }
27
+ return {
28
+ storage: h(i.storage),
29
+ paths: g(i.paths),
30
+ github: _(i.github)
31
+ };
32
+ }
33
+ function h(e) {
34
+ return typeof e == "string" && d.includes(e) ? e : u;
35
+ }
36
+ function g(e) {
37
+ let t = b(e) ? e : {};
38
+ return {
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
+ };
43
+ }
44
+ function _(e) {
45
+ let t = b(e) ? e : {}, n = b(t.labels) ? t.labels : {};
46
+ return {
47
+ ...typeof t.repo == "string" ? { repo: t.repo } : {},
48
+ labels: {
49
+ prd: typeof n.prd == "string" ? n.prd : p.labels.prd,
50
+ plan: typeof n.plan == "string" ? n.plan : p.labels.plan
51
+ }
52
+ };
53
+ }
54
+ function v(r, i) {
55
+ let c = s(r, ".tracerkit", "config.json");
56
+ t(o(c), { recursive: !0 });
57
+ let l = {};
58
+ if (e(c)) try {
59
+ l = JSON.parse(n(c, "utf8"));
60
+ } catch {
61
+ l = {};
62
+ }
63
+ let u = y(l, i);
64
+ a(c, JSON.stringify(u, null, 2) + "\n");
65
+ }
66
+ function y(e, t) {
67
+ let n = { ...e };
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
+ return n;
70
+ }
71
+ function b(e) {
72
+ return typeof e == "object" && !!e && !Array.isArray(e);
73
+ }
74
+ var x = [
75
+ "tk:brief",
76
+ "tk:prd",
77
+ "tk:plan",
78
+ "tk:check"
79
+ ], S = ["tk:verify"], C = {
80
+ force: "--force",
81
+ help: "--help",
82
+ version: "--version"
83
+ }, w = [
84
+ "brief",
85
+ "progress",
86
+ "archive"
87
+ ], T = [
88
+ {
89
+ name: "init",
90
+ args: "[path]",
91
+ desc: "Install skills to ~/.claude/skills/ (or [path] if given)"
92
+ },
93
+ {
94
+ name: "update",
95
+ args: "[path]",
96
+ desc: "Refresh unchanged files from latest version, skip modified"
97
+ },
98
+ {
99
+ name: "config",
100
+ args: "[path] [key] [value]",
101
+ desc: "Get or set TracerKit configuration"
102
+ },
103
+ {
104
+ name: "uninstall",
105
+ args: "[path]",
106
+ desc: "Remove TracerKit skill directories, keep .tracerkit/ artifacts"
107
+ }
108
+ ], E = s(o(l(import.meta.url)), "..", "skills");
109
+ function D(e, t = "") {
110
+ let n = r(e, { withFileTypes: !0 }), i = [];
111
+ for (let r of n) {
112
+ let n = t ? `${t}/${r.name}` : r.name;
113
+ r.isDirectory() ? i.push(...D(s(e, r.name), n)) : i.push(n);
114
+ }
115
+ return i.sort();
116
+ }
117
+ function O(e) {
118
+ return `.claude/skills/tk:${e}`;
119
+ }
120
+ function k(e) {
121
+ return e.slice(18);
122
+ }
123
+ function A(e, t) {
124
+ let n = e;
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;
126
+ }
127
+ function j(e, r, i) {
128
+ let c = i ?? D(E).map(O);
129
+ for (let i of c) {
130
+ let c = s(E, k(i)), l = s(e, i);
131
+ t(o(l), { recursive: !0 }), a(l, A(n(c, "utf8"), r));
132
+ }
133
+ return { copied: c };
134
+ }
135
+ function M(e) {
136
+ return c("sha256").update(e).digest("hex");
137
+ }
138
+ function N(t, r) {
139
+ let i = D(E).map(O), a = [], o = [], c = [];
140
+ for (let l of i) {
141
+ let i = s(t, l);
142
+ if (!e(i)) c.push(l);
143
+ else {
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);
146
+ }
147
+ }
148
+ return {
149
+ unchanged: a,
150
+ modified: o,
151
+ missing: c
152
+ };
153
+ }
154
+ //#endregion
155
+ //#region src/commands/update.ts
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) {
160
+ let r = s(t, ".claude", "skills", n);
161
+ e(r) && (i(r, {
162
+ recursive: !0,
163
+ force: !0
164
+ }), l.push(`✗ .claude/skills/${n}/ removed (deprecated)`));
165
+ }
166
+ let u = n?.force ?? !1, d = [
167
+ ...a,
168
+ ...c,
169
+ ...u ? o : []
170
+ ];
171
+ if (d.length > 0) {
172
+ j(t, r, d);
173
+ for (let e of a) l.push(`✓ ${e}`);
174
+ for (let e of c) l.push(`✓ ${e} (added)`);
175
+ if (u) for (let e of o) l.push(`✓ ${e} (replaced)`);
176
+ }
177
+ if (!u && o.length > 0) {
178
+ for (let e of o) l.push(`⚠ ${e} (skipped — modified)`);
179
+ l.push("", "Run `tracerkit update --force` to replace modified files with latest versions.");
180
+ }
181
+ return l;
182
+ }
183
+ //#endregion
184
+ //#region src/commands/init.ts
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}`);
189
+ }
190
+ //#endregion
191
+ //#region src/commands/uninstall.ts
192
+ function I(t) {
193
+ if (!x.some((n) => e(s(t, ".claude", "skills", n)))) throw Error("TracerKit not initialized — nothing to uninstall");
194
+ let n = [];
195
+ for (let r of x) {
196
+ let a = s(t, ".claude", "skills", r);
197
+ e(a) && (i(a, {
198
+ recursive: !0,
199
+ force: !0
200
+ }), n.push(`✗ .claude/skills/${r}/ removed`));
201
+ }
202
+ return n;
203
+ }
204
+ //#endregion
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tracerkit",
3
- "version": "1.11.3",
3
+ "version": "1.13.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": {
@@ -2,45 +2,62 @@
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
- Get a quick overview of all active features, their progress, and what to focus on next.
9
+ Overview of active features, progress, and suggested focus.
8
10
 
9
11
  ## Pre-loaded context
10
12
 
13
+ <!-- if:local -->
14
+
11
15
  - Available PRDs: !`ls .tracerkit/prds/ 2>&1`
16
+ <!-- end:local -->
17
+ <!-- if:github -->
18
+ - Available PRDs: list open GitHub Issues with label `{{github.labels.prd}}`
19
+ <!-- end:github -->
12
20
 
13
21
  ## Algorithm
14
22
 
15
- Follow these steps exactly to build the briefing table:
16
-
17
23
  ### 1. Discover features
18
24
 
19
- For each `.md` file in `.tracerkit/prds/`:
25
+ <!-- if:local -->
26
+
27
+ For each `.md` file in `.tracerkit/prds/`: parse frontmatter, extract `status` and `created`. Skip `status: done`. Slug = filename without `.md`.
20
28
 
21
- 1. Read the file
22
- 2. Parse YAML frontmatter (the block between `---` fences at the top)
23
- 3. Extract `status` and `created` fields
24
- 4. Skip files where `status: done`
25
- 5. The slug is the filename without `.md`
29
+ <!-- end:local -->
30
+ <!-- if:github -->
31
+
32
+ List open GitHub Issues with label `{{github.labels.prd}}`:
33
+
34
+ 6. For each issue, parse the `<!-- tk:metadata -->` comment in the body
35
+ 7. Extract `status` and `created` fields from the metadata
36
+ 8. Also check labels: `tk:created`, `tk:in-progress`
37
+ 9. Skip issues with `tk:done` label
38
+ 10. The slug is extracted from the title: `[{{github.labels.prd}}] <slug>: ...`
39
+ <!-- end:github -->
26
40
 
27
41
  ### 2. Count progress from plans
28
42
 
29
- For each slug, check if `.tracerkit/plans/<slug>.md` exists. If it does:
43
+ <!-- if:local -->
44
+
45
+ For each slug with a plan at `.tracerkit/plans/<slug>.md`:
30
46
 
31
- 1. Read the plan file
32
- 2. Find every `## Phase N` heading (regex: `^## Phase \d+`)
33
- 3. Within each phase section (until the next `## ` heading), count:
34
- - Checked items: lines matching `^- \[x\] ` (case-insensitive)
35
- - Unchecked items: lines matching `^- \[ \] `
36
- 4. Sum checked and total across all phases → `checked/total`
37
- 5. Find the first unchecked item (`^- \[ \] (.+)`) in the entire plan — that's the "Next" value. Strip any trailing `[tag]` markers.
47
+ Count `- [x]` and `- [ ]` lines under each `## Phase N` heading. Sum `checked/total`. First unchecked item → "Next" (strip trailing `[tag]`). No plan → `—`.
38
48
 
39
- If no plan exists, progress is `—` and next is `—`.
49
+ <!-- end:local -->
50
+ <!-- if:github -->
51
+
52
+ For each slug, find plan issue with label `{{github.labels.plan}}` and matching title. If found:
53
+
54
+ Count `- [x]` and `- [ ]` lines under each `## Phase N` heading. Sum → `checked/total`. First unchecked item → "Next" (strip trailing `[tag]`). No plan → `—`.
55
+
56
+ <!-- end:github -->
40
57
 
41
58
  ### 3. Build the table
42
59
 
43
- Sort features by `created` date ascending (no-date entries last). Calculate age from `created`:
60
+ Sort by `created` ascending (no-date last). Age from `created`:
44
61
 
45
62
  - < 7 days → `Nd` (e.g. `3d`)
46
63
  - < 30 days → `Nw` (e.g. `2w`)
@@ -72,8 +89,13 @@ Append below the table:
72
89
 
73
90
  ### 5. Offer next steps
74
91
 
75
- Ask the user what they'd like to do:
92
+ <!-- if:local -->
93
+
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.
76
100
 
77
- - Continue the focused feature (read its plan at `.tracerkit/plans/<slug>.md`)
78
- - Start a new feature with `/tk:prd`
79
- - Check progress on a feature with `/tk:check <slug>`
101
+ <!-- end:github -->
@@ -3,13 +3,21 @@ 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.
9
11
 
10
12
  ## Pre-loaded context
11
13
 
14
+ <!-- if:local -->
15
+
12
16
  - Available plans: !`ls .tracerkit/plans/ 2>&1`
17
+ <!-- end:local -->
18
+ <!-- if:github -->
19
+ - Available plans: list open GitHub Issues with label `{{github.labels.plan}}`
20
+ <!-- end:github -->
13
21
 
14
22
  ## Input
15
23
 
@@ -25,38 +33,60 @@ If no argument is provided, build a summary table before asking which one to che
25
33
  | <slug> | ... | 3/7 |
26
34
  ```
27
35
 
36
+ <!-- if:local -->
37
+
28
38
  For each `.md` file in `.tracerkit/prds/`:
29
39
 
30
40
  1. Read the file, parse YAML frontmatter (block between `---` fences)
31
41
  2. Extract `status` — use `unknown` if missing
32
42
  3. If `.tracerkit/plans/<slug>.md` exists, count progress (see Progress Algorithm below). Show `—` if no plan.
43
+ <!-- end:local -->
44
+ <!-- if:github -->
33
45
 
34
- After the table, ask which feature to verify.
46
+ List open GitHub Issues with label `{{github.labels.prd}}`:
35
47
 
36
- ## Progress Algorithm
48
+ 4. For each PRD issue, extract `status` from labels (`tk:created`, `tk:in-progress`)
49
+ 5. Find matching plan issue with label `{{github.labels.plan}}` and same slug in title
50
+ 6. If plan issue exists, count progress from checkboxes in its body (see Progress Algorithm below). Show `—` if no plan.
51
+ <!-- end:github -->
37
52
 
38
- To count progress for a plan file:
53
+ Ask which feature to verify.
39
54
 
40
- 1. Find every `## Phase N` heading (regex: `^## Phase \d+`)
41
- 2. Within each phase section (until the next `## ` heading), count:
42
- - Checked: lines matching `^- \[x\] ` (case-insensitive)
43
- - Unchecked: lines matching `^- \[ \] `
44
- 3. Per-phase output: ` Phase N — title: checked/total`
45
- 4. Sum across all phases → `Total: checked/total`
55
+ ## Progress Algorithm
56
+
57
+ Count `- [x]` and `- [ ]` lines under each `## Phase N` heading. Per-phase: `Phase N — title: checked/total`. Sum → `Total: checked/total`.
46
58
 
47
59
  ## Workflow
48
60
 
49
61
  ### 1. Load the plan
50
62
 
51
- Read `.tracerkit/plans/<slug>.md`. If it does not exist, list available plans and ask.
63
+ <!-- if:local -->
64
+
65
+ Read `.tracerkit/plans/<slug>.md`. If missing, list plans and ask.
66
+
67
+ <!-- end:local -->
68
+ <!-- if:github -->
69
+
70
+ Find plan issue: open issue with label `{{github.labels.plan}}`, title matching `[{{github.labels.plan}}] <slug>:`. If missing, list plans and ask.
71
+
72
+ <!-- end:github -->
52
73
 
53
74
  ### 2. Load the PRD
54
75
 
55
- Read the source PRD referenced in the plan header (`> Source PRD: ...`).
76
+ <!-- if:local -->
77
+
78
+ Read source PRD referenced in plan header (`> Source PRD: ...`).
79
+
80
+ <!-- end:local -->
81
+ <!-- if:github -->
82
+
83
+ Read source PRD issue referenced in plan body (`> Source PRD: #<number>`).
84
+
85
+ <!-- end:github -->
56
86
 
57
87
  ### 3. Fast-path: check if implementation exists
58
88
 
59
- Before launching a subagent, check whether the primary module file(s) from Phase 1 exist. If none exist, skip the subagent entirely and report `0/N — not yet started`. List Phase 1's "Done when" items as next steps and jump to Step 5.
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.
60
90
 
61
91
  ### 3b. Launch read-only review
62
92
 
@@ -76,8 +106,17 @@ Collect findings into two categories:
76
106
 
77
107
  ### 3c. Update checkboxes
78
108
 
109
+ <!-- if:local -->
110
+
79
111
  Using the subagent's report, update each checkbox in `.tracerkit/plans/<slug>.md` to `[x]` or `[ ]`.
80
112
 
113
+ <!-- end:local -->
114
+ <!-- if:github -->
115
+
116
+ Using the subagent's report, update each checkbox in the plan issue body to `[x]` or `[ ]` by editing the issue.
117
+
118
+ <!-- end:github -->
119
+
81
120
  ### 4. Determine outcome
82
121
 
83
122
  Based on checks and findings, decide the status transition:
@@ -88,7 +127,7 @@ Based on checks and findings, decide the status transition:
88
127
 
89
128
  ### 5. Report to user
90
129
 
91
- Count progress per phase using the Progress Algorithm above, then print the verdict report:
130
+ Count progress per phase (Progress Algorithm), then print:
92
131
 
93
132
  ```markdown
94
133
  ## Verification: <slug>
@@ -112,8 +151,17 @@ Total: checked/total
112
151
 
113
152
  ### 6. Stamp the plan
114
153
 
154
+ <!-- if:local -->
155
+
115
156
  Append a verdict block at the bottom of `.tracerkit/plans/<slug>.md`:
116
157
 
158
+ <!-- end:local -->
159
+ <!-- if:github -->
160
+
161
+ Append a verdict block at the bottom of the plan issue body by editing the issue:
162
+
163
+ <!-- end:github -->
164
+
117
165
  ```markdown
118
166
  ---
119
167
 
@@ -129,21 +177,25 @@ If a previous verdict block exists, replace it with the new one.
129
177
 
130
178
  ### 7. On `done` — archive
131
179
 
132
- If all checks pass and zero BLOCKERS, perform these steps in order:
180
+ If all checks pass and zero BLOCKERS:
181
+
182
+ <!-- if:local -->
183
+
184
+ Archive to `.tracerkit/archives/<slug>/`:
185
+
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
133
189
 
134
- 1. Create directory `.tracerkit/archives/<slug>/`
135
- 2. If `.tracerkit/prds/<slug>.md` exists:
136
- - Read the PRD file
137
- - 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.
138
- - Add a `completed: <current UTC ISO 8601 timestamp>` line inside the frontmatter block (e.g. `completed: 2025-06-15T14:30:00Z`)
139
- - Write the updated content to `.tracerkit/archives/<slug>/prd.md`
140
- 3. Read `.tracerkit/plans/<slug>.md`
141
- - Append to the end: `\n## Archived\n\nArchived on YYYY-MM-DD.\n`
142
- - Write the result to `.tracerkit/archives/<slug>/plan.md`
143
- 4. Delete `.tracerkit/prds/<slug>.md` (if it exists)
144
- 5. Delete `.tracerkit/plans/<slug>.md`
190
+ <!-- end:local -->
191
+ <!-- if:github -->
145
192
 
146
- Tell the user: archived to `.tracerkit/archives/<slug>/`, 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
197
+
198
+ <!-- end:github -->
147
199
 
148
200
  ### 8. On `in_progress` (no blockers)
149
201
 
@@ -159,10 +211,3 @@ List the blockers to fix, then re-run `/tk:check <slug>`.
159
211
  - The only file writes this skill makes are: checkboxes + verdict block in the plan, and the archive steps on `done`
160
212
  - Never modify implementation code — only observe and report
161
213
  - If the PRD file is missing but all checks pass, warn and proceed — archive the plan only (skip PRD steps in archive)
162
-
163
- ## Error Handling
164
-
165
- - Plan not found — list available plans and ask
166
- - PRD referenced in plan not found — warn and continue with plan checks only
167
- - `.tracerkit/plans/` missing — tell user to run `/tk:plan` first
168
- - `.tracerkit/archives/<slug>/` already exists — warn and ask whether to remove it first
@@ -1,41 +1,76 @@
1
1
  ---
2
- description: Turn a PRD into a multi-phase implementation plan using tracer-bullet vertical slices, saved to .tracerkit/plans/. Use after /tk:prd.
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
- Break a PRD into phased vertical slices (tracer bullets). Output: `.tracerkit/plans/<slug>.md`.
10
+ Break a PRD into phased vertical slices (tracer bullets).
11
+
12
+ <!-- if:local -->
13
+
14
+ Output: `.tracerkit/plans/<slug>.md`.
15
+
16
+ <!-- end:local -->
17
+ <!-- if:github -->
18
+
19
+ Output: a GitHub Issue with label `{{github.labels.plan}}`.
20
+
21
+ <!-- end:github -->
9
22
 
10
23
  ## Pre-loaded context
11
24
 
25
+ <!-- if:local -->
26
+
12
27
  - Available PRDs: !`ls .tracerkit/prds/ 2>&1`
28
+ <!-- end:local -->
29
+ <!-- if:github -->
30
+ - Available PRDs: list open GitHub Issues with label `{{github.labels.prd}}`
31
+ <!-- end:github -->
13
32
 
14
33
  ## Input
15
34
 
16
35
  The argument (if provided) is: $ARGUMENTS
17
36
 
18
- Use the argument as `<slug>` if given. If no argument is provided, list available PRDs and ask which one to plan.
37
+ Use argument as `<slug>`. If empty, list available PRDs and ask.
19
38
 
20
39
  ## Workflow
21
40
 
22
41
  ### 1. Read the PRD
23
42
 
24
- Read `.tracerkit/prds/<slug>.md`. If it does not exist, list available PRDs and ask.
43
+ <!-- if:local -->
44
+
45
+ Read `.tracerkit/prds/<slug>.md`. If missing, list PRDs and ask. If `.tracerkit/plans/<slug>.md` exists, ask: overwrite or new name?
25
46
 
26
- If `.tracerkit/plans/<slug>.md` already exists, tell the user and ask whether to overwrite or pick a new name.
47
+ <!-- end:local -->
48
+ <!-- if:github -->
49
+
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?
51
+
52
+ <!-- end:github -->
27
53
 
28
54
  ### 1b. Update PRD status
29
55
 
30
- Update the YAML frontmatter in `.tracerkit/prds/<slug>.md` to `status: in_progress`. Change only the `status` field — do not touch any other frontmatter fields or the markdown content below the closing `---`.
56
+ <!-- if:local -->
57
+
58
+ Set `status: in_progress` in `.tracerkit/prds/<slug>.md` frontmatter. Change only `status`.
59
+
60
+ <!-- end:local -->
61
+ <!-- if:github -->
31
62
 
32
- If the PRD has no frontmatter, skip this step silently.
63
+ Update the PRD issue:
64
+
65
+ - Remove `tk:created` label, add `tk:in-progress` label
66
+ - Update the `<!-- tk:metadata -->` comment in the issue body to `status: in_progress`
67
+ <!-- end:github -->
33
68
 
34
69
  ### 2. Explore the codebase
35
70
 
36
- Understand current architecture, existing patterns, and integration points. If you already have codebase context from a prior step in this conversation (e.g., you just ran `/tk:prd`), skip the exploration and note which context you're reusing.
71
+ Map architecture, patterns, integration points. Skip if codebase context exists from prior step.
37
72
 
38
- **Research protocol**: codebase first, then project docs. If you cannot verify a technical claim from these sources, flag it as uncertain never fabricate.
73
+ **Research protocol**: codebase first, then docs. Unverifiable claims flag as uncertain, never fabricate.
39
74
 
40
75
  ### 3. Identify durable architectural decisions
41
76
 
@@ -49,7 +84,7 @@ Before slicing, extract decisions that hold across all phases:
49
84
 
50
85
  ### 4. Draft vertical slices
51
86
 
52
- Each phase is a thin **tracer bullet** — a narrow but complete path through every integration layer (schema, service, API, UI, tests). A completed phase is demoable on its own.
87
+ Each phase: thin vertical slice through all layers (schema service API UI tests). Demoable alone.
53
88
 
54
89
  **Deriving tasks from the PRD:**
55
90
 
@@ -67,9 +102,9 @@ Each phase is a thin **tracer bullet** — a narrow but complete path through ev
67
102
 
68
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.
69
104
 
70
- **Done when:** write as a checkbox list of atomic, verifiable conditions not prose. Each item must pass this test: _"Can an agent verify this by reading files, running a command, or checking a test result — with no subjective judgment?"_ Bad: "API is clean". Good: "`GET /api/revenue` returns `{ total: number }`". The agent marks `[x]` during implementation to track progress.
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.
71
106
 
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.
107
+ **Layer-by-layer exception:** if complex schema changes underpin all modules and no story stands alone, build data foundation first, then slice vertically.
73
108
 
74
109
  **Phase count thresholds:**
75
110
 
@@ -87,23 +122,43 @@ Assign an agent tag to tasks where appropriate:
87
122
 
88
123
  ### 5. Quiz the user
89
124
 
90
- Present the breakdown. For each phase show:
91
-
92
- - **Title**: short goal phrase
93
- - **User stories covered**: which PRD stories this addresses
94
- - **Done when**: the testable condition
95
-
96
- 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.
97
126
 
98
127
  ### 6. Save plan
99
128
 
100
- Save to `.tracerkit/plans/<slug>.md` (create `.tracerkit/plans/` if missing).
129
+ <!-- if:local -->
130
+
131
+ Save to `.tracerkit/plans/<slug>.md` (create dir if missing).
101
132
 
102
133
  ```markdown
103
134
  # Plan: <Feature Name>
104
135
 
105
136
  > Source PRD: `.tracerkit/prds/<slug>.md`
137
+ ```
138
+
139
+ <!-- end:local -->
140
+ <!-- if:github -->
141
+
142
+ Ensure labels exist: `{{github.labels.plan}}`, `tk:in-progress` (create if missing).
143
+
144
+ Create GitHub Issue — title: `[{{github.labels.plan}}] <slug>: Plan: <Feature Title>`, labels: `{{github.labels.plan}}`, `tk:in-progress`.
145
+
146
+ ```markdown
147
+ <!-- tk:metadata
148
+ source_prd: #<PRD issue number>
149
+ slug: <slug>
150
+ -->
151
+
152
+ # Plan: <Feature Name>
106
153
 
154
+ > Source PRD: #<PRD issue number>
155
+ ```
156
+
157
+ <!-- end:github -->
158
+
159
+ Use this structure for the plan body:
160
+
161
+ ```markdown
107
162
  ## Architectural Decisions
108
163
 
109
164
  Durable decisions that apply across all phases:
@@ -138,7 +193,7 @@ Carried forward from PRD verbatim.
138
193
  Gaps found in the PRD needing resolution. Blank if none.
139
194
  ```
140
195
 
141
- Print saved path and one line per phase: `Phase N — <title> (<condition summary>)`. Then ask: "Run `/tk:check <slug>` when ready?"
196
+ Print one line per phase: `Phase N — <title> (<condition summary>)`. Then ask: "Run `/tk:check <slug>` when ready?"
142
197
 
143
198
  ## Rules
144
199
 
@@ -146,11 +201,10 @@ Print saved path and one line per phase: `Phase N — <title> (<condition summar
146
201
  - Each phase must be demoable end-to-end on its own
147
202
  - "Done when" must be a checkbox list of testable conditions, not prose
148
203
  - **Safety valve**: if a phase has >5 "Done when" items, stop and split it into smaller phases before continuing
204
+ <!-- if:local -->
149
205
  - Never modify the source PRD content — only update frontmatter status fields
206
+ <!-- end:local -->
207
+ <!-- if:github -->
208
+ - Never modify the source PRD content — only update metadata and labels
209
+ <!-- end:github -->
150
210
  - Carry PRD's Out of Scope forward verbatim
151
-
152
- ## Error Handling
153
-
154
- - PRD not found — list available PRDs and ask
155
- - PRD missing sections — note gaps inline and continue
156
- - `.tracerkit/plans/` missing — create it
@@ -1,23 +1,29 @@
1
1
  ---
2
- description: Create a PRD through user interview, codebase exploration, and module design, saved to .tracerkit/prds/. Use when starting a new feature or change.
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 already satisfied. If user provided a description via arguments, skip to Step 2.
10
+ Skip satisfied steps. If argument provided, skip to Step 2.
9
11
 
10
12
  ## Pre-loaded context
11
13
 
14
+ <!-- if:local -->
15
+
12
16
  - Existing PRDs: !`ls .tracerkit/prds/ 2>&1`
17
+ <!-- end:local -->
18
+ <!-- if:github -->
19
+ - Existing PRDs: list open GitHub Issues with label `{{github.labels.prd}}`
20
+ <!-- end:github -->
13
21
 
14
22
  ## Input
15
23
 
16
24
  The argument is: $ARGUMENTS
17
25
 
18
- If the argument is empty, go straight to Step 1 (gather problem description). After gathering the idea, derive the slug from the idea.
19
-
20
- 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:
21
27
 
22
28
  1. Take only the text before the first `—` or `–` (if present)
23
29
  2. Lowercase the text
@@ -25,9 +31,16 @@ If the argument is provided, derive a slug using this exact algorithm:
25
31
  4. Take the first 4 remaining words (or fewer if less exist)
26
32
  5. Join with hyphens → `<slug>`
27
33
 
28
- The output file is `.tracerkit/prds/<slug>.md`.
34
+ <!-- if:local -->
35
+
36
+ Output: `.tracerkit/prds/<slug>.md`. If exists, ask: overwrite or new name?
37
+
38
+ <!-- end:local -->
39
+ <!-- if:github -->
40
+
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?
29
42
 
30
- If `.tracerkit/prds/<slug>.md` already exists, tell the user and ask whether to overwrite or pick a new name.
43
+ <!-- end:github -->
31
44
 
32
45
  ## Workflow
33
46
 
@@ -37,129 +50,86 @@ Ask the user for a detailed description of the problem and any solution ideas.
37
50
 
38
51
  ### 2. Explore codebase
39
52
 
40
- Verify assertions and map current state: data models, services, API routes, frontend structure, and test patterns. Note what exists vs. what must be built.
53
+ Map current state: data models, services, API routes, frontend, tests. Note exists vs. must build.
41
54
 
42
- **Research protocol**: codebase first, then project docs. If you cannot verify a technical claim from these sources, flag it as uncertain never fabricate.
55
+ **Research protocol**: codebase first, then docs. Unverifiable claims flag as uncertain, never fabricate.
43
56
 
44
57
  ### 3. Interview
45
58
 
46
- 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).
47
-
48
- Walk these branches. **Skip rule**: skip a branch when the project type makes it irrelevant (e.g., skip Display/Access/Navigation for CLIs and libraries) AND the user's idea does not mention it.
49
-
50
- - **Scope & Surface** — Where does this live? New page/view or integrated? Which user roles? _Skip if_: single-surface project (CLI, library) with no new entry points.
51
- - **Data & Concepts** — Precise definitions for each new concept. What data exists, what's missing? _Never skip_ — every feature has data.
52
- - **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.
53
- - **Display & Output** — Numbers, tables, charts, forms? Exportable? URL-driven state? _Skip if_: no UI or formatted output involved.
54
- - **Access & Privacy** — Who sees what? Role-based restrictions? Sensitive data concerns? _Skip if_: single-user project with no auth layer.
55
- - **Boundaries** — What is explicitly out of scope? Adjacent features to defer? _Never skip_ — scope control prevents creep.
56
- - **Integration** — Schema changes? New or extended services? External dependencies? _Skip if_: self-contained change touching no external systems or storage.
57
-
58
- ### 3b. Gray area checkpoint
59
-
60
- Before continuing, scan the interview for gray areas. Something is a gray area if any of these are true:
61
-
62
- - **Vague answer**: user said "maybe", "probably", "I think", or gave a one-word answer to a multi-part question
63
- - **Contradiction**: two answers conflict (e.g., "no auth needed" but "only admins can access")
64
- - **Unstated assumption**: you filled in a detail the user never confirmed
65
- - **Ambiguous scope**: a feature boundary is unclear (could be in or out of scope)
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.
66
60
 
67
- Present as a numbered list:
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 |
68
70
 
69
- ```
70
- Gray areas found:
71
- 1. <ambiguity> — assumed <X>, confirm?
72
- 2. <ambiguity> — two options: A or B
73
- ```
71
+ ### 3b. Gray areas
74
72
 
75
- 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.
76
74
 
77
75
  ### 4. Design modules
78
76
 
79
- Sketch major modules to build or modify. Favor **deep modules** — a simple interface (13 entry points) hiding a large implementation that rarely changes, over shallow modules where the interface is nearly as complex as the implementation.
77
+ Sketch modules. Favor **deep modules** — simple interface (1-3 entry points) hiding large implementation over shallow modules where interface implementation.
80
78
 
81
- Signals of shallow design: many small functions with 1:1 query mapping, callers compose multiple calls, adding a feature requires changing the interface.
79
+ Shallow signals: many small 1:1 functions, callers compose multiple calls, feature changes require interface changes.
82
80
 
83
- Present modules to user. Confirm which need tests.
81
+ Present modules. Confirm which need tests.
84
82
 
85
83
  ### 5. Write PRD
86
84
 
87
- Save to `.tracerkit/prds/<slug>.md` (create `.tracerkit/prds/` if missing).
85
+ <!-- if:local -->
86
+
87
+ Save to `.tracerkit/prds/<slug>.md` (create dir if missing).
88
88
 
89
89
  ```markdown
90
90
  ---
91
- created: <current UTC timestamp, ISO 8601, e.g. 2025-06-15T14:30:00Z>
91
+ created: <UTC ISO 8601>
92
92
  status: created
93
93
  ---
94
94
 
95
95
  # Feature Name
96
+ ```
96
97
 
97
- ## Problem Statement
98
-
99
- The problem from the user's perspective. Focus on pain and impact.
100
-
101
- ## Current State
102
-
103
- What exists today that this feature changes or builds on. Skip for greenfield.
98
+ <!-- end:local -->
99
+ <!-- if:github -->
104
100
 
105
- - Relevant modules, services, or UI surfaces already in place
106
- - Current behavior the user experiences
107
- - Known limitations or workarounds
101
+ Ensure labels exist: `{{github.labels.prd}}`, `tk:created` (create if missing).
108
102
 
109
- ## Solution
103
+ Create GitHub Issue — title: `[{{github.labels.prd}}] <slug>: <Feature Title>`, labels: `{{github.labels.prd}}`, `tk:created`.
110
104
 
111
- The solution from the user's perspective. Describe the experience, not the architecture.
105
+ ```markdown
106
+ <!-- tk:metadata
107
+ created: <UTC ISO 8601>
108
+ status: created
109
+ -->
112
110
 
113
- ## User Stories
111
+ # Feature Name
112
+ ```
114
113
 
115
- Long numbered list. Cover happy path, edge cases, error states.
114
+ <!-- end:github -->
116
115
 
117
- 1. As a <actor>, I want <feature>, so that <benefit>
116
+ PRD body structure (same for local file and issue body). Omit empty sections. No file paths or code snippets.
118
117
 
118
+ ```
119
+ ## Problem Statement
120
+ ## Current State (skip if greenfield)
121
+ ## Solution (user experience, not architecture)
122
+ ## User Stories (numbered, cover happy + edge + error)
119
123
  ## Implementation Decisions
120
-
121
- ### New Modules
122
-
123
- - Module name, purpose, and public interface (function signatures with param types)
124
- - Why each module exists as a separate unit
125
-
126
- ### Architectural Decisions
127
-
128
- - Key definitions (precise meaning of domain terms)
129
- - Data flow from storage to display
130
- - State management approach
131
-
124
+ ### New Modules (name, purpose, interface signatures)
125
+ ### Architectural Decisions (definitions, data flow, state)
132
126
  ### Schema Changes
133
-
134
- - New tables/columns needed, or "None required"
135
-
136
127
  ### API Contracts
137
-
138
- - New routes, request/response shapes
139
-
140
128
  ### Navigation
141
-
142
- - Where the feature is accessed, new routes added
143
-
144
- Do NOT include file paths or code snippets — they go stale.
145
-
146
- Omit any section whose content would be "None required" — only include sections with actual content.
147
-
148
- ## Testing Decisions
149
-
150
- - What makes a good test (behavior, not implementation)
151
- - Which modules need tests
152
- - Key test cases (empty state, boundaries, isolation)
153
- - Prior art: similar test patterns in the codebase
154
-
155
- ## Out of Scope
156
-
157
- Explicit list. Be specific — vague exclusions invite scope creep.
129
+ ## Testing Decisions (behavior tests, key cases, prior art)
130
+ ## Out of Scope (be specific)
158
131
  ```
159
132
 
160
- Tell the user: file created, one-line summary. Then ask: "Run `/tk:plan <slug>` next?"
161
-
162
- ## Error Handling
133
+ ---
163
134
 
164
- - `.tracerkit/prds/` missing create it
165
- - Scope larger than expected — surface and re-scope with user before continuing
135
+ Then ask: "Run `/tk:plan <slug>` next?"
@@ -1,153 +0,0 @@
1
- import { existsSync as e, mkdirSync as t, readFileSync as n, readdirSync as r, rmSync as i, writeFileSync as a } from "node:fs";
2
- import { dirname as o, join as s } from "node:path";
3
- import { createHash as c } from "node:crypto";
4
- import { fileURLToPath as l } from "node:url";
5
- //#region src/config.ts
6
- var u = {
7
- prds: ".tracerkit/prds",
8
- plans: ".tracerkit/plans",
9
- archives: ".tracerkit/archives"
10
- };
11
- function d(t) {
12
- let r = s(t, ".tracerkit", "config.json");
13
- if (!e(r)) return { paths: { ...u } };
14
- let i, a;
15
- try {
16
- i = n(r, "utf8"), a = JSON.parse(i);
17
- } catch {
18
- throw Error("Invalid .tracerkit/config.json — expected valid JSON");
19
- }
20
- let o = typeof a.paths == "object" && a.paths !== null ? a.paths : {};
21
- return { paths: {
22
- prds: typeof o.prds == "string" ? o.prds : u.prds,
23
- plans: typeof o.plans == "string" ? o.plans : u.plans,
24
- archives: typeof o.archives == "string" ? o.archives : u.archives
25
- } };
26
- }
27
- var f = [
28
- "tk:brief",
29
- "tk:prd",
30
- "tk:plan",
31
- "tk:check"
32
- ], p = ["tk:verify"], m = {
33
- force: "--force",
34
- help: "--help",
35
- version: "--version"
36
- }, h = [
37
- "brief",
38
- "progress",
39
- "archive"
40
- ], g = [
41
- {
42
- name: "init",
43
- args: "[path]",
44
- desc: "Install skills to ~/.claude/skills/ (or [path] if given)"
45
- },
46
- {
47
- name: "update",
48
- args: "[path]",
49
- desc: "Refresh unchanged files from latest version, skip modified"
50
- },
51
- {
52
- name: "uninstall",
53
- args: "[path]",
54
- desc: "Remove TracerKit skill directories, keep .tracerkit/ artifacts"
55
- }
56
- ], _ = s(o(l(import.meta.url)), "..", "skills");
57
- function v(e, t = "") {
58
- let n = r(e, { withFileTypes: !0 }), i = [];
59
- for (let r of n) {
60
- let n = t ? `${t}/${r.name}` : r.name;
61
- r.isDirectory() ? i.push(...v(s(e, r.name), n)) : i.push(n);
62
- }
63
- return i.sort();
64
- }
65
- function y(e) {
66
- return `.claude/skills/tk:${e}`;
67
- }
68
- function b(e) {
69
- return e.slice(18);
70
- }
71
- function x(e, t) {
72
- let n = e;
73
- return t.paths.prds !== u.prds && (n = n.replaceAll(u.prds, t.paths.prds)), t.paths.plans !== u.plans && (n = n.replaceAll(u.plans, t.paths.plans)), t.paths.archives !== u.archives && (n = n.replaceAll(u.archives, t.paths.archives)), n;
74
- }
75
- function S(e, r, i) {
76
- let c = i ?? v(_).map(y);
77
- for (let i of c) {
78
- let c = s(_, b(i)), l = s(e, i);
79
- t(o(l), { recursive: !0 }), a(l, x(n(c, "utf8"), r));
80
- }
81
- return { copied: c };
82
- }
83
- function C(e) {
84
- return c("sha256").update(e).digest("hex");
85
- }
86
- function w(t, r) {
87
- let i = v(_).map(y), a = [], o = [], c = [];
88
- for (let l of i) {
89
- let i = s(t, l);
90
- if (!e(i)) c.push(l);
91
- else {
92
- let e = x(n(s(_, b(l)), "utf8"), r);
93
- C(Buffer.from(e)) === C(n(i)) ? a.push(l) : o.push(l);
94
- }
95
- }
96
- return {
97
- unchanged: a,
98
- modified: o,
99
- missing: c
100
- };
101
- }
102
- //#endregion
103
- //#region src/commands/update.ts
104
- function T(t, n) {
105
- if (!f.some((n) => e(s(t, ".claude", "skills", n)))) throw Error("TracerKit not initialized — run `tracerkit init` first");
106
- let r = d(t), { unchanged: a, modified: o, missing: c } = w(t, r), l = [];
107
- for (let n of p) {
108
- let r = s(t, ".claude", "skills", n);
109
- e(r) && (i(r, {
110
- recursive: !0,
111
- force: !0
112
- }), l.push(`✗ .claude/skills/${n}/ removed (deprecated)`));
113
- }
114
- let u = n?.force ?? !1, m = [
115
- ...a,
116
- ...c,
117
- ...u ? o : []
118
- ];
119
- if (m.length > 0) {
120
- S(t, r, m);
121
- for (let e of a) l.push(`✓ ${e}`);
122
- for (let e of c) l.push(`✓ ${e} (added)`);
123
- if (u) for (let e of o) l.push(`✓ ${e} (replaced)`);
124
- }
125
- if (!u && o.length > 0) {
126
- for (let e of o) l.push(`⚠ ${e} (skipped — modified)`);
127
- l.push("", "Run `tracerkit update --force` to replace modified files with latest versions.");
128
- }
129
- return l;
130
- }
131
- //#endregion
132
- //#region src/commands/init.ts
133
- function E(t) {
134
- if (f.some((n) => e(s(t, ".claude", "skills", n)))) return T(t);
135
- let { copied: n } = S(t, d(t));
136
- return n.map((e) => `✓ ${e}`);
137
- }
138
- //#endregion
139
- //#region src/commands/uninstall.ts
140
- function D(t) {
141
- if (!f.some((n) => e(s(t, ".claude", "skills", n)))) throw Error("TracerKit not initialized — nothing to uninstall");
142
- let n = [];
143
- for (let r of f) {
144
- let a = s(t, ".claude", "skills", r);
145
- e(a) && (i(a, {
146
- recursive: !0,
147
- force: !0
148
- }), n.push(`✗ .claude/skills/${r}/ removed`));
149
- }
150
- return n;
151
- }
152
- //#endregion
153
- export { h as a, f as c, g as i, E as n, p as o, T as r, m as s, D as t };