create-harness-vibe-coding 0.1.3 → 0.1.5

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 (40) hide show
  1. package/README.md +96 -79
  2. package/package.json +2 -2
  3. package/src/generator.js +3 -5
  4. package/src/index.js +51 -15
  5. package/templates/common/.claude/agents/architect.md +35 -0
  6. package/templates/common/.claude/agents/debugger.md +42 -0
  7. package/templates/common/.claude/agents/docs-researcher.md +43 -0
  8. package/templates/common/.claude/agents/implementer.md +41 -0
  9. package/templates/common/.claude/agents/planner.md +35 -0
  10. package/templates/common/.claude/agents/researcher.md +42 -0
  11. package/templates/common/.claude/agents/reviewer.md +34 -0
  12. package/templates/common/.claude/agents/test-writer.md +39 -0
  13. package/templates/common/.claude/agents/verifier.md +33 -0
  14. package/templates/common/.claude/rules/ecc/common.md +25 -22
  15. package/templates/common/.claude/skills/harness-build-loop/SKILL.md +21 -0
  16. package/templates/common/.claude/skills/harness-context/SKILL.md +24 -0
  17. package/templates/common/.claude/skills/harness-lifecycle/SKILL.md +19 -0
  18. package/templates/common/.claude/skills/harness-research/SKILL.md +29 -0
  19. package/templates/common/.claude/skills/harness-router/SKILL.md +14 -0
  20. package/templates/common/AGENTS.md +3 -1
  21. package/templates/common/CLAUDE.md +30 -33
  22. package/templates/common/MEMORY.md +30 -7
  23. package/templates/common/SETUP.md +56 -59
  24. package/templates/common/docs/README.md +81 -96
  25. package/templates/common/docs/domain/ports.md +26 -26
  26. package/templates/common/docs/features/_template.md +34 -25
  27. package/templates/common/docs/harness/PLAN.md +80 -0
  28. package/templates/common/docs/harness/agent-workflow.md +57 -116
  29. package/templates/common/docs/harness/architecture.md +51 -48
  30. package/templates/common/docs/harness/context-loading.md +93 -0
  31. package/templates/common/docs/harness/data-flow.md +20 -20
  32. package/templates/common/docs/harness/dispatch.md +82 -0
  33. package/templates/common/docs/harness/extension.md +67 -0
  34. package/templates/common/docs/harness/lifecycle.md +33 -0
  35. package/templates/common/docs/harness/state-machines.md +15 -15
  36. package/templates/common/docs/research/PRD.md +25 -23
  37. package/templates/common/docs/research/README.md +121 -0
  38. package/templates/common/docs/research/research-results.md +66 -0
  39. package/templates/common/scripts/validate-harness.mjs +207 -0
  40. 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
- # 状态机 — {{projectName}}
1
+ # State Machines — {{projectName}}
2
2
 
3
- > **职责**:定义所有有状态组件的状态、转移、守卫条件、边界行为。长流程 harness 的大量 bug 来自非法状态转移。
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
- > 哲学来源:UML 2.5.1 15.3.14 + "转移表是整个文档最重要的产物"
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
- | 当前状态 ↓ / 事件 → | `{{EVENT_1}}` | `{{EVENT_2}}` | `{{EVENT_3}}` |
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
- > **提示**:当前 state-machines.md 是空模板。请按项目实际的有状态组件填写。
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
- > **读者**:AI + 未来的你。不是给 PM 审批用的,是给实现和审查用的。
4
- > **原则**:不超过一页。用 checkbox,不用散文。负面定义 > 正面定义。
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
- > 哲学来源:Miqdad Jaffer (OpenAI) AI 时代精益 PRD 模板。
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. **架构边界**不允许让 domain 依赖 harness/infrastructure/interfaces,也不让 harness 承担领域判断。
32
- 3. **可验证性**新行为必须有测试或明确的人工验证记录。
33
- 4. **正确性**行为符合设计文档、端口合同、数据流和状态机。
34
- 5. **简洁性**最少代码解决当前 MVP,不为未来场景预埋抽象。
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 Non-goals 都是项目事实,不保留 `{{...}}` 占位符。
61
- - [ ] 决策优先级能指导 tradeoff,而不是泛泛而谈。
62
- - [ ] 每条验收标准都能被测试、命令或人工步骤验证。
63
- - [ ] 如果实现偏离 PRD,先更新本文件再改代码。
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}}