@pieerry/harness-kit 3.1.1 → 3.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 (65) hide show
  1. package/.claude/.hk-version +1 -0
  2. package/.claude/agents/product-manager.md +2 -2
  3. package/.claude/agents/staff-software-engineer.md +2 -2
  4. package/.claude/commands/pipeline/continue.md +8 -8
  5. package/.claude/commands/pipeline/reset.md +4 -4
  6. package/.claude/commands/product-manager/prd.md +4 -4
  7. package/.claude/commands/product-manager/prp.md +7 -7
  8. package/.claude/commands/product-manager/run.md +5 -5
  9. package/.claude/commands/sse/dev.md +17 -12
  10. package/.claude/commands/sse/plan.md +8 -8
  11. package/.claude/commands/sse/pr-monitor.md +56 -0
  12. package/.claude/commands/sse/pr.md +21 -11
  13. package/.claude/commands/sse/run.md +7 -7
  14. package/.claude/commands/sse/test.md +15 -9
  15. package/.claude/conventions/README.md +12 -0
  16. package/.claude/hooks/activity-pre-read.sh +18 -0
  17. package/.claude/hooks/pipeline-session-start.sh +26 -2
  18. package/.claude/hooks/status-line.sh +17 -1
  19. package/.claude/plugins/product-manager/evals/prd-quality.md +3 -3
  20. package/.claude/plugins/product-manager/evals/prd-readiness.md +1 -1
  21. package/.claude/plugins/product-manager/evals/prp-context-readiness.md +5 -5
  22. package/.claude/plugins/product-manager/evals/prp-quality.md +1 -1
  23. package/.claude/plugins/product-manager/guides/pipeline.md +14 -14
  24. package/.claude/plugins/product-manager/guides/prd-guidelines.md +4 -4
  25. package/.claude/plugins/product-manager/guides/product-guidelines.md +16 -16
  26. package/.claude/plugins/product-manager/guides/prp-guidelines.md +16 -16
  27. package/.claude/plugins/product-manager/guides/writing-style.md +9 -9
  28. package/.claude/plugins/product-manager/sensors/prd-acceptance-criteria.md +6 -6
  29. package/.claude/plugins/product-manager/sensors/prd-structure.md +2 -2
  30. package/.claude/plugins/product-manager/sensors/prp-context-quality.md +6 -6
  31. package/.claude/plugins/product-manager/sensors/prp-links.md +2 -2
  32. package/.claude/plugins/product-manager/sensors/prp-structure.md +1 -1
  33. package/.claude/plugins/staff-software-engineer/evals/dev-quality.md +48 -0
  34. package/.claude/plugins/staff-software-engineer/evals/plan-quality.md +6 -6
  35. package/.claude/plugins/staff-software-engineer/evals/pr-quality.md +48 -0
  36. package/.claude/plugins/staff-software-engineer/evals/test-quality.md +48 -0
  37. package/.claude/plugins/staff-software-engineer/guides/coding-style.md +7 -7
  38. package/.claude/plugins/staff-software-engineer/guides/commit-style.md +3 -3
  39. package/.claude/plugins/staff-software-engineer/guides/conventions-override.md +13 -13
  40. package/.claude/plugins/staff-software-engineer/guides/pipeline.md +12 -12
  41. package/.claude/plugins/staff-software-engineer/hooks/post-eval-sse.sh +65 -0
  42. package/.claude/plugins/staff-software-engineer/hooks/post-write-sse.sh +60 -0
  43. package/.claude/plugins/staff-software-engineer/sensors/code-conventions.md +4 -4
  44. package/.claude/plugins/staff-software-engineer/sensors/dev-structure.md +46 -0
  45. package/.claude/plugins/staff-software-engineer/sensors/pr-structure.md +49 -0
  46. package/.claude/plugins/staff-software-engineer/sensors/test-coverage.md +6 -6
  47. package/.claude/plugins/staff-software-engineer/sensors/test-structure.md +46 -0
  48. package/.claude/plugins/staff-software-engineer/skills/backend/SKILL.md +8 -8
  49. package/.claude/plugins/staff-software-engineer/skills/devops/SKILL.md +3 -3
  50. package/.claude/plugins/staff-software-engineer/skills/mobile/SKILL.md +3 -3
  51. package/.claude/plugins/staff-software-engineer/skills/web/SKILL.md +2 -2
  52. package/.claude/scripts/activity.py +68 -0
  53. package/.claude/scripts/pipeline.py +10 -0
  54. package/.claude/scripts/pr-monitor.py +113 -0
  55. package/.claude/scripts/stage-card.md +37 -34
  56. package/.claude/settings.json +74 -0
  57. package/.claude/settings.local.json +14 -1
  58. package/CLAUDE.md +6 -0
  59. package/README.md +204 -60
  60. package/VERSION +1 -1
  61. package/bin/hk.js +6 -1
  62. package/package.json +1 -1
  63. package/setup/install.sh +16 -8
  64. package/.claude/plugins/staff-software-engineer/hooks/post-eval-plan.sh +0 -43
  65. package/.claude/plugins/staff-software-engineer/hooks/post-write-plan.sh +0 -49
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env python3
2
+ """Live activity tracker for the status bar.
3
+
4
+ Writes the current sensor/eval/guide being touched to .claude/.activity so
5
+ status-line.sh can surface it. Auto-expires after 60s to avoid stale state
6
+ if a hook crashes before clearing.
7
+
8
+ Subcommands:
9
+ set <kind> <name> record kind+name (kind: sensor|eval|guide)
10
+ clear remove activity file
11
+ read print one-line "kind: name" (or empty if stale/absent)
12
+ """
13
+
14
+ import json
15
+ import sys
16
+ import time
17
+ from pathlib import Path
18
+
19
+ ACTIVITY_FILE = Path(".claude/.activity")
20
+ TTL_SECONDS = 60
21
+
22
+
23
+ def cmd_set(args):
24
+ if len(args) < 2:
25
+ return 1
26
+ kind, name = args[0], args[1]
27
+ if kind not in ("sensor", "eval", "guide"):
28
+ return 1
29
+ ACTIVITY_FILE.parent.mkdir(parents=True, exist_ok=True)
30
+ ACTIVITY_FILE.write_text(json.dumps({"kind": kind, "name": name, "ts": time.time()}))
31
+ return 0
32
+
33
+
34
+ def cmd_clear(_args):
35
+ if ACTIVITY_FILE.exists():
36
+ ACTIVITY_FILE.unlink()
37
+ return 0
38
+
39
+
40
+ def cmd_read(_args):
41
+ if not ACTIVITY_FILE.exists():
42
+ return 0
43
+ try:
44
+ d = json.loads(ACTIVITY_FILE.read_text())
45
+ except (json.JSONDecodeError, OSError):
46
+ return 0
47
+ if time.time() - d.get("ts", 0) > TTL_SECONDS:
48
+ try:
49
+ ACTIVITY_FILE.unlink()
50
+ except OSError:
51
+ pass
52
+ return 0
53
+ print(f"{d.get('kind', '?')}: {d.get('name', '?')}")
54
+ return 0
55
+
56
+
57
+ COMMANDS = {"set": cmd_set, "clear": cmd_clear, "read": cmd_read}
58
+
59
+
60
+ def main():
61
+ if len(sys.argv) < 2 or sys.argv[1] not in COMMANDS:
62
+ print(__doc__, file=sys.stderr)
63
+ return 2
64
+ return COMMANDS[sys.argv[1]](sys.argv[2:])
65
+
66
+
67
+ if __name__ == "__main__":
68
+ sys.exit(main())
@@ -162,6 +162,16 @@ def render_line():
162
162
  next_cmd = STAGE_TO_COMMAND.get(current, "?")
