forge-workflow 0.1.0-beta.4 → 0.1.0-beta.6

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 (196) hide show
  1. package/AGENTS.md +18 -7
  2. package/CHANGELOG.md +79 -1
  3. package/CLAUDE.md +0 -12
  4. package/CODING_STANDARDS.md +72 -0
  5. package/README.md +6 -2
  6. package/bin/forge-cmd.js +20 -0
  7. package/bin/forge.js +28 -375
  8. package/docs/INDEX.md +1 -1
  9. package/docs/guides/BEADS_GITHUB_SYNC.md +2 -31
  10. package/docs/guides/MIGRATION.md +4 -4
  11. package/docs/guides/SETUP.md +16 -16
  12. package/docs/reference/COMMANDS.md +8 -5
  13. package/docs/reference/FORGE_KERNEL_STORAGE_MODEL.md +4 -0
  14. package/docs/reference/INSIGHTS_RECAP.md +9 -20
  15. package/docs/reference/INSTALL.md +4 -0
  16. package/docs/reference/LEGACY_CLAIM_REPAIR.md +112 -0
  17. package/docs/reference/RELEASE.md +5 -3
  18. package/docs/reference/TOOLCHAIN.md +8 -0
  19. package/docs/reference/github-accounts.md +134 -0
  20. package/docs/reference/protected-state-surfaces.md +4 -4
  21. package/docs/reference/shepherd.md +114 -35
  22. package/lefthook.yml +12 -0
  23. package/lib/activation/ensure-forge-home.js +33 -15
  24. package/lib/adapters/pr-state-adapter.js +359 -144
  25. package/lib/audit-evidence.js +71 -110
  26. package/lib/base-remote.js +138 -0
  27. package/lib/beta5-compatibility-evidence.js +1093 -0
  28. package/lib/bun-lockfile-proof.js +413 -0
  29. package/lib/bun-workflow-pins.js +461 -0
  30. package/lib/capabilities/index.js +9 -0
  31. package/lib/capabilities/model.js +141 -0
  32. package/lib/capabilities/probes.js +347 -0
  33. package/lib/capped-jsonl-log.js +236 -0
  34. package/lib/codex-skills.js +2 -2
  35. package/lib/commands/_manifest.js +1 -0
  36. package/lib/commands/_registry.js +50 -20
  37. package/lib/commands/clean.js +252 -32
  38. package/lib/commands/dev.js +4 -33
  39. package/lib/commands/doctor.js +37 -6
  40. package/lib/commands/gate.js +197 -27
  41. package/lib/commands/github.js +215 -0
  42. package/lib/commands/hooks.js +276 -30
  43. package/lib/commands/insights.js +8 -3
  44. package/lib/commands/memory.js +66 -2
  45. package/lib/commands/merge.js +1265 -58
  46. package/lib/commands/plan.js +33 -2
  47. package/lib/commands/pr.js +3 -1
  48. package/lib/commands/preflight.js +21 -4
  49. package/lib/commands/prime.js +21 -8
  50. package/lib/commands/push.js +146 -54
  51. package/lib/commands/recall.js +127 -49
  52. package/lib/commands/recap.js +6 -1
  53. package/lib/commands/release.js +39 -3
  54. package/lib/commands/remember.js +28 -4
  55. package/lib/commands/serve.js +26 -9
  56. package/lib/commands/setup.js +323 -98
  57. package/lib/commands/shepherd.js +591 -73
  58. package/lib/commands/ship.js +36 -91
  59. package/lib/commands/skill.js +127 -11
  60. package/lib/commands/status.js +17 -1
  61. package/lib/commands/team.js +47 -8
  62. package/lib/commands/test.js +187 -38
  63. package/lib/commands/validate.js +65 -21
  64. package/lib/commands/worktree.js +359 -45
  65. package/lib/core/runtime-graph.js +1 -1
  66. package/lib/doc-assertions.js +297 -0
  67. package/lib/existing-tdd-gate.js +253 -0
  68. package/lib/fixtures/beta5-corpus/v1/README.md +9 -0
  69. package/lib/fixtures/beta5-corpus/v1/contract/command-contract.json +26 -0
  70. package/lib/fixtures/beta5-corpus/v1/contract/package-contract.json +13 -0
  71. package/lib/fixtures/beta5-corpus/v1/contract/workflow-stage-matrix.json +8 -0
  72. package/lib/fixtures/beta5-corpus/v1/manifest.json +25 -0
  73. package/lib/fixtures/beta5-corpus/v1/state/comments.jsonl +1 -0
  74. package/lib/fixtures/beta5-corpus/v1/state/config.yaml +6 -0
  75. package/lib/fixtures/beta5-corpus/v1/state/dependencies.jsonl +1 -0
  76. package/lib/fixtures/beta5-corpus/v1/state/issues.jsonl +2 -0
  77. package/lib/fixtures/beta5-corpus/v1/state/kernel.sql +20 -0
  78. package/lib/forge-context.js +1 -4
  79. package/lib/forge-issues.js +134 -32
  80. package/lib/gate-events.js +98 -10
  81. package/lib/git-defaults.js +56 -0
  82. package/lib/github-context.js +308 -0
  83. package/lib/global-flags.js +1 -0
  84. package/lib/harness-capability-matrix.js +3 -3
  85. package/lib/hook-renderer.js +122 -5
  86. package/lib/insights.js +96 -80
  87. package/lib/issue-render.js +19 -0
  88. package/lib/kernel/backing-issue.js +14 -2
  89. package/lib/kernel/broker.js +739 -31
  90. package/lib/kernel/claim-reconciler.js +238 -0
  91. package/lib/kernel/cli-broker-factory.js +12 -1
  92. package/lib/kernel/close-on-merge.js +154 -0
  93. package/lib/kernel/fs-class.js +42 -25
  94. package/lib/kernel/lease-enforcer.js +9 -4
  95. package/lib/kernel/legacy-claim-repair.js +442 -0
  96. package/lib/kernel/live-claim-projection.js +26 -0
  97. package/lib/kernel/migrations.js +118 -3
  98. package/lib/kernel/readiness-model.js +184 -12
  99. package/lib/kernel/schema.js +49 -1
  100. package/lib/kernel/sqlite-driver.js +3435 -172
  101. package/lib/kernel/taxonomy-validator.js +4 -1
  102. package/lib/kernel/windows-private-acl.js +239 -0
  103. package/lib/lefthook-wiring.js +21 -1
  104. package/lib/memory/hygiene.js +191 -0
  105. package/lib/memory/router.js +110 -28
  106. package/lib/memory/usage-evidence.js +4 -0
  107. package/lib/memory-digest.js +106 -15
  108. package/lib/memory-recall-events.js +145 -0
  109. package/lib/memory-recall.js +71 -10
  110. package/lib/merge-rules.js +143 -21
  111. package/lib/npm-publish-workflow.js +465 -0
  112. package/lib/orientation.js +68 -43
  113. package/lib/package-root.js +2 -0
  114. package/lib/plugin-catalog.js +14 -4
  115. package/lib/pr-bundle.js +5 -6
  116. package/lib/pr-monitor/auto-actions.js +169 -28
  117. package/lib/pr-monitor/differ.js +110 -4
  118. package/lib/pr-monitor/events.js +0 -0
  119. package/lib/pr-monitor/flow-monitor.js +1424 -0
  120. package/lib/pr-monitor/gather.js +251 -44
  121. package/lib/pr-monitor/journal.js +18 -39
  122. package/lib/pr-monitor/monitor.js +117 -10
  123. package/lib/pr-monitor/process-identity.js +117 -0
  124. package/lib/pr-monitor/reconcile-executor.js +1129 -470
  125. package/lib/pr-monitor/reconcile.js +0 -0
  126. package/lib/pr-monitor/render-summary.js +293 -0
  127. package/lib/pr-monitor/review-preflight.js +269 -0
  128. package/lib/pr-monitor/shepherd-lease.js +38 -20
  129. package/lib/pr-monitor/verdict.js +438 -0
  130. package/lib/pr-monitor/watch-lifecycle.js +145 -27
  131. package/lib/pr-monitor/watch-owner.js +1414 -0
  132. package/lib/pr-monitor/watch.js +129 -58
  133. package/lib/pr-pull.js +33 -14
  134. package/lib/pr-shepherd.js +51 -11
  135. package/lib/preflight/gates.js +65 -18
  136. package/lib/preflight/runner.js +5 -0
  137. package/lib/project-memory.js +178 -4
  138. package/lib/protected-state-authority.js +1100 -0
  139. package/lib/protected-state-surfaces.js +243 -45
  140. package/lib/release-readiness.js +53 -7
  141. package/lib/review-adapter.js +65 -0
  142. package/lib/shell-utils.js +1 -1
  143. package/lib/skills-sync.js +71 -35
  144. package/lib/smart-merge.js +28 -4
  145. package/lib/symlink-utils.js +74 -26
  146. package/lib/upgrade-safety.js +39 -0
  147. package/lib/using-forge.js +19 -6
  148. package/lib/validation/risk-manifest.js +339 -0
  149. package/lib/workflow/enforce-stage.js +44 -0
  150. package/lib/workflow/plan-authority.js +225 -0
  151. package/package.json +12 -9
  152. package/scripts/commitlint.js +13 -15
  153. package/scripts/doc-asserting-tests.js +158 -0
  154. package/scripts/generate-risk-manifest.js +91 -0
  155. package/scripts/github-context-bridge.sh +10 -0
  156. package/scripts/legacy-claim-repair.js +145 -0
  157. package/scripts/lib/behavioral-eval-runner.js +310 -0
  158. package/scripts/lib/behavioral-eval-runtime.js +457 -0
  159. package/scripts/lib/eval-evidence.js +328 -0
  160. package/scripts/lib/eval-runner.js +81 -41
  161. package/scripts/lib/immutable-eval-corpus.js +309 -0
  162. package/scripts/lib/promotion-evidence-loader.js +94 -0
  163. package/scripts/lib/promotion-scorecard.js +314 -0
  164. package/scripts/npm-release-receipt.js +134 -0
  165. package/scripts/process-tree.js +773 -0
  166. package/scripts/protected-state-check.js +479 -31
  167. package/scripts/run-command-eval.js +29 -1
  168. package/scripts/sync-agent-skills.js +333 -34
  169. package/scripts/sync-d20-audit.js +172 -0
  170. package/scripts/test-full-suite.js +935 -37
  171. package/scripts/test-profile.js +13 -3
  172. package/scripts/test.js +271 -57
  173. package/skills/coverage.json +1 -0
  174. package/skills/review/SKILL.md +6 -11
  175. package/skills/review/evals/scorecard.json +4 -4
  176. package/skills/rollback/SKILL.md +4 -11
  177. package/skills/rollback/evals/scorecard.json +3 -3
  178. package/skills/setup/SKILL.md +18 -0
  179. package/skills/setup/evals/scorecard.json +3 -3
  180. package/skills/shepherd/SKILL.md +39 -16
  181. package/skills/shepherd/evals/scorecard.json +4 -4
  182. package/skills/ship/SKILL.md +4 -12
  183. package/skills/ship/evals/scorecard.json +3 -3
  184. package/skills/validate/SKILL.md +3 -0
  185. package/skills/validate/evals/scorecard.json +1 -1
  186. package/skills/worktree/SKILL.md +6 -1
  187. package/skills/worktree/evals/scorecard.json +2 -2
  188. package/lib/beads-setup.js +0 -538
  189. package/lib/beads-sync-scaffold.js +0 -189
  190. package/lib/pat-setup.js +0 -207
  191. package/lib/pr-monitor/render-sticky.js +0 -206
  192. package/lib/pr-monitor/upsert-sticky.js +0 -169
  193. package/scripts/beads-context.sh +0 -577
  194. package/scripts/beads-migrate-to-dolt.sh +0 -7
  195. package/scripts/beads-upgrade-smoke.sh +0 -284
  196. package/scripts/lib/beads-migrate-to-dolt.mjs +0 -503
