@pieerry/harness-kit 3.3.1 → 4.0.1
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/.claude/{plugins → agents}/product-manager/README.md +32 -30
- package/.claude/{plugins → agents}/product-manager/guides/examples/good-prp-example.md +2 -2
- package/.claude/{plugins → agents}/product-manager/guides/pipeline.md +7 -7
- package/.claude/{plugins → agents}/product-manager/sensors/prp-links.md +1 -1
- package/.claude/{plugins → agents}/product-manager/skills/prd/SKILL.md +2 -2
- package/.claude/{plugins → agents}/product-manager/skills/prp/SKILL.md +4 -4
- package/.claude/agents/product-manager.md +2 -2
- package/.claude/agents/staff-software-engineer/README.md +87 -0
- package/.claude/{plugins → agents}/staff-software-engineer/guides/conventions-override.md +3 -3
- package/.claude/{plugins → agents}/staff-software-engineer/guides/pipeline.md +4 -4
- package/.claude/{plugins → agents}/staff-software-engineer/sensors/dev-structure.md +2 -2
- package/.claude/{plugins → agents}/staff-software-engineer/sensors/pr-structure.md +3 -3
- package/.claude/{plugins → agents}/staff-software-engineer/sensors/test-structure.md +2 -2
- package/.claude/agents/staff-software-engineer.md +4 -4
- package/.claude/commands/pipeline/reset.md +1 -1
- package/.claude/commands/product-manager/prd.md +11 -11
- package/.claude/commands/product-manager/prp.md +12 -12
- package/.claude/commands/product-manager/run.md +4 -4
- package/.claude/commands/sse/dev.md +11 -11
- package/.claude/commands/sse/plan.md +11 -12
- package/.claude/commands/sse/pr.md +6 -7
- package/.claude/commands/sse/run.md +4 -4
- package/.claude/commands/sse/test.md +5 -5
- package/.claude/conventions/README.md +1 -1
- package/.claude/hooks/activity-pre-read.sh +4 -4
- package/.claude/hooks/status-line.sh +11 -11
- package/.claude/{plugins/product-manager/hooks → runtime/hooks/product-manager}/post-eval-prd.sh +11 -9
- package/.claude/{plugins/product-manager/hooks → runtime/hooks/product-manager}/post-eval-prp.sh +11 -9
- package/.claude/{plugins/product-manager/hooks → runtime/hooks/product-manager}/post-write-prd.sh +7 -5
- package/.claude/{plugins/product-manager/hooks → runtime/hooks/product-manager}/post-write-prp.sh +8 -6
- package/.claude/{plugins/product-manager/hooks → runtime/hooks/product-manager}/pre-prp-check.sh +5 -3
- package/.claude/{plugins/staff-software-engineer/hooks → runtime/hooks/staff-software-engineer}/post-eval-sse.sh +13 -11
- package/.claude/{plugins/staff-software-engineer/hooks → runtime/hooks/staff-software-engineer}/post-write-sse.sh +11 -9
- package/.claude/runtime/scripts/product-manager/__pycache__/confluence-publish.cpython-314.pyc +0 -0
- package/.claude/runtime/scripts/product-manager/__pycache__/link-validator.cpython-314.pyc +0 -0
- package/.claude/runtime/scripts/product-manager/__pycache__/sensor-runner.cpython-314.pyc +0 -0
- package/.claude/runtime/scripts/product-manager/__pycache__/token-phase.cpython-314.pyc +0 -0
- package/.claude/runtime/scripts/product-manager/confluence-publish.py +206 -0
- package/.claude/{plugins/product-manager/scripts → runtime/scripts/product-manager}/link-validator.py +1 -1
- package/.claude/{plugins/product-manager/scripts → runtime/scripts/product-manager}/token-phase.py +2 -2
- package/.claude/scripts/__pycache__/activity.cpython-314.pyc +0 -0
- package/.claude/scripts/__pycache__/pipeline.cpython-314.pyc +0 -0
- package/.claude/scripts/__pycache__/pr-monitor.cpython-314.pyc +0 -0
- package/.claude/scripts/pipeline.py +6 -6
- package/.claude/settings.json +7 -7
- package/.claude/settings.local.json +11 -3
- package/AGENTS.md +141 -0
- package/CLAUDE.md +9 -7
- package/README.md +122 -269
- package/VERSION +1 -1
- package/bin/hk.js +16 -8
- package/package.json +5 -3
- package/setup/install.sh +63 -44
- package/setup/update.sh +5 -0
- package/.claude/plugins/product-manager/scripts/confluence-publish.py +0 -205
- package/.claude/plugins/staff-software-engineer/README.md +0 -90
- /package/.claude/{plugins → agents}/product-manager/evals/prd-quality.md +0 -0
- /package/.claude/{plugins → agents}/product-manager/evals/prd-readiness.md +0 -0
- /package/.claude/{plugins → agents}/product-manager/evals/prp-context-readiness.md +0 -0
- /package/.claude/{plugins → agents}/product-manager/evals/prp-quality.md +0 -0
- /package/.claude/{plugins → agents}/product-manager/guides/examples/good-prd-example.md +0 -0
- /package/.claude/{plugins → agents}/product-manager/guides/prd-guidelines.md +0 -0
- /package/.claude/{plugins → agents}/product-manager/guides/product-guidelines.md +0 -0
- /package/.claude/{plugins → agents}/product-manager/guides/prp-guidelines.md +0 -0
- /package/.claude/{plugins → agents}/product-manager/guides/templates/prd.md +0 -0
- /package/.claude/{plugins → agents}/product-manager/guides/templates/prp.md +0 -0
- /package/.claude/{plugins → agents}/product-manager/guides/writing-style.md +0 -0
- /package/.claude/{plugins → agents}/product-manager/sensors/prd-acceptance-criteria.md +0 -0
- /package/.claude/{plugins → agents}/product-manager/sensors/prd-structure.md +0 -0
- /package/.claude/{plugins → agents}/product-manager/sensors/prp-context-quality.md +0 -0
- /package/.claude/{plugins → agents}/product-manager/sensors/prp-structure.md +0 -0
- /package/.claude/{plugins → agents}/staff-software-engineer/evals/dev-quality.md +0 -0
- /package/.claude/{plugins → agents}/staff-software-engineer/evals/plan-quality.md +0 -0
- /package/.claude/{plugins → agents}/staff-software-engineer/evals/pr-quality.md +0 -0
- /package/.claude/{plugins → agents}/staff-software-engineer/evals/test-quality.md +0 -0
- /package/.claude/{plugins → agents}/staff-software-engineer/guides/coding-style.md +0 -0
- /package/.claude/{plugins → agents}/staff-software-engineer/guides/commit-style.md +0 -0
- /package/.claude/{plugins → agents}/staff-software-engineer/sensors/code-conventions.md +0 -0
- /package/.claude/{plugins → agents}/staff-software-engineer/sensors/plan-structure.md +0 -0
- /package/.claude/{plugins → agents}/staff-software-engineer/sensors/test-coverage.md +0 -0
- /package/.claude/{plugins → agents}/staff-software-engineer/skills/backend/SKILL.md +0 -0
- /package/.claude/{plugins → agents}/staff-software-engineer/skills/devops/SKILL.md +0 -0
- /package/.claude/{plugins → agents}/staff-software-engineer/skills/mobile/SKILL.md +0 -0
- /package/.claude/{plugins → agents}/staff-software-engineer/skills/web/SKILL.md +0 -0
- /package/.claude/{plugins/product-manager/outputs → runtime/outputs/pm}/.markers/.gitkeep +0 -0
- /package/.claude/{plugins/staff-software-engineer/outputs → runtime/outputs/sse}/.markers/.gitkeep +0 -0
- /package/.claude/{plugins/product-manager/scripts → runtime/scripts/product-manager}/sensor-runner.py +0 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Publish a PRD or PRP to Confluence.
|
|
4
|
+
|
|
5
|
+
Reads credentials from environment:
|
|
6
|
+
- JIRA_USERNAME (email)
|
|
7
|
+
- JIRA_API_TOKEN (API token)
|
|
8
|
+
|
|
9
|
+
Targets the Confluence at https://YOUR-DOMAIN.atlassian.net.
|
|
10
|
+
|
|
11
|
+
Usage:
|
|
12
|
+
confluence-publish.py --artifact PATH.md --kind {prd|prp}
|
|
13
|
+
|
|
14
|
+
Exit 0 on success, 1 on failure. Stays silent on routine output, prints
|
|
15
|
+
errors to stderr.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import argparse
|
|
19
|
+
import base64
|
|
20
|
+
import html
|
|
21
|
+
import json
|
|
22
|
+
import os
|
|
23
|
+
import re
|
|
24
|
+
import sys
|
|
25
|
+
import urllib.error
|
|
26
|
+
import urllib.request
|
|
27
|
+
from pathlib import Path
|
|
28
|
+
|
|
29
|
+
CONFLUENCE_BASE = "https://YOUR-DOMAIN.atlassian.net/wiki/rest/api/content"
|
|
30
|
+
SPACE_KEY = "TET1"
|
|
31
|
+
|
|
32
|
+
# Parent page IDs per kind. Override via env if needed.
|
|
33
|
+
PARENT_IDS = {
|
|
34
|
+
"prd": os.environ.get("CONFLUENCE_PARENT_PRD", "11351457795"),
|
|
35
|
+
"prp": os.environ.get("CONFLUENCE_PARENT_PRP", "11351457795"),
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def md_to_storage(md: str) -> str:
|
|
40
|
+
"""Minimal Markdown to Confluence storage XHTML.
|
|
41
|
+
Good enough for headings, paragraphs, fenced code, lists, tables.
|
|
42
|
+
For richer rendering, swap for a real converter later.
|
|
43
|
+
"""
|
|
44
|
+
lines = md.splitlines()
|
|
45
|
+
out: list[str] = []
|
|
46
|
+
in_code = False
|
|
47
|
+
in_list: str | None = None # 'ul' or 'ol'
|
|
48
|
+
in_table = False
|
|
49
|
+
|
|
50
|
+
def close_list():
|
|
51
|
+
nonlocal in_list
|
|
52
|
+
if in_list:
|
|
53
|
+
out.append(f"</{in_list}>")
|
|
54
|
+
in_list = None
|
|
55
|
+
|
|
56
|
+
def close_table():
|
|
57
|
+
nonlocal in_table
|
|
58
|
+
if in_table:
|
|
59
|
+
out.append("</tbody></table>")
|
|
60
|
+
in_table = False
|
|
61
|
+
|
|
62
|
+
for line in lines:
|
|
63
|
+
if line.startswith("```"):
|
|
64
|
+
close_list()
|
|
65
|
+
close_table()
|
|
66
|
+
if not in_code:
|
|
67
|
+
lang = line[3:].strip() or "none"
|
|
68
|
+
out.append(
|
|
69
|
+
f'<ac:structured-macro ac:name="code">'
|
|
70
|
+
f'<ac:parameter ac:name="language">{html.escape(lang)}</ac:parameter>'
|
|
71
|
+
f'<ac:plain-text-body><![CDATA['
|
|
72
|
+
)
|
|
73
|
+
in_code = True
|
|
74
|
+
else:
|
|
75
|
+
out.append("]]></ac:plain-text-body></ac:structured-macro>")
|
|
76
|
+
in_code = False
|
|
77
|
+
continue
|
|
78
|
+
|
|
79
|
+
if in_code:
|
|
80
|
+
out.append(line)
|
|
81
|
+
continue
|
|
82
|
+
|
|
83
|
+
h = re.match(r"^(#{1,6})\s+(.+)$", line)
|
|
84
|
+
if h:
|
|
85
|
+
close_list()
|
|
86
|
+
close_table()
|
|
87
|
+
level = len(h.group(1))
|
|
88
|
+
out.append(f"<h{level}>{html.escape(h.group(2))}</h{level}>")
|
|
89
|
+
continue
|
|
90
|
+
|
|
91
|
+
if re.match(r"^[-*]\s+", line):
|
|
92
|
+
close_table()
|
|
93
|
+
if in_list != "ul":
|
|
94
|
+
close_list()
|
|
95
|
+
out.append("<ul>")
|
|
96
|
+
in_list = "ul"
|
|
97
|
+
item = re.sub(r"^[-*]\s+", "", line)
|
|
98
|
+
out.append(f"<li>{html.escape(item)}</li>")
|
|
99
|
+
continue
|
|
100
|
+
|
|
101
|
+
if re.match(r"^\d+\.\s+", line):
|
|
102
|
+
close_table()
|
|
103
|
+
if in_list != "ol":
|
|
104
|
+
close_list()
|
|
105
|
+
out.append("<ol>")
|
|
106
|
+
in_list = "ol"
|
|
107
|
+
item = re.sub(r"^\d+\.\s+", "", line)
|
|
108
|
+
out.append(f"<li>{html.escape(item)}</li>")
|
|
109
|
+
continue
|
|
110
|
+
|
|
111
|
+
if line.startswith("|") and "|" in line[1:]:
|
|
112
|
+
close_list()
|
|
113
|
+
cells = [c.strip() for c in line.strip("|").split("|")]
|
|
114
|
+
if not in_table:
|
|
115
|
+
out.append("<table><tbody>")
|
|
116
|
+
in_table = True
|
|
117
|
+
out.append(
|
|
118
|
+
"<tr>"
|
|
119
|
+
+ "".join(f"<th>{html.escape(c)}</th>" for c in cells)
|
|
120
|
+
+ "</tr>"
|
|
121
|
+
)
|
|
122
|
+
elif all(re.fullmatch(r":?-+:?", c) for c in cells):
|
|
123
|
+
# separator row, skip
|
|
124
|
+
pass
|
|
125
|
+
else:
|
|
126
|
+
out.append(
|
|
127
|
+
"<tr>"
|
|
128
|
+
+ "".join(f"<td>{html.escape(c)}</td>" for c in cells)
|
|
129
|
+
+ "</tr>"
|
|
130
|
+
)
|
|
131
|
+
continue
|
|
132
|
+
|
|
133
|
+
# paragraph or blank
|
|
134
|
+
close_list()
|
|
135
|
+
close_table()
|
|
136
|
+
if line.strip():
|
|
137
|
+
out.append(f"<p>{html.escape(line)}</p>")
|
|
138
|
+
|
|
139
|
+
close_list()
|
|
140
|
+
close_table()
|
|
141
|
+
return "\n".join(out)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def extract_title(md: str) -> str:
|
|
145
|
+
for line in md.splitlines():
|
|
146
|
+
m = re.match(r"^#\s+(.+)$", line)
|
|
147
|
+
if m:
|
|
148
|
+
return m.group(1).strip()
|
|
149
|
+
return "Untitled"
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def main() -> int:
|
|
153
|
+
parser = argparse.ArgumentParser()
|
|
154
|
+
parser.add_argument("--artifact", required=True, type=Path)
|
|
155
|
+
parser.add_argument("--kind", required=True, choices=["prd", "prp"])
|
|
156
|
+
args = parser.parse_args()
|
|
157
|
+
|
|
158
|
+
username = os.environ.get("JIRA_USERNAME")
|
|
159
|
+
token = os.environ.get("JIRA_API_TOKEN")
|
|
160
|
+
if not username or not token:
|
|
161
|
+
print("[confluence-publish] JIRA_USERNAME/JIRA_API_TOKEN not set", file=sys.stderr)
|
|
162
|
+
return 1
|
|
163
|
+
|
|
164
|
+
md = args.artifact.read_text(encoding="utf-8")
|
|
165
|
+
title = extract_title(md)
|
|
166
|
+
storage = md_to_storage(md)
|
|
167
|
+
|
|
168
|
+
payload = {
|
|
169
|
+
"type": "page",
|
|
170
|
+
"title": title,
|
|
171
|
+
"ancestors": [{"id": PARENT_IDS[args.kind]}],
|
|
172
|
+
"space": {"key": SPACE_KEY},
|
|
173
|
+
"body": {"storage": {"value": storage, "representation": "storage"}},
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
auth = base64.b64encode(f"{username}:{token}".encode()).decode()
|
|
177
|
+
req = urllib.request.Request(
|
|
178
|
+
CONFLUENCE_BASE,
|
|
179
|
+
data=json.dumps(payload).encode("utf-8"),
|
|
180
|
+
method="POST",
|
|
181
|
+
headers={
|
|
182
|
+
"Authorization": f"Basic {auth}",
|
|
183
|
+
"Content-Type": "application/json",
|
|
184
|
+
"Accept": "application/json",
|
|
185
|
+
},
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
try:
|
|
189
|
+
with urllib.request.urlopen(req, timeout=20) as resp:
|
|
190
|
+
data = json.loads(resp.read().decode("utf-8"))
|
|
191
|
+
page_url = data.get("_links", {}).get("base", "") + data.get(
|
|
192
|
+
"_links", {}
|
|
193
|
+
).get("webui", "")
|
|
194
|
+
print(f"[confluence-publish] published: {page_url}", file=sys.stderr)
|
|
195
|
+
return 0
|
|
196
|
+
except urllib.error.HTTPError as e:
|
|
197
|
+
body = e.read().decode("utf-8", errors="replace")
|
|
198
|
+
print(f"[confluence-publish] HTTP {e.code}: {body[:500]}", file=sys.stderr)
|
|
199
|
+
return 1
|
|
200
|
+
except Exception as e:
|
|
201
|
+
print(f"[confluence-publish] error: {e}", file=sys.stderr)
|
|
202
|
+
return 1
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
if __name__ == "__main__":
|
|
206
|
+
sys.exit(main())
|
|
@@ -42,7 +42,7 @@ def main() -> int:
|
|
|
42
42
|
candidates = [
|
|
43
43
|
args.repo_root / prd_rel,
|
|
44
44
|
args.artifact.parent / prd_rel,
|
|
45
|
-
args.repo_root / ".claude/
|
|
45
|
+
args.repo_root / ".claude/agents/product-manager" / prd_rel,
|
|
46
46
|
]
|
|
47
47
|
if not any(c.exists() for c in candidates):
|
|
48
48
|
failures.append(f"Source PRD path does not resolve: {prd_rel}")
|
package/.claude/{plugins/product-manager/scripts → runtime/scripts/product-manager}/token-phase.py
RENAMED
|
@@ -137,7 +137,7 @@ def main() -> int:
|
|
|
137
137
|
parser.add_argument("--details", default="{}")
|
|
138
138
|
args = parser.parse_args()
|
|
139
139
|
|
|
140
|
-
markers_dir = args.plugin_dir / "
|
|
140
|
+
markers_dir = args.plugin_dir / ".markers"
|
|
141
141
|
start_marker = markers_dir / f"{args.feature_id}.{args.phase}.start"
|
|
142
142
|
end_marker = markers_dir / f"{args.feature_id}.{args.phase}.end"
|
|
143
143
|
|
|
@@ -187,7 +187,7 @@ def main() -> int:
|
|
|
187
187
|
files["prp"] = args.prp_path
|
|
188
188
|
|
|
189
189
|
tokens_path = (
|
|
190
|
-
args.plugin_dir / "
|
|
190
|
+
args.plugin_dir / "tokens" / f"{args.feature_id}.json"
|
|
191
191
|
)
|
|
192
192
|
update_tokens_json(tokens_path, args.feature_id, files, phase_entry)
|
|
193
193
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -55,12 +55,12 @@ STAGE_TO_COMMAND = {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
STAGE_TO_OUTPUT_DIR = {
|
|
58
|
-
"prd": ".claude/
|
|
59
|
-
"prp": ".claude/
|
|
60
|
-
"plan": ".claude/
|
|
61
|
-
"dev": ".claude/
|
|
62
|
-
"test": ".claude/
|
|
63
|
-
"pr": ".claude/
|
|
58
|
+
"prd": ".claude/runtime/outputs/pm/prd",
|
|
59
|
+
"prp": ".claude/runtime/outputs/pm/prp",
|
|
60
|
+
"plan": ".claude/runtime/outputs/sse/plan",
|
|
61
|
+
"dev": ".claude/runtime/outputs/sse/dev",
|
|
62
|
+
"test": ".claude/runtime/outputs/sse/test",
|
|
63
|
+
"pr": ".claude/runtime/outputs/sse/pr",
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
|
package/.claude/settings.json
CHANGED
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
{
|
|
37
37
|
"matcher": "Write",
|
|
38
38
|
"hooks": [
|
|
39
|
-
{ "type": "command", "command": "[ -x .claude/
|
|
39
|
+
{ "type": "command", "command": "[ -x .claude/runtime/hooks/product-manager/pre-prp-check.sh ] && bash .claude/runtime/hooks/product-manager/pre-prp-check.sh; exit 0" }
|
|
40
40
|
]
|
|
41
41
|
},
|
|
42
42
|
{
|
|
@@ -50,18 +50,18 @@
|
|
|
50
50
|
{
|
|
51
51
|
"matcher": "Write",
|
|
52
52
|
"hooks": [
|
|
53
|
-
{ "type": "command", "command": "[ -x .claude/
|
|
54
|
-
{ "type": "command", "command": "[ -x .claude/
|
|
55
|
-
{ "type": "command", "command": "[ -x .claude/
|
|
53
|
+
{ "type": "command", "command": "[ -x .claude/runtime/hooks/product-manager/post-write-prd.sh ] && bash .claude/runtime/hooks/product-manager/post-write-prd.sh; exit 0" },
|
|
54
|
+
{ "type": "command", "command": "[ -x .claude/runtime/hooks/product-manager/post-write-prp.sh ] && bash .claude/runtime/hooks/product-manager/post-write-prp.sh; exit 0" },
|
|
55
|
+
{ "type": "command", "command": "[ -x .claude/runtime/hooks/staff-software-engineer/post-write-sse.sh ] && bash .claude/runtime/hooks/staff-software-engineer/post-write-sse.sh; exit 0" },
|
|
56
56
|
{ "type": "command", "command": "[ -x .claude/hooks/pipeline-postwrite.sh ] && bash .claude/hooks/pipeline-postwrite.sh; exit 0" }
|
|
57
57
|
]
|
|
58
58
|
},
|
|
59
59
|
{
|
|
60
60
|
"matcher": "Edit",
|
|
61
61
|
"hooks": [
|
|
62
|
-
{ "type": "command", "command": "[ -x .claude/
|
|
63
|
-
{ "type": "command", "command": "[ -x .claude/
|
|
64
|
-
{ "type": "command", "command": "[ -x .claude/
|
|
62
|
+
{ "type": "command", "command": "[ -x .claude/runtime/hooks/product-manager/post-eval-prd.sh ] && bash .claude/runtime/hooks/product-manager/post-eval-prd.sh; exit 0" },
|
|
63
|
+
{ "type": "command", "command": "[ -x .claude/runtime/hooks/product-manager/post-eval-prp.sh ] && bash .claude/runtime/hooks/product-manager/post-eval-prp.sh; exit 0" },
|
|
64
|
+
{ "type": "command", "command": "[ -x .claude/runtime/hooks/staff-software-engineer/post-eval-sse.sh ] && bash .claude/runtime/hooks/staff-software-engineer/post-eval-sse.sh; exit 0" },
|
|
65
65
|
{ "type": "command", "command": "[ -x .claude/hooks/pipeline-postedit.sh ] && bash .claude/hooks/pipeline-postedit.sh; exit 0" }
|
|
66
66
|
]
|
|
67
67
|
}
|
|
@@ -74,8 +74,8 @@
|
|
|
74
74
|
"Bash(npm publish *)",
|
|
75
75
|
"Bash(git tag *)",
|
|
76
76
|
"Bash(sh -n /Users/pierryborges/Development/harness-kit/.claude/hooks/pipeline-session-start.sh)",
|
|
77
|
-
"Bash(sh -n .claude/
|
|
78
|
-
"Bash(sh -n .claude/
|
|
77
|
+
"Bash(sh -n .claude/runtime/hooks/staff-software-engineer/post-write-sse.sh)",
|
|
78
|
+
"Bash(sh -n .claude/runtime/hooks/staff-software-engineer/post-eval-sse.sh)",
|
|
79
79
|
"Bash(sh -n .claude/hooks/activity-pre-read.sh)",
|
|
80
80
|
"Bash(sh -n .claude/hooks/status-line.sh)",
|
|
81
81
|
"Read(//private/tmp/act-test/**)",
|
|
@@ -84,7 +84,15 @@
|
|
|
84
84
|
"Bash(cp /Users/pierryborges/Development/harness-kit/.claude/hooks/status-line.sh .claude/hooks/)",
|
|
85
85
|
"Bash(cp /Users/pierryborges/Development/harness-kit/.claude/scripts/pipeline.py .claude/scripts/)",
|
|
86
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)"
|
|
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)",
|
|
88
|
+
"WebFetch(domain:arxiv.org)",
|
|
89
|
+
"WebFetch(domain:openai.com)",
|
|
90
|
+
"Bash(grep -v \"^$\")",
|
|
91
|
+
"Bash(grep \"Error\\\\|^[^:]*:[^:]*:$\")",
|
|
92
|
+
"Bash(echo \"exit=$?\")",
|
|
93
|
+
"Bash(echo \"next exit=$? \\(expect 1, nothing to do\\)\")",
|
|
94
|
+
"Bash(:)",
|
|
95
|
+
"Bash(ffmpeg -y -i out/demo.mp4 -vf \"fps=8,scale=640:-1:flags=lanczos,split[s0][s1];[s0]palettegen=max_colors=64[p];[s1][p]paletteuse=dither=bayer:bayer_scale=5\" -loop 0 preview.gif)"
|
|
88
96
|
]
|
|
89
97
|
}
|
|
90
98
|
}
|
package/AGENTS.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# AGENTS.md — Agent Registry & Routing
|
|
2
|
+
|
|
3
|
+
Source of truth for every agent, skill, and runtime path in this workspace.
|
|
4
|
+
|
|
5
|
+
This file is the **declarative spec**. Execution lives in `.claude/agents/` (definitions), `.claude/runtime/` (state, outputs), and `.claude/shared/` (cross-agent docs). Pipelines like `/sse:run` and `/product-manager:run` consult this registry when dispatching.
|
|
6
|
+
|
|
7
|
+
Portable across tools (Claude Code, Cursor, Codex) — all read `AGENTS.md` at the repo root.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Quick map
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
AGENTS.md ← this file: registry + routing
|
|
15
|
+
CLAUDE.md ← project context (style, role, conventions)
|
|
16
|
+
.claude/
|
|
17
|
+
├── agents/ ← per-agent definitions + bundled assets
|
|
18
|
+
│ ├── product-manager/
|
|
19
|
+
│ │ ├── README.md
|
|
20
|
+
│ │ ├── sensors/ deterministic checks
|
|
21
|
+
│ │ ├── evals/ LLM-judge rubrics
|
|
22
|
+
│ │ ├── guides/ pipeline, writing style, templates, examples
|
|
23
|
+
│ │ └── skills/ prd, prp
|
|
24
|
+
│ ├── staff-software-engineer/
|
|
25
|
+
│ │ ├── README.md
|
|
26
|
+
│ │ ├── sensors/
|
|
27
|
+
│ │ ├── evals/
|
|
28
|
+
│ │ ├── guides/ pipeline, coding-style, commit-style, conventions-override
|
|
29
|
+
│ │ └── skills/ backend, web, mobile, devops
|
|
30
|
+
│ ├── product-manager.md orchestrator agent
|
|
31
|
+
│ └── staff-software-engineer.md orchestrator agent
|
|
32
|
+
├── commands/ ← slash-command entry points
|
|
33
|
+
│ ├── product-manager/ /product-manager:{prd,prp,run}
|
|
34
|
+
│ ├── sse/ /sse:{plan,dev,test,pr,run}
|
|
35
|
+
│ └── pipeline/ /pipeline:{continue,reset}
|
|
36
|
+
├── conventions/ ← generic conventions (overridable per repo)
|
|
37
|
+
├── hooks/ ← root lifecycle hooks (session-start, prompt, postedit, postwrite, status-line, activity-pre-read)
|
|
38
|
+
├── scripts/ ← root utilities (pipeline.py, activity.py, pr-monitor.py)
|
|
39
|
+
└── runtime/ ← generated artifacts + per-agent hooks/scripts
|
|
40
|
+
├── outputs/
|
|
41
|
+
│ ├── pm/{prd,prp,tokens,.markers}/
|
|
42
|
+
│ └── sse/{plan,dev,test,pr,tokens,.markers}/
|
|
43
|
+
├── hooks/
|
|
44
|
+
│ ├── product-manager/ phase markers, sensor gates, eval, publish
|
|
45
|
+
│ └── staff-software-engineer/
|
|
46
|
+
└── scripts/
|
|
47
|
+
├── product-manager/ sensor-runner, token-phase, link-validator, confluence-publish
|
|
48
|
+
└── staff-software-engineer/ token-phase
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Agent registry
|
|
54
|
+
|
|
55
|
+
### Orchestrators
|
|
56
|
+
|
|
57
|
+
| Agent | When to use | Entry | Definition |
|
|
58
|
+
|---|---|---|---|
|
|
59
|
+
| `product-manager` | Generate PRD then PRP for a squad/feature | `/product-manager:run` | `.claude/agents/product-manager.md` |
|
|
60
|
+
| `staff-software-engineer` | Full engineering pipeline: plan → dev → test → pr | `/sse:run` | `.claude/agents/staff-software-engineer.md` |
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Routing
|
|
65
|
+
|
|
66
|
+
When the user types a slash command, the entry point is unambiguous. When the user describes work in natural language, the main session consults this routing table:
|
|
67
|
+
|
|
68
|
+
| User intent | Route |
|
|
69
|
+
|---|---|
|
|
70
|
+
| "ship a new feature end-to-end" | `staff-software-engineer` (`/sse:run` full pipeline) |
|
|
71
|
+
| "draft a PRD" | `product-manager` → `/product-manager:prd` |
|
|
72
|
+
| "draft a PRP" | `product-manager` → `/product-manager:prp` |
|
|
73
|
+
| "full PM pipeline" | `product-manager` → `/product-manager:run` |
|
|
74
|
+
| "make the plan" | `/sse:plan` |
|
|
75
|
+
| "implement the plan" | `/sse:dev` |
|
|
76
|
+
| "run tests" | `/sse:test` |
|
|
77
|
+
| "open the PR" | `/sse:pr` |
|
|
78
|
+
| "continue the active pipeline" | `/pipeline:continue` |
|
|
79
|
+
| "abandon active feature" | `/pipeline:reset` |
|
|
80
|
+
|
|
81
|
+
**Rule of thumb:** if you know the agent, invoke directly. If you only know the intent, this table dispatches.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Pipeline stages
|
|
86
|
+
|
|
87
|
+
Six gated stages, one feature: `prd → prp → plan → dev → test → pr`.
|
|
88
|
+
|
|
89
|
+
Each stage:
|
|
90
|
+
1. Writes a markdown artifact to `.claude/runtime/outputs/{pm,sse}/{stage}/{feature_id}.md`.
|
|
91
|
+
2. Triggers deterministic sensors (markdown rules + Python runner) on save.
|
|
92
|
+
3. Applies an LLM-judge eval rubric, retries on low score (up to 3).
|
|
93
|
+
4. On approval, records token spend per phase under `.claude/runtime/outputs/{pm,sse}/tokens/{feature_id}.json`.
|
|
94
|
+
|
|
95
|
+
Phase markers under `.claude/runtime/outputs/{pm,sse}/.markers/` track stage boundaries (`{feature}.{phase}.{start,end}`) for token accounting and pipeline status.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Runtime (state, outputs, hooks)
|
|
100
|
+
|
|
101
|
+
Generated artifacts and lifecycle hooks live under `.claude/runtime/`.
|
|
102
|
+
|
|
103
|
+
| Path | Contents |
|
|
104
|
+
|---|---|
|
|
105
|
+
| `runtime/outputs/pm/{prd,prp,tokens,.markers}/` | PRD/PRP artifacts, token JSONs, phase markers |
|
|
106
|
+
| `runtime/outputs/sse/{plan,dev,test,pr,tokens,.markers}/` | Plan/dev/test/pr artifacts, token JSONs, phase markers |
|
|
107
|
+
| `runtime/hooks/<agent>/` | Per-agent lifecycle hooks (post-write, post-eval, pre-prp-check) |
|
|
108
|
+
| `runtime/scripts/<agent>/` | Per-agent utilities (sensor-runner, token-phase, link-validator, confluence-publish) |
|
|
109
|
+
|
|
110
|
+
`settings.json` `hooks` blocks reference these paths. `.claude/scripts/pipeline.py` reads/writes markers and outputs.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Distribution
|
|
115
|
+
|
|
116
|
+
This repo is **harness-kit**, the source-of-truth template. Consumer repos install the harness via `setup/install.sh`, which copies:
|
|
117
|
+
|
|
118
|
+
- `AGENTS.md` and `CLAUDE.md` to the target root
|
|
119
|
+
- `.claude/agents/`, `.claude/commands/`, `.claude/hooks/`, `.claude/scripts/`, `.claude/conventions/` to the target `.claude/`
|
|
120
|
+
- `.claude/runtime/hooks/`, `.claude/runtime/scripts/` to the target (definition-side only; `outputs/`, `state/`, `.markers/` are runtime, not distributed)
|
|
121
|
+
- `.claude/settings.json` `hooks` block, merged with the consumer's existing settings
|
|
122
|
+
|
|
123
|
+
`setup/update.sh` migrates v3.x consumers (which have `.claude/plugins/`) to v4.x layout in place. v3.x consumers were the **plugin-shaped** distribution.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Adding a new agent
|
|
128
|
+
|
|
129
|
+
1. Create `.claude/agents/<name>.md` (or `.claude/agents/<name>/agent.md` if bundled assets).
|
|
130
|
+
2. Register here under the right section.
|
|
131
|
+
3. If invocable via slash command, add `.claude/commands/<name>.md`.
|
|
132
|
+
4. If it needs lifecycle hooks, add under `.claude/runtime/hooks/<name>/` and wire in `.claude/settings.json`.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## See also
|
|
137
|
+
|
|
138
|
+
- [`CLAUDE.md`](./CLAUDE.md) — workspace context, style, role
|
|
139
|
+
- [`.claude/commands/`](./.claude/commands/) — slash command definitions
|
|
140
|
+
- [`setup/install.sh`](./setup/install.sh) — consumer installer
|
|
141
|
+
- [`setup/update.sh`](./setup/update.sh) — v3→v4 migration tool
|
package/CLAUDE.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Read by Claude Code on every session. Defines how to work in this harness-kit workspace.
|
|
4
4
|
|
|
5
|
+
**See [`AGENTS.md`](./AGENTS.md) for the full agent registry, routing table, and runtime paths.** Consult it whenever you need to decide which agent handles a request, where assets live, or how stages flow.
|
|
6
|
+
|
|
5
7
|
## Response Style
|
|
6
8
|
|
|
7
9
|
- **Language:** match the user. Default English. Domain terms stay native.
|
|
@@ -29,9 +31,9 @@ AI copilot for product + engineering delivery. Thinking partner and execution as
|
|
|
29
31
|
|
|
30
32
|
Configurable per consumer. Fill `context-library/business-info.md` and `context-library/squads/{slug}/` with your own structure. Ask which squad the work belongs to when not clear.
|
|
31
33
|
|
|
32
|
-
##
|
|
34
|
+
## Agents
|
|
33
35
|
|
|
34
|
-
|
|
36
|
+
Two orchestrator agents, registered in [`AGENTS.md`](./AGENTS.md). Each lives under `.claude/agents/<name>/` with its own README, sensors, evals, guides, and skills.
|
|
35
37
|
|
|
36
38
|
### product-manager
|
|
37
39
|
|
|
@@ -40,7 +42,7 @@ PRD and PRP generation. Slash commands:
|
|
|
40
42
|
- `/product-manager:prp` draft a PRP (engineering-ready spec)
|
|
41
43
|
- `/product-manager:run` full PM pipeline
|
|
42
44
|
|
|
43
|
-
Sub-agent `product-manager` is also Task-tool-invokable for delegation.
|
|
45
|
+
Sub-agent `product-manager` is also Task-tool-invokable for delegation. Assets: `.claude/agents/product-manager/`.
|
|
44
46
|
|
|
45
47
|
### staff-software-engineer
|
|
46
48
|
|
|
@@ -51,13 +53,13 @@ Engineering pipeline. Slash commands:
|
|
|
51
53
|
- `/sse:pr` open the draft PR
|
|
52
54
|
- `/sse:run` full SSE pipeline
|
|
53
55
|
|
|
54
|
-
Sub-agent `staff-software-engineer` is also Task-tool-invokable.
|
|
56
|
+
Sub-agent `staff-software-engineer` is also Task-tool-invokable. Assets: `.claude/agents/staff-software-engineer/`.
|
|
55
57
|
|
|
56
58
|
Full pipeline order: `prd → prp → plan → dev → test → pr`. Each stage gets an approval marker. The status bar tracks the current one.
|
|
57
59
|
|
|
58
60
|
## Project conventions override
|
|
59
61
|
|
|
60
|
-
Each target repo can override SSE
|
|
62
|
+
Each target repo can override SSE defaults with files in `.claude/conventions/`:
|
|
61
63
|
|
|
62
64
|
```
|
|
63
65
|
{repo}/.claude/conventions/
|
|
@@ -67,11 +69,11 @@ Each target repo can override SSE plugin defaults with files in `.claude/convent
|
|
|
67
69
|
└── devops.md
|
|
68
70
|
```
|
|
69
71
|
|
|
70
|
-
When a file exists,
|
|
72
|
+
When a file exists, the agent reads it on top of defaults. Project wins. Reference: `.claude/agents/staff-software-engineer/guides/conventions-override.md`.
|
|
71
73
|
|
|
72
74
|
## Token accounting and status bar
|
|
73
75
|
|
|
74
|
-
After approval, hooks compute tokens used per phase from the Claude transcript and append to
|
|
76
|
+
After approval, hooks compute tokens used per phase from the Claude transcript and append to `.claude/runtime/outputs/{pm,sse}/tokens/{feature_id}.json` (per agent). One JSON per agent collects phases across the full lifecycle.
|
|
75
77
|
|
|
76
78
|
The status bar follows the active feature through the 6-stage pipeline. See `.claude/hooks/status-line.sh`.
|
|
77
79
|
|