163
163
 
164
164
  shape = "+".join(pipeline)
165
+
166
+ # No work started yet: show full menu instead of locking to next stage
167
+ no_work_started = (
168
+ not fid
169
+ and not prev
170
+ and all(stages.get(s) == "pending" for s in pipeline)
171
+ )
172
+ if no_work_started:
173
+ return f"{name} [{shape}] · /product-manager:run · /sse:run · /pipeline:continue · /pipeline:reset"
174
+
165
175
  if prev:
166
176
  return f"{name} [{shape}] · {prev} approved · {current} {cur_state} · next {next_cmd}"
167
177
  return f"{name} [{shape}] · {current} {cur_state} · next {next_cmd}"
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env python3
2
+ """PR-merge monitor state for harness-kit.
3
+
4
+ Tracks the PR being watched and the polling cadence. Stored at
5
+ .claude/.pr-monitor-state.json relative to repo root.
6
+
7
+ Polling schedule: 3 -> 6 -> 12 -> 24 -> 30 minutes (cap). Bumps to next rung
8
+ after 5 attempts at the current interval. Stays at 30 once reached.
9
+
10
+ Subcommands:
11
+ init <pr_number> <pr_url> <branch> create state, interval=3min
12
+ bump +1 attempt, escalate if 5 hit;
13
+ prints next interval in seconds
14
+ read print state JSON
15
+ clear remove state file
16
+ """
17
+
18
+ import json
19
+ import sys
20
+ from datetime import datetime, timezone
21
+ from pathlib import Path
22
+
23
+ STATE_FILE = Path(".claude/.pr-monitor-state.json")
24
+ START_MIN = 3
25
+ CAP_MIN = 30
26
+ ATTEMPTS_PER_RUNG = 5
27
+
28
+
29
+ def now_iso():
30
+ return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
31
+
32
+
33
+ def load():
34
+ if not STATE_FILE.exists():
35
+ return None
36
+ try:
37
+ return json.loads(STATE_FILE.read_text())
38
+ except (json.JSONDecodeError, OSError):
39
+ return None
40
+
41
+
42
+ def save(state):
43
+ state["updated_at"] = now_iso()
44
+ STATE_FILE.parent.mkdir(parents=True, exist_ok=True)
45
+ STATE_FILE.write_text(json.dumps(state, indent=2) + "\n")
46
+
47
+
48
+ def cmd_init(args):
49
+ if len(args) < 3:
50
+ print("usage: pr-monitor.py init <pr_number> <pr_url> <branch>", file=sys.stderr)
51
+ return 1
52
+ state = {
53
+ "pr_number": int(args[0]),
54
+ "pr_url": args[1],
55
+ "branch": args[2],
56
+ "current_interval_min": START_MIN,
57
+ "attempts_at_interval": 0,
58
+ "total_attempts": 0,
59
+ "started_at": now_iso(),
60
+ "updated_at": now_iso(),
61
+ }
62
+ save(state)
63
+ print(START_MIN * 60)
64
+ return 0
65
+
66
+
67
+ def cmd_bump(_args):
68
+ state = load()
69
+ if not state:
70
+ print("no state", file=sys.stderr)
71
+ return 1
72
+ state["attempts_at_interval"] += 1
73
+ state["total_attempts"] += 1
74
+ if (
75
+ state["attempts_at_interval"] >= ATTEMPTS_PER_RUNG
76
+ and state["current_interval_min"] < CAP_MIN
77
+ ):
78
+ state["current_interval_min"] = min(state["current_interval_min"] * 2, CAP_MIN)
79
+ state["attempts_at_interval"] = 0
80
+ save(state)
81
+ print(state["current_interval_min"] * 60)
82
+ return 0
83
+
84
+
85
+ def cmd_read(_args):
86
+ state = load()
87
+ print(json.dumps(state or {}, indent=2))
88
+ return 0
89
+
90
+
91
+ def cmd_clear(_args):
92
+ if STATE_FILE.exists():
93
+ STATE_FILE.unlink()
94
+ return 0
95
+
96
+
97
+ COMMANDS = {
98
+ "init": cmd_init,
99
+ "bump": cmd_bump,
100
+ "read": cmd_read,
101
+ "clear": cmd_clear,
102
+ }
103
+
104
+
105
+ def main():
106
+ if len(sys.argv) < 2 or sys.argv[1] not in COMMANDS:
107
+ print(__doc__, file=sys.stderr)
108
+ return 2
109
+ return COMMANDS[sys.argv[1]](sys.argv[2:])
110
+
111
+
112
+ if __name__ == "__main__":
113
+ sys.exit(main())
@@ -9,17 +9,20 @@ The card is part of the LLM's output, not a hook. Hooks update the status bar;
9
9
  this card explains what the stage is about to do (or just did) in human-readable
