@jabworks/condux 0.2.0 → 0.3.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.
Files changed (48) hide show
  1. package/README.md +27 -29
  2. package/index.js +21 -0
  3. package/package.json +6 -4
  4. package/skills/code-review/SKILL.md +136 -0
  5. package/skills/code-review/evals/trigger_eval.json +22 -0
  6. package/skills/discovery/SKILL.md +242 -0
  7. package/skills/discovery/evals/trigger_eval.json +24 -0
  8. package/skills/discovery/references/choice-server.js +216 -0
  9. package/skills/discovery/references/mockup-picker.md +90 -0
  10. package/skills/discovery/references/package.json +3 -0
  11. package/skills/draft-plan/SKILL.md +229 -0
  12. package/skills/draft-plan/evals/trigger_eval.json +22 -0
  13. package/skills/draft-plan/references/plan-template.md +96 -0
  14. package/skills/finalize/SKILL.md +123 -0
  15. package/skills/finalize/evals/trigger_eval.json +22 -0
  16. package/skills/finalize/references/rationalization-table.md +15 -0
  17. package/skills/plan-review/SKILL.md +215 -0
  18. package/skills/plan-review/evals/trigger_eval.json +22 -0
  19. package/skills/plan-review/references/annotate-server.js +465 -0
  20. package/skills/plan-review/references/install-codex-hook.sh +112 -0
  21. package/skills/plan-review/references/package.json +3 -0
  22. package/skills/plan-review/references/plan-review-template.html +730 -0
  23. package/skills/preflight/SKILL.md +128 -0
  24. package/skills/preflight/evals/trigger_eval.json +26 -0
  25. package/skills/root-cause-analysis/SKILL.md +82 -0
  26. package/skills/root-cause-analysis/evals/trigger_eval.json +22 -0
  27. package/skills/subagent-deployment/SKILL.md +105 -0
  28. package/skills/subagent-deployment/evals/trigger_eval.json +22 -0
  29. package/skills/subagent-deployment/references/safety-checklist.md +54 -0
  30. package/skills/subagent-execution/SKILL.md +182 -0
  31. package/skills/subagent-execution/agents/coder.md +55 -0
  32. package/skills/subagent-execution/agents/explorer.md +77 -0
  33. package/skills/subagent-execution/agents/planner.md +101 -0
  34. package/skills/subagent-execution/agents/researcher.md +78 -0
  35. package/skills/subagent-execution/evals/trigger_eval.json +22 -0
  36. package/skills/subagent-execution/references/install-codex-agents.mjs +98 -0
  37. package/skills/subagent-execution/references/review-package.sh +29 -0
  38. package/skills/subagent-execution/references/spawn-rules.md +88 -0
  39. package/skills/subagent-execution/references/task-brief.sh +39 -0
  40. package/skills/technical-spec/SKILL.md +190 -0
  41. package/skills/technical-spec/evals/trigger_eval.json +23 -0
  42. package/skills/technical-spec/references/scaffold.sh +98 -0
  43. package/skills/technical-spec/references/templates.md +159 -0
  44. package/skills/test-first-development/SKILL.md +121 -0
  45. package/skills/test-first-development/evals/trigger_eval.json +22 -0
  46. package/skills/test-first-development/references/rationalization-table.md +16 -0
  47. package/skills/workflow/SKILL.md +241 -0
  48. package/skills/workflow/evals/trigger_eval.json +30 -0
