create-harness-vibe-coding 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -74
- package/package.json +2 -2
- package/src/generator.js +3 -5
- package/src/index.js +8 -8
- package/templates/common/.claude/agents/architect.md +35 -0
- package/templates/common/.claude/agents/debugger.md +42 -0
- package/templates/common/.claude/agents/docs-researcher.md +43 -0
- package/templates/common/.claude/agents/implementer.md +41 -0
- package/templates/common/.claude/agents/planner.md +35 -0
- package/templates/common/.claude/agents/researcher.md +42 -0
- package/templates/common/.claude/agents/reviewer.md +34 -0
- package/templates/common/.claude/agents/test-writer.md +39 -0
- package/templates/common/.claude/agents/verifier.md +33 -0
- package/templates/common/.claude/rules/ecc/common.md +25 -22
- package/templates/common/.claude/skills/harness-build-loop/SKILL.md +21 -0
- package/templates/common/.claude/skills/harness-context/SKILL.md +24 -0
- package/templates/common/.claude/skills/harness-lifecycle/SKILL.md +19 -0
- package/templates/common/.claude/skills/harness-research/SKILL.md +29 -0
- package/templates/common/.claude/skills/harness-router/SKILL.md +14 -0
- package/templates/common/AGENTS.md +3 -1
- package/templates/common/CLAUDE.md +30 -33
- package/templates/common/MEMORY.md +30 -7
- package/templates/common/SETUP.md +42 -68
- package/templates/common/docs/README.md +81 -96
- package/templates/common/docs/domain/ports.md +26 -26
- package/templates/common/docs/features/_template.md +34 -25
- package/templates/common/docs/harness/PLAN.md +80 -0
- package/templates/common/docs/harness/agent-workflow.md +57 -116
- package/templates/common/docs/harness/architecture.md +51 -48
- package/templates/common/docs/harness/context-loading.md +93 -0
- package/templates/common/docs/harness/data-flow.md +20 -20
- package/templates/common/docs/harness/dispatch.md +82 -0
- package/templates/common/docs/harness/extension.md +67 -0
- package/templates/common/docs/harness/lifecycle.md +33 -0
- package/templates/common/docs/harness/state-machines.md +15 -15
- package/templates/common/docs/research/PRD.md +25 -23
- package/templates/common/docs/research/README.md +121 -0
- package/templates/common/docs/research/research-results.md +66 -0
- package/templates/common/scripts/validate-harness.mjs +207 -0
- package/templates/common/docs/research/scaffolds.md +0 -60
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# 0-1 Product Lifecycle
|
|
2
|
+
|
|
3
|
+
Use when starting a new product, clarifying a vague idea, or deciding the next phase.
|
|
4
|
+
|
|
5
|
+
## Phase Contract
|
|
6
|
+
|
|
7
|
+
| Phase | Input | Output | Gate |
|
|
8
|
+
| --- | --- | --- | --- |
|
|
9
|
+
| Idea | user intent | problem, target user, non-goals | unclear points asked or assumptions recorded |
|
|
10
|
+
| Research | problem and constraints | `research/research-results.md` | `research/README.md` followed; at least 3 references or explicit reason not possible |
|
|
11
|
+
| PRD | research decision | `research/PRD.md` | MVP, non-goals, acceptance criteria are verifiable |
|
|
12
|
+
| Architecture | PRD | `harness/architecture.md`, `domain/ports.md` | boundaries and first ports are defined |
|
|
13
|
+
| Plan | PRD and architecture | `docs/harness/PLAN.md`, optional `docs/harness/dispatch.md`, one `docs/features/<name>.md` per PRD scope item | tasks have owners, write sets, verification |
|
|
14
|
+
| Build | plan and tests | minimal vertical slice | tests or manual checks prove behavior |
|
|
15
|
+
| Verify | implementation | review findings, test evidence | no unresolved critical/high findings |
|
|
16
|
+
| Feedback | verified slice | next iteration or release decision | learnings recorded in PRD, PLAN, or MEMORY |
|
|
17
|
+
|
|
18
|
+
## Operating Rules
|
|
19
|
+
|
|
20
|
+
- Move one phase at a time unless the user explicitly asks for a fast lane.
|
|
21
|
+
- Start coding only after PRD and minimum architecture gates pass.
|
|
22
|
+
- Prefer one thin vertical slice over broad scaffolding.
|
|
23
|
+
- If feedback changes scope, update PRD before implementation.
|
|
24
|
+
- If implementation reveals a boundary problem, update architecture or ports before continuing.
|
|
25
|
+
|
|
26
|
+
## Fast Lane
|
|
27
|
+
|
|
28
|
+
Small edits may skip full lifecycle when all are true:
|
|
29
|
+
|
|
30
|
+
- user intent is clear
|
|
31
|
+
- one file or one narrow behavior
|
|
32
|
+
- no architecture, port, data-flow, state, permission, or public API change
|
|
33
|
+
- one verification command or one manual check is enough
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
#
|
|
1
|
+
# State Machines — {{projectName}}
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> **Responsibility**: Define the states, transitions, guard conditions, and boundary behaviors for every stateful component. The majority of bugs in long-running harness pipelines originate from illegal state transitions.
|
|
4
4
|
>
|
|
5
|
-
>
|
|
5
|
+
> Philosophical source: UML 2.5.1 Section 15.3.14 + "The transition table is the single most important artifact in the document."
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## State Machine Template
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Fill out each stateful component using this format:
|
|
12
12
|
|
|
13
|
-
###
|
|
13
|
+
### State Enumeration
|
|
14
14
|
|
|
15
|
-
|
|
|
15
|
+
| State | Description | Entry Condition | Exit Condition |
|
|
16
16
|
| --- | --- | --- | --- |
|
|
17
17
|
| `{{STATE_1}}` | {{DESCRIPTION}} | {{CONDITION}} | {{CONDITION}} |
|
|
18
18
|
| `{{STATE_2}}` | {{DESCRIPTION}} | {{CONDITION}} | {{CONDITION}} |
|
|
19
19
|
|
|
20
|
-
###
|
|
20
|
+
### State Transition Diagram
|
|
21
21
|
|
|
22
22
|
```mermaid
|
|
23
23
|
stateDiagram-v2
|
|
@@ -26,25 +26,25 @@ stateDiagram-v2
|
|
|
26
26
|
{{STATE_2}} --> {{INITIAL_STATE}} : {{TRIGGER}}
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
###
|
|
29
|
+
### Transition Table (Most Important)
|
|
30
30
|
|
|
31
|
-
|
|
|
31
|
+
| Current State ↓ / Event → | `{{EVENT_1}}` | `{{EVENT_2}}` | `{{EVENT_3}}` |
|
|
32
32
|
| --- | --- | --- | --- |
|
|
33
33
|
| **`{{STATE_1}}`** | {{TARGET}} | {{TARGET}} | {{TARGET}} |
|
|
34
34
|
| **`{{STATE_2}}`** | {{TARGET}} | {{TARGET}} | {{TARGET}} |
|
|
35
35
|
|
|
36
|
-
###
|
|
36
|
+
### Guard Conditions
|
|
37
37
|
|
|
38
|
-
|
|
|
38
|
+
| Transition | Guard Condition | Notes |
|
|
39
39
|
| --- | --- | --- |
|
|
40
40
|
| `{{SOURCE}} -> {{TARGET}}` | {{GUARD}} | {{NOTE}} |
|
|
41
41
|
|
|
42
|
-
###
|
|
42
|
+
### Illegal Transitions
|
|
43
43
|
|
|
44
|
-
|
|
|
44
|
+
| Transition | Why Illegal |
|
|
45
45
|
| --- | --- |
|
|
46
46
|
| `{{SOURCE}} -> {{TARGET}}` | {{REASON}} |
|
|
47
47
|
|
|
48
48
|
---
|
|
49
49
|
|
|
50
|
-
>
|
|
50
|
+
> **Note**: The current state-machines.md is an empty template. Please fill it in according to the project's actual stateful components.
|
|
@@ -1,63 +1,65 @@
|
|
|
1
1
|
# PRD: {{projectName}}
|
|
2
2
|
|
|
3
|
-
>
|
|
4
|
-
>
|
|
3
|
+
> **Audience**: AI + future you. Not for PM approval — for implementation and review.
|
|
4
|
+
> **Principle**: One page max. Use checkboxes, not prose. Negative definitions > positive definitions.
|
|
5
5
|
>
|
|
6
|
-
>
|
|
6
|
+
> Philosophy source: Miqdad Jaffer (OpenAI)'s lean PRD template for the AI era.
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
-
## 1.
|
|
10
|
+
## 1. Why
|
|
11
11
|
|
|
12
12
|
{{WHY_THIS_PROJECT_EXISTS}}
|
|
13
13
|
|
|
14
|
-
## 2. MVP
|
|
14
|
+
## 2. MVP Scope
|
|
15
15
|
|
|
16
|
-
### v0.1
|
|
16
|
+
### v0.1 Must Be Able To
|
|
17
|
+
|
|
18
|
+
> Each item below must be split into a separate `docs/features/<name>.md` created from `docs/features/_template.md` before implementation begins. One feature = one doc = one implementation unit.
|
|
17
19
|
|
|
18
20
|
- [ ] {{MUST_1}}
|
|
19
21
|
- [ ] {{MUST_2}}
|
|
20
22
|
- [ ] {{MUST_3}}
|
|
21
23
|
|
|
22
|
-
###
|
|
24
|
+
### Explicitly Out of Scope
|
|
23
25
|
|
|
24
26
|
- {{NON_GOAL_1}}
|
|
25
27
|
- {{NON_GOAL_2}}
|
|
26
28
|
- {{NON_GOAL_3}}
|
|
27
29
|
|
|
28
|
-
## 3.
|
|
30
|
+
## 3. Decision Priorities
|
|
29
31
|
|
|
30
|
-
1.
|
|
31
|
-
2.
|
|
32
|
-
3.
|
|
33
|
-
4.
|
|
34
|
-
5.
|
|
32
|
+
1. **Security Boundary** — No bypassing permissions, security gates, or audit.
|
|
33
|
+
2. **Architecture Boundary** — Domain must not depend on harness/infrastructure/interfaces, and harness must not make domain judgments.
|
|
34
|
+
3. **Verifiability** — New behavior must have tests or explicit manual verification records.
|
|
35
|
+
4. **Correctness** — Behavior must match design docs, port contracts, data flows, and state machines.
|
|
36
|
+
5. **Simplicity** — Minimum code to solve the current MVP. No abstractions pre-built for future scenarios.
|
|
35
37
|
|
|
36
|
-
## 4.
|
|
38
|
+
## 4. Users & Usage Scenarios
|
|
37
39
|
|
|
38
|
-
|
|
|
40
|
+
| User Role | Core Scenario | Frequency | Pain Point |
|
|
39
41
|
| --- | --- | --- | --- |
|
|
40
42
|
| {{USER_ROLE_1}} | {{SCENARIO}} | {{FREQUENCY}} | {{PAIN}} |
|
|
41
43
|
| {{USER_ROLE_2}} | {{SCENARIO}} | {{FREQUENCY}} | {{PAIN}} |
|
|
42
44
|
|
|
43
|
-
## 5.
|
|
45
|
+
## 5. Acceptance Criteria
|
|
44
46
|
|
|
45
47
|
- [ ] {{ACCEPTANCE_1}}
|
|
46
48
|
- [ ] {{ACCEPTANCE_2}}
|
|
47
49
|
- [ ] {{ACCEPTANCE_3}}
|
|
48
50
|
|
|
49
|
-
## 6.
|
|
51
|
+
## 6. Non-Functional Requirements
|
|
50
52
|
|
|
51
|
-
|
|
|
53
|
+
| Dimension | Target | Measurement |
|
|
52
54
|
| --- | --- | --- |
|
|
53
55
|
| {{DIMENSION_1}} | {{TARGET}} | {{MEASUREMENT}} |
|
|
54
56
|
| {{DIMENSION_2}} | {{TARGET}} | {{MEASUREMENT}} |
|
|
55
57
|
|
|
56
58
|
---
|
|
57
59
|
|
|
58
|
-
##
|
|
60
|
+
## Fill Completion Standard
|
|
59
61
|
|
|
60
|
-
- [ ] MVP
|
|
61
|
-
- [ ]
|
|
62
|
-
- [ ]
|
|
63
|
-
- [ ]
|
|
62
|
+
- [ ] MVP and Non-goals are project facts; no `{{...}}` placeholders remain.
|
|
63
|
+
- [ ] Decision priorities guide tradeoffs, not generic platitudes.
|
|
64
|
+
- [ ] Every acceptance criterion is verifiable by test, command, or manual step.
|
|
65
|
+
- [ ] If implementation diverges from the PRD, update this file before changing code.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Research Protocol
|
|
2
|
+
|
|
3
|
+
Purpose: guide agent research. Record conclusions in [research-results.md](research-results.md); do not put raw search notes there.
|
|
4
|
+
|
|
5
|
+
## When To Research
|
|
6
|
+
|
|
7
|
+
Use this before PRD, stack choice, external API use, public dependency choice, pricing/legal/security assumptions, or any fact likely to change.
|
|
8
|
+
|
|
9
|
+
Skip only when the task is local, narrow, and fully answerable from existing project files. Record the skip reason in `docs/harness/PLAN.md`.
|
|
10
|
+
|
|
11
|
+
## Research Agent
|
|
12
|
+
|
|
13
|
+
Spawn a Research Agent, or emulate one in a bounded pass, when any are true:
|
|
14
|
+
|
|
15
|
+
- more than two external sources are needed
|
|
16
|
+
- the answer depends on current docs, releases, pricing, policy, or community practice
|
|
17
|
+
- a framework, API, architecture, or dependency choice affects implementation
|
|
18
|
+
|
|
19
|
+
Built-in agents:
|
|
20
|
+
|
|
21
|
+
- `.claude/agents/researcher.md`: product, market, open-source, dependency, pricing, policy, and ecosystem research.
|
|
22
|
+
- `.claude/agents/docs-researcher.md`: official docs, API, SDK, config, limits, errors, and examples verification.
|
|
23
|
+
|
|
24
|
+
For multi-agent research plus build work, create the dispatch table in `docs/harness/PLAN.md` and follow `docs/harness/dispatch.md`.
|
|
25
|
+
|
|
26
|
+
Research Agent input:
|
|
27
|
+
|
|
28
|
+
- question
|
|
29
|
+
- decision needed
|
|
30
|
+
- source boundaries
|
|
31
|
+
- allowed tools
|
|
32
|
+
- output format
|
|
33
|
+
|
|
34
|
+
Research Agent output:
|
|
35
|
+
|
|
36
|
+
- searched queries and tools used
|
|
37
|
+
- source list with links and source type
|
|
38
|
+
- adopted / rejected / watch decisions
|
|
39
|
+
- risks, unknowns, and follow-up questions
|
|
40
|
+
- patch-ready updates for [research-results.md](research-results.md)
|
|
41
|
+
|
|
42
|
+
## Tool Order
|
|
43
|
+
|
|
44
|
+
1. Local first: inspect this repo, existing docs, lockfiles, tests, and package metadata.
|
|
45
|
+
2. GitHub / open source: prefer official repos, docs folders, examples, issues with maintainer answers, releases, and active forks.
|
|
46
|
+
3. Tavily: use when configured for broad web search or source discovery.
|
|
47
|
+
4. TinyFish: use when configured for rendered pages, dynamic sites, browser workflows, or structured extraction.
|
|
48
|
+
5. Built-in web search: free fallback when no external research tool is configured; expect less structure and verify more carefully.
|
|
49
|
+
6. Ask the user for sources when network or tool access is unavailable.
|
|
50
|
+
|
|
51
|
+
Do not require paid tools. If Tavily or TinyFish is unavailable, use the fallback and record the limitation.
|
|
52
|
+
|
|
53
|
+
## Optional Tool Setup
|
|
54
|
+
|
|
55
|
+
Tavily:
|
|
56
|
+
|
|
57
|
+
```text
|
|
58
|
+
# Optional: requires a Tavily API key or configured CLI/tool.
|
|
59
|
+
tvly search "query" --depth advanced --max-results 10 --json
|
|
60
|
+
tvly search "query" --include-domains github.com,docs.github.com --json
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
TinyFish:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# Optional: requires TINYFISH_API_KEY or tinyfish auth login.
|
|
67
|
+
npm install -g @tiny-fish/cli
|
|
68
|
+
tinyfish auth login
|
|
69
|
+
tinyfish agent run --url "https://example.com" "Extract product data. Return JSON."
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
GitHub CLI:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
gh search repos "topic keywords" --archived=false --json fullName,url,description,stargazersCount,pushedAt
|
|
76
|
+
gh search code "symbol or config" --repo owner/name
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Fallback web search examples:
|
|
80
|
+
|
|
81
|
+
```text
|
|
82
|
+
site:github.com <framework> starter template
|
|
83
|
+
site:github.com <library> examples
|
|
84
|
+
site:docs.<vendor>.com <api> limits errors
|
|
85
|
+
<product category> alternatives pricing docs
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Source Rules
|
|
89
|
+
|
|
90
|
+
- Prefer primary sources: official docs, official GitHub repos, standards, papers, release notes.
|
|
91
|
+
- Use community sources for pitfalls and adoption signals only; label them as community evidence.
|
|
92
|
+
- Check dates for unstable facts.
|
|
93
|
+
- Compare at least three sources, or record why fewer are enough.
|
|
94
|
+
- Do not copy large source text. Summarize the decision-relevant facts.
|
|
95
|
+
|
|
96
|
+
## Requirement Quality
|
|
97
|
+
|
|
98
|
+
Use these patterns when turning research into PRD or feature docs:
|
|
99
|
+
|
|
100
|
+
- PRD: why, target user, MVP, non-goals, success measures, acceptance criteria.
|
|
101
|
+
- EARS: `When <trigger>, the <system> shall <response>` for precise requirements.
|
|
102
|
+
- Gherkin: `Given / When / Then` for testable behavior scenarios.
|
|
103
|
+
- Spec-first: requirements before plan, plan before tasks, tasks before implementation.
|
|
104
|
+
|
|
105
|
+
## Write Target
|
|
106
|
+
|
|
107
|
+
- Research process, queries, and limitations: this file or `docs/harness/PLAN.md`.
|
|
108
|
+
- Final research decisions: [research-results.md](research-results.md).
|
|
109
|
+
- Product scope: [PRD.md](PRD.md).
|
|
110
|
+
- Architecture consequences: `docs/harness/architecture.md` and `docs/domain/ports.md`.
|
|
111
|
+
|
|
112
|
+
## Method References
|
|
113
|
+
|
|
114
|
+
- GitHub Spec Kit: spec-first phases and AI coding-agent workflow: https://github.github.com/spec-kit/
|
|
115
|
+
- Atlassian PRD guidance: goals, assumptions, user stories, out-of-scope, success criteria: https://www.atlassian.com/agile/requirements
|
|
116
|
+
- EARS: structured textual requirements: https://alistairmavin.com/ears/
|
|
117
|
+
- Cucumber Gherkin: `Given / When / Then` executable examples: https://cucumber.io/docs/gherkin/reference
|
|
118
|
+
- Tavily search docs: search depth, domain filters, max results, raw content: https://docs.tavily.com/documentation/api-reference/endpoint/search
|
|
119
|
+
- Tavily CLI docs: `tvly search`, crawl, map, extract: https://docs.tavily.com/documentation/tavily-cli
|
|
120
|
+
- TinyFish CLI docs: web search and browser-agent runs: https://docs.tinyfish.ai/cli
|
|
121
|
+
- GitHub CLI search docs: repository and code search from terminal: https://cli.github.com/manual/gh_search_repos
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# {{projectName}} - Research Results
|
|
2
|
+
|
|
3
|
+
> **Purpose**: Record final research results and decisions. Use [README.md](README.md) for process, tools, queries, and research-agent rules.
|
|
4
|
+
> **Principle**: Each candidate has a clear Purpose / Strength / Weakness / Decision.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Research Date
|
|
9
|
+
|
|
10
|
+
{{YYYY-MM-DD}}
|
|
11
|
+
|
|
12
|
+
## Research Goal
|
|
13
|
+
|
|
14
|
+
{{WHAT_YOU_ARE_RESEARCHING}}
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Candidate References
|
|
19
|
+
|
|
20
|
+
### 1) {{CANDIDATE_1}}
|
|
21
|
+
|
|
22
|
+
- **What it is**: {{DESCRIPTION}}
|
|
23
|
+
- **Source Type**: {{OFFICIAL_DOCS / GITHUB_REPO / COMMUNITY / PAPER / OTHER}}
|
|
24
|
+
- **Checked Date**: {{YYYY-MM-DD}}
|
|
25
|
+
- **Strengths**: {{STRENGTHS}}
|
|
26
|
+
- **Weaknesses**: {{WEAKNESSES}}
|
|
27
|
+
- **Decision**: {{ADOPT / REJECT / WATCH}}
|
|
28
|
+
- **Link**: {{URL}}
|
|
29
|
+
|
|
30
|
+
### 2) {{CANDIDATE_2}}
|
|
31
|
+
|
|
32
|
+
- **What it is**: {{DESCRIPTION}}
|
|
33
|
+
- **Source Type**: {{OFFICIAL_DOCS / GITHUB_REPO / COMMUNITY / PAPER / OTHER}}
|
|
34
|
+
- **Checked Date**: {{YYYY-MM-DD}}
|
|
35
|
+
- **Strengths**: {{STRENGTHS}}
|
|
36
|
+
- **Weaknesses**: {{WEAKNESSES}}
|
|
37
|
+
- **Decision**: {{ADOPT / REJECT / WATCH}}
|
|
38
|
+
- **Link**: {{URL}}
|
|
39
|
+
|
|
40
|
+
### 3) {{CANDIDATE_3}}
|
|
41
|
+
|
|
42
|
+
- **What it is**: {{DESCRIPTION}}
|
|
43
|
+
- **Source Type**: {{OFFICIAL_DOCS / GITHUB_REPO / COMMUNITY / PAPER / OTHER}}
|
|
44
|
+
- **Checked Date**: {{YYYY-MM-DD}}
|
|
45
|
+
- **Strengths**: {{STRENGTHS}}
|
|
46
|
+
- **Weaknesses**: {{WEAKNESSES}}
|
|
47
|
+
- **Decision**: {{ADOPT / REJECT / WATCH}}
|
|
48
|
+
- **Link**: {{URL}}
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Final Decision
|
|
53
|
+
|
|
54
|
+
- **Architecture Style**: {{DECISION}}
|
|
55
|
+
- **Core References**: {{REFERENCES}}
|
|
56
|
+
- **Key Constraints**:
|
|
57
|
+
- {{CONSTRAINT_1}}
|
|
58
|
+
- {{CONSTRAINT_2}}
|
|
59
|
+
- {{CONSTRAINT_3}}
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Not Adopted But Worth Watching
|
|
64
|
+
|
|
65
|
+
- {{ALTERNATIVE_1}}
|
|
66
|
+
- {{ALTERNATIVE_2}}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
const root = process.cwd();
|
|
6
|
+
const args = new Set(process.argv.slice(2));
|
|
7
|
+
const strict = args.has('--strict') || args.has('--post-bootstrap');
|
|
8
|
+
|
|
9
|
+
if (args.has('--help') || args.has('-h')) {
|
|
10
|
+
console.log(`Usage: node scripts/validate-harness.mjs [--strict]
|
|
11
|
+
|
|
12
|
+
Default mode checks scaffold structure, links, agents, and skills.
|
|
13
|
+
--strict also fails when project fact docs still contain {{...}} placeholders.`);
|
|
14
|
+
process.exit(0);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const commonAgents = [
|
|
18
|
+
'researcher',
|
|
19
|
+
'docs-researcher',
|
|
20
|
+
'planner',
|
|
21
|
+
'architect',
|
|
22
|
+
'test-writer',
|
|
23
|
+
'implementer',
|
|
24
|
+
'debugger',
|
|
25
|
+
'reviewer',
|
|
26
|
+
'verifier',
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
const commonSkills = [
|
|
30
|
+
'harness-router',
|
|
31
|
+
'harness-lifecycle',
|
|
32
|
+
'harness-research',
|
|
33
|
+
'harness-context',
|
|
34
|
+
'harness-build-loop',
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
const required = [
|
|
38
|
+
'AGENTS.md',
|
|
39
|
+
'CLAUDE.md',
|
|
40
|
+
'MEMORY.md',
|
|
41
|
+
'.claude/settings.json',
|
|
42
|
+
'.claude/rules/ecc/common.md',
|
|
43
|
+
...commonAgents.map(agent => `.claude/agents/${agent}.md`),
|
|
44
|
+
...commonSkills.map(skill => `.claude/skills/${skill}/SKILL.md`),
|
|
45
|
+
'docs/README.md',
|
|
46
|
+
'docs/harness/PLAN.md',
|
|
47
|
+
'docs/harness/lifecycle.md',
|
|
48
|
+
'docs/harness/dispatch.md',
|
|
49
|
+
'docs/harness/extension.md',
|
|
50
|
+
'docs/harness/context-loading.md',
|
|
51
|
+
'docs/harness/agent-workflow.md',
|
|
52
|
+
'docs/harness/architecture.md',
|
|
53
|
+
'docs/harness/data-flow.md',
|
|
54
|
+
'docs/harness/state-machines.md',
|
|
55
|
+
'docs/features/_template.md',
|
|
56
|
+
'docs/research/README.md',
|
|
57
|
+
'docs/research/research-results.md',
|
|
58
|
+
'docs/research/PRD.md',
|
|
59
|
+
'docs/domain/ports.md',
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
const projectFacts = [
|
|
63
|
+
'docs/harness/PLAN.md',
|
|
64
|
+
'docs/research/PRD.md',
|
|
65
|
+
'docs/research/research-results.md',
|
|
66
|
+
'docs/harness/architecture.md',
|
|
67
|
+
'docs/domain/ports.md',
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
const contextPacks = [
|
|
71
|
+
'Explorer Pass:',
|
|
72
|
+
'Planner:',
|
|
73
|
+
'Researcher:',
|
|
74
|
+
'Docs Researcher:',
|
|
75
|
+
'Architect:',
|
|
76
|
+
'Test Writer:',
|
|
77
|
+
'Implementer:',
|
|
78
|
+
'Reviewer:',
|
|
79
|
+
'Debugger:',
|
|
80
|
+
'Verifier:',
|
|
81
|
+
];
|
|
82
|
+
|
|
83
|
+
const errors = [];
|
|
84
|
+
|
|
85
|
+
function read(rel) {
|
|
86
|
+
const file = path.join(root, rel);
|
|
87
|
+
return fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : '';
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function requireText(rel, text, label = text) {
|
|
91
|
+
const body = read(rel);
|
|
92
|
+
if (body && !body.includes(text)) errors.push(`${rel} missing ${label}`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function frontmatterField(text, field) {
|
|
96
|
+
const match = text.match(new RegExp(`^${field}:\\s*(.+)$`, 'm'));
|
|
97
|
+
return match ? match[1].trim() : '';
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
for (const rel of required) {
|
|
101
|
+
if (!fs.existsSync(path.join(root, rel))) {
|
|
102
|
+
errors.push(`missing required file: ${rel}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (fs.existsSync(path.join(root, 'docs/research/scaffolds.md'))) {
|
|
107
|
+
errors.push('legacy research file should be renamed: docs/research/scaffolds.md -> docs/research/research-results.md');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (strict) {
|
|
111
|
+
for (const rel of projectFacts) {
|
|
112
|
+
const text = read(rel);
|
|
113
|
+
if (text.includes('{{')) {
|
|
114
|
+
errors.push(`template placeholders remain in project fact file: ${rel}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const docsReadme = read('docs/README.md');
|
|
120
|
+
if (docsReadme) {
|
|
121
|
+
for (const marker of ['## Keyword Routing', '## Load By Task', 'When to Read', 'Keywords']) {
|
|
122
|
+
if (!docsReadme.includes(marker)) errors.push(`docs/README.md missing router marker: ${marker}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const plan = read('docs/harness/PLAN.md');
|
|
127
|
+
if (plan) {
|
|
128
|
+
for (const heading of ['## Current Goal', '## Phase', '## Success Criteria', '## Loaded Context', '## Tasks', '## Parallel Dispatch', '## Verification']) {
|
|
129
|
+
if (!plan.includes(heading)) errors.push(`docs/harness/PLAN.md missing heading: ${heading}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const dispatch = read('docs/harness/dispatch.md');
|
|
134
|
+
if (dispatch) {
|
|
135
|
+
for (const agent of commonAgents) {
|
|
136
|
+
if (!dispatch.includes(`\`${agent}\``)) errors.push(`docs/harness/dispatch.md missing common agent: ${agent}`);
|
|
137
|
+
}
|
|
138
|
+
if (!dispatch.includes('## Handoff Format')) errors.push('docs/harness/dispatch.md missing heading: ## Handoff Format');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const contextLoading = read('docs/harness/context-loading.md');
|
|
142
|
+
if (contextLoading) {
|
|
143
|
+
if (!contextLoading.includes('docs/README.md` is the primary router')) {
|
|
144
|
+
errors.push('docs/harness/context-loading.md must declare docs/README.md as the primary router');
|
|
145
|
+
}
|
|
146
|
+
for (const pack of contextPacks) {
|
|
147
|
+
if (!contextLoading.includes(pack)) errors.push(`docs/harness/context-loading.md missing subagent pack: ${pack}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const memory = read('MEMORY.md');
|
|
152
|
+
if (memory) {
|
|
153
|
+
for (const agent of commonAgents) {
|
|
154
|
+
const rel = `.claude/agents/${agent}.md`;
|
|
155
|
+
if (!memory.includes(rel)) errors.push(`MEMORY.md missing agent registration: ${rel}`);
|
|
156
|
+
}
|
|
157
|
+
for (const skill of commonSkills) {
|
|
158
|
+
const rel = `.claude/skills/${skill}/SKILL.md`;
|
|
159
|
+
if (!memory.includes(rel)) errors.push(`MEMORY.md missing skill registration: ${rel}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
for (const skill of commonSkills) {
|
|
164
|
+
const rel = `.claude/skills/${skill}/SKILL.md`;
|
|
165
|
+
const text = read(rel);
|
|
166
|
+
if (!text) continue;
|
|
167
|
+
if (frontmatterField(text, 'name') !== skill) errors.push(`${rel} frontmatter name does not match directory`);
|
|
168
|
+
if (!frontmatterField(text, 'description')) errors.push(`${rel} missing frontmatter field: description`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
for (const agent of commonAgents) {
|
|
172
|
+
const rel = `.claude/agents/${agent}.md`;
|
|
173
|
+
const text = read(rel);
|
|
174
|
+
if (!text) continue;
|
|
175
|
+
|
|
176
|
+
for (const field of ['name', 'description', 'tools', 'model', 'skills']) {
|
|
177
|
+
if (!frontmatterField(text, field)) errors.push(`${rel} missing frontmatter field: ${field}:`);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (frontmatterField(text, 'name') !== agent) {
|
|
181
|
+
errors.push(`${rel} frontmatter name does not match filename`);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const skill = frontmatterField(text, 'skills');
|
|
185
|
+
if (skill && !commonSkills.includes(skill)) {
|
|
186
|
+
errors.push(`${rel} references unknown skill: ${skill}`);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (skill && !fs.existsSync(path.join(root, `.claude/skills/${skill}/SKILL.md`))) {
|
|
190
|
+
errors.push(`${rel} references missing skill file: .claude/skills/${skill}/SKILL.md`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
requireText('docs/harness/extension.md', 'Skills should extend the harness');
|
|
195
|
+
requireText('docs/harness/agent-workflow.md', 'docs/harness/PLAN.md');
|
|
196
|
+
requireText('docs/research/README.md', 'research-results.md');
|
|
197
|
+
|
|
198
|
+
if (errors.length) {
|
|
199
|
+
console.error(`Harness validation failed${strict ? ' (strict)' : ''}:`);
|
|
200
|
+
for (const error of errors) console.error(`- ${error}`);
|
|
201
|
+
process.exit(1);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
console.log(`Harness validation passed${strict ? ' (strict)' : ''}.`);
|
|
205
|
+
if (!strict) {
|
|
206
|
+
console.log('Tip: run `node scripts/validate-harness.mjs --strict` after bootstrap to check unresolved project placeholders.');
|
|
207
|
+
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
# {{projectName}} — 前期调研
|
|
2
|
-
|
|
3
|
-
> **职责**:记录"为什么选了这些技术/参考"。新加入的人不需要重新做一遍调研。
|
|
4
|
-
> **原则**:每个候选物有明确的 Purpose / Strength / Weakness / Decision。
|
|
5
|
-
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## 调研时间
|
|
9
|
-
|
|
10
|
-
{{YYYY-MM-DD}}
|
|
11
|
-
|
|
12
|
-
## 调研目标
|
|
13
|
-
|
|
14
|
-
{{WHAT_YOU_ARE_RESEARCHING}}
|
|
15
|
-
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
## 候选参考物
|
|
19
|
-
|
|
20
|
-
### 1) {{CANDIDATE_1}}
|
|
21
|
-
|
|
22
|
-
- **是什么**:{{DESCRIPTION}}
|
|
23
|
-
- **优势**:{{STRENGTHS}}
|
|
24
|
-
- **局限**:{{WEAKNESSES}}
|
|
25
|
-
- **结论**:{{ADOPT / REJECT / WATCH}}
|
|
26
|
-
- **链接**:{{URL}}
|
|
27
|
-
|
|
28
|
-
### 2) {{CANDIDATE_2}}
|
|
29
|
-
|
|
30
|
-
- **是什么**:{{DESCRIPTION}}
|
|
31
|
-
- **优势**:{{STRENGTHS}}
|
|
32
|
-
- **局限**:{{WEAKNESSES}}
|
|
33
|
-
- **结论**:{{ADOPT / REJECT / WATCH}}
|
|
34
|
-
- **链接**:{{URL}}
|
|
35
|
-
|
|
36
|
-
### 3) {{CANDIDATE_3}}
|
|
37
|
-
|
|
38
|
-
- **是什么**:{{DESCRIPTION}}
|
|
39
|
-
- **优势**:{{STRENGTHS}}
|
|
40
|
-
- **局限**:{{WEAKNESSES}}
|
|
41
|
-
- **结论**:{{ADOPT / REJECT / WATCH}}
|
|
42
|
-
- **链接**:{{URL}}
|
|
43
|
-
|
|
44
|
-
---
|
|
45
|
-
|
|
46
|
-
## 最终决策
|
|
47
|
-
|
|
48
|
-
- **架构风格**:{{DECISION}}
|
|
49
|
-
- **核心参考**:{{REFERENCES}}
|
|
50
|
-
- **关键约束**:
|
|
51
|
-
- {{CONSTRAINT_1}}
|
|
52
|
-
- {{CONSTRAINT_2}}
|
|
53
|
-
- {{CONSTRAINT_3}}
|
|
54
|
-
|
|
55
|
-
---
|
|
56
|
-
|
|
57
|
-
## 未采用但值得关注的
|
|
58
|
-
|
|
59
|
-
- {{ALTERNATIVE_1}}
|
|
60
|
-
- {{ALTERNATIVE_2}}
|