10
10
  form.
11
11
 
12
+ Render the card **outside** a code fence so markdown bold renders. Two visual
13
+ weights: bold labels, plain values. No extra colors.
14
+
12
15
  ## Header card
13
16
 
14
17
  Printed before drafting begins. Lists what will be loaded and what comes next.
15
18
 
16
- ```
19
+ ```text
17
20
  ━━━ {command} · {feature_id}{area_suffix} ━━━
18
- guides: {guide-1.md}, {guide-2.md}, ...
19
- refs: {ref-1.md}, {ref-2.md}, ...
20
- sensors: {sensor-name}, {sensor-name}, ...
21
- eval: {eval-name}
22
- next: {/next:command}
21
+ **guides:** {guide-1.md}, {guide-2.md}, ...
22
+ **refs:** {ref-1.md}, {ref-2.md}, ...
23
+ **sensors:** {sensor-name}, {sensor-name}, ...
24
+ **eval:** {eval-name}
25
+ **next:** {/next:command}
23
26
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
24
27
  ```
25
28
 
@@ -28,47 +31,47 @@ empty otherwise.
28
31
 
29
32
  ## Footer card
30
33
 
31
- Printed after the artifact is saved and gates ran. Shows pass/fail and score.
34
+ Printed after the artifact is saved and gates ran. Shows pass/fail, eval score,
35
+ and token spend for the phase.
32
36
 
33
- ```
37
+ ```text
34
38
  ━━━ done · {command} ━━━
35
- artifact: {relative/output/path.md}
36
- sensors: {pass | failed: name1, name2}
37
- eval: {N}/10
38
- next: {/next:command | (pipeline complete)}
39
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
39
+ **artifact:** {relative/output/path.md}
40
+ **sensors:** {pass | failed: name1, name2}
41
+ **eval:** {N}/10
42
+ **tokens:** in={N} out={N} cache_r={N}
43
+ **next:** {/next:command | (pipeline complete)}
44
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
40
45
  ```
