harness-everything 0.2.1 → 0.2.2

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 (70) hide show
  1. package/README.md +1 -1
  2. package/build-multi-agent-system/SKILL.md +68 -68
  3. package/create-agent-launcher/SKILL.md +48 -48
  4. package/docs/architecture.md +2 -2
  5. package/docs/workflows/build-multi-agent-system.md +62 -62
  6. package/docs/workflows/create-agent-launcher.md +62 -62
  7. package/docs/workflows/environment-detection.md +63 -63
  8. package/docs/workflows/eval-harness.md +57 -57
  9. package/docs/workflows/fable-discipline.md +59 -59
  10. package/docs/workflows/fable-mode.md +32 -32
  11. package/docs/workflows/git-commit.md +62 -62
  12. package/docs/workflows/grill-me.md +62 -62
  13. package/docs/workflows/grill-with-docs.md +62 -62
  14. package/docs/workflows/improve-codebase-architecture.md +60 -60
  15. package/docs/workflows/repo-docs.md +59 -59
  16. package/docs/workflows/rewrite-commits.md +60 -60
  17. package/docs/workflows/security-review.md +58 -58
  18. package/docs/workflows/self-evolve.md +59 -59
  19. package/docs/workflows/tdd.md +39 -39
  20. package/docs/workflows/todo-driven-workflow.md +36 -36
  21. package/docs/workflows/using-git-worktrees.md +63 -63
  22. package/docs/workflows/verification-loop.md +69 -69
  23. package/docs/workflows/verify-before-claim.md +60 -60
  24. package/docs/workflows/zoom-out.md +62 -62
  25. package/environment-detection/SKILL.md +77 -77
  26. package/eval-framework/behavioral-test.js +105 -105
  27. package/eval-framework/mechanism-test.js +251 -251
  28. package/eval-harness/SKILL.md +59 -59
  29. package/fable-discipline/SKILL.md +38 -38
  30. package/fable-mode/SKILL.md +51 -51
  31. package/git-commit/SKILL.md +55 -55
  32. package/grill-me/SKILL.md +36 -36
  33. package/grill-with-docs/SKILL.md +99 -99
  34. package/harness-everything/SKILL.md +141 -141
  35. package/harness-everything/examples/README.md +9 -9
  36. package/harness-everything/examples/todo-workflow.md +22 -22
  37. package/harness-everything/scripts/todo-cli.js +157 -157
  38. package/harness-everything/scripts/verify-gate.js +31 -31
  39. package/hooks/scripts/atomic-commit-check.js +68 -68
  40. package/hooks/scripts/context-compact.js +114 -114
  41. package/hooks/scripts/lib/platforms/claude.js +132 -42
  42. package/hooks/scripts/lib/platforms/codex.js +96 -46
  43. package/hooks/scripts/lib/platforms/continue.js +73 -41
  44. package/hooks/scripts/lib/platforms/copilot.js +91 -41
  45. package/hooks/scripts/lib/platforms/cursor.js +71 -41
  46. package/hooks/scripts/lib/platforms/hermes.js +25 -0
  47. package/hooks/scripts/rule-of-3.js +176 -176
  48. package/improve-codebase-architecture/SKILL.md +44 -44
  49. package/install-cognitive-os/SKILL.md +95 -95
  50. package/package.json +1 -1
  51. package/repo-docs/SKILL.md +45 -45
  52. package/rewrite-commits/SKILL.md +32 -32
  53. package/scripts/installer.js +57 -200
  54. package/scripts/lib/advisory-text.js +163 -163
  55. package/scripts/lib/claude-hooks.js +71 -71
  56. package/scripts/lib/manifest.js +82 -82
  57. package/scripts/lib/prompts.js +241 -241
  58. package/scripts/lib/skills.js +174 -172
  59. package/scripts/lib/workspace.js +28 -28
  60. package/security-review/SKILL.md +510 -510
  61. package/self-evolve/SKILL.md +54 -54
  62. package/skill-creator/SKILL.md +91 -91
  63. package/skill-creator/references/testing-workflow.md +32 -32
  64. package/skill-style/SKILL.md +48 -48
  65. package/tdd/SKILL.md +53 -53
  66. package/todo-driven-workflow/SKILL.md +54 -54
  67. package/using-git-worktrees/SKILL.md +161 -161
  68. package/verification-loop/SKILL.md +138 -138
  69. package/verify-before-claim/SKILL.md +86 -86
  70. package/zoom-out/SKILL.md +90 -90
