create-harness-vibe-coding 0.8.8 → 0.8.9

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 (80) hide show
  1. package/README-CN.md +7 -1
  2. package/README.md +21 -2
  3. package/docs/images/harness-icon.png +0 -0
  4. package/package.json +2 -1
  5. package/src/generator.js +36 -0
  6. package/src/index.js +72 -4
  7. package/templates/common/.claude/agents/architect.md +31 -31
  8. package/templates/common/.claude/agents/codebase-explorer.md +45 -0
  9. package/templates/common/.claude/agents/docs-researcher.md +41 -41
  10. package/templates/common/.claude/agents/memory-master.md +26 -8
  11. package/templates/common/.claude/agents/reviewer.md +34 -34
  12. package/templates/common/.claude/agents/task-scribe.md +70 -0
  13. package/templates/common/.claude/commands/wf-help.md +8 -4
  14. package/templates/common/.claude/commands/wf-update.md +24 -0
  15. package/templates/common/.claude/rules/ecc/common.md +15 -2
  16. package/templates/common/.claude/settings.json +13 -0
  17. package/templates/common/.claude/skills/subagent-orchestrator/SKILL.md +8 -4
  18. package/templates/common/.claude/skills/wf/SKILL.md +15 -8
  19. package/templates/common/.claude/skills/wf-auto/SKILL.md +3 -2
  20. package/templates/common/.claude/skills/wf-learn/SKILL.md +9 -2
  21. package/templates/common/.claude/skills/wf-max/SKILL.md +23 -5
  22. package/templates/common/.claude/skills/wf-update/SKILL.md +15 -2
  23. package/templates/common/.codex/hooks.json +17 -0
  24. package/templates/common/.harness-version +89 -44
  25. package/templates/common/.opencode/agents/architect.md +24 -24
  26. package/templates/common/.opencode/agents/codebase-explorer.md +45 -0
  27. package/templates/common/.opencode/agents/docs-researcher.md +34 -34
  28. package/templates/common/.opencode/agents/memory-master.md +26 -8
  29. package/templates/common/.opencode/agents/reviewer.md +27 -27
  30. package/templates/common/.opencode/agents/task-scribe.md +70 -0
  31. package/templates/common/.opencode/commands/wf-auto-spark.md +15 -0
  32. package/templates/common/.opencode/commands/wf-auto.md +15 -0
  33. package/templates/common/.opencode/commands/wf-help.md +8 -4
  34. package/templates/common/.opencode/commands/wf-learn.md +15 -0
  35. package/templates/common/.opencode/commands/wf-max.md +15 -0
  36. package/templates/common/.opencode/commands/wf-readme.md +15 -0
  37. package/templates/common/.opencode/commands/wf-remove.md +15 -0
  38. package/templates/common/.opencode/commands/wf-review.md +15 -0
  39. package/templates/common/.opencode/commands/wf-update.md +24 -0
  40. package/templates/common/.opencode/commands/wf.md +15 -0
  41. package/templates/common/.opencode/plugins/harness-wf-status.mjs +135 -0
  42. package/templates/common/AGENTS.md +2 -29
  43. package/templates/common/CLAUDE.md +35 -6
  44. package/templates/common/Harness/ACCEPTANCE_PROTOCOL.md +2 -2
  45. package/templates/common/{MEMORY.md → Harness/MEMORY.md} +16 -3
  46. package/templates/common/Harness/MEMORY_PROTOCOL.md +80 -30
  47. package/templates/common/Harness/README.md +50 -22
  48. package/templates/common/{SETUP.md → Harness/SETUP.md} +278 -276
  49. package/templates/common/Harness/TASK_ARCHIVE.md +56 -0
  50. package/templates/common/Harness/WF-AUTO-SPARK.md +5 -14
  51. package/templates/common/Harness/WF-AUTO.md +13 -76
  52. package/templates/common/Harness/WF-KERNEL.md +189 -0
  53. package/templates/common/Harness/WF-MAX.md +60 -328
  54. package/templates/common/Harness/WF-STATE.md +83 -0
  55. package/templates/common/Harness/WF.md +117 -237
  56. package/templates/common/Harness/agent-workflow.md +2 -2
  57. package/templates/common/Harness/context-loading.md +3 -3
  58. package/templates/common/Harness/dispatch.md +43 -35
  59. package/templates/common/Harness/scripts/archive-tasks.mjs +239 -0
  60. package/templates/common/{scripts → Harness/scripts}/scan-clean.mjs +28 -1
  61. package/templates/common/{scripts → Harness/scripts}/validate-harness.mjs +909 -699
  62. package/templates/common/Harness/scripts/wf-auto-update-prompt.mjs +258 -0
  63. package/templates/common/{scripts → Harness/scripts}/wf-update-check.mjs +40 -7
  64. package/templates/common/Harness/subagents.md +28 -27
  65. package/templates/common/Harness/tasks/_template/PLAN.md +5 -0
  66. package/templates/common/Harness/tasks/_template/STATE.json +23 -0
  67. package/templates/common/README.md +1 -1
  68. package/templates/common/memory/agent-lessons-patterns.md +9 -8
  69. package/templates/common/memory/routes.md +43 -0
  70. package/templates/common/memory/startup-hints.md +32 -0
  71. package/templates/common/memory/tool-usage-reflections.md +9 -8
  72. package/templates/common/memory/user-corrections-preferences.md +11 -9
  73. package/templates/optional/catalog.json +8 -0
  74. package/templates/optional/skills/browser-e2e/.claude/skills/browser-e2e/SKILL.md +42 -42
  75. package/templates/optional/skills/browser-e2e/.opencode/commands/wf-browser.md +15 -0
  76. package/templates/optional/skills/github-pr-review/.claude/skills/github-pr-review/SKILL.md +40 -40
  77. package/templates/optional/skills/python-backend/.claude/skills/python-backend/SKILL.md +40 -40
  78. package/templates/optional/skills/ts-react-frontend/.claude/skills/ts-react-frontend/SKILL.md +43 -43
  79. package/templates/optional/skills/ui-ux-review/.claude/skills/ui-ux-review/SKILL.md +40 -40
  80. /package/templates/common/{scripts → Harness/scripts}/wf-remove.mjs +0 -0
@@ -0,0 +1,258 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * wf-auto-update-prompt.mjs
4
+ *
5
+ * Lightweight hook helper for Claude Code, Codex, and OpenCode.
6
+ * It checks the installed Harness update plan and emits a prompt reminder only
7
+ * when an update is available. It never applies updates.
8
+ */
9
+
10
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
11
+ import { dirname, resolve } from 'path';
12
+ import { spawnSync } from 'child_process';
13
+
14
+ const DEFAULT_CHECK_INTERVAL_MS = 6 * 60 * 60 * 1000;
15
+ const DEFAULT_NOTICE_INTERVAL_MS = 60 * 60 * 1000;
16
+ const args = process.argv.slice(2);
17
+ const format = readFlagValue('--format') || 'plain';
18
+ const force = args.includes('--force');
19
+ const modeOnly = args.includes('--mode-only');
20
+ const input = readStdinJson();
21
+ const root = findRoot();
22
+
23
+ function readFlagValue(flagName) {
24
+ const index = args.indexOf(flagName);
25
+ if (index === -1) return null;
26
+ const value = args[index + 1];
27
+ return value && !value.startsWith('--') ? value : null;
28
+ }
29
+
30
+ function readStdinJson() {
31
+ try {
32
+ if (process.stdin.isTTY) return {};
33
+ const raw = readFileSync(0, 'utf-8').trim();
34
+ return raw ? JSON.parse(raw) : {};
35
+ } catch {
36
+ return {};
37
+ }
38
+ }
39
+
40
+ function findRoot() {
41
+ const candidates = [
42
+ process.env.WF_ROOT,
43
+ input.cwd,
44
+ input.workspace,
45
+ process.cwd(),
46
+ ].filter(Boolean);
47
+
48
+ for (const candidate of candidates) {
49
+ const found = ascendToHarnessRoot(resolve(candidate));
50
+ if (found) return found;
51
+ }
52
+ return process.cwd();
53
+ }
54
+
55
+ function ascendToHarnessRoot(start) {
56
+ let current = start;
57
+ for (;;) {
58
+ if (existsSync(resolve(current, 'Harness', '.harness-version'))) return current;
59
+ const parent = dirname(current);
60
+ if (parent === current) return null;
61
+ current = parent;
62
+ }
63
+ }
64
+
65
+ function runtimeDir() {
66
+ return resolve(root, 'Harness', '.runtime');
67
+ }
68
+
69
+ function cachePath() {
70
+ return resolve(runtimeDir(), 'update-check.json');
71
+ }
72
+
73
+ function modePath() {
74
+ return resolve(runtimeDir(), 'current-mode.json');
75
+ }
76
+
77
+ function readJsonFile(file, fallback) {
78
+ try {
79
+ return JSON.parse(readFileSync(file, 'utf-8'));
80
+ } catch {
81
+ return fallback;
82
+ }
83
+ }
84
+
85
+ function writeJsonFile(file, value) {
86
+ mkdirSync(dirname(file), { recursive: true });
87
+ writeFileSync(file, JSON.stringify(value, null, 2) + '\n', 'utf-8');
88
+ }
89
+
90
+ function readVersion() {
91
+ return readJsonFile(resolve(root, 'Harness', '.harness-version'), null);
92
+ }
93
+
94
+ function shouldSkipPrompt() {
95
+ const prompt = String(input.prompt || input.message || '');
96
+ return /\b\/?wf-update\b|\$wf-update\b/.test(prompt);
97
+ }
98
+
99
+ function intervalFromEnv(name, fallback) {
100
+ const raw = process.env[name];
101
+ if (!raw) return fallback;
102
+ const parsed = Number(raw);
103
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback;
104
+ }
105
+
106
+ function runUpdateCheck() {
107
+ const script = resolve(root, 'Harness', 'scripts', 'wf-update-check.mjs');
108
+ if (!existsSync(script)) {
109
+ return { status: 'error', message: 'Harness/scripts/wf-update-check.mjs not found.' };
110
+ }
111
+ const result = spawnSync(process.execPath, [script, '--json'], {
112
+ cwd: root,
113
+ encoding: 'utf-8',
114
+ timeout: intervalFromEnv('WF_UPDATE_CHECK_TIMEOUT_MS', 30000),
115
+ env: process.env,
116
+ });
117
+
118
+ if (result.error) {
119
+ return { status: 'offline', message: result.error.message };
120
+ }
121
+
122
+ const stdout = (result.stdout || '').trim();
123
+ if (!stdout) {
124
+ return { status: 'error', message: `Update checker exited with no JSON output (${result.status ?? 'unknown'}).` };
125
+ }
126
+
127
+ try {
128
+ return JSON.parse(stdout);
129
+ } catch {
130
+ return { status: 'error', message: 'Update checker returned invalid JSON.' };
131
+ }
132
+ }
133
+
134
+ function isUpdateStatus(status) {
135
+ return status === 'update-available' || status === 'partial-update';
136
+ }
137
+
138
+ function buildMessage(update) {
139
+ const from = update.from || update.version || 'unknown';
140
+ const to = update.to || update.remote || 'unknown';
141
+ const parts = [
142
+ `Harness update available: ${from} -> ${to}.`,
143
+ `Before unrelated work, ask the user whether to run /wf-update.`,
144
+ ];
145
+ // Only include summary counts — never list individual conflict files in hook output
146
+ if (update.conflict > 0) {
147
+ parts.push(`${update.conflict} conflict file(s) will need agent/user merge decisions.`);
148
+ }
149
+ if ((update.updated > 0 || update.created > 0) && update.updated !== undefined) {
150
+ const safeCount = (update.updated || 0) + (update.created || 0);
151
+ parts.push(`${safeCount} safe file update(s) available.`);
152
+ }
153
+ // Max 2 lines total, never include plan details
154
+ return parts.slice(0, 2).join(' ');
155
+ }
156
+
157
+ function readModeLabel() {
158
+ const mode = readJsonFile(modePath(), null);
159
+ if (!mode || !mode.active || !mode.mode) return null;
160
+ return `${mode.mode} mode on`;
161
+ }
162
+
163
+ function emit(message, payload = {}) {
164
+ if (!message && !payload.modeLabel) return;
165
+
166
+ if (format === 'claude') {
167
+ const context = [message, payload.modeLabel].filter(Boolean).join('\n');
168
+ if (context) console.log(JSON.stringify({ additionalContext: context }));
169
+ return;
170
+ }
171
+
172
+ if (format === 'codex') {
173
+ const context = [message, payload.modeLabel].filter(Boolean).join('\n');
174
+ if (context) {
175
+ console.log(JSON.stringify({
176
+ hookSpecificOutput: {
177
+ hookEventName: input.hook_event_name || 'UserPromptSubmit',
178
+ additionalContext: context,
179
+ },
180
+ }));
181
+ }
182
+ return;
183
+ }
184
+
185
+ if (format === 'json') {
186
+ console.log(JSON.stringify({ message, ...payload }, null, 2));
187
+ return;
188
+ }
189
+
190
+ if (message) console.log(message);
191
+ if (payload.modeLabel) console.log(payload.modeLabel);
192
+ }
193
+
194
+ function main() {
195
+ if (!existsSync(resolve(root, 'Harness', '.harness-version'))) return;
196
+ const version = readVersion();
197
+ if (version?.autoCheck === false) return;
198
+
199
+ const modeLabel = readModeLabel();
200
+ if (modeOnly) {
201
+ emit('', { modeLabel, status: 'mode' });
202
+ return;
203
+ }
204
+
205
+ if (shouldSkipPrompt()) {
206
+ emit('', { modeLabel, status: 'skipped-update-command' });
207
+ return;
208
+ }
209
+
210
+ const now = Date.now();
211
+ const cache = readJsonFile(cachePath(), {});
212
+ const checkInterval = intervalFromEnv('WF_UPDATE_CHECK_INTERVAL_MS', DEFAULT_CHECK_INTERVAL_MS);
213
+ const noticeInterval = intervalFromEnv('WF_UPDATE_NOTICE_INTERVAL_MS', DEFAULT_NOTICE_INTERVAL_MS);
214
+
215
+ let update = cache.update;
216
+ const shouldCheck = force
217
+ || !cache.checkedAt
218
+ || now - Date.parse(cache.checkedAt) >= checkInterval;
219
+
220
+ if (shouldCheck) {
221
+ update = runUpdateCheck();
222
+ writeJsonFile(cachePath(), {
223
+ checkedAt: new Date(now).toISOString(),
224
+ noticedAt: cache.noticedAt || null,
225
+ update,
226
+ });
227
+ }
228
+
229
+ if (!isUpdateStatus(update?.status)) {
230
+ emit('', { modeLabel, status: update?.status || 'unknown' });
231
+ return;
232
+ }
233
+
234
+ const shouldNotice = force
235
+ || !cache.noticedAt
236
+ || now - Date.parse(cache.noticedAt) >= noticeInterval
237
+ || cache.update?.to !== update.to
238
+ || cache.update?.remote !== update.remote;
239
+
240
+ if (!shouldNotice) {
241
+ emit('', { modeLabel, status: update.status, suppressed: true });
242
+ return;
243
+ }
244
+
245
+ writeJsonFile(cachePath(), {
246
+ checkedAt: cache.checkedAt || new Date(now).toISOString(),
247
+ noticedAt: new Date(now).toISOString(),
248
+ update,
249
+ });
250
+
251
+ emit(buildMessage(update), { modeLabel, status: update.status, update });
252
+ }
253
+
254
+ try {
255
+ main();
256
+ } catch {
257
+ // Hooks must fail open. A broken update reminder should never block work.
258
+ }
@@ -7,8 +7,12 @@
7
7
  * Usage:
8
8
  * node Harness/scripts/wf-update-check.mjs # full dry-run plan
9
9
  * node Harness/scripts/wf-update-check.mjs --json # JSON output for AI consumption
10
+ * node Harness/scripts/wf-update-check.mjs --json # summary/counts + short agent hints only (token-safe)
11
+ * node Harness/scripts/wf-update-check.mjs --json --full-plan # also include full plan + conflict details (verbose)
10
12
  * node Harness/scripts/wf-update-check.mjs --apply-safe # apply SAFE+NEW, leave CONFLICT for AI
11
13
  * node Harness/scripts/wf-update-check.mjs --apply # apply only when no CONFLICT exists
14
+ *
15
+ * --full-plan and --verbose are aliases.
12
16
  */
13
17
 
14
18
  import { readFileSync, writeFileSync, existsSync, mkdirSync, lstatSync } from 'fs';
@@ -187,9 +191,18 @@ async function main() {
187
191
  // 1. Read local state
188
192
  if (!existsSync(VERSION_FILE)) {
189
193
  if (jsonOut) {
190
- console.log(JSON.stringify({ status: 'error', message: 'Local Harness/.harness-version not found.' }));
194
+ console.log(JSON.stringify({
195
+ status: 'error',
196
+ message: 'Local Harness/.harness-version not found. Is Harness installed?',
197
+ recovery: 'If this is an old Harness install that predates .harness-version, do not reinstall blindly. Restore Harness/.harness-version from backup if available. If the updater script is also missing, run from the project root: npx create-harness-vibe-coding@latest <name> . -y --on-conflict skip --json to restore missing updater infrastructure without overwriting user files.',
198
+ }));
191
199
  } else {
192
200
  console.error('ERROR: Harness/.harness-version not found. Is Harness installed?');
201
+ console.error(' If this is an old Harness install without version tracking, do not reinstall blindly.');
202
+ console.error(' Restore Harness/.harness-version from backup if available.');
203
+ console.error(' If the updater script is also missing, recover with:');
204
+ console.error(' npx create-harness-vibe-coding@latest <project-name> . -y --on-conflict skip --json');
205
+ console.error(' This restores missing updater infrastructure without overwriting user data.');
193
206
  }
194
207
  process.exitCode = 1;
195
208
  return;
@@ -200,10 +213,16 @@ async function main() {
200
213
  localVersion = JSON.parse(readFileSync(VERSION_FILE, 'utf-8'));
201
214
  } catch (e) {
202
215
  if (jsonOut) {
203
- console.log(JSON.stringify({ status: 'error', message: 'Failed to parse Harness/.harness-version: ' + e.message }));
216
+ console.log(JSON.stringify({
217
+ status: 'error',
218
+ message: 'Failed to parse Harness/.harness-version: ' + e.message,
219
+ recovery: 'The .harness-version file may be corrupted. Do not overwrite user files. Back up or move the corrupted Harness/.harness-version before manual recovery. If the updater script is also missing, run from the project root: npx create-harness-vibe-coding@latest <name> . -y --on-conflict skip --json to restore missing updater infrastructure.',
220
+ }));
204
221
  } else {
205
222
  console.error('ERROR: Failed to parse Harness/.harness-version:', e.message);
206
- console.error(' The file may be corrupted. If this is an old project, try reinstalling the harness.');
223
+ console.error(' The file may be corrupted. Back up or move Harness/.harness-version before manual recovery.');
224
+ console.error(' If the updater script is also missing, recover with:');
225
+ console.error(' npx create-harness-vibe-coding@latest <project-name> . -y --on-conflict skip --json');
207
226
  }
208
227
  process.exitCode = 1;
209
228
  return;
@@ -320,16 +339,26 @@ async function main() {
320
339
  }
321
340
 
322
341
  function buildJsonPlan() {
342
+ const verbose = args.includes('--verbose') || args.includes('--full-plan');
323
343
  return {
324
344
  updated: plan.updated.map(withRemoteMeta),
325
345
  created: plan.created.map(withRemoteMeta),
326
346
  adopted: plan.adopted.map(withRemoteMeta),
327
- conflict: plan.conflict.map(withConflictActions),
347
+ conflict: verbose ? plan.conflict.map(withConflictActions) : plan.conflict.map(withConflictActions).slice(0, 5),
348
+ conflictTruncated: !verbose && plan.conflict.length > 5 ? plan.conflict.length - 5 : undefined,
328
349
  skipped: plan.skipped.map(withRemoteMeta),
329
350
  };
330
351
  }
331
352
 
332
353
  function buildAgentHints(jsonPlan) {
354
+ // Token-safe by default: omit the conflict array; full list available via --json --verbose (or --full-plan)
355
+ const verbose = args.includes('--verbose') || args.includes('--full-plan');
356
+ const maxConflictDetails = verbose ? Infinity : 5;
357
+ const totalConflicts = plan.conflict.length;
358
+ const conflicts = jsonPlan.conflict.slice(0, maxConflictDetails);
359
+ const truncated = totalConflicts > maxConflictDetails
360
+ ? totalConflicts - maxConflictDetails
361
+ : 0;
333
362
  return {
334
363
  mode: 'script-first-ai-conflicts',
335
364
  dryRunJsonCommand: 'node Harness/scripts/wf-update-check.mjs --json',
@@ -338,8 +367,10 @@ async function main() {
338
367
  finalizeCommand: 'node Harness/scripts/wf-update-check.mjs --finalize',
339
368
  partialUpdate: localVersion.partialUpdate || null,
340
369
  acceptedConflicts: localVersion.acceptedConflicts || {},
341
- aiMergeRequired: jsonPlan.conflict,
342
- aiMergeRequiredCount: jsonPlan.conflict.length,
370
+ // aiMergeRequired array is attached only in verbose mode to keep default output token-safe.
371
+ ...(verbose ? { aiMergeRequired: conflicts } : {}),
372
+ aiMergeRequiredCount: totalConflicts,
373
+ aiMergeRequiredTruncated: truncated > 0 ? truncated : undefined,
343
374
  conflictPolicy: 'Use the script for SAFE/NEW/adopted files. For each CONFLICT file, compare local content with templateHint/remoteUrl, then record the decision with --accept-local, --accept-merged, or --accept-template. Do not hand-edit Harness/.harness-version.',
344
375
  postUpdateCommands: [
345
376
  'node Harness/scripts/validate-harness.mjs',
@@ -512,6 +543,7 @@ async function main() {
512
543
 
513
544
  // 3. Output
514
545
  if (jsonOut) {
546
+ const verbose = args.includes('--verbose') || args.includes('--full-plan');
515
547
  const jsonPlan = buildJsonPlan();
516
548
  console.log(JSON.stringify({
517
549
  status: localVersion.partialUpdate ? 'partial-update' : 'update-available',
@@ -525,7 +557,8 @@ async function main() {
525
557
  adopted: plan.adopted.length,
526
558
  conflict: plan.conflict.length,
527
559
  skipped: plan.skipped.length,
528
- plan: jsonPlan,
560
+ // Token-safe by default: attach the full plan only when --verbose / --full-plan is passed.
561
+ ...(verbose ? { plan: jsonPlan } : {}),
529
562
  agent: buildAgentHints(jsonPlan),
530
563
  }, null, 2));
531
564
  return;
@@ -2,7 +2,7 @@
2
2
 
3
3
  Purpose: coordinate subagents for speed without losing control of scope, evidence, or integration.
4
4
 
5
- Use this file when work needs multiple roles, parallel reading, independent review, broad context, repeated failures, or `/wf`.
5
+ Use this file when work needs multiple roles, parallel reading, independent review, broad context, repeated failures, or explicit `/wf` / `/wf-max` invocation.
6
6
 
7
7
  project files are the only durable communication channel; chat/subagent transcript state is non-authoritative. Important assumptions, decisions, blockers, evidence, and handoffs must be written to `Harness/tasks/<task-id>/PROGRESS.md` and `Harness/tasks/<task-id>/PLAN.md`, the current feature doc, `Harness/MEMORY.md`, or `Harness/memory/*` as appropriate.
8
8
 
@@ -43,20 +43,22 @@ Subagents provide bounded work. They do not own final scope, architecture, relea
43
43
 
44
44
  Use the installed roster under `.claude/agents/` before inventing ad hoc roles.
45
45
 
46
- | Agent | Default Use |
47
- | --- | --- |
48
- | `planner` | decompose goals, map unknowns, define success criteria and write sets |
49
- | `researcher` | local/external ecosystem context, comparable projects, current facts |
50
- | `docs-researcher` | official docs, SDK/API behavior, browser/tool constraints |
51
- | `architect` | boundaries, interface decoupling, state ownership, data flow, migration risk |
52
- | `test-writer` | failing tests, manual check contracts, browser/API evidence plan |
53
- | `implementer` | bounded code or doc changes after the second plan |
54
- | `reviewer` | spec compliance, code quality, maintainability, security, missing tests |
55
- | `debugger` | reproduced failures, root cause isolation, smallest safe fix |
56
- | `verifier` | command execution, real browser/API checks, final evidence |
57
- | `reflector` | closeout synthesis, unresolved-risk check, acceptance gate verdict |
58
- | `memory-master` | write/consolidate memory entries, dedup, cross-project extraction; dispatched on repeated failures, user corrections, and WF closeout |
59
- | `context-master` | analyze context usage, recommend compression at ~85% window, extract durable session knowledge during closeout |
46
+ | Agent | Default Use | Model Tier |
47
+ | --- | --- | --- |
48
+ | `planner` | decompose goals, map unknowns, define success criteria and write sets | standard |
49
+ | `researcher` | local/external ecosystem context, comparable projects, current facts | standard |
50
+ | `docs-researcher` | official docs, SDK/API behavior, browser/tool constraints | standard |
51
+ | `architect` | boundaries, interface decoupling, state ownership, data flow, migration risk | standard |
52
+ | `test-writer` | failing tests, manual check contracts, browser/API evidence plan | standard |
53
+ | `implementer` | bounded code or doc changes after the second plan | standard |
54
+ | `reviewer` | spec compliance, code quality, maintainability, security, missing tests | standard |
55
+ | `debugger` | reproduced failures, root cause isolation, smallest safe fix | standard |
56
+ | `verifier` | command execution, real browser/API checks, final evidence | standard or small-fast |
57
+ | `reflector` | closeout synthesis, unresolved-risk check, acceptance gate verdict | standard |
58
+ | `task-scribe` | task state, heartbeat, dispatch ledger, evidence pointers NEVER source code | small-fast (haiku) |
59
+ | `codebase-explorer` | scoped read-only source exploration, file discovery, symbol tracing | small-fast (haiku) |
60
+ | `context-master` | analyze context usage, recommend compression at ~85% window, extract durable session knowledge during closeout | small-fast (haiku) |
61
+ | `memory-master` | write/consolidate memory entries, dedup, cross-project extraction; dispatched on repeated failures, user corrections, and WF closeout | standard |
60
62
 
61
63
  ## Acceptance Role Passes
62
64
 
@@ -80,8 +82,10 @@ Hard rule: implementer may not be the independent validator for the same AC ID.
80
82
 
81
83
  ## WF Default Fan-Out
82
84
 
83
- Explicit `/wf`, `wf mode`, `workflow mode`, or `wk mode` requires complete
84
- role-chain coverage from `.claude/agents/` before closeout: plan,
85
+ Explicit `/wf`, `$wf`, or `/skills wf` requires tier-specific role coverage per `Harness/WF.md`.
86
+ WF-Light: planner + test-writer + implementer + verifier.
87
+ WF-Standard: adds research/docs + one review lens.
88
+ WF-Full: complete role-chain coverage from `.claude/agents/` before closeout: plan,
85
89
  research/docs research as needed, architecture, test, implement, independent
86
90
  validation, cross-review, reflector, and accept.
87
91
 
@@ -102,7 +106,7 @@ Then add phase-specific agents:
102
106
  - `context-master` before closeout for knowledge extraction
103
107
  - `memory-master` after repeated failures and during closeout for consolidation
104
108
 
105
- Collaboration mode is determined by concrete conditions, not a fixed ratio. See `Harness/WF.md#Complete Role Chain Requirement` for the full decision tree. Summary: explicit WF/WK mode always uses the complete role chain. 3+ files or cross-layer work uses multi-agent orchestration. 1-2 local files, well-understood, not in WF mode can be solo. Repeated failure stops solo work and switches to multi-agent.
109
+ Collaboration mode is determined by WF tier and concrete conditions, not a fixed ratio. See `Harness/WF.md` for the tier decision guide. Summary: WF-Light uses minimal roles. WF-Standard uses moderate roles with one review lens. WF-Full always uses the complete role chain. Non-WF complex work may still use subagents and planning without entering any WF mode. Repeated failure after two attempts escalates to next tier.
106
110
 
107
111
  ## Efficiency Ladder
108
112
 
@@ -115,7 +119,7 @@ Choose the cheapest coordination level that is safe.
115
119
  | Parallel read-only | broad reading, research, architecture, multiple independent failures | 2-3 read-only agents |
116
120
  | Serial build lane | normal feature or fix | acceptance/contract -> test-writer -> implementer -> verifier evidence -> cross-review -> reflector -> acceptance |
117
121
  | Isolated lanes | disjoint write sets or competing approaches | separate worktrees, then review and merge |
118
- | Max parallelism | 5+ disjoint files, fan-out benefit > coordination cost | /wf max: write-set coloring -> wave dispatch -> parallel review |
122
+ | Max parallelism | 5+ disjoint files, fan-out benefit > coordination cost | /wf-max: write-set coloring -> wave dispatch -> parallel review |
119
123
 
120
124
  Max parallelism removes the Harness default cap, not the runtime's physical or
121
125
  account cap. For WF-MAX, record the current runtime budget, use native
@@ -127,10 +131,7 @@ bottleneck, ask the user before raising `agents.max_threads` and keep
127
131
  `max_depth = 1` unless recursive delegation is explicitly approved. Do not rely
128
132
  on undocumented fork/derive bypasses as stable capacity.
129
133
 
130
- Default for automatic WF triggers: 3-5 active read-only agents before second
131
- planning. For explicit WF/WK mode, never use the solo pass; schedule the
132
- complete role chain and use bounded role passes as the recorded fallback when
133
- subagents are unavailable.
134
+ Default for explicit WF invocation: tier-based. WF-Light: planner + test-writer + implementer + verifier (bounded passes acceptable). WF-Standard: adds research/docs + one independent review lens. WF-Full: complete role chain, use bounded role passes as the recorded fallback when subagents are unavailable.
134
135
 
135
136
  ## WF Orchestration Shape
136
137
 
@@ -148,10 +149,10 @@ controller intake
148
149
  -> close with evidence
149
150
  ```
150
151
 
151
- Use this shape for `/wf`, long tasks, multi-file changes, architecture work, migrations, browser/API behavior, or repeated failures.
152
+ Use this shape for explicit `/wf`, `/wf-max`, or non-WF complex work with subagents.
152
153
 
153
154
  ```text
154
- /wf max orchestration shape:
155
+ /wf-max orchestration shape:
155
156
  controller intake
156
157
  -> wave 0: max-parallel exploration (4-14 read-only agents)
157
158
  -> E-GATE: Exploration Gate - all questions answered, findings synthesized (per WF-MAX.md)
@@ -167,14 +168,14 @@ controller intake
167
168
 
168
169
  ## Dispatch Pack
169
170
 
170
- Use the canonical dispatch input and handoff format in `Harness/dispatch.md`. Every subagent dispatch must be self-contained - inject only the docs selected by `Harness/README.md` and `Harness/context-loading.md`.
171
+ Use the canonical dispatch input and handoff format in `Harness/dispatch.md`. Every subagent dispatch must be self-contained - inject only the docs selected by `Harness/README.md` and `Harness/context-loading.md`. On session start, the controller reads `Harness/tasks/<task-id>/STATE.json` per [WF-STATE.md](WF-STATE.md) to resume the dispatch ledger and ready queue.
171
172
 
172
173
  ## Parallelism Rules
173
174
 
174
175
  - Read-only agents may run in parallel.
175
176
  - Writing agents run serially unless write sets are disjoint and the controller has chosen an isolated worktree.
176
177
  - Reviewers may run in parallel after implementation, but spec compliance is evaluated before code-quality approval.
177
- - Subagents are readers and reporters. They return findings and PLAN patch suggestions. Only the controller (main agent) commits state changes to task files.
178
+ - Subagents are readers and reporters. They return findings and PLAN patch suggestions. Only the controller (main agent) or task-scribe commits state changes to task files. Production source agents (implementer, debugger, test-writer) never write task state unless explicitly dispatched as task-scribe.
178
179
  - Do not let two agents edit `Harness/tasks/<task-id>/PROGRESS.md`, `Harness/tasks/<task-id>/PLAN.md`, `Harness/MEMORY.md`, or `Harness/memory/*` concurrently. The controller writes durable state.
179
180
  - If two agents disagree, the controller records the conflict in `Harness/tasks/<task-id>/PLAN.md` and chooses the smallest reversible next step.
180
181
 
@@ -35,6 +35,11 @@ Forbidden:
35
35
  -
36
36
  - Truth files (PRD, ACs, UI/API contracts, test plan, validation report) unless a Change Request is recorded.
37
37
 
38
+ ## Memory Preflight
39
+
40
+ - Memory preflight: done | exempt | blocked
41
+ - Memory hints: none | <file/path + reason>
42
+
38
43
  ## Context
39
44
 
40
45
  - Loaded:
@@ -0,0 +1,23 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "taskId": "task-example",
4
+ "status": "active",
5
+ "mode": "direct",
6
+ "tier": "none",
7
+ "phase": "intake",
8
+ "gate": null,
9
+ "updatedAt": "2026-07-16T00:00:00.000Z",
10
+ "activeQuestion": null,
11
+ "nextAction": "Define goal and acceptance criteria",
12
+ "acceptance": [],
13
+ "queues": {
14
+ "ready": [],
15
+ "running": [],
16
+ "blocked": [],
17
+ "done": []
18
+ },
19
+ "dispatchLedger": [],
20
+ "decisions": [],
21
+ "risks": [],
22
+ "artifacts": []
23
+ }
@@ -37,7 +37,7 @@ The agentic engineering harness lives in `Harness/`.
37
37
  - Start at `Harness/README.md`.
38
38
  - Load memory and resource registrations from `Harness/MEMORY.md`.
39
39
  - Track active work in `Harness/PROGRESS.md` and `Harness/tasks/<task-id>/PROGRESS.md`.
40
- - Use `Harness/WF.md` for long, difficult, multi-agent work.
40
+ - Use `Harness/WF.md` only when the user explicitly invokes a WF command such as `/wf` or `/wf-max`; complex work may still use direct planning, tests, and subagents without entering WF.
41
41
  - Claude Code: invoke the `wf` skill with `/wf`.
42
42
  - Codex: invoke the `wf` skill with `$wf` or `/skills`.
43
43
  - Use `Harness/subagents.md` when coordinating multiple agents.
@@ -7,15 +7,16 @@ Write here when:
7
7
  - A validation failure exposes a missing regression check.
8
8
  - A handoff, dispatch, or context-loading pattern should be repeated or avoided.
9
9
 
10
- Entry format, newest first:
10
+ Entry format (compact, default no date):
11
11
 
12
12
  ```markdown
13
- ## YYYY-MM-DD - Short Lesson Name
14
-
15
- - Lesson: the reusable pattern.
16
- - Source: review finding, debug loop, failed verification, or handoff.
17
- - Apply when: the task shape or files where this matters.
18
- - Regression guard: test, validator check, docs update, or manual evidence to keep it from recurring.
13
+ - When <scenario>: <rule>. Avoid <over-application>. Signals: <signals>.
19
14
  ```
20
15
 
21
- Keep entries lightweight and actionable. Avoid secrets and speculative lessons.
16
+ Only use date/timestamp headings when:
17
+ - Entry supersedes prior conflicting guidance
18
+ - Time-sensitive context (version, deprecation)
19
+ - Conflict resolution needed
20
+
21
+ Keep entries lightweight and actionable. Avoid secrets, speculative lessons, task logs, and process summaries.
22
+ - Entry supersedes prior conflicting guidance: add date stamp.
@@ -0,0 +1,43 @@
1
+ # Memory Routes (L3 Route Index)
2
+
3
+ > L3 = 详细 durable memory 路由索引。不是详细 memory,而是命中规则索引。
4
+ > 详细 memory 文件按 scenario 匹配后按需加载。
5
+
6
+ | id | signals | load | avoid |
7
+ | --- | --- | --- | --- |
8
+ | explicit-user-preference | remember, next time, 下次, 记住, 不要再, never, always, I prefer | user-corrections-preferences.md | current-task-only notes, transient mood |
9
+ | hooks-only-wf-auto | hook, runtime hook, .claude/settings.json, .codex/hooks.json, WF-AUTO.md | agent-lessons-patterns.md#only-wf-auto-may-use-runtime-hooks | non-runtime docs, broad hook designs |
10
+ | tool-repeat-failure | same command fails 3x, error signature repeats | tool-usage-reflections.md | one-off command failures |
11
+ | review-debug-lesson | reusable review/debug/validation pattern | agent-lessons-patterns.md | task-specific logs |
12
+ | startup-digest | new session, startup | startup-hints.md | full MEMORY.md index |
13
+ | wf-closeout | /wf-learn, workflow closeout | all memory files via context-master -> memory-master | premature writes before extraction |
14
+
15
+ ## Matching Algorithm
16
+
17
+ 1. 把当前请求压缩成 **scenario pack**: intent / files / commands / signals / risk
18
+ 2. 与上表 Signals 列匹配,计算 score:
19
+ - +4 exact file/path match
20
+ - +3 explicit trigger phrase match
21
+ - +3 command/error signature match
22
+ - +2 workflow/mode match
23
+ - +1 keyword overlap
24
+ - -4 avoid match
25
+ 3. 阈值:
26
+ - score >= 5: 加载对应 memory entry/file section
27
+ - score 3-4: 只加载 route 摘要,必要时再读详细文件
28
+ - score < 3: 不加载
29
+ 4. Hard trigger 优先:
30
+ - 用户显式记忆语句 -> user-corrections-preferences.md
31
+ - 同命令失败 3 次 -> tool-usage-reflections.md
32
+ - review/debug/validation 可复用 lesson -> agent-lessons-patterns.md
33
+ - 修改 hook 相关文件 -> 加载 only-wf-auto hook lesson
34
+ - /wf-learn -> 完整 learning cycle
35
+
36
+ ## Load Logging
37
+
38
+ 每次加载 memory hints 需说明原因:
39
+ ```
40
+ memory hints loaded: <id> because <signal>
41
+ ```
42
+
43
+ 不使用 embedding;保持稳定、可解释、省 token。
@@ -0,0 +1,32 @@
1
+ # Startup Hints (L2 Memory Digest)
2
+
3
+ > L2 = 启动极简 memory digest。每次 Harness 会话启动可读此文件,但不要加载完整 Harness/MEMORY.md 或 Harness/README.md。
4
+
5
+ ## Core Principles
6
+
7
+ - Memory 是短场景规则,不是 task log。
8
+ - 时间戳默认不要写;只有 superseded / conflict / time-sensitive 才写。
9
+ - Broad runtime hooks 禁止;只有 `/wf-auto` bounded tick hook 例外。
10
+ - Direct mode 不加载完整 Harness router,但 startup-hints 是允许的轻量启动提示。
11
+ - 详细 memory 仍按 `MEMORY_PROTOCOL.md` 场景命中后再读。
12
+
13
+ ## Memory Candidate Detection
14
+
15
+ 用户说以下触发词时,识别为 memory candidate:
16
+
17
+ **英文**: remember, next time, don't, do not, never, always, I prefer, I want you to
18
+ **中文**: 记住, 下次, 以后, 不要再, 总是, 永远不要, 我偏好, 我希望你以后
19
+
20
+ ## When to Write Memory
21
+
22
+ - **Explicit user preference**: 清晰、安全、场景明确时,可立即写入 L3,不必等 `/wf-learn`。
23
+ - **Repeated implicit correction**: 同一假设/模式被纠正 2+ 次。
24
+ - **Tool/command failure**: 同类工具/命令失败 3+ 次。
25
+ - **Review/debug lesson**: 只有可复用、能防回归时才写。
26
+
27
+ ## What NOT to Write
28
+
29
+ - Task log、过程总结、一次性情绪
30
+ - Raw logs、transcripts
31
+ - Secrets, tokens, credentials, private data
32
+ - 临时偏好、无复用价值的笔记
@@ -7,15 +7,16 @@ Write here when:
7
7
  - A more reliable command pattern replaces a brittle one.
8
8
  - The environment needs a durable fix, flag, path rule, shell syntax, or startup sequence.
9
9
 
10
- Entry format, newest first:
10
+ Entry format (compact, default no date):
11
11
 
12
12
  ```markdown
13
- ## YYYY-MM-DD - Short Pattern Name
14
-
15
- - Trigger: what failed or repeated.
16
- - Better pattern: the command, tool usage, or sequence to use next time.
17
- - Evidence: command output summary, error text, or affected environment.
18
- - Scope: when this applies and when it does not.
13
+ - When <scenario>: <rule>. Avoid <over-application>. Signals: <signals>.
19
14
  ```
20
15
 
21
- Keep entries concise. Do not record secrets, credentials, private tokens, or one-off noise.
16
+ Only use date/timestamp headings when:
17
+ - Entry supersedes prior conflicting guidance
18
+ - Time-sensitive context (version, deprecation)
19
+ - Conflict resolution needed
20
+
21
+ Never record one-off command failures. Never store secrets, credentials, or private tokens.
22
+ - Entry supersedes prior conflicting guidance: add date stamp.