package/bin/forge.js CHANGED
@@ -80,10 +80,8 @@ const { firstPositionalIndex } = require('../lib/global-flags');
80
80
  const contextMerge = require('../lib/context-merge');
81
81
  const projectDiscovery = require('../lib/project-discovery');
82
82
 
83
- // Load lib modules for symlink, beads, and PAT setup
83
+ // Load lib modules for symlink setup
84
84
  const { createSymlinkOrCopy: libCreateSymlinkOrCopy } = require('../lib/symlink-utils');
85
- const beadsSetupLib = require('../lib/beads-setup');
86
- const { scaffoldBeadsSync } = require('../lib/beads-sync-scaffold');
87
85
 
88
86
  // Load incremental setup modules
89
87
  const { detectEnvironment } = require('../lib/detect-agent');
@@ -113,7 +111,6 @@ let FORCE_MODE = false;
113
111
  let VERBOSE_MODE = false;
114
112
  let NON_INTERACTIVE = false;
115
113
  let SYMLINK_ONLY = false; // --symlink: fail instead of copy fallback
116
- let SYNC_ENABLED = false; // --sync: scaffold Beads GitHub sync workflows
117
114
  let actionLog = new SetupActionLog();
118
115
 
119
116
  // Detected package manager
@@ -429,7 +426,7 @@ Use these default-template commands via \`/command-name\`:
429
426
  - \`/validate\` - Type check, lint, security, tests (HARD-GATE)
430
427
  - \`/ship\` - Push and create PR with design doc reference
431
428
  - \`/review\` - Handle ALL PR issues (Actions, Greptile, SonarCloud)
432
- - \`/verify\` - Post-merge health check (CI on main, close Beads)
429
+ - \`/verify\` - Post-merge health check (CI on main, close kernel issues)
433
430
 
434
431
  Pre-merge gate (not a numbered stage): finish docs + confirm CI green + hand off the PR — embedded in the /ship and /review stages.
435
432
 
@@ -706,9 +703,7 @@ async function detectProjectStatus() {
706
703
  agentsMdLines: 0,
707
704
  claudeMdLines: 0,
708
705
  // Project tools status
709
- hasBeads: isBeadsInitialized(),
710
706
  hasSkills: isSkillsInitialized(),
711
- beadsInstallType: checkForBeads(),
712
707
  skillsInstallType: checkForSkills(),
713
708
  // Enhanced: Auto-detected project context
714
709
  autoDetected: null
@@ -1701,6 +1696,13 @@ function ensureDirWithNote(dir, purpose) {
1701
1696
 
1702
1697
  // Setup core documentation and directories
1703
1698
  function setupCoreDocs() {
1699
+ // Review skills reference this root contract in every installed repository.
1700
+ // It is a consumer-owned extension point after creation, so setup never overwrites it.
1701
+ const codingStandardsDest = path.join(projectRoot, 'CODING_STANDARDS.md');
1702
+ if (!fs.existsSync(codingStandardsDest)) {
1703
+ copyFile(path.join(packageDir, 'CODING_STANDARDS.md'), 'CODING_STANDARDS.md');
1704
+ }
1705
+
1704
1706
  // docs/planning/ and docs/research/ are created lazily on first use
1705
1707
  // by /plan Phase 1 and Phase 2 respectively, via ensureDirWithNote().
1706
1708
  // TEMPLATE.md and PROGRESS.md are also deferred to first use.
@@ -2196,15 +2198,6 @@ function displaySetupSummary(selectedAgents) {
2196
2198
  console.log('Project Tools Status:');
2197
2199
  console.log('');
2198
2200
 
2199
- // Beads status
2200
- if (isBeadsInitialized()) {
2201
- console.log(' ✓ Beads initialized - Track work: forge ready');
2202
- } else if (checkForBeads()) {
2203
- console.log(' ! Beads available - Run: bd init');
2204
- } else {
2205
- console.log(` - Beads not installed - Run: ${PKG_MANAGER} install -g @beads/bd && bd init`);
2206
- }
2207
-
2208
2201
  // Skills status
2209
2202
  if (isSkillsInitialized()) {
2210
2203
  console.log(' ✓ Skills initialized - Manage skills: skills list');
@@ -2351,7 +2344,7 @@ function parseFlags() {
2351
2344
  verbose: false, // Show file-by-file detail in setup summary
2352
2345
  dryRun: false, // Preview planned actions without writing files
2353
2346
  symlink: false, // Create CLAUDE.md as symlink to AGENTS.md (--symlink)
2354
- sync: false, // Scaffold Beads GitHub sync workflows (--sync)
2347
+ skillsOnly: false, // Install skills without Git or harness hook enforcement
2355
2348
  };
2356
2349
 
2357
2350
  // Issue passthrough commands delegate all flags to bd.
@@ -2368,6 +2361,9 @@ function parseFlags() {
2368
2361
  for (let i = 0; i < args.length;) {
2369
2362
  const arg = args[i];
2370
2363
 
2364
+ // Everything after the explicit launcher delimiter belongs to the child.
2365
+ if (arg === '--' && args[0] === 'github' && args[firstPositionalIndex(args, 1)] === 'run') break;
2366
+
2371
2367
  if (arg === '--quick' || arg === '-q') {
2372
2368
  flags.quick = true;
2373
2369
  i++;
@@ -2417,8 +2413,8 @@ function parseFlags() {
2417
2413
  } else if (arg === '--symlink') {
2418
2414
  flags.symlink = true;
2419
2415
  i++;
2420
- } else if (arg === '--sync') {
2421
- flags.sync = true;
2416
+ } else if (arg === '--skills-only' || arg === '--no-hooks') {
2417
+ flags.skillsOnly = true;
2422
2418
  i++;
2423
2419
  } else if (arg === '--interview') {
2424
2420
  flags.interview = true;
@@ -2577,6 +2573,8 @@ function showHelp() {
2577
2573
  console.log(' --type <type> Set workflow profile type manually');
2578
2574
  console.log(' Options: critical, standard, simple, hotfix, docs, refactor');
2579
2575
  console.log(' --dry-run Preview planned actions without writing any files');
2576
+ console.log(' --skills-only Install skills without Git hooks, Forge-native, or harness hooks');
2577
+ console.log(' Alias: --no-hooks');
2580
2578
  console.log(' --interview Force context interview (gather project information)');
2581
2579
  console.log(' --budget <mode> Budget mode for recommend (free, open-source, startup, professional, custom)');
2582
2580
  console.log(' --yes, -y Non-interactive setup with sensible defaults');
@@ -2602,6 +2600,7 @@ function showHelp() {
2602
2600
  console.log(' npx forge setup --yes # Non-interactive, defaults to claude');
2603
2601
  console.log(' npx forge setup --yes --agents cursor # Non-interactive, specific agent');
2604
2602
  console.log(' npx forge setup --all --skip-external # All agents, no services');
2603
+ console.log(' npx forge setup --agents claude --skills-only # Skills without hook enforcement');
2605
2604
  console.log(' npx forge setup --merge=smart # Use intelligent merge for existing files');
2606
2605
  console.log(' npx forge setup --type=critical # Set workflow profile manually');
2607
2606
  console.log(' npx forge setup --interview # Force context interview');
@@ -2835,121 +2834,6 @@ function checkForLefthook() {
2835
2834
  return status;
2836
2835
  }
2837
2836
 
2838
- // Check if Beads is installed (global, local, or bunx-capable)
2839
- function checkForBeads() {
2840
- // Try global install first
2841
- try {
2842
- secureExecFileSync('bd', ['version'], { stdio: 'ignore' });
2843
- return 'global';
2844
- } catch (err) {
2845
- // Not global
2846
- console.warn('Beads not found globally:', err.message);
2847
- }
2848
-
2849
- // Check if bunx can run it
2850
- try {
2851
- secureExecFileSync('bunx', ['@beads/bd', 'version'], { stdio: 'ignore' });
2852
- return 'bunx';
2853
- } catch (err) {
2854
- // Not bunx-capable
2855
- console.warn('Beads not available via bunx:', err.message);
2856
- }
2857
-
2858
- // Check local project installation
2859
- const pkgPath = path.join(projectRoot, 'package.json');
2860
- if (!fs.existsSync(pkgPath)) return null;
2861
-
2862
- try {
2863
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
2864
- const isInstalled = pkg.devDependencies?.['@beads/bd'] || pkg.dependencies?.['@beads/bd'];
2865
- return isInstalled ? 'local' : null;
2866
- } catch (err) {
2867
- console.warn('Failed to check Beads in package.json:', err.message);
2868
- return null;
2869
- }
2870
- }
2871
- // Check if Beads is initialized in project — delegates to lib/beads-setup
2872
- function isBeadsInitialized() {
2873
- return beadsSetupLib.isBeadsInitialized(projectRoot);
2874
- }
2875
-
2876
- function migrateExistingBeadsLocalState() {
2877
- if (!fs.existsSync(path.join(projectRoot, '.beads'))) {
2878
- return;
2879
- }
2880
-
2881
- try {
2882
- beadsSetupLib.ensureBeadsGitExclude(projectRoot);
2883
- } catch (err) {
2884
- console.warn(` Warning: failed to migrate Beads local state: ${err.message}`);
2885
- }
2886
- }
2887
-
2888
- // Initialize Beads in the project using the defensive safeBeadsInit wrapper
2889
- // Handles config/gitignore writes, hook snapshot/restore, and JSONL pre-seeding
2890
- function initializeBeads(installType) {
2891
- console.log('Initializing Beads in project...');
2892
-
2893
- // Build the execBdInit function based on installType
2894
- const execBdInit = (root) => {
2895
- // SECURITY: execFileSync with hardcoded commands
2896
- if (installType === 'global') {
2897
- secureExecFileSync('bd', ['init'], { stdio: 'inherit', cwd: root });
2898
- } else if (installType === 'bunx') {
2899
- secureExecFileSync('bunx', ['@beads/bd', 'init'], { stdio: 'inherit', cwd: root });
2900
- } else if (installType === 'local') {
2901
- secureExecFileSync('npx', ['bd', 'init'], { stdio: 'inherit', cwd: root });
2902
- }
2903
- };
2904
-
2905
- // Derive prefix from package.json name or directory name
2906
- let prefix;
2907
- try {
2908
- const pkg = JSON.parse(fs.readFileSync(path.join(projectRoot, 'package.json'), 'utf8'));
2909
- prefix = pkg.name || path.basename(projectRoot);
2910
- } catch (_e) {
2911
- prefix = path.basename(projectRoot);
2912
- }
2913
-
2914
- try {
2915
- const result = beadsSetupLib.safeBeadsInit(projectRoot, {
2916
- prefix,
2917
- execBdInit,
2918
- restoreLefthook: (root) => {
2919
- try {
2920
- secureExecFileSync('lefthook', ['install'], { stdio: 'ignore', cwd: root });
2921
- } catch (_e) {
2922
- // lefthook may not be installed yet — non-fatal
2923
- }
2924
- }
2925
- });
2926
-
2927
- if (result.skipped) {
2928
- console.log(' ✓ Beads already initialized');
2929
- return true;
2930
- }
2931
-
2932
- if (!result.success) {
2933
- for (const e of result.errors) {
2934
- console.log(` ⚠ ${e}`);
2935
- }
2936
- console.log(' Run manually: bd init');
2937
- return false;
2938
- }
2939
-
2940
- for (const w of result.warnings) {
2941
- console.warn(` ⚠ ${w}`);
2942
- }
2943
- console.log(' ✓ Beads initialized');
2944
-
2945
- return true;
2946
- } catch (err) {
2947
- console.log(' ⚠ Failed to initialize Beads:', err.message);
2948
- console.log(' Run manually: bd init');
2949
- return false;
2950
- }
2951
- }
2952
-
2953
2837
  // Check if Skills CLI is installed
2954
2838
  function checkForSkills() {
2955
2839
  // Try global install first
@@ -3006,60 +2890,6 @@ function initializeSkills(installType) {
3006
2890
  }
3007
2891
  }
3008
2892
 
3009
- // Prompt for Beads setup - extracted to reduce cognitive complexity
3010
- async function promptBeadsSetup(question) {
3011
- console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
3012
- console.log('Beads Setup (Recommended)');
3013
- console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
3014
- console.log('');
3015
-
3016
- const beadsInitialized = isBeadsInitialized();
3017
- const beadsStatus = checkForBeads();
3018
-
3019
- if (beadsInitialized) {
3020
- migrateExistingBeadsLocalState();
3021
- console.log('✓ Beads is already initialized in this project');
3022
- console.log('');
3023
- return;
3024
- }
3025
-
3026
- if (beadsStatus) {
3027
- // Already installed, just need to initialize
3028
- console.log(`ℹ Beads is installed (${beadsStatus}), but not initialized`);
3029
- const initBeads = await question('Initialize Beads in this project? (y/n): ');
3030
-
3031
- if (initBeads.toLowerCase() === 'y') {
3032
- initializeBeads(beadsStatus);
3033
- } else {
3034
- console.log('Skipped Beads initialization. Run manually: bd init');
3035
- }
3036
- console.log('');
3037
- return;
3038
- }
3039
-
3040
- // Not installed
3041
- console.log('ℹ Beads is not installed');
3042
- const installBeads = await question('Install Beads? (y/n): ');
3043
-
3044
- if (installBeads.toLowerCase() !== 'y') {
3045
- console.log('Skipped Beads installation');
3046
- console.log('');
3047
- return;
3048
- }
3049
-
3050
- console.log('');
3051
- console.log('Choose installation method:');
3052
- console.log(' 1. Global (recommended) - Available system-wide');
3053
- console.log(' 2. Local - Project-specific devDependency');
3054
- console.log(' 3. Bunx - Use via bunx (requires bun)');
3055
- console.log('');
3056
- const method = await question('Choose method (1-3): ');
3057
-
3058
- console.log('');
3059
- installBeadsWithMethod(method);
3060
- console.log('');
3061
- }
3062
-
3063
2893
  // Helper: Install tool via bunx - extracted to reduce cognitive complexity
3064
2894
  function installViaBunx(packageName, versionArgs, initFn, toolName) {
3065
2895
  console.log('Testing bunx capability...');
@@ -3073,68 +2903,6 @@ function installViaBunx(packageName, versionArgs, initFn, toolName) {
3073
2903
  }
3074
2904
  }
3075
2905
 
3076
- // Helper: Install Beads with chosen method - extracted to reduce cognitive complexity
3077
- // SECURITY NOTE: Downloads and executes a remote PowerShell script.
3078
- // The npm @beads/bd package is broken on Windows (GitHub Issue #1031, closed "not planned"),
3079
- // so the official PowerShell installer is the only supported path.
3080
- // Mitigations: HTTPS transport (prevents MITM), official beads repo, user-visible URL.
3081
- // TODO: Pin to a versioned release tag once beads publishes tagged releases (e.g. v0.49.1).
3082
- const BEADS_INSTALL_PS1_URL = 'https://raw.githubusercontent.com/steveyegge/beads/main/install.ps1';
3083
-
3084
- function installBeadsOnWindows() {
3085
- console.log(' (Windows detected: using PowerShell installer)');
3086
- console.log(` Downloading: ${BEADS_INSTALL_PS1_URL}`);
3087
- secureExecFileSync('powershell.exe', [
3088
- '-NoProfile', '-NonInteractive', '-Command',
3089
- `irm ${BEADS_INSTALL_PS1_URL} | iex`
3090
- ], { stdio: 'inherit' });
3091
- }
3092
-
3093
- function installBeadsWithMethod(method) {
3094
- try {
3095
- // SECURITY: secureExecFileSync with hardcoded commands
3096
- if (method === '1') {
3097
- console.log('Installing Beads globally...');
3098
- if (process.platform === 'win32') {
3099
- installBeadsOnWindows();
3100
- } else {
3101
- const pkgManager = PKG_MANAGER === 'bun' ? 'bun' : 'npm';
3102
- secureExecFileSync(pkgManager, ['install', '-g', '@beads/bd'], { stdio: 'inherit' });
3103
- }
3104
- console.log(' ✓ Beads installed globally');
3105
- initializeBeads('global');
3106
- } else if (method === '2') {
3107
- console.log('Installing Beads locally...');
3108
- // On Windows, npm postinstall for @beads/bd runs Expand-Archive which has EPERM file-locking
3109
- // (GitHub Issue #1031, closed "not planned") — same root cause as global install.
3110
- // Redirect Windows users to the global PowerShell installer instead.
3111
- if (process.platform === 'win32') {
3112
- console.log(' ⚠ Local install not supported on Windows (npm @beads/bd EPERM issue).');
3113
- console.log(' Falling back to global PowerShell installer...');
3114
- installBeadsOnWindows();
3115
- } else {
3116
- const pkgManager = PKG_MANAGER === 'bun' ? 'bun' : 'npm';
3117
- secureExecFileSync(pkgManager, ['install', '-D', '@beads/bd'], { stdio: 'inherit', cwd: projectRoot });
3118
- }
3119
- console.log(' ✓ Beads installed');
3120
- // On Windows the fallback was global (PowerShell installer), so init as 'global'
3121
- initializeBeads(process.platform === 'win32' ? 'global' : 'local');
3122
- } else if (method === '3') {
3123
- installViaBunx('@beads/bd', ['version'], initializeBeads, 'Beads');
3124
- } else {
3125
- console.log('Invalid choice. Skipping Beads installation.');
3126
- }
3127
- } catch (err) {
3128
- console.warn('Beads installation failed:', err.message);
3129
- console.log(' ⚠ Failed to install Beads:', err.message);
3130
- if (process.platform === 'win32') {
3131
- console.log(` Run manually: irm ${BEADS_INSTALL_PS1_URL} | iex`);
3132
- } else {
3133
- console.log(` Run manually: ${PKG_MANAGER === 'bun' ? 'bun add -g' : 'npm install -g'} @beads/bd && bd init`);
3134
- }
3135
- }
3136
- }
3137
-
3138
2906
  // Helper: Get package-manager-specific install args for Skills
3139
2907
  function getSkillsInstallArgs(scope) {
3140
2908
  const globalFlag = scope === 'global' ? '-g' : '-D';
@@ -3223,68 +2991,23 @@ async function promptSkillsSetup(question) {
3223
2991
  console.log('');
3224
2992
  }
3225
2993
 
3226
- // Interactive setup for Beads and Skills
3227
- async function setupProjectTools(rl, question) {
2994
+ // Interactive setup for Skills
2995
+ async function setupProjectTools(_rl, question) {
3228
2996
  console.log('');
3229
2997
  console.log('═══════════════════════════════════════════════════════════');
3230
2998
  console.log(' STEP 2: Project Tools (Recommended)');
3231
2999
  console.log('═══════════════════════════════════════════════════════════');
3232
3000
  console.log('');
3233
- console.log('Forge recommends three tools for enhanced workflows:');
3234
- console.log('');
3235
- console.log('• Beads - Git-backed issue tracking');
3236
- console.log(' Persists tasks across sessions, tracks dependencies.');
3237
- console.log(' Command: forge ready, forge create, forge close');
3001
+ console.log('Forge recommends the following tool for enhanced workflows:');
3238
3002
  console.log('');
3239
3003
  console.log('• Skills - Universal SKILL.md management');
3240
3004
  console.log(' Manage AI agent skills across all agents.');
3241
3005
  console.log(' Command: skills create, skills list, skills sync');
3242
3006
  console.log('');
3243
3007
 
3244
- // Use helper functions to reduce complexity
3245
- await promptBeadsSetup(question);
3246
3008
  await promptSkillsSetup(question);
3247
3009
  }
3248
3010
 
3249
- // Auto-setup Beads in quick mode - extracted to reduce cognitive complexity
3250
- function autoSetupBeadsInQuickMode() {
3251
- const beadsStatus = checkForBeads();
3252
- const beadsInitialized = isBeadsInitialized();
3253
-
3254
- if (beadsInitialized) {
3255
- migrateExistingBeadsLocalState();
3256
- }
3257
-
3258
- if (!beadsInitialized && beadsStatus) {
3259
- console.log('📦 Initializing Beads...');
3260
- initializeBeads(beadsStatus);
3261
- console.log('');
3262
- } else if (!beadsInitialized && !beadsStatus) {
3263
- console.log('📦 Installing Beads globally...');
3264
- try {
3265
- // SECURITY: use PowerShell on Windows (npm @beads/bd is broken on Windows - Issue #1031)
3266
- if (process.platform === 'win32') {
3267
- installBeadsOnWindows();
3268
- } else {
3269
- const pkgManager = PKG_MANAGER === 'bun' ? 'bun' : 'npm';
3270
- secureExecFileSync(pkgManager, ['install', '-g', '@beads/bd'], { stdio: 'inherit' });
3271
- }
3272
- console.log(' ✓ Beads installed globally');
3273
- initializeBeads('global');
3274
- } catch (err) {
3275
- // Installation failed - provide manual instructions
3276
- console.log(' ⚠ Could not install Beads automatically');
3277
- console.log(` Error: ${err.message}`);
3278
- if (process.platform === 'win32') {
3279
- console.log(` Run manually: irm ${BEADS_INSTALL_PS1_URL} | iex`);
3280
- } else {
3281
- console.log(` Run manually: ${PKG_MANAGER === 'bun' ? 'bun add -g' : 'npm install -g'} @beads/bd && bd init`);
3282
- }
3283
- }
3284
- console.log('');
3285
- }
3286
- }
3287
-
3288
3011
  // Helper: Auto-install lefthook if not present - extracted to reduce cognitive complexity
3289
3012
  function autoInstallLefthook() {
3290
3013
  const status = checkForLefthook();
@@ -3340,26 +3063,9 @@ function autoInstallLefthook() {
3340
3063
  }
3341
3064
 
3342
3065
  // Helper: Verify a tool is callable after install - extracted to reduce cognitive complexity
3343
- function verifyToolInstall(command, args, toolName) {
3344
- try {
3345
- secureExecFileSync(command, args, { stdio: 'ignore' });
3346
- return true;
3347
- } catch (_err) { // NOSONAR - S2486: Intentionally ignored; verification failure is handled by caller
3348
- console.log(` ⚠ ${toolName} installed but not callable. Check your PATH.`);
3349
- return false;
3350
- }
3351
- }
3352
3066
 
3353
3067
  // Helper: Auto-setup tools (Skills) in quick mode - extracted to reduce cognitive complexity
3354
3068
  function autoSetupToolsInQuickMode() {
3355
- // Beads: auto-install or initialize
3356
- autoSetupBeadsInQuickMode();
3357
-
3358
- // Post-install verification for Beads
3359
- if (isBeadsInitialized()) {
3360
- verifyToolInstall('bd', ['version'], 'Beads');
3361
- }
3362
-
3363
3069
  // Skills: only initialize if already installed (recommended tool)
3364
3070
  const skillsStatus = checkForSkills();
3365
3071
  if (skillsStatus && !isSkillsInitialized()) {
@@ -3421,7 +3127,7 @@ async function quickSetup(selectedAgents, skipExternal) {
3421
3127
  // Auto-install lefthook if missing
3422
3128
  autoInstallLefthook();
3423
3129
 
3424
- // Auto-setup project tools (Beads, Skills)
3130
+ // Auto-setup project tools (Skills)
3425
3131
  autoSetupToolsInQuickMode();
3426
3132
 
3427
3133
  // Setup Claude first if selected, then remaining agents
@@ -3440,11 +3146,6 @@ async function quickSetup(selectedAgents, skipExternal) {
3440
3146
  // Configure external services with defaults (unless skipped)
3441
3147
  configureDefaultExternalServices(skipExternal);
3442
3148
 
3443
- // --sync flag: scaffold Beads GitHub sync workflows without prompting
3444
- if (SYNC_ENABLED) {
3445
- await handleSyncScaffold();
3446
- }
3447
-
3448
3149
  // Progressive setup summary
3449
3150
  console.log('');
3450
3151
  console.log(renderSetupSummary(actionLog, selectedAgents, VERBOSE_MODE));
@@ -3789,8 +3490,9 @@ function dryRunSetup(agents) {
3789
3490
  }
3790
3491
  }
3791
3492
 
3792
- // AGENTS.md
3493
+ // Root policy files
3793
3494
  addFileAction('AGENTS.md', 'Copy workflow documentation');
3495
+ addFileAction('CODING_STANDARDS.md', 'Install Forge coding standards');
3794
3496
 
3795
3497
  // Per-agent planned actions
3796
3498
  for (const agentKey of agents) {
@@ -3862,8 +3564,6 @@ async function executeSetup(config) {
3862
3564
  checkPrerequisites();
3863
3565
  console.log('');
3864
3566
 
3865
- migrateExistingBeadsLocalState();
3866
-
3867
3567
  // Copy AGENTS.md (only if not exists — preserve user customizations; actionLog tracks it)
3868
3568
  const agentsDest = path.join(projectRoot, 'AGENTS.md');
3869
3569
  if (fs.existsSync(agentsDest)) {
@@ -3894,32 +3594,12 @@ async function executeSetup(config) {
3894
3594
  // External services (unless skipped)
3895
3595
  await handleExternalServices(skipExternal, agents);
3896
3596
 
3897
- // --sync flag: scaffold Beads GitHub sync workflows without prompting
3898
- if (SYNC_ENABLED) {
3899
- await handleSyncScaffold();
3900
- }
3901
-
3902
3597
  // Progressive setup summary
3903
3598
  console.log('');
3904
3599
  console.log(renderSetupSummary(actionLog, agents, VERBOSE_MODE));
3905
3600
  console.log('');
3906
3601
  }
3907
3602
 
3908
- // Helper: Scaffold Beads GitHub sync when --sync flag is provided
3909
- async function handleSyncScaffold() {
3910
- console.log('');
3911
- console.log('Beads GitHub sync scaffolding is deprecated (--sync).');
3912
- try {
3913
- const result = scaffoldBeadsSync(projectRoot, packageDir);
3914
- console.log(` ${result.message}`);
3915
- for (const f of result.filesRemoved || []) {
3916
- console.log(` Removed deprecated sync file: ${f}`);
3917
- }
3918
- } catch (err) {
3919
- console.error(` Error scaffolding GitHub-Beads sync: ${err.message}`);
3920
- }
3921
- }
3922
-
3923
3603
  // Helper: Handle setup command in non-quick mode
3924
3604
  async function handleSetupCommand(selectedAgents, flags) {
3925
3605
  // Allow callers (e.g. reinstall) to override projectRoot without process.chdir()
@@ -3938,7 +3618,6 @@ async function handleSetupCommand(selectedAgents, flags) {
3938
3618
  }
3939
3619
 
3940
3620
  async function runInteractiveSetupFallback(flags, interactiveSetup = interactiveSetupWithFlags) {
3941
- migrateExistingBeadsLocalState();
3942
3621
  return interactiveSetup(flags);
3943
3622
  }
3944
3623
 
@@ -3989,7 +3668,6 @@ async function main() {
3989
3668
  VERBOSE_MODE = flags.verbose;
3990
3669
  NON_INTERACTIVE = flags.nonInteractive || flags.yes || isNonInteractive();
3991
3670
  SYMLINK_ONLY = flags.symlink;
3992
- SYNC_ENABLED = flags.sync;
3993
3671
  actionLog = new SetupActionLog();
3994
3672
 
3995
3673
  // The non-interactive agent-selection notice is DEBUG-ONLY (kernel issue
@@ -4159,11 +3837,10 @@ async function main() {
4159
3837
  console.error(`Error running '${command}':`, err.message);
4160
3838
  process.exit(1);
4161
3839
  }
4162
- // NOTE: the autonomous-shepherd per-command trigger is intentionally NOT wired here.
4163
- // The reconcile engine + daemon land in this PR; the auto-fire wiring is deferred to a
4164
- // follow-up (W-S4c) because a naive dispatch-finally trigger spawns a session-outliving
4165
- // daemon on EVERY command, which breaks test isolation (Windows rmSync EBUSY) and needs
4166
- // its own firing-policy + containment design. Start the daemon via `forge shepherd daemon`.
3840
+ // NOTE: an autonomous-shepherd every-command dispatch-finally trigger is intentionally
3841
+ // NOT wired here. Automatic firing is deliberately limited to the approved seams:
3842
+ // supported session start, successful push, and successful non-dry-run ship. Ordinary
3843
+ // commands cannot spawn a session-outliving daemon or break test isolation.
4167
3844
  return;
4168
3845
  }
4169
3846
 
@@ -4216,12 +3893,6 @@ async function main() {
4216
3893
  return;
4217
3894
  }
4218
3895
 
4219
- if (flags.sync && selectedAgents.length === 0) {
4220
- migrateExistingBeadsLocalState();
4221
- await handleSyncScaffold();
4222
- return;
4223
- }
4224
-
4225
3896
  // Agents specified via flag or --yes default (non-quick mode)
4226
3897
  if (selectedAgents.length > 0) {
4227
3898
  await handleSetupCommand(selectedAgents, flags);
@@ -4621,20 +4292,6 @@ function checkGitWorkingDirectory() {
4621
4292
  }
4622
4293
  }
4623
4294
 
4624
- // Helper: Update Beads issue after PR rollback
4625
- function updateBeadsIssue(commitMessage) {
4626
- const issueMatch = commitMessage.match(/#(\d+)/);
4627
- if (!issueMatch) return;
4628
-
4629
- try {
4630
- const { execFileSync } = require('node:child_process');
4631
- execFileSync('bd', ['update', issueMatch[1], '--status', 'reverted', '--comment', 'PR reverted'], { stdio: 'inherit' });
4632
- console.log(` Updated Beads issue #${issueMatch[1]} to 'reverted'`);
4633
- } catch {
4634
- // Beads not installed - silently continue
4635
- }
4636
- }
4637
-
4638
4295
  // Helper: Handle commit rollback
