@curdx/flow 1.1.4 → 1.1.6

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 (89) hide show
  1. package/.claude-plugin/marketplace.json +25 -0
  2. package/.claude-plugin/plugin.json +43 -0
  3. package/CHANGELOG.md +279 -0
  4. package/agent-preamble/preamble.md +214 -0
  5. package/agents/flow-adversary.md +216 -0
  6. package/agents/flow-architect.md +190 -0
  7. package/agents/flow-debugger.md +325 -0
  8. package/agents/flow-edge-hunter.md +273 -0
  9. package/agents/flow-executor.md +246 -0
  10. package/agents/flow-planner.md +204 -0
  11. package/agents/flow-product-designer.md +146 -0
  12. package/agents/flow-qa-engineer.md +276 -0
  13. package/agents/flow-researcher.md +155 -0
  14. package/agents/flow-reviewer.md +280 -0
  15. package/agents/flow-security-auditor.md +398 -0
  16. package/agents/flow-triage-analyst.md +290 -0
  17. package/agents/flow-ui-researcher.md +227 -0
  18. package/agents/flow-ux-designer.md +247 -0
  19. package/agents/flow-verifier.md +283 -0
  20. package/agents/persona-amelia.md +128 -0
  21. package/agents/persona-david.md +141 -0
  22. package/agents/persona-emma.md +179 -0
  23. package/agents/persona-john.md +105 -0
  24. package/agents/persona-mary.md +95 -0
  25. package/agents/persona-oliver.md +136 -0
  26. package/agents/persona-rachel.md +126 -0
  27. package/agents/persona-serena.md +175 -0
  28. package/agents/persona-winston.md +117 -0
  29. package/bin/curdx-flow.js +5 -2
  30. package/cli/install.js +44 -5
  31. package/commands/audit.md +170 -0
  32. package/commands/autoplan.md +184 -0
  33. package/commands/debug.md +199 -0
  34. package/commands/design.md +155 -0
  35. package/commands/discuss.md +162 -0
  36. package/commands/doctor.md +124 -0
  37. package/commands/fast.md +128 -0
  38. package/commands/help.md +119 -0
  39. package/commands/implement.md +381 -0
  40. package/commands/index.md +261 -0
  41. package/commands/init.md +105 -0
  42. package/commands/install-deps.md +128 -0
  43. package/commands/party.md +241 -0
  44. package/commands/plan-ceo.md +117 -0
  45. package/commands/plan-design.md +107 -0
  46. package/commands/plan-dx.md +104 -0
  47. package/commands/plan-eng.md +108 -0
  48. package/commands/qa.md +118 -0
  49. package/commands/requirements.md +146 -0
  50. package/commands/research.md +141 -0
  51. package/commands/review.md +168 -0
  52. package/commands/security.md +109 -0
  53. package/commands/sketch.md +118 -0
  54. package/commands/spec.md +135 -0
  55. package/commands/spike.md +181 -0
  56. package/commands/start.md +189 -0
  57. package/commands/status.md +139 -0
  58. package/commands/switch.md +95 -0
  59. package/commands/tasks.md +189 -0
  60. package/commands/triage.md +160 -0
  61. package/commands/verify.md +124 -0
  62. package/gates/adversarial-review-gate.md +219 -0
  63. package/gates/coverage-audit-gate.md +184 -0
  64. package/gates/devex-gate.md +255 -0
  65. package/gates/edge-case-gate.md +194 -0
  66. package/gates/karpathy-gate.md +130 -0
  67. package/gates/security-gate.md +218 -0
  68. package/gates/tdd-gate.md +188 -0
  69. package/gates/verification-gate.md +183 -0
  70. package/hooks/hooks.json +56 -0
  71. package/hooks/scripts/fail-tracker.sh +31 -0
  72. package/hooks/scripts/inject-karpathy.sh +52 -0
  73. package/hooks/scripts/quick-mode-guard.sh +64 -0
  74. package/hooks/scripts/session-start.sh +76 -0
  75. package/hooks/scripts/stop-watcher.sh +166 -0
  76. package/knowledge/atomic-commits.md +262 -0
  77. package/knowledge/epic-decomposition.md +307 -0
  78. package/knowledge/execution-strategies.md +278 -0
  79. package/knowledge/karpathy-guidelines.md +219 -0
  80. package/knowledge/planning-reviews.md +211 -0
  81. package/knowledge/poc-first-workflow.md +227 -0
  82. package/knowledge/spec-driven-development.md +183 -0
  83. package/knowledge/systematic-debugging.md +384 -0
  84. package/knowledge/two-stage-review.md +233 -0
  85. package/knowledge/wave-execution.md +387 -0
  86. package/package.json +14 -3
  87. package/schemas/config.schema.json +100 -0
  88. package/schemas/spec-frontmatter.schema.json +42 -0
  89. package/schemas/spec-state.schema.json +117 -0
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env bash
2
+ # CurDX-Flow InstructionsLoaded Hook
3
+ # Injects the L1 baseline (Karpathy 4 principles + mandatory tool rules + 3 red lines)
4
+ # into every session after CLAUDE.md is loaded.
5
+ #
6
+ # This is what makes the baseline "always on" — it doesn't rely on CLAUDE.md being
7
+ # present in every project, and it survives context compaction.
8
+
9
+ set -u
10
+
11
+ CONTEXT='## CurDX-Flow Mind Baseline (L1 — always on)
12
+
13
+ ### 1. Think Before Coding
14
+ - State assumptions before any non-trivial task
15
+ - When uncertain, use AskUserQuestion — do not silently assume
16
+ - When confused, stop — do not push forward
17
+
18
+ ### 2. Simplicity First
19
+ - YAGNI: do not write features beyond what was requested
20
+ - No single-use abstractions
21
+ - If 200 lines suffice, do not write 1000
22
+
23
+ ### 3. Surgical Changes
24
+ - Modify only the lines that must change
25
+ - Match existing style
26
+ - Do not delete pre-existing dead code
27
+
28
+ ### 4. Goal-Driven
29
+ - Define a verifiable success criterion first
30
+ - Forbidden to say done/fixed/working without evidence
31
+
32
+ ## Mandatory Tools (L2 — enforced)
33
+
34
+ - library/framework questions → **context7 first** (`mcp__context7__*`); forbidden to rely on training memory
35
+ - planning / design / architecture / review → **sequential-thinking first** (≥5 thoughts)
36
+ - before any task → **claude-mem search** (if installed)
37
+ - UI code → **frontend-design skill** (if installed)
38
+ - browser QA → **chrome-devtools MCP**
39
+
40
+ ## Three Red Lines (L3 — inherited from pua, universal)
41
+
42
+ 1. **Closed loop**: claiming "done"? Provide evidence (build output / passing tests / curl result)
43
+ 2. **Fact-driven**: verify before saying "probably". An unverified attribution is blame-shifting
44
+ 3. **Exhaust everything**: before saying "I cannot", complete the systematic 4-stage debugging'
45
+
46
+ # Emit JSON with safe encoding
47
+ if command -v python3 >/dev/null 2>&1; then
48
+ ESCAPED="$(printf '%s' "$CONTEXT" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))')"
49
+ printf '{"hookSpecificOutput":{"hookEventName":"InstructionsLoaded","additionalContext":%s}}\n' "$ESCAPED"
50
+ fi
51
+
52
+ exit 0
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env bash
2
+ # CurDX-Flow PreToolUse Hook for AskUserQuestion
3
+ # Blocks AskUserQuestion when the active spec has quickMode=true or mode=autonomous.
4
+ # This prevents the autonomous loop from stalling waiting for user input.
5
+ #
6
+ # The hook reads Claude's PreToolUse input JSON from stdin. We only act when
7
+ # the tool being invoked is AskUserQuestion.
8
+
9
+ set -u
10
+
11
+ # Read input (Claude sends JSON on stdin for PreToolUse)
12
+ INPUT=$(cat 2>/dev/null || echo "{}")
13
+
14
+ if ! command -v python3 >/dev/null 2>&1; then
15
+ # Without JSON parsing, allow everything (fail open)
16
+ exit 0
17
+ fi
18
+
19
+ # Parse the tool name being invoked
20
+ TOOL_NAME=$(echo "$INPUT" | python3 -c '
21
+ import json, sys
22
+ try:
23
+ d = json.load(sys.stdin)
24
+ print(d.get("tool_name", ""))
25
+ except Exception:
26
+ print("")
27
+ ' 2>/dev/null)
28
+
29
+ # We only guard AskUserQuestion
30
+ if [ "$TOOL_NAME" != "AskUserQuestion" ]; then
31
+ exit 0
32
+ fi
33
+
34
+ # Check if we're in a flow project with quick mode enabled
35
+ [ ! -d ".flow" ] && exit 0
36
+
37
+ ACTIVE=$(cat .flow/.active-spec 2>/dev/null)
38
+ [ -z "$ACTIVE" ] && exit 0
39
+
40
+ STATE_FILE=".flow/specs/$ACTIVE/.state.json"
41
+ [ ! -f "$STATE_FILE" ] && exit 0
42
+
43
+ # Read quickMode + mode
44
+ QUICK_MODE=$(python3 -c "
45
+ import json
46
+ try:
47
+ s = json.load(open('$STATE_FILE'))
48
+ qm = s.get('quickMode', False)
49
+ mode = s.get('mode', '')
50
+ print('true' if (qm or mode == 'autonomous') else 'false')
51
+ except Exception:
52
+ print('false')
53
+ " 2>/dev/null)
54
+
55
+ if [ "$QUICK_MODE" = "true" ]; then
56
+ # Block and inject guidance
57
+ MSG="[CurDX-Flow quick-mode-guard] Active spec '$ACTIVE' is in quick mode or autonomous mode — AskUserQuestion is forbidden. Decide autonomously based on user preferences in .flow/CONTEXT.md plus the most reasonable assumption, and record your assumption in .progress.md."
58
+ ESCAPED=$(printf '%s' "$MSG" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))')
59
+ printf '{"decision":"block","reason":%s}\n' "$ESCAPED"
60
+ exit 0
61
+ fi
62
+
63
+ # Allow
64
+ exit 0
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env bash
2
+ # CurDX-Flow SessionStart Hook
3
+ # Duties:
4
+ # 1. Daily dependency check — nudge user to /flow-install-deps if recommended plugins missing
5
+ # 2. Load active spec progress into session context
6
+ #
7
+ # Design notes:
8
+ # - Idempotent: marker file tracks last check date
9
+ # - Silent when everything is healthy (no noise)
10
+ # - Graceful degradation: missing `claude` CLI doesn't break hook
11
+
12
+ set -u
13
+
14
+ DATA_DIR="${CLAUDE_PLUGIN_DATA:-$HOME/.claude/plugins/data/curdx-flow}"
15
+ MARKER="$DATA_DIR/.deps-checked"
16
+ TODAY="$(date +%Y-%m-%d)"
17
+ ADDITIONAL_CONTEXT=""
18
+
19
+ mkdir -p "$DATA_DIR" 2>/dev/null || true
20
+
21
+ # ---------- 1. Dependency check (once per day) ----------
22
+ LAST_CHECK=""
23
+ [ -f "$MARKER" ] && LAST_CHECK="$(cat "$MARKER" 2>/dev/null)"
24
+
25
+ if [ "$LAST_CHECK" != "$TODAY" ]; then
26
+ MISSING=()
27
+
28
+ # Skip if `claude` CLI is not on PATH
29
+ if command -v claude >/dev/null 2>&1; then
30
+ INSTALLED="$(claude plugin list 2>/dev/null || true)"
31
+
32
+ echo "$INSTALLED" | grep -q 'pua' || MISSING+=("pua")
33
+ echo "$INSTALLED" | grep -q 'claude-mem' || MISSING+=("claude-mem")
34
+ echo "$INSTALLED" | grep -q 'frontend-design' || MISSING+=("frontend-design")
35
+ fi
36
+
37
+ if [ "${#MISSING[@]}" -gt 0 ]; then
38
+ JOINED="$(IFS=,; echo "${MISSING[*]}")"
39
+ ADDITIONAL_CONTEXT+="## CurDX-Flow Recommended Plugins Check\n\nThe following recommended plugins were not detected: **${JOINED}**\n\nRun \`/curdx-flow:install-deps\` for interactive one-shot install. Run \`/curdx-flow:doctor\` for the full health report.\n\n"
40
+ fi
41
+
42
+ echo "$TODAY" > "$MARKER" 2>/dev/null || true
43
+ fi
44
+
45
+ # ---------- 2. Load .flow/ state (if project is a flow project) ----------
46
+ if [ -d ".flow" ]; then
47
+ ADDITIONAL_CONTEXT+="## CurDX-Flow Project Active\n\n"
48
+
49
+ if [ -f ".flow/PROJECT.md" ]; then
50
+ ADDITIONAL_CONTEXT+="### Project Vision\n$(head -80 .flow/PROJECT.md)\n\n"
51
+ fi
52
+
53
+ if [ -f ".flow/.active-spec" ]; then
54
+ ACTIVE="$(cat .flow/.active-spec 2>/dev/null)"
55
+ if [ -n "$ACTIVE" ] && [ -d ".flow/specs/$ACTIVE" ]; then
56
+ ADDITIONAL_CONTEXT+="### Active Spec: \`$ACTIVE\`\n\n"
57
+ if [ -f ".flow/specs/$ACTIVE/.progress.md" ]; then
58
+ ADDITIONAL_CONTEXT+="$(head -40 ".flow/specs/$ACTIVE/.progress.md")\n\n"
59
+ fi
60
+ fi
61
+ fi
62
+ fi
63
+
64
+ # ---------- 3. Emit hook output ----------
65
+ if [ -n "$ADDITIONAL_CONTEXT" ]; then
66
+ # Use python3 for safe JSON encoding (handles newlines, quotes)
67
+ if command -v python3 >/dev/null 2>&1; then
68
+ ESCAPED="$(printf '%s' "$ADDITIONAL_CONTEXT" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))')"
69
+ else
70
+ # Fallback: naive escape (only newlines and quotes)
71
+ ESCAPED="$(printf '%s' "$ADDITIONAL_CONTEXT" | sed 's/\\/\\\\/g; s/"/\\"/g' | awk 'BEGIN{printf "\""} {printf "%s\\n", $0} END{printf "\""}')"
72
+ fi
73
+ printf '{"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":%s}}\n' "$ESCAPED"
74
+ fi
75
+
76
+ exit 0
@@ -0,0 +1,166 @@
1
+ #!/usr/bin/env bash
2
+ # CurDX-Flow Stop Hook — StopHookLoop strategy implementation
3
+ #
4
+ # Fires when Claude's turn ends. Decides whether to block (force continue)
5
+ # or allow the session to stop.
6
+ #
7
+ # Decision logic:
8
+ # 1. Not a flow project? → allow stop
9
+ # 2. No active spec? → allow stop
10
+ # 3. Strategy is not "stop-hook"? → allow stop
11
+ # 4. Phase != "execute"? → allow stop
12
+ # 5. All tasks done OR "ALL_TASKS_COMPLETE" in transcript? → cleanup + allow stop
13
+ # 6. Too many rounds (>100) or too many failures (>3)? → stop + warn
14
+ # 7. Otherwise → block and force continue next task
15
+
16
+ set -u
17
+
18
+ DATA_DIR="${CLAUDE_PLUGIN_DATA:-$HOME/.claude/plugins/data/curdx-flow}"
19
+
20
+ # ---------- helper: exit with "allow stop" ----------
21
+ allow_stop() {
22
+ # No output = allow stop normally
23
+ exit 0
24
+ }
25
+
26
+ # ---------- helper: block and inject continuation ----------
27
+ block_continue() {
28
+ local reason="$1"
29
+ # Safely JSON-encode via python3 if available
30
+ if command -v python3 >/dev/null 2>&1; then
31
+ printf '{"decision":"block","reason":%s}\n' \
32
+ "$(printf '%s' "$reason" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))')"
33
+ else
34
+ # Fallback: escape quotes and newlines naively
35
+ local escaped=$(printf '%s' "$reason" | sed 's/\\/\\\\/g; s/"/\\"/g' | tr '\n' ' ')
36
+ printf '{"decision":"block","reason":"%s"}\n' "$escaped"
37
+ fi
38
+ exit 0
39
+ }
40
+
41
+ # ---------- 1. Must be a flow project ----------
42
+ [ ! -d ".flow" ] && allow_stop
43
+
44
+ # ---------- 2. Must have active spec ----------
45
+ ACTIVE=$(cat .flow/.active-spec 2>/dev/null)
46
+ [ -z "$ACTIVE" ] && allow_stop
47
+ SPEC_DIR=".flow/specs/$ACTIVE"
48
+ [ ! -d "$SPEC_DIR" ] && allow_stop
49
+
50
+ STATE_FILE="$SPEC_DIR/.state.json"
51
+ [ ! -f "$STATE_FILE" ] && allow_stop
52
+
53
+ # ---------- 3-4. Strategy + phase check (use python3 for JSON parsing) ----------
54
+ if ! command -v python3 >/dev/null 2>&1; then
55
+ # Without python3 we can't safely parse JSON. Allow stop.
56
+ allow_stop
57
+ fi
58
+
59
+ read STRATEGY PHASE TASK_INDEX TOTAL_TASKS FAILED ROUNDS <<EOF
60
+ $(python3 <<'PY'
61
+ import json, os, sys
62
+ p = os.environ.get("STATE_FILE")
63
+ try:
64
+ s = json.load(open(p))
65
+ except Exception:
66
+ sys.exit(0)
67
+ strategy = s.get("strategy", "auto")
68
+ phase = s.get("phase", "")
69
+ ex = s.get("execute_state", {}) or {}
70
+ ti = ex.get("task_index", 0)
71
+ tt = ex.get("total_tasks", 0)
72
+ failed = ex.get("failed_attempts", 0)
73
+ rounds = ex.get("global_iteration", 0)
74
+ print(strategy, phase, ti, tt, failed, rounds)
75
+ PY
76
+ )
77
+ EOF
78
+ export STATE_FILE
79
+
80
+ # Only activate for stop-hook strategy + execute phase
81
+ [ "$STRATEGY" != "stop-hook" ] && allow_stop
82
+ [ "$PHASE" != "execute" ] && allow_stop
83
+
84
+ # ---------- 5. Check for completion signal in transcript ----------
85
+ # Claude Code passes transcript path via stdin as JSON: {"transcript_path": "/path/..."}
86
+ # We read stdin to detect ALL_TASKS_COMPLETE or TASK_FAILED
87
+ INPUT=$(cat 2>/dev/null || echo "{}")
88
+ TRANSCRIPT_PATH=$(echo "$INPUT" | python3 -c 'import json,sys;
89
+ try: print(json.load(sys.stdin).get("transcript_path",""))
90
+ except: print("")' 2>/dev/null)
91
+
92
+ TRANSCRIPT_TAIL=""
93
+ if [ -n "$TRANSCRIPT_PATH" ] && [ -f "$TRANSCRIPT_PATH" ]; then
94
+ # Read last 50KB only (efficiency)
95
+ TRANSCRIPT_TAIL=$(tail -c 51200 "$TRANSCRIPT_PATH" 2>/dev/null || echo "")
96
+ fi
97
+
98
+ # Check for explicit completion signals
99
+ if echo "$TRANSCRIPT_TAIL" | grep -q "ALL_TASKS_COMPLETE"; then
100
+ # Cleanup: mark phase completed
101
+ python3 <<PY 2>/dev/null
102
+ import json
103
+ p = "$STATE_FILE"
104
+ s = json.load(open(p))
105
+ s.setdefault("phase_status", {})["execute"] = "completed"
106
+ s["phase"] = "verify" # move to verify phase
107
+ json.dump(s, open(p, "w"), indent=2, ensure_ascii=False)
108
+ PY
109
+ allow_stop
110
+ fi
111
+
112
+ # Check for fail signal (accumulate; actual stop decision below)
113
+ if echo "$TRANSCRIPT_TAIL" | grep -q "TASK_FAILED"; then
114
+ # Increment failed_attempts
115
+ python3 <<PY 2>/dev/null
116
+ import json
117
+ p = "$STATE_FILE"
118
+ s = json.load(open(p))
119
+ s.setdefault("execute_state", {})
120
+ s["execute_state"]["failed_attempts"] = s["execute_state"].get("failed_attempts", 0) + 1
121
+ json.dump(s, open(p, "w"), indent=2, ensure_ascii=False)
122
+ PY
123
+ # Re-read
124
+ FAILED=$(python3 -c "import json; print(json.load(open('$STATE_FILE'))['execute_state']['failed_attempts'])" 2>/dev/null || echo 0)
125
+ fi
126
+
127
+ # ---------- 6. Safety brakes ----------
128
+ if [ "$FAILED" -ge 3 ]; then
129
+ # Too many failures — stop and surface
130
+ allow_stop
131
+ fi
132
+
133
+ if [ "$ROUNDS" -ge 100 ]; then
134
+ # Runaway loop protection
135
+ allow_stop
136
+ fi
137
+
138
+ # Check if all tasks done
139
+ if [ "$TASK_INDEX" -ge "$TOTAL_TASKS" ] && [ "$TOTAL_TASKS" -gt 0 ]; then
140
+ # Mark complete
141
+ python3 <<PY 2>/dev/null
142
+ import json
143
+ p = "$STATE_FILE"
144
+ s = json.load(open(p))
145
+ s.setdefault("phase_status", {})["execute"] = "completed"
146
+ s["phase"] = "verify"
147
+ json.dump(s, open(p, "w"), indent=2, ensure_ascii=False)
148
+ PY
149
+ allow_stop
150
+ fi
151
+
152
+ # ---------- 7. Block and continue ----------
153
+ # Increment round counter
154
+ python3 <<PY 2>/dev/null
155
+ import json
156
+ p = "$STATE_FILE"
157
+ s = json.load(open(p))
158
+ s.setdefault("execute_state", {})
159
+ s["execute_state"]["global_iteration"] = s["execute_state"].get("global_iteration", 0) + 1
160
+ json.dump(s, open(p, "w"), indent=2, ensure_ascii=False)
161
+ PY
162
+
163
+ NEXT_INDEX=$((TASK_INDEX + 1))
164
+ REASON="[CurDX-Flow stop-hook] Spec '$ACTIVE' has tasks remaining ($TASK_INDEX/$TOTAL_TASKS). Continue to the next task. Dispatch flow-executor for task_id=next. On completion, emit TASK_COMPLETE or TASK_FAILED. When all tasks are done, emit ALL_TASKS_COMPLETE."
165
+
166
+ block_continue "$REASON"
@@ -0,0 +1,262 @@
1
+ # Atomic Commits — Atomic Commit Rules
2
+
3
+ > One task, one commit. This is the iron rule for all execution agents in CurDX-Flow.
4
+ >
5
+ > Agents reference this via `@${CLAUDE_PLUGIN_ROOT}/knowledge/atomic-commits.md`.
6
+
7
+ ---
8
+
9
+ ## Core Principle
10
+
11
+ **One task = one commit = one rollback unit.**
12
+
13
+ Why:
14
+ - `git bisect` can pinpoint a problem to a specific task
15
+ - `git revert <hash>` can undo a single task in isolation
16
+ - PR review can walk through changes commit-by-commit
17
+ - Downstream agents can trace "which AD / FR this change came from" via commit history
18
+
19
+ ---
20
+
21
+ ## Commit Message Format (Conventional Commits + CurDX-Flow extensions)
22
+
23
+ ```
24
+ <type>(<scope>): <summary>
25
+
26
+ [body - explain why, not what]
27
+
28
+ [footer - reference IDs]
29
+ ```
30
+
31
+ ### Type (required)
32
+
33
+ | Type | Purpose | Example |
34
+ |------|---------|---------|
35
+ | `feat` | New feature | `feat(auth): add JWT refresh endpoint` |
36
+ | `fix` | Bug fix | `fix(login): handle empty email case` |
37
+ | `refactor` | Refactor (behavior unchanged) | `refactor(db): extract connection pool` |
38
+ | `test` | Tests | `test(auth): red - add login validation tests` |
39
+ | `docs` | Documentation | `docs(readme): add install instructions` |
40
+ | `chore` | Misc (deps, config) | `chore(deps): upgrade bcrypt to 5.1.0` |
41
+ | `perf` | Performance | `perf(query): cache user lookups` |
42
+ | `style` | Formatting (no behavior change) | `style: fix indentation in auth module` |
43
+ | `build` | Build config | `build(tsconfig): enable strict mode` |
44
+ | `ci` | CI config | `ci(github): add test workflow` |
45
+
46
+ ### TDD phase markers (used in Phase 3)
47
+
48
+ | Phase | Type + suffix | Example |
49
+ |-------|--------------|---------|
50
+ | RED | `test(scope): red - ...` | `test(auth): red - login validation` |
51
+ | GREEN | `feat(scope): green - ...` | `feat(auth): green - satisfy login test` |
52
+ | YELLOW | `refactor(scope): yellow - ...` | `refactor(auth): yellow - extract validator` |
53
+
54
+ ### Scope
55
+
56
+ - Module name (`auth`, `db`, `ui`, `api`)
57
+ - Or file name (without extension)
58
+ - Or `(spec-name)` if spanning multiple modules
59
+
60
+ ### Summary
61
+
62
+ - Imperative mood (`add`, `fix`, not `added`, `fixes`)
63
+ - Lowercase start (unless a proper noun)
64
+ - No trailing period
65
+ - ≤ 70 characters
66
+
67
+ ---
68
+
69
+ ## Body (optional but recommended)
70
+
71
+ Explain **why**. Do not explain **what** (the diff shows what).
72
+
73
+ ```
74
+ feat(auth): implement JWT refresh flow
75
+
76
+ Tokens expire after 15 minutes. Without refresh, users get
77
+ logged out mid-session. This adds a refresh endpoint that
78
+ validates the refresh_token and issues a new access_token.
79
+
80
+ Per AD-03: use rotating refresh tokens to mitigate theft.
81
+ ```
82
+
83
+ Do NOT write:
84
+ ```
85
+ feat(auth): implement JWT refresh flow
86
+
87
+ Added refreshToken() function in auth.ts.
88
+ Added POST /auth/refresh endpoint.
89
+ Added tests for success and failure cases.
90
+ ```
91
+ ← the diff already shows this; it wastes commit message space.
92
+
93
+ ---
94
+
95
+ ## Footer (reference IDs)
96
+
97
+ CurDX-Flow extension: if a task references FR / AC / AD / D-NN, list them in the footer:
98
+
99
+ ```
100
+ feat(auth): implement JWT refresh flow
101
+
102
+ Refresh tokens rotate on each use, preventing replay attacks.
103
+
104
+ Requirements: FR-03, AC-2.1
105
+ Design: AD-03
106
+ Decisions: D-07 (session storage strategy)
107
+ Task: spec/auth-system/tasks.md#3.2
108
+ ```
109
+
110
+ Fields:
111
+ - `Requirements:` lists implemented FR / AC
112
+ - `Design:` lists related AD
113
+ - `Decisions:` lists referenced project-level decisions (D-NN)
114
+ - `Task:` optional, points at the task definition location
115
+
116
+ ---
117
+
118
+ ## Concrete Rules for Atomicity
119
+
120
+ ### 1. One commit does one thing
121
+
122
+ ✗ **Bad**:
123
+ ```
124
+ feat: add login + fix typo + refactor db connection
125
+ ```
126
+
127
+ ✓ **Good** (split into 3 commits):
128
+ ```
129
+ feat(auth): add login endpoint
130
+ docs: fix typo in README
131
+ refactor(db): extract connection factory
132
+ ```
133
+
134
+ ### 2. Do not mix "task code" and "cleanup"
135
+
136
+ ✗ **Bad**:
137
+ ```
138
+ feat(auth): add JWT + remove unused imports in user.ts
139
+ ```
140
+
141
+ ✓ **Good**:
142
+ ```
143
+ feat(auth): add JWT endpoint
144
+ chore: remove unused imports in user.ts
145
+ ```
146
+
147
+ ### 3. Every commit must pass tests independently
148
+
149
+ This is what makes `git bisect` work.
150
+
151
+ - Do not commit "broken intermediate states"
152
+ - Even WIP should build + test (even with few tests)
153
+ - For a large change that truly must be split, use a feature branch and squash at the end
154
+
155
+ ### 4. The file change scope should match the commit message
156
+
157
+ If the commit is `feat(auth): ...`, it should not include changes under `src/ui/`. Otherwise you actually did two things.
158
+
159
+ ---
160
+
161
+ ## The flow-executor Agent's Commit Flow
162
+
163
+ ```bash
164
+ # Step 1: git add only the files involved in the task
165
+ git add src/auth/login.ts src/auth/login.test.ts
166
+
167
+ # Step 2: check that staged diff matches the commit message
168
+ git diff --cached --stat
169
+
170
+ # Step 3: ensure no unexpected changes sneaked in
171
+ # (if you see a file that shouldn't be there, git reset HEAD <file>)
172
+
173
+ # Step 4: commit
174
+ git commit -m "feat(auth): green - implement login endpoint
175
+
176
+ Per AD-03, uses bcrypt for password hashing.
177
+
178
+ Requirements: FR-01
179
+ Design: AD-03
180
+ "
181
+
182
+ # Step 5: record the hash
183
+ COMMIT_HASH=$(git rev-parse --short HEAD)
184
+ echo "✓ Committed: $COMMIT_HASH"
185
+ ```
186
+
187
+ ---
188
+
189
+ ## Forbidden Patterns
190
+
191
+ ### ✗ Giant commit
192
+ ```
193
+ feat(auth): implement entire authentication system
194
+ ```
195
+ Too large, cannot review, cannot bisect. Split into N small commits.
196
+
197
+ ### ✗ Hedging words
198
+ ```
199
+ feat(auth): maybe fix login issue?
200
+ ```
201
+ If unsure, do not commit yet. A commit is a definitive operation.
202
+
203
+ ### ✗ Meaningless commits
204
+ ```
205
+ wip
206
+ fix
207
+ update
208
+ ```
209
+ Future maintainers will curse you. At minimum write `wip(auth): placeholder for token refresh`.
210
+
211
+ ### ✗ `--amend` on a pushed commit
212
+ ```
213
+ git commit --amend # after push
214
+ git push -f # overwrite remote
215
+ ```
216
+ Destroys shared history. Only amend local, unpushed commits.
217
+
218
+ ### ✗ Skipping hooks
219
+ ```
220
+ git commit --no-verify
221
+ ```
222
+ Unless the user explicitly requests it. Hooks exist for reasons (pre-commit lint, commit-msg check).
223
+
224
+ ---
225
+
226
+ ## Relationship to PR Review
227
+
228
+ PR review reads each commit's message.
229
+
230
+ - Good commit message → reviewer finishes in 5 minutes
231
+ - Bad commit message → reviewer either rubber-stamps or blocks without reading
232
+
233
+ CurDX-Flow's `/curdx-flow:ship` command (Phase 6) will turn atomic commits into a clean PR description. Poor commit quality yields poor PR descriptions.
234
+
235
+ ---
236
+
237
+ ## Real Example (commit history for a full spec execution)
238
+
239
+ ```
240
+ $ git log --oneline auth-system spec
241
+
242
+ abc123f feat(auth): green - implement login endpoint (Requirements: FR-01)
243
+ def456g feat(auth): green - implement password hashing (Design: AD-03)
244
+ ghi789h test(auth): red - add login endpoint tests
245
+ jkl012i test(auth): red - add password hash tests
246
+ mno345j chore(deps): add bcrypt@5.1.0
247
+ pqr678k docs(auth): add design.md for JWT authentication
248
+ stu901l docs(auth): add requirements.md
249
+ vwx234m docs(auth): add research.md (initial spec)
250
+ ```
251
+
252
+ Reading this history, anyone can understand:
253
+ - First came research → requirements → design (doc commits)
254
+ - Then a dependency was added
255
+ - Then TDD red (tests) → green (implementation)
256
+ - Every step is atomic
257
+
258
+ This is the quality CurDX-Flow demands.
259
+
260
+ ---
261
+
262
+ _CurDX-Flow internal rule. Violation counts as a flow-executor task failure._