41
46
 
42
- ## Examples
47
+ Pull token totals from `outputs/tokens/{feature_id}.json` (`totals` block).
48
+ Skip the tokens line if the file is absent.
49
+
50
+ ## Examples (rendered output)
43
51
 
44
- ```
45
52
  ━━━ /product-manager:prd · 2026-05-13-billing-multi-currency ━━━
46
- guides: prd-guidelines.md, writing-style.md
47
- refs: business-info.md, squads/billing/context.md
48
- sensors: prd-structure, prd-acceptance-criteria
49
- eval: prd-quality
50
- next: /product-manager:prp
53
+ **guides:** prd-guidelines.md, writing-style.md
54
+ **refs:** business-info.md, squads/billing/context.md
55
+ **sensors:** prd-structure, prd-acceptance-criteria
56
+ **eval:** prd-quality
57
+ **next:** /product-manager:prp
51
58
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
52
- ```
53
59
 
54
- ```
55
60
  ━━━ done · /product-manager:prd ━━━
56
- artifact: outputs/prd/2026-05-13-billing-multi-currency.md
57
- sensors: pass
58
- eval: 8.6/10
59
- next: /product-manager:prp
61
+ **artifact:** outputs/prd/2026-05-13-billing-multi-currency.md
62
+ **sensors:** pass
63
+ **eval:** 8.6/10
64
+ **tokens:** in=12.4k out=3.1k cache_r=42.0k
65
+ **next:** /product-manager:prp
60
66
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
61
- ```
62
67
 