@@ -216,113 +216,40 @@ async function main() {
216
216
  console.log(`Installing Harness OS to ${isGlobal ? 'Global Home' : 'Local Workspace'}`);
217
217
  console.log("-------------------------------------------------");
218
218
 
219
- // Merge into .claude/settings.json (only if Claude Code selected)
220
- if (targets.claude) {
221
- installClaudeHooks({ isGlobal, targetWorkspaceRoot });
222
- }
223
-
224
- // Cursor
225
- if (targets.cursor) {
226
- const targetFile = isGlobal ? path.join(userHome, '.cursorrules') : path.join(targetWorkspaceRoot, '.cursorrules');
227
- advisory.injectAdvisoryText(targetFile, '# Cursor Project Rules', isGlobal ? '~/.cursorrules' : '.cursorrules');
228
- }
229
- // Copilot Chat
230
- if (targets.copilot) {
231
- if (!isGlobal) {
232
- const targetFile = path.join(targetWorkspaceRoot, '.github', 'copilot-instructions.md');
233
- advisory.injectAdvisoryText(targetFile, '# Copilot Instructions', '.github/copilot-instructions.md');
234
- } else {
235
- try {
236
- const promptsDir = getUserPromptsDir();
237
- if (!fs.existsSync(promptsDir)) {
238
- fs.mkdirSync(promptsDir, { recursive: true });
239
- }
240
- const vscodeInstFile = path.join(promptsDir, 'harness.instructions.md');
241
- fs.writeFileSync(vscodeInstFile, advisory.buildCopilotGlobalContent(), 'utf8');
242
- console.log(` ✅ Installed global Copilot instructions to VS Code: ${vscodeInstFile}`);
243
- } catch (err) {
244
- console.warn(` ⚠️ Failed to write VS Code user prompts folder: ${err.message}`);
245
- }
246
- }
247
- }
248
- // Codex
249
- if (targets.codex) {
250
- if (!isGlobal) {
251
- const targetFile = path.join(targetWorkspaceRoot, 'AGENTS.md');
252
- advisory.injectAdvisoryText(targetFile, '# AGENTS.md', 'AGENTS.md');
253
- } else {
254
- try {
255
- const promptsDir = getUserPromptsDir();
256
- if (!fs.existsSync(promptsDir)) {
257
- fs.mkdirSync(promptsDir, { recursive: true });
258
- }
259
- const vscodeAgentFile = path.join(promptsDir, 'harness.agent.md');
260
- fs.writeFileSync(vscodeAgentFile, advisory.buildCodexGlobalContent(), 'utf8');
261
- console.log(` ✅ Installed global Codex agent to VS Code: ${vscodeAgentFile}`);
262
- } catch (err) {
263
- console.warn(` ⚠️ Failed to write VS Code user prompts folder: ${err.message}`);
264
- }
265
- }
266
- }
267
- // Continue.dev
268
- if (targets.continue) {
269
- const targetFile = isGlobal ? path.join(userHome, '.continue', 'rules', 'harness.md') : path.join(workspaceRoot, '.continue', 'rules', 'harness.md');
270
- advisory.installContinueRule(targetFile, isGlobal ? '~/.continue/rules/harness.md' : '.continue/rules/harness.md');
271
- }
272
- // Hermes Agent (reads .hermes.md/AGENTS.md/CLAUDE.md/.cursorrules from the
273
- // project it's launched in - project scope only, no documented global
274
- // equivalent, so --global is a documented no-op here rather than a guess).
275
- if (targets.hermes) {
276
- if (!isGlobal) {
277
- const targetFile = path.join(targetWorkspaceRoot, '.hermes.md');
278
- advisory.injectAdvisoryText(targetFile, '# .hermes.md', '.hermes.md');
279
- } else {
280
- console.log(` ℹ️ Hermes Agent has no documented global instructions file (it reads .hermes.md from the current project directory only) - skipping global install for --hermes.`);
219
+ for (const platform of platformModules) {
220
+ if (targets[platform.name] && typeof platform.install === 'function') {
221
+ platform.install({
222
+ isGlobal,
223
+ targetWorkspaceRoot,
224
+ harnessSourceDir,
225
+ packageVersion,
226
+ getUserPromptsDir,
227
+ advisory,
228
+ claudeHooks,
229
+ manifest,
230
+ userHome,
231
+ workspaceRoot
232
+ });
281
233
  }
282
234
  }
283
235
 
284
236
  // Install chosen skills. Every platform's skills stay at that platform's
285
- // own native location (unchanged) EXCEPT Claude, which never had one -
286
- // its copy lives under its own harness-everything/ subfolder instead.
287
- // Every platform still gets its own harness-everything/manifest.json so
288
- // "what did we install here" is always precisely answerable per platform.
237
+ // own native location (unchanged) EXCEPT Claude, which has its copy under
238
+ // .claude/skills/. Each platform's manifest.json tracks its own.
289
239
  if (chosenSkills.length > 0) {
290
240
  const targetDirs = [];
291
- if (isGlobal) {
292
- const globalAgentsDir = path.join(userHome, '.agents');
293
- targetDirs.push({
294
- path: path.join(globalAgentsDir, 'skills'),
295
- label: '~/.agents/skills/',
296
- manifestPath: manifest.getManifestPath(globalAgentsDir),
297
- });
298
- } else {
299
- if (targets.claude) {
300
- const claudeDir = path.join(workspaceRoot, '.claude');
301
- targetDirs.push({
302
- path: path.join(manifest.getHarnessDir(claudeDir), 'skills'),
303
- label: '.claude/harness-everything/skills/',
304
- manifestPath: manifest.getManifestPath(claudeDir),
305
- });
306
- }
307
- if (targets.cursor) {
308
- const cursorDir = path.join(workspaceRoot, '.cursor');
309
- targetDirs.push({ path: path.join(cursorDir, 'skills'), label: '.cursor/skills/', manifestPath: manifest.getManifestPath(cursorDir) });
310
- }
311
- if (targets.copilot) {
312
- const githubDir = path.join(workspaceRoot, '.github');
313
- targetDirs.push({ path: path.join(githubDir, 'skills'), label: '.github/skills/', manifestPath: manifest.getManifestPath(githubDir) });
314
- }
315
- if (targets.codex) {
316
- const codexDir = path.join(workspaceRoot, '.codex');
317
- targetDirs.push({ path: path.join(codexDir, 'skills'), label: '.codex/skills/', manifestPath: manifest.getManifestPath(codexDir) });
318
- }
319
- if (targets.continue) {
320
- const continueDir = path.join(workspaceRoot, '.continue');
321
- targetDirs.push({ path: path.join(continueDir, 'skills'), label: '.continue/skills/', manifestPath: manifest.getManifestPath(continueDir) });
241
+ const addedPaths = new Set();
242
+ for (const platform of platformModules) {
243
+ // If it's a global install, gather all configured/selected platforms or defaults
244
+ if (targets[platform.name] || (isGlobal && (targets.claude || targets.cursor || targets.copilot || targets.codex || targets.continue || targets.hermes))) {
245
+ if (typeof platform.getSkillsTarget === 'function') {
246
+ const tgt = platform.getSkillsTarget({ workspaceRoot, userHome, isGlobal, manifest });
247
+ if (tgt && tgt.path && !addedPaths.has(tgt.path)) {
248
+ targetDirs.push(tgt);
249
+ addedPaths.add(tgt.path);
250
+ }
251
+ }
322
252
  }
323
- // Hermes has no documented project-level skills directory - its skills
324
- // system is per-profile only (~/.hermes/skills/), which the isGlobal
325
- // branch above already covers via the shared global harness-everything/ target.
326
253
  }
327
254
 
328
255
  console.log(`\nInstalling Harness skills:`);
@@ -357,61 +284,6 @@ async function main() {
357
284
  console.log("=================================================");
358
285
  }
359
286
 
360
- function installClaudeHooks({ isGlobal, targetWorkspaceRoot }) {
361
- const claudeDir = isGlobal ? path.join(userHome, '.claude') : path.join(targetWorkspaceRoot, '.claude');
362
- if (!fs.existsSync(claudeDir)) {
363
- fs.mkdirSync(claudeDir, { recursive: true });
364
- console.log(` Created ${isGlobal ? '~/.claude' : '.claude'} directory`);
365
- }
366
- const claudeSettingsFile = path.join(claudeDir, 'settings.json');
367
- let claudeConfig = {};
368
- if (fs.existsSync(claudeSettingsFile)) {
369
- try {
370
- claudeConfig = JSON.parse(fs.readFileSync(claudeSettingsFile, 'utf8'));
371
- } catch (e) {
372
- console.warn(` ⚠️ Existing ${isGlobal ? '~' : ''}/.claude/settings.json is malformed, creating fresh one.`);
373
- }
374
- }
375
-
376
- const resolvedHooks = resolveSourceHooks();
377
- claudeHooks.mergeHarnessHooks(claudeConfig, resolvedHooks);
378
-
379
- fs.writeFileSync(claudeSettingsFile, JSON.stringify(claudeConfig, null, 2), 'utf8');
380
- console.log(` ✅ Configured Claude Code hooks safely in ${isGlobal ? '~' : ''}/.claude/settings.json`);
381
- }
382
-
383
- // Resolves the source hooks.json into absolute script paths and stamps each
384
- // entry with which package/version/author installed it (informational -
385
- // removal itself still keys off the `harness:` id prefix alone).
386
- function resolveSourceHooks() {
387
- const sourceHooksFile = path.join(harnessSourceDir, 'hooks', 'hooks.json');
388
- if (!fs.existsSync(sourceHooksFile)) {
389
- throw new Error(`Harness source hooks definition not found at: ${sourceHooksFile}`);
390
- }
391
- const sourceHooksObj = JSON.parse(fs.readFileSync(sourceHooksFile, 'utf8'));
392
-
393
- const resolvedHooks = {};
394
- for (const [hookType, hookList] of Object.entries(sourceHooksObj.hooks || {})) {
395
- resolvedHooks[hookType] = hookList.map(hookItem => {
396
- const cloned = JSON.parse(JSON.stringify(hookItem));
397
- if (cloned.hooks) {
398
- cloned.hooks = cloned.hooks.map(h => {
399
- if (h.type === 'command' && h.command) {
400
- h.command = h.command.replace(/^node\s+"?([^"\s]+)"?/, (m, scriptPath) => {
401
- const abs = path.isAbsolute(scriptPath) ? scriptPath : path.join(harnessSourceDir, scriptPath);
402
- return `node "${abs}"`;
403
- });
404
- }
405
- return h;
406
- });
407
- }
408
- cloned.harness = { package: manifest.PACKAGE_NAME, version: packageVersion, author: manifest.HARNESS_AUTHOR };
409
- return cloned;
410
- });
411
- }
412
- return resolvedHooks;
413
- }
414
-
415
287
  async function runUninstall({ hasYesFlag, args, isInteractive }) {
416
288
  const localHarnessDirs = platformModules
417
289
  .filter(p => typeof p.getHarnessDir === 'function')
@@ -524,36 +396,30 @@ async function runUninstall({ hasYesFlag, args, isInteractive }) {
524
396
  console.log("Uninstalling Harness OS from Local Workspace...");
525
397
  console.log("-------------------------------------------------");
526
398
 
527
- const localSettingsFile = path.join(workspaceRoot, '.claude', 'settings.json');
528
- claudeHooks.removeHarnessHooks(localSettingsFile);
529
-
530
- // Clear each platform's own runtime hook-state. Manifest + any remaining
531
- // skills are a separate, opt-in concern handled by the skills-removal
532
- // step below, so the harness-everything/ dir itself isn't swept here yet
533
- // - manifest.json (deleted only once its skills list empties out) may
534
- // still be sitting in it at this point. The final sweep near the end of
535
- // this function catches it once skill removal has actually run.
536
399
  for (const platform of platformModules) {
537
- if (typeof platform.getStateDir !== 'function') continue;
538
- const stateDir = platform.getStateDir(workspaceRoot);
539
- if (fs.existsSync(stateDir)) {
540
- fs.rmSync(stateDir, { recursive: true, force: true });
541
- console.log(` ✅ Removed local ${path.relative(workspaceRoot, stateDir).replace(/\\/g, '/')}/ directory`);
400
+ if (typeof platform.uninstall === 'function') {
401
+ platform.uninstall({
402
+ removeLocal: true,
403
+ removeGlobal: false,
404
+ workspaceRoot,
405
+ userHome,
406
+ getUserPromptsDir,
407
+ cleanEmptyDirs,
408
+ claudeHooks
409
+ });
542
410
  }
543
- }
544
-
545
- advisory.removeAdvisoryText(path.join(workspaceRoot, '.cursorrules'));
546
- advisory.removeAdvisoryText(path.join(workspaceRoot, '.github', 'copilot-instructions.md'));
547
- advisory.removeAdvisoryText(path.join(workspaceRoot, 'AGENTS.md'));
548
- advisory.removeAdvisoryText(path.join(workspaceRoot, '.hermes.md'));
549
411
 
550
- advisory.removeContinueRule(path.join(workspaceRoot, '.continue', 'rules', 'harness.md'));
551
- cleanEmptyDirs(path.join(workspaceRoot, '.continue', 'rules'), [workspaceRoot, userHome]);
412
+ if (typeof platform.getStateDir === 'function') {
413
+ const stateDir = platform.getStateDir(workspaceRoot);
414
+ if (fs.existsSync(stateDir)) {
415
+ fs.rmSync(stateDir, { recursive: true, force: true });
416
+ console.log(` ✅ Removed local ${path.relative(workspaceRoot, stateDir).replace(/\\/g, '/')}/ directory`);
417
+ }
418
+ }
419
+ }
552
420
 
553
421
  // One-time migration cleanup: earlier versions used a self-invented
554
422
  // top-level .harness/ directory for Claude's manifest + skill copies.
555
- // It was never shared with anything else in the workspace, so - unlike
556
- // every other removal in this file - it's always safe to wipe wholesale.
557
423
  const legacyHarnessDir = path.join(workspaceRoot, '.harness');
558
424
  if (fs.existsSync(legacyHarnessDir)) {
559
425
  fs.rmSync(legacyHarnessDir, { recursive: true, force: true });
@@ -566,28 +432,19 @@ async function runUninstall({ hasYesFlag, args, isInteractive }) {
566
432
  console.log("Uninstalling Harness OS from Global Home...");
567
433
  console.log("-------------------------------------------------");
568
434
 
569
- const globalSettingsFile = path.join(userHome, '.claude', 'settings.json');
570
- claudeHooks.removeHarnessHooks(globalSettingsFile);
571
- const globalClaudeDir = path.join(userHome, '.claude');
572
- cleanEmptyDirs(globalClaudeDir, [userHome]);
573
-
574
- advisory.removeAdvisoryText(path.join(userHome, '.cursorrules'));
575
-
576
- advisory.removeContinueRule(path.join(userHome, '.continue', 'rules', 'harness.md'));
577
- cleanEmptyDirs(path.join(userHome, '.continue', 'rules'), [userHome]);
578
-
579
- const promptsDir = getUserPromptsDir();
580
- const vscodeInstFile = path.join(promptsDir, 'harness.instructions.md');
581
- if (fs.existsSync(vscodeInstFile)) {
582
- fs.unlinkSync(vscodeInstFile);
583
- console.log(` ✅ Removed global Copilot instructions: ${vscodeInstFile}`);
584
- }
585
- const vscodeAgentFile = path.join(promptsDir, 'harness.agent.md');
586
- if (fs.existsSync(vscodeAgentFile)) {
587
- fs.unlinkSync(vscodeAgentFile);
588
- console.log(` ✅ Removed global Codex agent: ${vscodeAgentFile}`);
435
+ for (const platform of platformModules) {
436
+ if (typeof platform.uninstall === 'function') {
437
+ platform.uninstall({
438
+ removeLocal: false,
439
+ removeGlobal: true,
440
+ workspaceRoot,
441
+ userHome,
442
+ getUserPromptsDir,
443
+ cleanEmptyDirs,
444
+ claudeHooks
445
+ });
446
+ }
589
447
  }
590
- cleanEmptyDirs(promptsDir, [userHome]);
591
448
 
592
449
  // ~/.agents is a shared directory - other tools or the user's own files
593
450
  // may live there. Never touch it directly; only clean up the
@@ -1,163 +1,163 @@
1
- // Prompt-injection-only guidance for platforms with no hook/execution
2
- // mechanism (Cursor, Copilot, Codex, Continue, Hermes). Single source of
3
- // truth for the advisory block - it used to be duplicated verbatim inside
4
- // installer.js's top level and again inside main().
5
- const fs = require('fs');
6
- const path = require('path');
7
-
8
- const MARKER = "Harness OS Guidance (Advisory)";
9
-
10
- const advisoryInstructions = [
11
- `\n# ${MARKER}`,
12
- `This file is advisory only - this platform has no hook/execution mechanism to`,
13
- `enforce it mechanically (unlike Claude Code's hook-based circuit breaker). Treat`,
14
- `these as strong defaults, not guarantees.`,
15
- ``,
16
- `## 🚦 MANDATORY ENTRY TRIAGE & ROUTING (ALWAYS RUN FIRST)`,
17
- `Every time you receive a new prompt, you MUST load the \`harness-everything\` skill and immediately do the following:`,
18
- `1. Run the Tier Router script: \`node harness-everything/scripts/tier-router.js "<Brief summary of user's prompt>"\` (or simulate its routing logic if terminal is not initialized yet).`,
19
- `2. Output a clear, stylized routing checkpoint block at the VERY BEGINNING of your response to the user:`,
20
- ` \`\`\`markdown`,
21
- ` ## 🚦 Harness OS Routing Checkpoint`,
22
- ` - **Active Tier**: Tier 1 (Trivial) | Tier 2 (Standard) | Tier 3 (Macro)`,
23
- ` - **Rationale**: <1-sentence rationale from the tier router output>`,
24
- ` - **Routed Skills, Guides & Actions**:`,
25
- ` - \`path/to/skill/or/guide.md\` (<Brief reason why this guide/skill is loaded/used>)`,
26
- ` \`\`\``,
27
- ``,
28
- `## 🤖 COGNITIVE COMPLIANCE (NO SILENT DEGRADES FOR NEW FEATURES)`,
29
- `- **Newly Added Features / Extensions**: Copilot is highly prone to treating new feature requests as Tier 1 direct edits. If a task introduces *any* new logic, a new API endpoint, or a new file/module, you **MUST NOT** treat it as Tier 1. It **MUST** be treated as a **Tier 2 (Standard Task)** or **Tier 3 (Macro Task)**.`,
30
- `- **Tier 2 Activation**: Initialize the \`todo-driven-workflow\` checklist first. Summon Domain Experts based on tech stack. Load and execute the \`tdd\` (Test-Driven Development) skill (write tests first, implement, refactor).`,
31
- `- **Tier 3 Activation**: Initialize the \`todo-driven-workflow\` checklist, load \`fable-mode\` and \`fable-discipline\`, run sub-agents via \`create-agent-launcher\`, and write global docs using \`repo-docs\`.`,
32
- `- **Memory Summarization (Self-Evolve)**: Upon task completion, you **MUST** run the \`self-evolve\` skill (running \`node self-evolve/scripts/self-regression.js\` or writing memories) to record key insights, lessons learned, and error boundaries so your context builds across sessions.`,
33
- `- **Environment Discovery**: Discover the environment (OS, shell, package manager) before running commands - don't assume.`,
34
- `- **Rule of 3**: If the same error repeats 3 times in a row, STOP retrying. Explain what's failing and ask the human for direction instead of continuing to guess.`,
35
- `- **Prefer Editing**: Prefer editing over rewriting; commit logically complete chunks rather than one giant diff.`,
36
- ``
37
- ].join('\n');
38
-
39
- function injectAdvisoryText(targetFile, header, label) {
40
- const dir = path.dirname(targetFile);
41
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
42
-
43
- if (fs.existsSync(targetFile)) {
44
- const content = fs.readFileSync(targetFile, 'utf8');
45
- if (!content.includes(MARKER)) {
46
- fs.appendFileSync(targetFile, advisoryInstructions, 'utf8');
47
- console.log(` ✅ Augmented existing ${label} with Harness guidance (advisory-only)`);
48
- }
49
- } else {
50
- fs.writeFileSync(targetFile, `${header}\n${advisoryInstructions}`, 'utf8');
51
- console.log(` ✅ Created ${label} with Harness guidance (advisory-only)`);
52
- }
53
- }
54
-
55
- function removeAdvisoryText(targetFile) {
56
- if (!fs.existsSync(targetFile)) return;
57
- try {
58
- let content = fs.readFileSync(targetFile, 'utf8');
59
- const markerIndex = content.indexOf(MARKER);
60
- if (markerIndex !== -1) {
61
- let cleanContent = content;
62
- const hashMarkerIndex = content.lastIndexOf('#', markerIndex);
63
- if (hashMarkerIndex !== -1) {
64
- cleanContent = content.substring(0, hashMarkerIndex).trim() + '\n';
65
- } else {
66
- cleanContent = content.substring(0, markerIndex).trim() + '\n';
67
- }
68
-
69
- const lines = cleanContent.trim().split('\n').map(l => l.trim()).filter(l => l !== '');
70
- if (lines.length === 0 || (lines.length === 1 && (lines[0] === '# Cursor Project Rules' || lines[0] === '# AGENTS.md' || lines[0] === '# Copilot Instructions' || lines[0] === '# .hermes.md'))) {
71
- fs.unlinkSync(targetFile);
72
- console.log(` ✅ Removed empty advisory file: ${targetFile}`);
73
- } else {
74
- fs.writeFileSync(targetFile, cleanContent.trim() + '\n', 'utf8');
75
- console.log(` ✅ Removed Harness guidance from: ${targetFile}`);
76
- }
77
- }
78
- } catch (e) {
79
- console.warn(` ⚠️ Error removing advisory text from ${targetFile}: ${e.message}`);
80
- }
81
- }
82
-
83
- // Continue.dev reads project rules as individual Markdown files (with YAML
84
- // frontmatter) from a `.continue/rules/` folder rather than one shared file,
85
- // so - unlike the shared-file platforms above - Harness gets its own
86
- // dedicated `harness.md` rule file instead of appending into an arbitrary
87
- // pre-existing one.
88
- function installContinueRule(targetFile, label) {
89
- const dir = path.dirname(targetFile);
90
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
91
- if (fs.existsSync(targetFile) && fs.readFileSync(targetFile, 'utf8').includes(MARKER)) {
92
- return;
93
- }
94
- const content = [
95
- `---`,
96
- `name: Harness OS Guidance`,
97
- `alwaysApply: true`,
98
- `description: "Harness OS routing, circuit-breaker awareness, and environment-discovery guidance (advisory only on Continue - no hook mechanism)"`,
99
- `---`,
100
- advisoryInstructions.replace(/^\n/, '')
101
- ].join('\n');
102
- fs.writeFileSync(targetFile, content, 'utf8');
103
- console.log(` ✅ Installed Continue rule file with Harness guidance (advisory-only): ${label}`);
104
- }
105
-
106
- function removeContinueRule(targetFile) {
107
- if (!fs.existsSync(targetFile)) return;
108
- try {
109
- const content = fs.readFileSync(targetFile, 'utf8');
110
- if (content.includes(MARKER)) {
111
- fs.unlinkSync(targetFile);
112
- console.log(` ✅ Removed Harness rule file: ${targetFile}`);
113
- }
114
- } catch (e) {
115
- console.warn(` ⚠️ Error removing ${targetFile}: ${e.message}`);
116
- }
117
- }
118
-
119
- function buildCopilotGlobalContent() {
120
- return [
121
- `---`,
122
- `description: "Harness OS Guidance (Advisory)"`,
123
- `applyTo: "**"`,
124
- `---`,
125
- `# Copilot Instructions`,
126
- ``,
127
- advisoryInstructions.replace(/^\n/, '')
128
- ].join('\n');
129
- }
130
-
131
- function buildCodexGlobalContent() {
132
- return [
133
- `---`,
134
- `description: "Harness OS Guidance - Global custom agent for orchestrating multi-agent workflows"`,
135
- `name: "Harness"`,
136
- `user-invocable: true`,
137
- `---`,
138
- `# AGENTS.md`,
139
- ``,
140
- `This file is advisory only - this platform has no hook/execution mechanism to`,
141
- `enforce it mechanically (unlike Claude Code's hook-based circuit breaker). Treat`,
142
- `these as strong defaults, not guarantees.`,
143
- ``,
144
- `- Discover the environment (OS, shell, package manager) before running commands - don't assume.`,
145
- `- Triage tasks: trivial fixes need no plan; standard features need tests; large refactors need`,
146
- ` an explicit plan reviewed with the human before implementation.`,
147
- `- If the same error repeats 3 times in a row, STOP retrying. Explain what's failing and ask the`,
148
- ` human for direction instead of continuing to guess.`,
149
- `- Prefer editing over rewriting; commit logically complete chunks rather than one giant diff.`,
150
- ``
151
- ].join('\n');
152
- }
153
-
154
- module.exports = {
155
- MARKER,
156
- advisoryInstructions,
157
- injectAdvisoryText,
158
- removeAdvisoryText,
159
- installContinueRule,
160
- removeContinueRule,
161
- buildCopilotGlobalContent,
162
- buildCodexGlobalContent,
163
- };
1
+ // Prompt-injection-only guidance for platforms with no hook/execution
2
+ // mechanism (Cursor, Copilot, Codex, Continue, Hermes). Single source of
3
+ // truth for the advisory block - it used to be duplicated verbatim inside
4
+ // installer.js's top level and again inside main().
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+
8
+ const MARKER = "Harness OS Guidance (Advisory)";
9
+
10
+ const advisoryInstructions = [
11
+ `\n# ${MARKER}`,
12
+ `This file is advisory only - this platform has no hook/execution mechanism to`,
13
+ `enforce it mechanically (unlike Claude Code's hook-based circuit breaker). Treat`,
14
+ `these as strong defaults, not guarantees.`,
15
+ ``,
16
+ `## 🚦 MANDATORY ENTRY TRIAGE & ROUTING (ALWAYS RUN FIRST)`,
17
+ `Every time you receive a new prompt, you MUST load the \`harness-everything\` skill and immediately do the following:`,
18
+ `1. Run the Tier Router script: \`node harness-everything/scripts/tier-router.js "<Brief summary of user's prompt>"\` (or simulate its routing logic if terminal is not initialized yet).`,
19
+ `2. Output a clear, stylized routing checkpoint block at the VERY BEGINNING of your response to the user:`,
20
+ ` \`\`\`markdown`,
21
+ ` ## 🚦 Harness OS Routing Checkpoint`,
22
+ ` - **Active Tier**: Tier 1 (Trivial) | Tier 2 (Standard) | Tier 3 (Macro)`,
23
+ ` - **Rationale**: <1-sentence rationale from the tier router output>`,
24
+ ` - **Routed Skills, Guides & Actions**:`,
25
+ ` - \`path/to/skill/or/guide.md\` (<Brief reason why this guide/skill is loaded/used>)`,
26
+ ` \`\`\``,
27
+ ``,
28
+ `## 🤖 COGNITIVE COMPLIANCE (NO SILENT DEGRADES FOR NEW FEATURES)`,
29
+ `- **Newly Added Features / Extensions**: Copilot is highly prone to treating new feature requests as Tier 1 direct edits. If a task introduces *any* new logic, a new API endpoint, or a new file/module, you **MUST NOT** treat it as Tier 1. It **MUST** be treated as a **Tier 2 (Standard Task)** or **Tier 3 (Macro Task)**.`,
30
+ `- **Tier 2 Activation**: Initialize the \`todo-driven-workflow\` checklist first. Summon Domain Experts based on tech stack. Load and execute the \`tdd\` (Test-Driven Development) skill (write tests first, implement, refactor).`,
31
+ `- **Tier 3 Activation**: Initialize the \`todo-driven-workflow\` checklist, load \`fable-mode\` and \`fable-discipline\`, run sub-agents via \`create-agent-launcher\`, and write global docs using \`repo-docs\`.`,
32
+ `- **Memory Summarization (Self-Evolve)**: Upon task completion, you **MUST** run the \`self-evolve\` skill (running \`node self-evolve/scripts/self-regression.js\` or writing memories) to record key insights, lessons learned, and error boundaries so your context builds across sessions.`,
33
+ `- **Environment Discovery**: Discover the environment (OS, shell, package manager) before running commands - don't assume.`,
34
+ `- **Rule of 3**: If the same error repeats 3 times in a row, STOP retrying. Explain what's failing and ask the human for direction instead of continuing to guess.`,
35
+ `- **Prefer Editing**: Prefer editing over rewriting; commit logically complete chunks rather than one giant diff.`,
36
+ ``
37
+ ].join('\n');
38
+
39
+ function injectAdvisoryText(targetFile, header, label) {
40
+ const dir = path.dirname(targetFile);
41
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
42
+
43
+ if (fs.existsSync(targetFile)) {
44
+ const content = fs.readFileSync(targetFile, 'utf8');
45
+ if (!content.includes(MARKER)) {
46
+ fs.appendFileSync(targetFile, advisoryInstructions, 'utf8');
47
+ console.log(` ✅ Augmented existing ${label} with Harness guidance (advisory-only)`);
48
+ }
49
+ } else {
50
+ fs.writeFileSync(targetFile, `${header}\n${advisoryInstructions}`, 'utf8');
51
+ console.log(` ✅ Created ${label} with Harness guidance (advisory-only)`);
52
+ }
53
+ }
54
+
55
+ function removeAdvisoryText(targetFile) {
56
+ if (!fs.existsSync(targetFile)) return;
57
+ try {
58
+ let content = fs.readFileSync(targetFile, 'utf8');
59
+ const markerIndex = content.indexOf(MARKER);
60
+ if (markerIndex !== -1) {
61
+ let cleanContent = content;
62
+ const hashMarkerIndex = content.lastIndexOf('#', markerIndex);
63
+ if (hashMarkerIndex !== -1) {
64
+ cleanContent = content.substring(0, hashMarkerIndex).trim() + '\n';
65
+ } else {
66
+ cleanContent = content.substring(0, markerIndex).trim() + '\n';
67
+ }
68
+
69
+ const lines = cleanContent.trim().split('\n').map(l => l.trim()).filter(l => l !== '');
70
+ if (lines.length === 0 || (lines.length === 1 && (lines[0] === '# Cursor Project Rules' || lines[0] === '# AGENTS.md' || lines[0] === '# Copilot Instructions' || lines[0] === '# .hermes.md'))) {
71
+ fs.unlinkSync(targetFile);
72
+ console.log(` ✅ Removed empty advisory file: ${targetFile}`);
73
+ } else {
74
+ fs.writeFileSync(targetFile, cleanContent.trim() + '\n', 'utf8');
75
+ console.log(` ✅ Removed Harness guidance from: ${targetFile}`);
76
+ }
77
+ }
78
+ } catch (e) {
79
+ console.warn(` ⚠️ Error removing advisory text from ${targetFile}: ${e.message}`);
80
+ }
81
+ }
82
+
83
+ // Continue.dev reads project rules as individual Markdown files (with YAML
84
+ // frontmatter) from a `.continue/rules/` folder rather than one shared file,
85
+ // so - unlike the shared-file platforms above - Harness gets its own
86
+ // dedicated `harness.md` rule file instead of appending into an arbitrary
87
+ // pre-existing one.
88
+ function installContinueRule(targetFile, label) {
89
+ const dir = path.dirname(targetFile);
90
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
91
+ if (fs.existsSync(targetFile) && fs.readFileSync(targetFile, 'utf8').includes(MARKER)) {
92
+ return;
93
+ }
94
+ const content = [
95
+ `---`,
96
+ `name: Harness OS Guidance`,
97
+ `alwaysApply: true`,
98
+ `description: "Harness OS routing, circuit-breaker awareness, and environment-discovery guidance (advisory only on Continue - no hook mechanism)"`,
99
+ `---`,
100
+ advisoryInstructions.replace(/^\n/, '')
101
+ ].join('\n');
102
+ fs.writeFileSync(targetFile, content, 'utf8');
103
+ console.log(` ✅ Installed Continue rule file with Harness guidance (advisory-only): ${label}`);
104
+ }
105
+
106
+ function removeContinueRule(targetFile) {
107
+ if (!fs.existsSync(targetFile)) return;
108
+ try {
109
+ const content = fs.readFileSync(targetFile, 'utf8');
110
+ if (content.includes(MARKER)) {
111
+ fs.unlinkSync(targetFile);
112
+ console.log(` ✅ Removed Harness rule file: ${targetFile}`);
113
+ }
114
+ } catch (e) {
115
+ console.warn(` ⚠️ Error removing ${targetFile}: ${e.message}`);
116
+ }
117
+ }
118
+
119
+ function buildCopilotGlobalContent() {
120
+ return [
121
+ `---`,
122
+ `description: "Harness OS Guidance (Advisory)"`,
123
+ `applyTo: "**"`,
124
+ `---`,
125
+ `# Copilot Instructions`,
126
+ ``,
127
+ advisoryInstructions.replace(/^\n/, '')
128
+ ].join('\n');
129
+ }
130
+
131
+ function buildCodexGlobalContent() {
132
+ return [
133
+ `---`,
134
+ `description: "Harness OS Guidance - Global custom agent for orchestrating multi-agent workflows"`,
135
+ `name: "Harness"`,
136
+ `user-invocable: true`,
137
+ `---`,
138
+ `# AGENTS.md`,
139
+ ``,
140
+ `This file is advisory only - this platform has no hook/execution mechanism to`,
141
+ `enforce it mechanically (unlike Claude Code's hook-based circuit breaker). Treat`,
142
+ `these as strong defaults, not guarantees.`,
143
+ ``,
144
+ `- Discover the environment (OS, shell, package manager) before running commands - don't assume.`,
145
+ `- Triage tasks: trivial fixes need no plan; standard features need tests; large refactors need`,
146
+ ` an explicit plan reviewed with the human before implementation.`,
147
+ `- If the same error repeats 3 times in a row, STOP retrying. Explain what's failing and ask the`,
148
+ ` human for direction instead of continuing to guess.`,
149
+ `- Prefer editing over rewriting; commit logically complete chunks rather than one giant diff.`,
150
+ ``
151
+ ].join('\n');
152
+ }
153
+
154
+ module.exports = {
155
+ MARKER,
156
+ advisoryInstructions,
157
+ injectAdvisoryText,
158
+ removeAdvisoryText,
159
+ installContinueRule,
160
+ removeContinueRule,
161
+ buildCopilotGlobalContent,
162
+ buildCodexGlobalContent,
163
+ };