@@ -0,0 +1,190 @@
1
+ ---
2
+ name: technical-spec
3
+ description: Use when a feature plan, design session, or implementation milestone is complete and the decisions, API contracts, implementation details, and quirks should be persisted for future reference. Also use when the user says "save spec", "document this", "write up what we decided", or "spec this out".
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # Save Tech Spec
8
+
9
+ ## Overview
10
+
11
+ Persists feature decisions, API contracts, implementation details, and quirks into a structured, queryable spec tree. One folder per feature, one file per concern — future sessions load only what they need. Specs are living contracts: `/preflight`'s Drift Check compares the implementation against them at end-of-task.
12
+
13
+ ## Spec Folder Layout
14
+
15
+ All specs live under one `specs/` tree at the **git root**, mirroring the
16
+ repo structure. The scaffold script detects the nearest package root (walking
17
+ up from CWD to the git root, finding the first `package.json`, `Cargo.toml`,
18
+ `go.mod`, or `pyproject.toml`) and uses its path *relative to the git root*
19
+ to place the spec.
20
+
21
+ ```
22
+ <git-root>/specs/
23
+ {feature-slug}/ # cross-cutting, or scaffolded from the repo root
24
+ apps/web/
25
+ {feature-slug}/ # scaffolded while working in apps/web
26
+ index.md # TOC, last updated, commit hash, changelog ← scaffold creates this
27
+ decisions.md # Design decisions with context + rationale
28
+ api.md # Endpoints, types, external APIs consumed
29
+ fields.md # Field mappings: BE/3rd-party → UI, or forwarding chains
30
+ implementation.md # Key files, patterns, how it hangs together
31
+ quirks.md # Edge cases, gotchas, known issues
32
+ ```
33
+
34
+ Slugs are kebab-case and acronym-aware: `WanConfig` → `wan-config`,
35
+ `UIFormControls` → `ui-form-controls`.
36
+
37
+ In a single-package repo the package root is the git root, so specs land at
38
+ `specs/<slug>/`. In a monorepo working on `apps/web`, they land at
39
+ `specs/apps/web/<slug>/` — one browsable tree, with a natural home for
40
+ cross-cutting features at `specs/<slug>/`.
41
+
42
+ Existing specs co-located inside packages (`apps/web/specs/…`) are not
43
+ auto-migrated — `git mv` them into the root tree if you want them unified.
44
+
45
+ Only create files that have actual content. Don't create empty files.
46
+
47
+ ## Workflow
48
+
49
+ ```dot
50
+ digraph save_spec {
51
+ rankdir=TB;
52
+ "Infer feature name from context" [shape=box];
53
+ "Feature name clear?" [shape=diamond];
54
+ "Ask user for feature name" [shape=box];
55
+ "Notify user — confirm before writing" [shape=box];
56
+ "User approves?" [shape=diamond];
57
+ "Stop" [shape=box];
58
+ "Run scaffold.sh <feature>" [shape=box];
59
+ "Output: exists or created?" [shape=diamond];
60
+ "Write content files, update index.md Contents" [shape=box];
61
+ "Read index.md, update changed files only" [shape=box];
62
+ "Ask: open live HTML preview?" [shape=diamond];
63
+ "Locate + run plan-review annotate-server.js on the spec dir" [shape=box];
64
+ "Tell user: Ctrl+C when done reviewing" [shape=box];
65
+ "Done" [shape=doublecircle];
66
+
67
+ "Infer feature name from context" -> "Feature name clear?";
68
+ "Feature name clear?" -> "Notify user — confirm before writing" [label="yes"];
69
+ "Feature name clear?" -> "Ask user for feature name" [label="no"];
70
+ "Ask user for feature name" -> "Notify user — confirm before writing";
71
+ "Notify user — confirm before writing" -> "User approves?";
72
+ "User approves?" -> "Stop" [label="no"];
73
+ "User approves?" -> "Run scaffold.sh <feature>" [label="yes"];
74
+ "Run scaffold.sh <feature>" -> "Output: exists or created?";
75
+ "Output: exists or created?" -> "Write content files, update index.md Contents" [label="created"];
76
+ "Output: exists or created?" -> "Read index.md, update changed files only" [label="exists"];
77
+ "Write content files, update index.md Contents" -> "Ask: open live HTML preview?";
78
+ "Read index.md, update changed files only" -> "Ask: open live HTML preview?";
79
+ "Ask: open live HTML preview?" -> "Locate + run plan-review annotate-server.js on the spec dir" [label="yes"];
80
+ "Ask: open live HTML preview?" -> "Done" [label="no"];
81
+ "Locate + run plan-review annotate-server.js on the spec dir" -> "Tell user: Ctrl+C when done reviewing";
82
+ "Tell user: Ctrl+C when done reviewing" -> "Done";
83
+ }
84
+ ```
85
+
86
+ ## Required Notifications
87
+
88
+ Always announce and confirm before writing or editing. Never silently modify files.
89
+
90
+ New spec:
91
+ ```
92
+ About to save tech spec for `wan-config` → specs/wan-config/
93
+ Proceed? [y/n]
94
+ ```
95
+
96
+ Updating existing spec:
97
+ ```
98
+ Updating spec for `wan-config` (last saved: 2026-06-20, commit abc1234)
99
+ Files to update: decisions.md, quirks.md
100
+ Proceed? [y/n]
101
+ ```
102
+
103
+ ## Running the Scaffold Script
104
+
105
+ The script lives next to this skill file. Find it relative to where this SKILL.md was loaded from:
106
+
107
+ ```bash
108
+ bash path/to/skill/references/scaffold.sh "WanConfig"
109
+ ```
110
+
111
+ The script outputs one line:
112
+ - `created:/abs/path/to/specs/wan-config commit:abc1234 date:2026-06-24` — new spec, `index.md` written
113
+ - `exists:/abs/path/to/specs/wan-config commit:abc1234 date:2026-06-24` — spec already exists
114
+
115
+ Parse `commit`, `date`, and the **absolute spec path** from the output — use the absolute path when writing content files and launching the preview server.
116
+
117
+ ## After Scaffold: Writing Content Files
118
+
119
+ Read [references/templates.md](references/templates.md) for the structure of each file.
120
+
121
+ - Write only files that have real content
122
+ - After writing, update the `## Contents` section in `index.md` with links to the files you created
123
+
124
+ ## Updating an Existing Spec
125
+
126
+ When scaffold output is `exists:`:
127
+ 1. Read `index.md` to see current state and which files exist
128
+ 2. Update only files with new or changed content
129
+ 3. Bump `Last updated` and `Commit` in `index.md` using values from scaffold output
130
+ 4. Append to the `## Changelog` in `index.md`
131
+
132
+ ## Live HTML Preview & Review (Optional)
133
+
134
+ Spec preview is served by the **plan-review** skill's annotate server in
135
+ directory mode — the same annotation UI used for plan review, so the user can
136
+ not only read the spec live but select text, attach notes per file, and submit
137
+ a decision.
138
+
139
+ After writing spec files, ask:
140
+
141
+ ```
142
+ Spec saved. Want a live HTML preview? It renders all spec files, updates as you edit, and lets you annotate. [y/n]
143
+ ```
144
+
145
+ If yes, locate the plan-review server script:
146
+
147
+ ```bash
148
+ find ~/.claude ~/.codex ~/.agents -name "annotate-server.js" -path "*plan-review*" 2>/dev/null | head -1
149
+ ```
150
+
151
+ Run it in the background, pointing at the spec folder:
152
+
153
+ ```bash
154
+ node /path/to/plan-review/references/annotate-server.js specs/wan-config
155
+ ```
156
+
157
+ It opens the browser automatically, lists every top-level `.md` in the folder
158
+ (Contents tab), watches for file changes, and re-renders live. If the user
159
+ submits a decision, it lands in `specs/<slug>/review.feedback.md` with notes
160
+ grouped by file — read it and action it:
161
+
162
+ - **Approve** — the spec is accurate; nothing to do.
163
+ - **Request Revisions** — fix the spec files per the notes.
164
+
165
+ Spec review is accept-or-fix, so the bar shows only these two verdicts (the
166
+ plan-only "Reject / don't build it" verdict is hidden in directory mode). If
167
+ the spec's whole premise is wrong, the user leaves a note saying so and stops
168
+ the server — treat that as a cue to discuss before rewriting, not a routine
169
+ revision.
170
+
171
+ Tell the user:
172
+
173
+ ```
174
+ Preview running. Edit your spec files and the browser updates live.
175
+ Annotate and submit a decision, or just press Ctrl+C in the terminal when done.
176
+ ```
177
+
178
+ The server is in-memory only — no HTML files are written to disk (only the
179
+ feedback file, if a decision is submitted).
180
+
181
+ ## Common Mistakes
182
+
183
+ | Mistake | Fix |
184
+ |---------|-----|
185
+ | Skipping the notification/confirmation | Always announce before writing, wait for approval |
186
+ | Not using scaffold output for date/commit | Parse them from the script — don't run git separately |
187
+ | Rewriting all files on update | Read `index.md` first, only touch files with new content |
188
+ | Vague decisions | Each decision needs context + rationale + consequences |
189
+ | Creating empty placeholder files | Only create a file when it has real content |
190
+ | Forgetting to update index.md Contents | Always link to files you create |
@@ -0,0 +1,23 @@
1
+ [
2
+ { "query": "save spec", "should_trigger": true, "expected_skill": "technical-spec" },
3
+ { "query": "document what we decided", "should_trigger": true, "expected_skill": "technical-spec" },
4
+ { "query": "spec this out", "should_trigger": true, "expected_skill": "technical-spec" },
5
+ { "query": "persist the api contract and the quirks we found", "should_trigger": true, "expected_skill": "technical-spec" },
6
+ { "query": "write up the field mappings from backend to UI", "should_trigger": true, "expected_skill": "technical-spec" },
7
+ { "query": "update the spec for wan-config", "should_trigger": true, "expected_skill": "technical-spec" },
8
+ { "query": "scaffold a spec folder for this feature", "should_trigger": true, "expected_skill": "technical-spec" },
9
+ { "query": "whats the format for quirks.md", "should_trigger": true, "expected_skill": "technical-spec", "kind": "in-context" },
10
+ { "query": "record the decision rationale for future sessions", "should_trigger": true, "expected_skill": "technical-spec" },
11
+ { "query": "bump the index.md changelog for the spec", "should_trigger": true, "expected_skill": "technical-spec" },
12
+ { "query": "save the design as a tech spec with live preview", "should_trigger": true, "expected_skill": "technical-spec" },
13
+ { "query": "sepc this out pls", "should_trigger": true, "expected_skill": "technical-spec" },
14
+ { "query": "write up what we decided about the milestone", "should_trigger": true, "expected_skill": "technical-spec" },
15
+ { "query": "update the spec with what we built", "should_trigger": true, "expected_skill": "technical-spec" },
16
+ { "query": "load the spec for checkout before we start the task", "should_trigger": true, "expected_skill": "workflow" },
17
+ { "query": "browse the specs tree", "should_trigger": true, "expected_skill": "spec-browser" },
18
+ { "query": "where is the spec for the auth feature", "should_trigger": true, "expected_skill": "spec-browser" },
19
+ { "query": "design the feature first before documenting", "should_trigger": true, "expected_skill": "discovery" },
20
+ { "query": "generate openapi yaml from the routes", "should_trigger": false, "expected_skill": null },
21
+ { "query": "write jsdoc comments for this module", "should_trigger": false, "expected_skill": null },
22
+ { "query": "host our swagger docs somewhere", "should_trigger": false, "expected_skill": null }
23
+ ]
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env bash
2
+ # Scaffolds a new tech spec directory for a feature.
3
+ # Usage: scaffold.sh <FeatureName or feature-name>
4
+ # Output (one line):
5
+ # created:<absolute-spec-path> commit:<hash> date:<YYYY-MM-DD>
6
+ # exists:<absolute-spec-path> commit:<hash> date:<YYYY-MM-DD>
7
+ #
8
+ # Spec location: <git-root>/specs/<pkg-relpath>/<slug>/
9
+ # pkg-relpath = path of the nearest package root (first directory above CWD
10
+ # with package.json, Cargo.toml, go.mod, or pyproject.toml) relative to the
11
+ # git root — empty when they coincide, giving <git-root>/specs/<slug>/.
12
+ # All specs live under the root specs/ tree, mirroring the repo structure.
13
+
14
+ set -euo pipefail
15
+
16
+ if [[ $# -lt 1 ]]; then
17
+ echo "Usage: scaffold.sh <feature-name>" >&2
18
+ exit 1
19
+ fi
20
+
21
+ INPUT="$*"
22
+
23
+ # PascalCase or spaces → kebab-case, acronym-aware: dashes go only at
24
+ # lower/digit→Upper and UPPER→Upper+lower boundaries, so AOGrcIntegration →
25
+ # ao-grc-integration and UIFormControls → ui-form-controls. Kebab input
26
+ # passes through unchanged.
27
+ SLUG=$(echo "$INPUT" \
28
+ | sed 's/\([a-z0-9]\)\([A-Z]\)/\1-\2/g' \
29
+ | sed 's/\([A-Z]\)\([A-Z][a-z]\)/\1-\2/g' \
30
+ | tr '[:upper:]' '[:lower:]' \
31
+ | tr ' _' '-' \
32
+ | tr -s '-' \
33
+ | sed 's/^-//; s/-$//')
34
+
35
+ if [[ -z "$SLUG" || ! "$SLUG" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]]; then
36
+ echo "ERROR: feature name must produce a kebab-case slug (letters, numbers, and hyphens only): $INPUT" >&2
37
+ exit 1
38
+ fi
39
+
40
+ DATE=$(date +%Y-%m-%d)
41
+ COMMIT=$(git rev-parse --short HEAD 2>/dev/null || echo "no-git")
42
+ REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
43
+ [[ -z "$REPO_ROOT" ]] && REPO_ROOT="${PWD}"
44
+
45
+ # ---------------------------------------------------------------------------
46
+ # Detect package root: nearest dir with a package manifest, up to git root.
47
+ # Used only to compute the path relative to the git root — specs themselves
48
+ # always live under <git-root>/specs/, mirroring the repo structure.
49
+ # ---------------------------------------------------------------------------
50
+ detect_spec_base() {
51
+ local dir="${PWD}"
52
+ while [[ "$dir" != "/" ]]; do
53
+ if [[ -f "$dir/package.json" || -f "$dir/Cargo.toml" || \
54
+ -f "$dir/go.mod" || -f "$dir/pyproject.toml" ]]; then
55
+ echo "$dir"
56
+ return
57
+ fi
58
+ [[ "$dir" == "$REPO_ROOT" ]] && break
59
+ dir=$(dirname "$dir")
60
+ done
61
+ echo "$REPO_ROOT"
62
+ }
63
+
64
+ SPEC_BASE=$(detect_spec_base)
65
+ PKG_REL="${SPEC_BASE#"$REPO_ROOT"}"
66
+ PKG_REL="${PKG_REL#/}"
67
+ if [[ -n "$PKG_REL" ]]; then
68
+ SPEC_DIR="$REPO_ROOT/specs/$PKG_REL/$SLUG"
69
+ else
70
+ SPEC_DIR="$REPO_ROOT/specs/$SLUG"
71
+ fi
72
+
73
+ case "$SPEC_DIR" in
74
+ "$REPO_ROOT/specs/"*) ;;
75
+ *) echo "ERROR: resolved spec path escapes $REPO_ROOT/specs: $SPEC_DIR" >&2; exit 1 ;;
76
+ esac
77
+
78
+ if [[ -d "$SPEC_DIR" ]]; then
79
+ echo "exists:$SPEC_DIR commit:$COMMIT date:$DATE"
80
+ exit 0
81
+ fi
82
+
83
+ mkdir -p "$SPEC_DIR"
84
+
85
+ cat > "$SPEC_DIR/index.md" <<EOF
86
+ # $INPUT — Tech Spec
87
+
88
+ **Last updated:** $DATE
89
+ **Commit:** $COMMIT
90
+ **Status:** draft
91
+
92
+ ## Contents
93
+
94
+ ## Changelog
95
+ - $DATE ($COMMIT): Initial spec
96
+ EOF
97
+
98
+ echo "created:$SPEC_DIR commit:$COMMIT date:$DATE"
@@ -0,0 +1,159 @@
1
+ # Spec File Templates
2
+
3
+ Copy-paste templates for each spec file. Omit sections that don't apply — don't leave empty headings.
4
+
5
+ ---
6
+
7
+ ## index.md
8
+
9
+ ```markdown
10
+ # {Feature Name} — Tech Spec
11
+
12
+ **Last updated:** {YYYY-MM-DD}
13
+ **Commit:** {short-hash}
14
+ **Status:** draft | review | stable
15
+
16
+ ## Contents
17
+ - [Decisions](decisions.md) — why we built it this way
18
+ - [API](api.md) — contracts, endpoints, types
19
+ - [Fields](fields.md) — field mappings: BE/3rd-party → UI
20
+ - [Implementation](implementation.md) — how it works, key files
21
+ - [Quirks](quirks.md) — edge cases and gotchas
22
+
23
+ ## Changelog
24
+ - {YYYY-MM-DD} ({short-hash}): Initial spec
25
+ ```
26
+
27
+ ---
28
+
29
+ ## decisions.md
30
+
31
+ ```markdown
32
+ # Decisions — {Feature Name}
33
+
34
+ ## {Decision Title}
35
+
36
+ **Date:** {YYYY-MM-DD}
37
+ **Status:** accepted | superseded | deprecated
38
+
39
+ ### Context
40
+ Why this decision needed to be made. What constraints or requirements drove it.
41
+
42
+ ### Decision
43
+ What was decided, stated clearly.
44
+
45
+ ### Rationale
46
+ Why this over the alternatives. Include alternatives considered and why they were rejected.
47
+
48
+ ### Consequences
49
+ What changes as a result — positive and negative trade-offs.
50
+ ```
51
+
52
+ ---
53
+
54
+ ## api.md
55
+
56
+ ```markdown
57
+ # API — {Feature Name}
58
+
59
+ ## Endpoints
60
+
61
+ | Method | Path | Description | Auth |
62
+ |--------|------|-------------|------|
63
+ | GET | /api/... | ... | Bearer |
64
+
65
+ ## Key Types / Schemas
66
+
67
+ \`\`\`typescript
68
+ interface ExampleType {
69
+ id: string;
70
+ // ...
71
+ }
72
+ \`\`\`
73
+
74
+ ## External APIs Consumed
75
+
76
+ | Service | Purpose | Notes |
77
+ |---------|---------|-------|
78
+ | {Service} | {What we use it for} | {Rate limits, quirks} |
79
+ ```
80
+
81
+ ---
82
+
83
+ ## fields.md
84
+
85
+ ```markdown
86
+ # Fields — {Feature Name}
87
+
88
+ Document which fields flow from source (BE or 3rd-party API) to destination (UI or your BE),
89
+ with descriptions so you can glance at the spec instead of traversing the codebase.
90
+
91
+ ## Response Fields — {Endpoint or Source Name}
92
+
93
+ > Source: `GET /api/...` or `{ThirdParty} → BE → FE`
94
+
95
+ | Source Field | UI Label / FE Key | Type | Nullable | Description |
96
+ |---|---|---|---|---|
97
+ | `user_full_name` | Full Name | `string` | no | Display name shown in profile card |
98
+ | `created_at` | Created | `string (ISO 8601)` | no | Formatted to `MMM D, YYYY` in UI |
99
+ | `metadata.region` | Region | `string` | yes | Omitted from UI when null |
100
+
101
+ ### Forwarding Chain (3rd-party → BE → FE)
102
+
103
+ Use this sub-section when your BE proxies a 3rd-party API and renames fields.
104
+
105
+ | 3rd-party Field | BE Field | FE Key | Notes |
106
+ |---|---|---|---|
107
+ | `usr_nm` | `username` | `username` | Renamed at BE layer |
108
+ | `acct_bal` | `accountBalance` | `balance` | Converted cents → dollars at BE |
109
+
110
+ ## Request Fields — {Endpoint or Action Name}
111
+
112
+ > Sent from FE to `POST /api/...`
113
+
114
+ | FE Key | BE Field | Type | Required | Description |
115
+ |---|---|---|---|---|
116
+ | `email` | `email` | `string` | yes | Validated client-side before send |
117
+ | `preferredName` | `preferred_name` | `string` | no | Optional; omitted if empty |
118
+ ```
119
+
120
+ ---
121
+
122
+ ## implementation.md
123
+
124
+ ```markdown
125
+ # Implementation — {Feature Name}
126
+
127
+ ## Overview
128
+ One paragraph on how the feature works end-to-end.
129
+
130
+ ## Key Files
131
+
132
+ | File | Role |
133
+ |------|------|
134
+ | `src/...` | ... |
135
+
136
+ ## Data Flow
137
+ Step-by-step description of how data moves through the system.
138
+
139
+ ## Patterns Used
140
+ Non-obvious patterns, abstractions, or conventions introduced.
141
+
142
+ ## Dependencies
143
+ Internal modules or external packages this feature leans on heavily.
144
+ ```
145
+
146
+ ---
147
+
148
+ ## quirks.md
149
+
150
+ ```markdown
151
+ # Quirks — {Feature Name}
152
+
153
+ ## {Quirk Title}
154
+
155
+ **Severity:** low | medium | high
156
+ **Discovered:** {date or commit}
157
+
158
+ Description of the edge case, gotcha, or known issue. Include what triggers it and how it's handled or worked around.
159
+ ```
@@ -0,0 +1,121 @@
1
+ ---
2
+ name: test-first-development
3
+ description: "Tests-first development — write tests before implementation. Opt-in only. Get one upfront consent (write tests first + auto-run), then run the cycle without re-asking. Still always ask before updating existing test specs. Never silently rewrite test specs to match new behavior. Trigger when the user explicitly asks for tests-first, picks it at a workflow checkpoint, or when implementing logic with clear input/output behavior. Also triggers whenever an existing test spec is about to be edited to make it pass — that decision runs through this skill."
4
+ argument-hint: "<what to test>"
5
+ ---
6
+
7
+ # /test-first-development
8
+
9
+ Tests first, implementation second. But only when you've asked for it.
10
+
11
+ ## Usage
12
+
13
+ ```
14
+ /test-first-development $ARGUMENTS
15
+ ```
16
+
17
+ ## The Ask Rules
18
+
19
+ **One upfront consent, then work.** At skill start, ask once:
20
+
21
+ ```
22
+ "Tests-first for this task: I'll write failing tests, auto-run them
23
+ through each red-green-refactor cycle, and implement against them.
24
+ Ok to proceed?"
25
+ ```
26
+
27
+ Wait for yes. After that, do **not** re-ask before writing new tests or
28
+ running them — the cycle needs fast red-green feedback, and re-asking at
29
+ every step is noise. If invoked from a `/workflow` checkpoint where the
30
+ user already picked "Write tests first", that pick *is* the consent —
31
+ start immediately.
32
+
33
+ **The one standing exception — updating existing test specs.** Always ask
34
+ before modifying any existing test file:
35
+
36
+ ```
37
+ "This change affects existing test specs — want me to update them,
38
+ or review the diffs first?"
39
+ ```
40
+
41
+ Never silently update an existing spec. That is a decision point every time.
42
+
43
+ ## The RED-GREEN-REFACTOR Cycle
44
+
45
+ ```
46
+ ┌──────────────────────────────────────────────────────────────────┐
47
+ │ TDD CYCLE │
48
+ ├──────────────────────────────────────────────────────────────────┤
49
+ │ RED │
50
+ │ → Write the failing test │
51
+ │ → Run it — it must fail before moving on │
52
+ │ (a test that passes immediately proves nothing) │
53
+ │ │
54
+ │ GREEN │
55
+ │ → Write the minimal implementation to make it pass │
56
+ │ → Run it — it must pass before moving on │
57
+ │ │
58
+ │ REFACTOR │
59
+ │ → Clean up without changing behavior │
60
+ │ → Run the tests again — they must still pass │
61
+ └──────────────────────────────────────────────────────────────────┘
62
+ ```
63
+
64
+ Run only the relevant test file(s) during the cycle — the full suite
65
+ belongs to `/finalize`.
66
+
67
+ ## What Makes a Good Test
68
+
69
+ ```
70
+ ✓ Tests behavior, not implementation details
71
+ ✓ One clear assertion per test
72
+ ✓ Descriptive name: "should return error when token is expired"
73
+ ✓ Tests edge cases discovered during thinking, not after
74
+ ✓ Independent — doesn't rely on other tests running first
75
+
76
+ ✗ Tests internal function calls or private methods
77
+ ✗ Tests that only pass because of the implementation you just wrote
78
+ ✗ Vague names: "test1", "should work"
79
+ ✗ Tests that need other tests to run first
80
+ ```
81
+
82
+ ## Updating Existing Test Specs
83
+
84
+ This is the most dangerous operation in TDD. Silently rewriting specs to make a bug fix pass is how bugs get buried.
85
+
86
+ Before touching any existing test file:
87
+
88
+ 1. Show the current spec and what would change
89
+ 2. Explain why the change is necessary (behavior change vs. test was wrong)
90
+ 3. Wait for explicit approval
91
+
92
+ ```
93
+ Legitimate reasons to update a spec:
94
+ ✓ The feature behavior intentionally changed (product decision)
95
+ ✓ The test was testing the wrong thing (implementation detail)
96
+ ✓ The test was brittle/flaky and needs a better assertion
97
+
98
+ NOT legitimate:
99
+ ✗ "The test was failing so I updated it to match the new output"
100
+ ✗ "The behavior changed as a side effect of the fix"
101
+ ```
102
+
103
+ ## When TDD Applies (and When It Doesn't)
104
+
105
+ ```
106
+ Good candidates for TDD:
107
+ ✓ Pure functions with clear inputs/outputs
108
+ ✓ Utility logic (date formatting, currency, validation)
109
+ ✓ API handlers with predictable request/response shapes
110
+ ✓ Bug fixes where a failing test proves the bug exists
111
+
112
+ Poor candidates (don't force TDD here):
113
+ ✗ UI layout and visual components
114
+ ✗ Framework glue code (wiring up routes, registering providers)
115
+ ✗ One-off scripts or migrations
116
+ ✗ Prototyping — test after shape is clear
117
+ ```
118
+
119
+ ## See Also
120
+
121
+ - `references/rationalization-table.md` — common rationalizations for skipping tests-first and why they're wrong
@@ -0,0 +1,22 @@
1
+ [
2
+ { "query": "write tests first for this", "should_trigger": true, "expected_skill": "test-first-development" },
3
+ { "query": "tdd this feature", "should_trigger": true, "expected_skill": "test-first-development" },
4
+ { "query": "test-first for the parser module", "should_trigger": true, "expected_skill": "test-first-development" },
5
+ { "query": "write failing tests before implementing", "should_trigger": true, "expected_skill": "test-first-development" },
6
+ { "query": "red green refactor cycle please", "should_trigger": true, "expected_skill": "test-first-development" },
7
+ { "query": "can you do this test driven", "should_trigger": true, "expected_skill": "test-first-development" },
8
+ { "query": "write unit tests for the date helpers before you code them", "should_trigger": true, "expected_skill": "test-first-development" },
9
+ { "query": "update the failing test to match the new behavior", "should_trigger": true, "expected_skill": "test-first-development" },
10
+ { "query": "the test is failing so just fix the test", "should_trigger": true, "expected_skill": "test-first-development" },
11
+ { "query": "should I tdd ui components", "should_trigger": true, "expected_skill": "test-first-development" },
12
+ { "query": "you already asked once, dont re-ask each cycle right?", "should_trigger": true, "expected_skill": "test-first-development", "kind": "in-context" },
13
+ { "query": "bug: prove it with a failing test then fix it", "should_trigger": true, "expected_skill": "test-first-development" },
14
+ { "query": "tets first plz", "should_trigger": true, "expected_skill": "test-first-development" },
15
+ { "query": "add tests for the existing legacy code", "should_trigger": true, "expected_skill": "workflow" },
16
+ { "query": "implement the currency formatter utility", "should_trigger": true, "expected_skill": "workflow" },
17
+ { "query": "write e2e tests with playwright for the flow", "should_trigger": true, "expected_skill": "workflow" },
18
+ { "query": "run the tests", "should_trigger": true, "expected_skill": "finalize" },
19
+ { "query": "why is this test flaky", "should_trigger": true, "expected_skill": "root-cause-analysis" },
20
+ { "query": "jest config setup for the monorepo", "should_trigger": true, "expected_skill": "workflow" },
21
+ { "query": "wheres the coverage report hosted", "should_trigger": false, "expected_skill": null }
22
+ ]
@@ -0,0 +1,16 @@
1
+ # Tests-First Rationalization Table
2
+
3
+ Common rationalizations agents (and developers) use to skip writing tests — and why they're wrong.
4
+
5
+ | Rationalization | Reality | Counter |
6
+ | ------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
7
+ | "This change is too small to need a test" | Small changes break things too. The test takes 2 minutes. | Write the test. It documents the behavior even if it never catches a regression. |
8
+ | "I'll write tests after the implementation is working" | Tests written after are biased by the implementation you built. You test what you know works, not what could break. | Tests first force you to think about edge cases before you're anchored to an implementation. |
9
+ | "The existing tests cover this" | They cover the old behavior. The new behavior needs its own test. | Add a test for the new behavior. Don't assume coverage. |
10
+ | "This is just UI, tests don't apply" | Logic in UI components (conditional rendering, state transitions, handlers) can and should be tested. Layout doesn't need tests. Logic does. | Separate the logic from the layout. Test the logic. |
11
+ | "We're moving fast, we'll add tests later" | "Later" doesn't come. The feature ships, the next feature starts, the tests never get written. | Tests now are cheaper than debugging later. The test is part of the task, not optional cleanup. |
12
+ | "The type system already catches this" | Types catch shape errors. Tests catch behavioral errors. These are different things. | Types and tests are complementary, not substitutes. |
13
+ | "Running tests takes too long" | Running the specific test for the specific change takes seconds. | Run only the relevant test file, not the full suite. |
14
+ | "I need to update the spec to make the test pass" | If you're rewriting the spec to match new output, you're not fixing a bug — you're hiding one. | Stop. Explain what changed and why. Get explicit approval before touching existing specs. |
15
+ | "This is a prototype, no tests needed" | Prototypes become production code. Untested prototypes become untested production code. | Decide: is this throwaway? If yes, delete it. If it might ship, test the core logic. |
16
+ | "The test is too hard to write" | If the test is hard to write, the code is too coupled or too complex. | Hard-to-test code is a design smell. Simplify the code, then write the test. |