63
- ```
64
68
  ━━━ /sse:plan · 2026-05-13-billing-multi-currency · backend ━━━
65
- guides: pipeline.md, coding-style.md, skills/backend/SKILL.md
66
- refs: prp/2026-05-13-billing-multi-currency.md, conventions/backend.md
67
- sensors: plan-structure
68
- eval: plan-quality
69
- next: /sse:dev
69
+ **guides:** pipeline.md, coding-style.md, skills/backend/SKILL.md
70
+ **refs:** prp/2026-05-13-billing-multi-currency.md, conventions/backend.md
71
+ **sensors:** plan-structure
72
+ **eval:** plan-quality
73
+ **next:** /sse:dev
70
74
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
71
- ```
72
75
 
73
76
  Keep the card terse. List filenames only (no full paths). Skip a line that has
74
77
  no entries.
@@ -0,0 +1,74 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(git:*)",
5
+ "Bash(./gradlew:*)",
6
+ "Bash(./mvnw:*)",
7
+ "Bash(npm:*)",
8
+ "Bash(gh:*)",
9
+ "Bash(jq:*)",
10
+ "Read(outputs/**)",
11
+ "Write(outputs/**)"
12
+ ],
13
+ "deny": [
14
+ "Bash(rm -rf:*)",
15
+ "Bash(git push --force:*)",
16
+ "Bash(git push -f:*)",
17
+ "Bash(git reset --hard:*)"
18
+ ]
19
+ },
20
+ "hooks": {
21
+ "SessionStart": [
22
+ {
23
+ "hooks": [
24
+ { "type": "command", "command": "[ -x .claude/hooks/pipeline-session-start.sh ] && bash .claude/hooks/pipeline-session-start.sh; exit 0" }
25
+ ]
26
+ }
27
+ ],
28
+ "UserPromptSubmit": [
29
+ {
30
+ "hooks": [
31
+ { "type": "command", "command": "[ -x .claude/hooks/pipeline-prompt.sh ] && bash .claude/hooks/pipeline-prompt.sh; exit 0" }
32
+ ]
33
+ }
34
+ ],
35
+ "PreToolUse": [
36
+ {
37
+ "matcher": "Write",
38
+ "hooks": [
39
+ { "type": "command", "command": "[ -x .claude/plugins/product-manager/hooks/pre-prp-check.sh ] && bash .claude/plugins/product-manager/hooks/pre-prp-check.sh; exit 0" }
40
+ ]
41
+ },
42
+ {
43
+ "matcher": "Read",
44
+ "hooks": [
45
+ { "type": "command", "command": "[ -x .claude/hooks/activity-pre-read.sh ] && bash .claude/hooks/activity-pre-read.sh; exit 0" }
46
+ ]
47
+ }
48
+ ],
49
+ "PostToolUse": [
50
+ {
51
+ "matcher": "Write",
52
+ "hooks": [
53
+ { "type": "command", "command": "[ -x .claude/plugins/product-manager/hooks/post-write-prd.sh ] && bash .claude/plugins/product-manager/hooks/post-write-prd.sh; exit 0" },
54
+ { "type": "command", "command": "[ -x .claude/plugins/product-manager/hooks/post-write-prp.sh ] && bash .claude/plugins/product-manager/hooks/post-write-prp.sh; exit 0" },
55
+ { "type": "command", "command": "[ -x .claude/plugins/staff-software-engineer/hooks/post-write-sse.sh ] && bash .claude/plugins/staff-software-engineer/hooks/post-write-sse.sh; exit 0" },
56
+ { "type": "command", "command": "[ -x .claude/hooks/pipeline-postwrite.sh ] && bash .claude/hooks/pipeline-postwrite.sh; exit 0" }
57
+ ]
58
+ },
59
+ {
60
+ "matcher": "Edit",
61
+ "hooks": [
62
+ { "type": "command", "command": "[ -x .claude/plugins/product-manager/hooks/post-eval-prd.sh ] && bash .claude/plugins/product-manager/hooks/post-eval-prd.sh; exit 0" },
63
+ { "type": "command", "command": "[ -x .claude/plugins/product-manager/hooks/post-eval-prp.sh ] && bash .claude/plugins/product-manager/hooks/post-eval-prp.sh; exit 0" },
64
+ { "type": "command", "command": "[ -x .claude/plugins/staff-software-engineer/hooks/post-eval-sse.sh ] && bash .claude/plugins/staff-software-engineer/hooks/post-eval-sse.sh; exit 0" },
65
+ { "type": "command", "command": "[ -x .claude/hooks/pipeline-postedit.sh ] && bash .claude/hooks/pipeline-postedit.sh; exit 0" }
66
+ ]
67
+ }
68
+ ]
69
+ },
70
+ "statusLine": {
71
+ "type": "command",
72
+ "command": "[ -x .claude/hooks/status-line.sh ] && bash .claude/hooks/status-line.sh || printf 'harness-kit not installed'"
73
+ }
74
+ }
@@ -71,7 +71,20 @@
71
71
  "Bash(git -C /Users/pierryborges/Development/harness-kit diff --stat)",