4639
4296
  function handleCommitRollback(target, dryRun, execSync) {
4640
4297
  if (dryRun) {
@@ -4656,10 +4313,6 @@ function handlePrRollback(target, dryRun, execSync) {
4656
4313
  files.trim().split('\n').forEach(f => console.log(` - ${f}`));
4657
4314
  } else {
4658
4315
  execSync(`git revert -m 1 --no-edit ${target}`, { stdio: 'inherit' });
4659
-
4660
- // Update Beads issue if linked
4661
- const commitMsg = execSync(`git log -1 --format=%B ${target}`, { encoding: 'utf-8' });
4662
- updateBeadsIssue(commitMsg);
4663
4316
  }
4664
4317
  }
4665
4318
 
package/docs/INDEX.md CHANGED
@@ -49,7 +49,7 @@ This is the canonical map for Forge documentation. DeepWiki and other generated
49
49
  - [Protected path manifest](reference/PROTECTED_PATH_MANIFEST.md) - protected path manifest schema, harness enforcement mapping, and evidence command.
50
50
  - [Patch format](reference/patch-md-format.md) - `.forge/patch.md` conventions.
51
51
  - [Upgrade safety](reference/upgrade-safety.md) - trust policy and rollback limits.
52
- - [Insights and recap](reference/INSIGHTS_RECAP.md) - `forge insights` and `forge recap` evidence sources, output, and limitations.
52
+ - [Insights and recap](reference/INSIGHTS_RECAP.md) - `forge insights` and `forge recap <issue>` evidence sources, output, and limitations.
53
53
  - [Examples](reference/EXAMPLES.md) - worked examples.
54
54
  - [Test environment](reference/test-environment.md) - test harness notes.
55
55
  - [Agent permissions](reference/agent-permissions.md) - agent permission model.
@@ -1,32 +1,3 @@
1
- # Beads/GitHub Sync Deprecation
1
+ # Beads/GitHub Sync (Retired)
2
2
 
3
- Beads/GitHub workflow sync is deprecated. Forge no longer ships active `github-to-beads.yml` or `beads-to-github.yml` workflow templates, and `forge setup --sync` must not create new Beads/GitHub sync scaffolding.
4
-
5
- ## Current Behavior
6
-
7
- - `.beads/` is local runtime/export state and is not committed.
8
- - `forge setup --sync` is retained only as a compatibility cleanup path and removes old generated Beads/GitHub sync files from existing installs when they are present.
9
- - Plain `forge setup` does not perform Beads/GitHub sync cleanup as a side effect.
10
- - `forge sync` may still run local Beads/Dolt sync operations while Beads compatibility remains, but it is not GitHub issue lifecycle sync.
11
-
12
- ## Removed Generated Files
13
-
14
- The `forge setup --sync` compatibility cleanup removes the old generated files:
15
-
16
- ```text
17
- .github/workflows/github-to-beads.yml
18
- .github/workflows/beads-to-github.yml
19
- .github/beads-mapping.json
20
- .github/beads-sync-config.json
21
- .github/scripts/beads-sync/*.mjs
22
- scripts/github-beads-sync.config.json
23
- scripts/github-beads-sync/*.mjs
24
- ```
25
-
26
- Unrelated GitHub workflows are preserved.
27
-
28
- ## Replacement Direction
29
-
30
- Future GitHub issue sync must use Forge Kernel/server authority. Local-only work is durable in local Kernel SQLite. Team or cross-machine issue state is serialized through server authority, then GitHub issues can be updated as a projection from that authority.
31
-
32
- Do not commit live `.beads/` files, create metadata-only PRs, or bypass protected branches to update issue tracker state.
3
+ **Historical.** Beads/GitHub workflow sync was retired with **D45** — Beads is no longer a live Forge feature, so there is nothing left to keep in sync. Forge ships no `github-to-beads.yml` or `beads-to-github.yml` templates and never scaffolds new sync files. Bringing an existing Beads store into Forge is a one-time import, `forge migrate --from beads`; after that the Forge Kernel is the sole issue-state authority, and GitHub issue updates are a server-side projection from that authority (see [docs/work/2026-04-28-skeleton-pivot/forge-kernel-authority-control-plane.md](../work/2026-04-28-skeleton-pivot/forge-kernel-authority-control-plane.md)). Installs that still carry old generated sync files are cleaned automatically: the `forge setup` compatibility cleanup removes the old generated files, with no flag required.