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.
- package/README-CN.md +7 -1
- package/README.md +21 -2
- package/docs/images/harness-icon.png +0 -0
- package/package.json +2 -1
- package/src/generator.js +36 -0
- package/src/index.js +72 -4
- package/templates/common/.claude/agents/architect.md +31 -31
- package/templates/common/.claude/agents/codebase-explorer.md +45 -0
- package/templates/common/.claude/agents/docs-researcher.md +41 -41
- package/templates/common/.claude/agents/memory-master.md +26 -8
- package/templates/common/.claude/agents/reviewer.md +34 -34
- package/templates/common/.claude/agents/task-scribe.md +70 -0
- package/templates/common/.claude/commands/wf-help.md +8 -4
- package/templates/common/.claude/commands/wf-update.md +24 -0
- package/templates/common/.claude/rules/ecc/common.md +15 -2
- package/templates/common/.claude/settings.json +13 -0
- package/templates/common/.claude/skills/subagent-orchestrator/SKILL.md +8 -4
- package/templates/common/.claude/skills/wf/SKILL.md +15 -8
- package/templates/common/.claude/skills/wf-auto/SKILL.md +3 -2
- package/templates/common/.claude/skills/wf-learn/SKILL.md +9 -2
- package/templates/common/.claude/skills/wf-max/SKILL.md +23 -5
- package/templates/common/.claude/skills/wf-update/SKILL.md +15 -2
- package/templates/common/.codex/hooks.json +17 -0
- package/templates/common/.harness-version +89 -44
- package/templates/common/.opencode/agents/architect.md +24 -24
- package/templates/common/.opencode/agents/codebase-explorer.md +45 -0
- package/templates/common/.opencode/agents/docs-researcher.md +34 -34
- package/templates/common/.opencode/agents/memory-master.md +26 -8
- package/templates/common/.opencode/agents/reviewer.md +27 -27
- package/templates/common/.opencode/agents/task-scribe.md +70 -0
- package/templates/common/.opencode/commands/wf-auto-spark.md +15 -0
- package/templates/common/.opencode/commands/wf-auto.md +15 -0
- package/templates/common/.opencode/commands/wf-help.md +8 -4
- package/templates/common/.opencode/commands/wf-learn.md +15 -0
- package/templates/common/.opencode/commands/wf-max.md +15 -0
- package/templates/common/.opencode/commands/wf-readme.md +15 -0
- package/templates/common/.opencode/commands/wf-remove.md +15 -0
- package/templates/common/.opencode/commands/wf-review.md +15 -0
- package/templates/common/.opencode/commands/wf-update.md +24 -0
- package/templates/common/.opencode/commands/wf.md +15 -0
- package/templates/common/.opencode/plugins/harness-wf-status.mjs +135 -0
- package/templates/common/AGENTS.md +2 -29
- package/templates/common/CLAUDE.md +35 -6
- package/templates/common/Harness/ACCEPTANCE_PROTOCOL.md +2 -2
- package/templates/common/{MEMORY.md → Harness/MEMORY.md} +16 -3
- package/templates/common/Harness/MEMORY_PROTOCOL.md +80 -30
- package/templates/common/Harness/README.md +50 -22
- package/templates/common/{SETUP.md → Harness/SETUP.md} +278 -276
- package/templates/common/Harness/TASK_ARCHIVE.md +56 -0
- package/templates/common/Harness/WF-AUTO-SPARK.md +5 -14
- package/templates/common/Harness/WF-AUTO.md +13 -76
- package/templates/common/Harness/WF-KERNEL.md +189 -0
- package/templates/common/Harness/WF-MAX.md +60 -328
- package/templates/common/Harness/WF-STATE.md +83 -0
- package/templates/common/Harness/WF.md +117 -237
- package/templates/common/Harness/agent-workflow.md +2 -2
- package/templates/common/Harness/context-loading.md +3 -3
- package/templates/common/Harness/dispatch.md +43 -35
- package/templates/common/Harness/scripts/archive-tasks.mjs +239 -0
- package/templates/common/{scripts → Harness/scripts}/scan-clean.mjs +28 -1
- package/templates/common/{scripts → Harness/scripts}/validate-harness.mjs +909 -699
- package/templates/common/Harness/scripts/wf-auto-update-prompt.mjs +258 -0
- package/templates/common/{scripts → Harness/scripts}/wf-update-check.mjs +40 -7
- package/templates/common/Harness/subagents.md +28 -27
- package/templates/common/Harness/tasks/_template/PLAN.md +5 -0
- package/templates/common/Harness/tasks/_template/STATE.json +23 -0
- package/templates/common/README.md +1 -1
- package/templates/common/memory/agent-lessons-patterns.md +9 -8
- package/templates/common/memory/routes.md +43 -0
- package/templates/common/memory/startup-hints.md +32 -0
- package/templates/common/memory/tool-usage-reflections.md +9 -8
- package/templates/common/memory/user-corrections-preferences.md +11 -9
- package/templates/optional/catalog.json +8 -0
- package/templates/optional/skills/browser-e2e/.claude/skills/browser-e2e/SKILL.md +42 -42
- package/templates/optional/skills/browser-e2e/.opencode/commands/wf-browser.md +15 -0
- package/templates/optional/skills/github-pr-review/.claude/skills/github-pr-review/SKILL.md +40 -40
- package/templates/optional/skills/python-backend/.claude/skills/python-backend/SKILL.md +40 -40
- package/templates/optional/skills/ts-react-frontend/.claude/skills/ts-react-frontend/SKILL.md +43 -43
- package/templates/optional/skills/ui-ux-review/.claude/skills/ui-ux-review/SKILL.md +40 -40
- /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({
|
|
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({
|
|
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.
|
|
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
|
|
342
|
-
|
|
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
|
-
|
|
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
|
-
| `
|
|
59
|
-
| `
|
|
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`,
|
|
84
|
-
|
|
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
|
|
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
|
|
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
|
|
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`,
|
|
152
|
+
Use this shape for explicit `/wf`, `/wf-max`, or non-WF complex work with subagents.
|
|
152
153
|
|
|
153
154
|
```text
|
|
154
|
-
/wf
|
|
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`
|
|
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,
|
|
10
|
+
Entry format (compact, default no date):
|
|
11
11
|
|
|
12
12
|
```markdown
|
|
13
|
-
|
|
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
|
-
|
|
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,
|
|
10
|
+
Entry format (compact, default no date):
|
|
11
11
|
|
|
12
12
|
```markdown
|
|
13
|
-
|
|
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
|
-
|
|
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.
|