72
72
  "Bash(rm -rf /tmp/hk-fresh /tmp/hk-existing)",
73
73
  "Bash(npm whoami *)",
74
- "Bash(npm publish *)"
74
+ "Bash(npm publish *)",
75
+ "Bash(git tag *)",
76
+ "Bash(sh -n /Users/pierryborges/Development/harness-kit/.claude/hooks/pipeline-session-start.sh)",
77
+ "Bash(sh -n .claude/plugins/staff-software-engineer/hooks/post-write-sse.sh)",
78
+ "Bash(sh -n .claude/plugins/staff-software-engineer/hooks/post-eval-sse.sh)",
79
+ "Bash(sh -n .claude/hooks/activity-pre-read.sh)",
80
+ "Bash(sh -n .claude/hooks/status-line.sh)",
81
+ "Read(//private/tmp/act-test/**)",
82
+ "Bash(cp /Users/pierryborges/Development/harness-kit/.claude/hooks/status-line.sh .claude/hooks/status-line.sh)",
83
+ "Bash(mkdir -p .claude/hooks)",
84
+ "Bash(cp /Users/pierryborges/Development/harness-kit/.claude/hooks/status-line.sh .claude/hooks/)",
85
+ "Bash(cp /Users/pierryborges/Development/harness-kit/.claude/scripts/pipeline.py .claude/scripts/)",
86
+ "Bash(npx --yes tsc --noEmit -p tsconfig.json)",
87
+ "Bash(ffmpeg -y -i out/demo.mp4 -vf 'fps=10,scale=720:-1:flags=lanczos,split[s0][s1];[s0]palettegen=max_colors=96[p];[s1][p]paletteuse=dither=bayer:bayer_scale=5' -loop 0 preview.gif)"
75
88
  ]
76
89
  }
77
90
  }
package/CLAUDE.md CHANGED
@@ -10,6 +10,12 @@ Read by Claude Code on every session. Defines how to work in this harness-kit wo
10
10
  - **Destructive/irreversible ops:** full clarity warning.
11
11
  - No emojis in output unless user explicitly asks.
12
12
 
13
+ ### Caveman-full convention (internal docs)
14
+
15
+ Internal docs (sensors, evals, guides, skills, sub-agent prompts, slash commands) are written in **caveman-full** style to save input tokens: drop articles, drop filler, fragments OK, short synonyms. Technical terms exact, code blocks unchanged, file paths verbatim. Chat reply templates inside slash commands follow the same style.
16
+
17
+ **Exception — artifacts stay natural English.** PRDs, PRPs, plans, dev/test/pr reports get read by external stakeholders. Generated artifact content must be readable prose, not caveman. Reference templates and good-* examples under `guides/templates/` and `guides/examples/` stay natural for the same reason — they teach Claude what good artifact prose looks like.
18
+
13
19
  ## Role
14
20
 
15
21
  AI copilot for product + engineering delivery. Thinking partner and execution assistant. Help PMs, EMs, devs to: