5-phase-workflow 3.0.1 → 3.1.0

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 (55) hide show
  1. package/README.md +31 -104
  2. package/bin/install.js +163 -178
  3. package/bin/sync-agents.js +59 -54
  4. package/docs/workflow-guide.md +35 -79
  5. package/package.json +1 -1
  6. package/src/agents/step-executor-agent.md +3 -3
  7. package/src/agents/step-orchestrator-agent.md +12 -12
  8. package/src/agents/verification-agent.md +5 -8
  9. package/src/codex-commands/plan.md +65 -0
  10. package/src/commands/5/address-review-findings.md +43 -52
  11. package/src/commands/5/analyze-feature.md +1 -1
  12. package/src/commands/5/configure.md +75 -179
  13. package/src/commands/5/eject.md +0 -1
  14. package/src/commands/5/implement.md +68 -74
  15. package/src/commands/5/lean-check.md +7 -5
  16. package/src/commands/5/reconfigure.md +48 -129
  17. package/src/commands/5/review.md +42 -14
  18. package/src/commands/5/synchronize-agents.md +1 -1
  19. package/src/commands/5/update.md +2 -2
  20. package/src/hooks/statusline.js +5 -3
  21. package/src/references/configure-tables.md +0 -33
  22. package/src/settings.json +0 -12
  23. package/src/skills/baseline-conventions/SKILL.md +37 -0
  24. package/src/skills/cognitive-load/SKILL.md +52 -0
  25. package/src/skills/configure-agents-md/SKILL.md +72 -0
  26. package/src/skills/configure-rules/SKILL.md +146 -0
  27. package/src/skills/documentation-style/SKILL.md +32 -0
  28. package/src/skills/fowler-code-smells/SKILL.md +25 -0
  29. package/src/skills/review-style/SKILL.md +142 -0
  30. package/src/templates/AGENTS.md +19 -27
  31. package/src/templates/workflow/REVIEW-FINDINGS.md +2 -9
  32. package/src/workflows/5-implement.js +53 -91
  33. package/docs/findings.md +0 -361
  34. package/docs/progress.md +0 -102
  35. package/src/commands/5/apply-review-findings.md +0 -66
  36. package/src/commands/5/commit.md +0 -43
  37. package/src/commands/5/plan.md +0 -190
  38. package/src/commands/5/reply-pr-comments.md +0 -48
  39. package/src/commands/5/split.md +0 -86
  40. package/src/commands/5/triage-pr-comments.md +0 -70
  41. package/src/hooks/config-guard.js +0 -30
  42. package/src/skills/configure-docs-index/SKILL.md +0 -243
  43. package/src/skills/configure-skills/SKILL.md +0 -311
  44. package/src/skills/generate-readme/EXAMPLES.md +0 -168
  45. package/src/skills/generate-readme/SKILL.md +0 -122
  46. package/src/skills/generate-readme/TEMPLATE.md +0 -141
  47. package/src/skills/use-index/SKILL.md +0 -49
  48. package/src/templates/ARCHITECTURE.md +0 -33
  49. package/src/templates/CONCERNS.md +0 -33
  50. package/src/templates/CONVENTIONS.md +0 -74
  51. package/src/templates/TESTING.md +0 -24
  52. package/src/templates/workflow/FIX-PLAN.md +0 -55
  53. package/src/templates/workflow/PLAN-COMPACT.md +0 -42
  54. package/src/templates/workflow/PLAN.md +0 -76
  55. package/src/templates/workflow/REVIEW-SUMMARY.md +0 -53
package/bin/install.js CHANGED
@@ -323,27 +323,15 @@ function copyWorkflowHelperBins(targetPath) {
323
323
  }
324
324
  }
325
325
 
326
- // Remove directory recursively
326
+ // Remove a directory recursively. fs.rmSync removes a symlink itself and never follows it,
327
+ // so a link planted in a checkout cannot redirect the deletion outside the project.
327
328
  function removeDir(dir) {
328
- if (fs.existsSync(dir)) {
329
- const entries = fs.readdirSync(dir, { withFileTypes: true });
330
-
331
- for (const entry of entries) {
332
- const fullPath = path.join(dir, entry.name);
333
-
334
- if (entry.isDirectory()) {
335
- removeDir(fullPath);
336
- } else {
337
- fs.unlinkSync(fullPath);
338
- }
339
- }
340
-
341
- fs.rmdirSync(dir);
342
- }
329
+ fs.rmSync(dir, { recursive: true, force: true });
343
330
  }
344
331
 
345
- // Files removed from the package before manifest tracking existed.
346
- // This list is frozen — future removals are handled by manifest diffing.
332
+ // Files removed from the package over time. Upgrades from installs with a manifest find
333
+ // removals by manifest diffing; this list covers installs that predate the manifest, and
334
+ // uninstall uses it to clear leftovers.
347
335
  const LEGACY_REMOVED_FILES = [
348
336
  'agents/feature-planner.md',
349
337
  'agents/implementation-planner.md',
@@ -379,7 +367,35 @@ const LEGACY_REMOVED_FILES = [
379
367
  'commands/5/discuss-feature.md',
380
368
  'templates/workflow/STATE.json',
381
369
  'skills/5-unlock',
382
- 'skills/5-discuss-feature'
370
+ 'skills/5-discuss-feature',
371
+ // Plans live in .5/planning/; no codebase index, scan cache, generated docs, or split
372
+ 'commands/5/split.md',
373
+ 'skills/5-split',
374
+ 'skills/use-index',
375
+ 'skills/configure-docs-index',
376
+ 'templates/ARCHITECTURE.md',
377
+ 'templates/CONCERNS.md',
378
+ 'templates/CONVENTIONS.md',
379
+ 'templates/TESTING.md',
380
+ // Lean core: Claude Code covers commits, READMEs, PR replies, and per-pattern skills natively
381
+ 'commands/5/commit.md',
382
+ // Claude Code plans in native plan mode under the AGENTS.md Planning rules; $5-plan stays for Codex
383
+ 'commands/5/plan.md',
384
+ 'commands/5/apply-review-findings.md',
385
+ 'commands/5/triage-pr-comments.md',
386
+ 'commands/5/reply-pr-comments.md',
387
+ 'skills/5-commit',
388
+ 'skills/5-apply-review-findings',
389
+ 'skills/5-triage-pr-comments',
390
+ 'skills/5-reply-pr-comments',
391
+ 'skills/generate-readme',
392
+ 'skills/configure-skills',
393
+ 'hooks/config-guard.js',
394
+ 'templates/workflow/FIX-PLAN.md',
395
+ // Plans have no fixed shape; plan mode and $5-plan decide it
396
+ 'templates/workflow/PLAN.md',
397
+ 'templates/workflow/PLAN-COMPACT.md',
398
+ 'templates/workflow/REVIEW-SUMMARY.md'
383
399
  ];
384
400
 
385
401
  // Get list of workflow-owned files/directories (not user-created)
@@ -388,6 +404,9 @@ function getWorkflowManagedFiles() {
388
404
  // Commands: only the 5/ namespace
389
405
  commands: ['5'],
390
406
 
407
+ // Codex-only commands, installed as skills/5-{name}: Claude Code covers them natively
408
+ codexCommands: ['plan.md'],
409
+
391
410
  // Agents: separate agent files referenced by commands via agent: frontmatter
392
411
  agents: [
393
412
  'step-executor-agent.md',
@@ -402,10 +421,14 @@ function getWorkflowManagedFiles() {
402
421
 
403
422
  // Skills: specific skill directories
404
423
  skills: [
405
- 'configure-docs-index',
406
- 'configure-skills',
407
- 'generate-readme',
408
- 'use-index'
424
+ 'configure-agents-md',
425
+ 'configure-rules',
426
+ // Review styles: review-style runs one reviewer per style listed in its SKILL.md
427
+ 'review-style',
428
+ 'fowler-code-smells',
429
+ 'cognitive-load',
430
+ 'documentation-style',
431
+ 'baseline-conventions'
409
432
  ],
410
433
 
411
434
  // Hooks: specific hook files
@@ -413,7 +436,6 @@ function getWorkflowManagedFiles() {
413
436
  'statusline.js',
414
437
  'check-updates.js',
415
438
  'check-reconfig.js',
416
- 'config-guard.js',
417
439
  'dependency-guard.js'
418
440
  ],
419
441
 
@@ -429,18 +451,10 @@ function getWorkflowManagedFiles() {
429
451
 
430
452
  // Templates: specific template files
431
453
  templates: [
432
- // Project documentation templates
454
+ // Project instructions template
433
455
  'AGENTS.md',
434
- 'ARCHITECTURE.md',
435
- 'CONCERNS.md',
436
- 'CONVENTIONS.md',
437
- 'TESTING.md',
438
456
  // Workflow output templates
439
- 'workflow/PLAN.md',
440
- 'workflow/PLAN-COMPACT.md',
441
- 'workflow/REVIEW-FINDINGS.md',
442
- 'workflow/REVIEW-SUMMARY.md',
443
- 'workflow/FIX-PLAN.md'
457
+ 'workflow/REVIEW-FINDINGS.md'
444
458
  ]
445
459
  };
446
460
  }
@@ -479,7 +493,7 @@ function getFileManifest() {
479
493
  manifest.push(`hooks/${hook}`);
480
494
  }
481
495
 
482
- // Templates are files (may include nested paths like workflow/PLAN.md)
496
+ // Templates are files (may include nested paths like workflow/REVIEW-FINDINGS.md)
483
497
  for (const template of managed.templates) {
484
498
  manifest.push(`templates/${template}`);
485
499
  }
@@ -539,14 +553,6 @@ function convertClaudeSetupCommandsToCodexNotes(content) {
539
553
  .replace(
540
554
  /- If user selects "Install now": execute the install command/g,
541
555
  '- If user selects "Install now": explain that Codex cannot run the Claude Code installer command; leave `tools.context7.available = false` unless Context7 is already detected'
542
- )
543
- .replace(
544
- /1\. "Install now \(recommended\)" — run `claude plugin install skill-creator@claude-plugins-official` via Bash/g,
545
- '1. "Install now" — not supported automatically in Codex; install an equivalent skill authoring workflow outside this command, then rerun configuration'
546
- )
547
- .replace(
548
- /- If user selects "Install now": execute the install command, then set `tools\.skillCreator\.available = true` in the config/g,
549
- '- If user selects "Install now": explain that Codex cannot run the Claude Code plugin installer; leave `tools.skillCreator.available = false` unless an equivalent tool is already detected'
550
556
  );
551
557
  }
552
558
 
@@ -567,6 +573,7 @@ This skill was authored for Claude Code. Map these tool references:
567
573
  | \`Agent(subagent_type="Explore")\` | \`spawn_agent(agent_type="explorer", model="gpt-5.4-mini", reasoning_effort="low", message="...")\` |
568
574
  | \`Agent(prompt="...", model="haiku")\` | \`spawn_agent(model="gpt-5.4-mini", reasoning_effort="low", message="...")\` |
569
575
  | \`Agent(prompt="...", model="sonnet")\` | \`spawn_agent(model="gpt-5.4", reasoning_effort="medium", message="...")\` |
576
+ | \`Agent(prompt="...", model="opus", effort="medium")\` | \`spawn_agent(model="gpt-5.4", reasoning_effort="high", message="...")\` |
570
577
  | \`Agent(prompt="...")\` | \`spawn_agent(model="gpt-5.4-mini", reasoning_effort="low", message="...")\` unless the prompt explicitly requires complex reasoning |
571
578
  | \`Read\` | \`read_file\` |
572
579
  | \`Write\` | \`write_file\` |
@@ -574,9 +581,10 @@ This skill was authored for Claude Code. Map these tool references:
574
581
  | \`Bash\` | \`shell\` |
575
582
  | \`Glob\` | \`glob\` / \`list_directory\` |
576
583
  | \`Grep\` | \`grep\` / \`search\` |
577
- | \`TaskCreate/TaskUpdate\` | Track progress internally |
578
584
  | \`Workflow\` | Not available — run the command's prose fallback loop instead |
579
585
  | \`Skill(skill="code-review")\` | Not available — run the command's prose fallback loop instead |
586
+ | \`Skill(skill="security-review")\` | Not available — skip it; the prose review fallback of \`$5-review\` covers security |
587
+ | \`Skill(skill="review-style", args="...")\` | Read \`.codex/skills/review-style/SKILL.md\` and follow it with the same arguments |
580
588
  | \`EnterPlanMode\` | Not available — run the command's prose fallback loop instead |
581
589
 
582
590
  ## Model Mapping (single source of truth)
@@ -586,28 +594,30 @@ When a skill, plan, or execution-graph component names a model, map it to Codex
586
594
  |-------------|-------------|------------------|
587
595
  | \`haiku\` (or unset) | \`gpt-5.4-mini\` | \`low\` |
588
596
  | \`sonnet\` | \`gpt-5.4\` | \`medium\` |
597
+ | \`opus\` | \`gpt-5.4\` | \`high\` |
589
598
  | Explore / explorer agent | \`gpt-5.4-mini\` (\`agent_type: explorer\`) | \`low\` |
590
599
 
591
600
  This table is authoritative — skill bodies do not repeat per-call model mappings.
592
601
 
593
602
  ## Codex Token Budget
594
603
  - Default to \`gpt-5.4-mini\` with \`reasoning_effort: low\` for exploration, orchestration, simple implementation, and mechanical file edits.
595
- - Use \`gpt-5.4\` with \`reasoning_effort: medium\` only for complex logic, cross-module behavior, security-sensitive changes, data migrations, final verification with meaningful logic review, or retries after failure.
604
+ - Use \`gpt-5.4\` with \`reasoning_effort: medium\` for ordinary logic and final verification with meaningful logic review.
605
+ - Use \`gpt-5.4\` with \`reasoning_effort: high\` only for complex logic, cross-module behavior, security-sensitive changes, data migrations, public API contracts, or retries after failure.
596
606
  - Use stronger models only when a previous cheaper attempt failed for reasoning reasons.
597
607
  - Keep the parent skill context lean: delegate read-heavy exploration to explorer agents and pass only compact findings, target paths, pattern references, and command summaries between agents.
598
608
 
599
609
  ## Guard Rules (Codex has no plan mode)
600
610
  Claude Code enforces these at the harness level via native plan mode. Codex has no equivalent, so honour them yourself while running \`$5-plan\`, **until the user approves the plan**:
601
- - Do NOT write to any file outside \`.5/\`
602
- - Do NOT write source code — only the unified plan and scan cache
611
+ - Do NOT write any file — the plan is written only after approval
612
+ - Do NOT write source code
603
613
  - Do NOT spawn implementation agents — only Explore/research agents
604
614
 
605
- After approval, \`$5-plan\` implements compact plans inline and hands larger ones to \`$5-implement\`.
615
+ After approval, \`$5-plan\` saves the plan in \`.5/planning/\` and hands it to \`$5-implement\`.
606
616
 
607
617
  ## Update & Migration Notices (replaces statusline hooks)
608
618
  At the very start of this skill, before doing anything else, read these two files if they exist:
609
619
  - \`.5/.update-cache.json\` — if \`latestAvailableVersion\` is set, compare it to \`packageVersion\` in \`.5/version.json\`. If a newer version is available, tell the user: "foifi update available: <version> — run \`npx foifi --codex --upgrade\` to update."
610
- - \`.5/.migration-v2\` — if this file exists, tell the user: "You upgraded from foifi v1 to v2. Run \`$5-reconfigure\` to update your project configuration."
620
+ - \`.5/.migration-v*\` — if a file such as \`.5/.migration-v4\` exists, tell the user: "You upgraded foifi to a new major version. Run \`$5-reconfigure\` to update your project configuration."
611
621
 
612
622
  Show each applicable notice once at the top of your response, then continue with the skill normally. Do not abort the skill because of a notice.
613
623
  </codex_skill_adapter>`;
@@ -645,20 +655,29 @@ function convertClaudeSkillToCodexSkill(content) {
645
655
  return convertClaudeToCodexMarkdown(content);
646
656
  }
647
657
 
658
+ // Command files that become Codex skills: the shared commands/5/ plus the Codex-only codex-commands/
659
+ // (Claude Code covers those natively, e.g. plan mode replaces /5:plan).
660
+ function getCodexCommandFiles(sourcePath) {
661
+ const toEntry = (dir, file) => ({ name: file.replace('.md', ''), file: path.join(dir, file) });
662
+ const sharedDir = path.join(sourcePath, 'commands', '5');
663
+ const shared = fs.existsSync(sharedDir)
664
+ ? fs.readdirSync(sharedDir).filter(f => f.endsWith('.md')).map(f => toEntry(sharedDir, f))
665
+ : [];
666
+ const codexDir = path.join(sourcePath, 'codex-commands');
667
+ const codexOnly = getWorkflowManagedFiles().codexCommands
668
+ .filter(f => fs.existsSync(path.join(codexDir, f)))
669
+ .map(f => toEntry(codexDir, f));
670
+ return [...shared, ...codexOnly];
671
+ }
672
+
648
673
  // Get file manifest for Codex installs (skills-based structure)
649
674
  function getCodexFileManifest() {
650
675
  const managed = getWorkflowManagedFiles();
651
676
  const manifest = [];
652
677
 
653
- // Commands become skills
654
- // Each command file in commands/5/ becomes skills/5-{name}/SKILL.md
655
- const commandsSrc = path.join(getSourcePath(), 'commands', '5');
656
- if (fs.existsSync(commandsSrc)) {
657
- const files = fs.readdirSync(commandsSrc).filter(f => f.endsWith('.md'));
658
- for (const file of files) {
659
- const name = file.replace('.md', '');
660
- manifest.push(`skills/5-${name}`);
661
- }
678
+ // Commands become skills: each command file becomes skills/5-{name}/SKILL.md
679
+ for (const { name } of getCodexCommandFiles(getSourcePath())) {
680
+ manifest.push(`skills/5-${name}`);
662
681
  }
663
682
 
664
683
  // Original skills also become Codex skills
@@ -689,9 +708,6 @@ function getCodexFileManifest() {
689
708
  }
690
709
  }
691
710
 
692
- // Instructions file
693
- manifest.push('instructions.md');
694
-
695
711
  return manifest;
696
712
  }
697
713
 
@@ -791,7 +807,7 @@ function selectiveUpdate(targetPath, sourcePath) {
791
807
  const src = path.join(templatesSrc, template);
792
808
  const dest = path.join(templatesDest, template);
793
809
  if (fs.existsSync(src)) {
794
- // Ensure parent directory exists for nested paths (e.g., workflow/PLAN.md)
810
+ // Ensure parent directory exists for nested paths (e.g., workflow/REVIEW-FINDINGS.md)
795
811
  const destDir = path.dirname(dest);
796
812
  if (!fs.existsSync(destDir)) {
797
813
  fs.mkdirSync(destDir, { recursive: true });
@@ -857,9 +873,12 @@ function cleanupOrphanedFiles(targetPath, dataDir) {
857
873
 
858
874
  if (oldManifest) {
859
875
  // Manifest exists: diff old vs current, delete orphans
876
+ const installRoot = path.resolve(targetPath) + path.sep;
860
877
  for (const entry of oldManifest) {
861
878
  if (!currentSet.has(entry)) {
862
- const fullPath = path.join(targetPath, entry);
879
+ const fullPath = path.resolve(targetPath, entry);
880
+ // version.json may come from the checkout, so an entry must stay inside the install dir
881
+ if (!fullPath.startsWith(installRoot)) continue;
863
882
  if (fs.existsSync(fullPath)) {
864
883
  const stat = fs.statSync(fullPath);
865
884
  if (stat.isDirectory()) {
@@ -1048,7 +1067,7 @@ function mergeSettings(targetPath, sourcePath) {
1048
1067
 
1049
1068
  if (fs.existsSync(targetSettings)) {
1050
1069
  const existingSettings = JSON.parse(fs.readFileSync(targetSettings, 'utf8'));
1051
- const merged = deepMerge(newSettings, existingSettings);
1070
+ const merged = deepMerge(existingSettings, newSettings);
1052
1071
  fs.writeFileSync(targetSettings, JSON.stringify(merged, null, 2));
1053
1072
  log.info('Merged settings with existing configuration');
1054
1073
  } else {
@@ -1065,37 +1084,35 @@ function checkExistingInstallation(targetPath) {
1065
1084
  const legacyMarkerFile = path.join(targetPath, 'skills', '5-plan-feature', 'SKILL.md');
1066
1085
  return fs.existsSync(markerFile) || fs.existsSync(legacyMarkerFile);
1067
1086
  }
1068
- const markerFile = path.join(targetPath, 'commands', '5', 'plan.md');
1069
- const legacyMarkerFile = path.join(targetPath, 'commands', '5', 'plan-feature.md');
1070
- return fs.existsSync(markerFile) || fs.existsSync(legacyMarkerFile);
1087
+ // plan.md and plan-feature.md mark installs from before plan mode replaced /5:plan
1088
+ return ['implement.md', 'plan.md', 'plan-feature.md']
1089
+ .some(file => fs.existsSync(path.join(targetPath, 'commands', '5', file)));
1071
1090
  }
1072
1091
 
1073
1092
  // Helper to show commands
1074
1093
  function showCommandsHelp(isGlobal) {
1075
1094
  if (activeRuntime === 'codex') {
1076
1095
  log.info('Available skills (invoke with $ prefix in Codex):');
1077
- log.info(' $5-plan - Create or refine a unified plan');
1078
- log.info(' $5-split - Split plan into smaller plans');
1096
+ log.info(' $5-plan - Create or refine a plan');
1079
1097
  log.info(' $5-implement - Execute implementation + verification');
1080
- log.info(' $5-review - Code review');
1098
+ log.info(' $5-review - Code and standards review');
1081
1099
  log.info(' $5-lean-check - Check a diff for scope drift/over-engineering');
1082
- log.info(' $5-commit - Create a templated git commit');
1083
- log.info(' $5-address-review-findings - Decide review findings & PR comments');
1100
+ log.info(' $5-address-review-findings - Decide on review findings, apply the fixes');
1101
+ log.info(' $5-analyze-feature - Document a feature with mermaid diagrams');
1084
1102
  log.info(' $5-configure - Interactive project setup');
1085
- log.info(' $5-reconfigure - Refresh docs/skills (no Q&A)');
1103
+ log.info(' $5-reconfigure - Refresh the AGENTS.md block and rules (no Q&A)');
1086
1104
  log.info(' $5-eject - Eject from update mechanism');
1087
1105
  log.info(' $5-synchronize-agents - Sync user content between runtimes');
1088
1106
  } else {
1107
+ log.info('Plan in native plan mode (shift+tab); AGENTS.md shapes the plan.');
1089
1108
  log.info('Available commands:');
1090
- log.info(' /5:plan - Create or refine a unified plan');
1091
- log.info(' /5:split - Split plan into smaller plans');
1092
1109
  log.info(' /5:implement - Execute implementation + verification');
1093
- log.info(' /5:review - Code review');
1110
+ log.info(' /5:review - Code and standards review');
1094
1111
  log.info(' /5:lean-check - Check a diff for scope drift/over-engineering');
1095
- log.info(' /5:commit - Create a templated git commit');
1096
- log.info(' /5:address-review-findings - Decide review findings & PR comments');
1112
+ log.info(' /5:address-review-findings - Decide on review findings, apply the fixes');
1113
+ log.info(' /5:analyze-feature - Document a feature with mermaid diagrams');
1097
1114
  log.info(' /5:configure - Interactive project setup');
1098
- log.info(' /5:reconfigure - Refresh docs/skills (no Q&A)');
1115
+ log.info(' /5:reconfigure - Refresh the AGENTS.md block and rules (no Q&A)');
1099
1116
  log.info(' /5:eject - Eject from update mechanism');
1100
1117
  log.info(' /5:synchronize-agents - Sync user content between runtimes');
1101
1118
  }
@@ -1141,10 +1158,8 @@ function performFreshInstall(targetPath, sourcePath, isGlobal) {
1141
1158
  log.info('This will:');
1142
1159
  log.info(' • Detect your project type and build commands');
1143
1160
  log.info(' • Set up ticket tracking conventions');
1144
- log.info(' • Generate comprehensive documentation (CLAUDE.md)');
1145
- log.info(' • Create project-specific skills');
1146
- log.info('');
1147
- log.info('Tip: Configure will offer to install helpful plugins like skill-creator');
1161
+ log.info(' • Add the workflow rules to AGENTS.md as one marked block, linking your repository standards');
1162
+ log.info(' • Create file-scoped rules from your conventions');
1148
1163
 
1149
1164
  showCommandsHelp(isGlobal);
1150
1165
  }
@@ -1195,24 +1210,31 @@ function removeContextForkFromSkills(targetPath) {
1195
1210
  } catch (e) {}
1196
1211
  }
1197
1212
 
1198
- // Remove the plan-guard PreToolUse hook entry from an existing settings.json.
1199
- // Native plan mode enforces read-only planning at the harness level, so the hook
1200
- // is gone. Claude Code only — Codex never had a settings.json.
1201
- function removePlanGuardHook(targetPath) {
1213
+ // Remove retired PreToolUse hook entries from an existing settings.json. Native plan mode
1214
+ // replaced plan-guard; config-guard blocked every Agent call in sessions outside the workflow.
1215
+ // Claude Code only — Codex never had a settings.json.
1216
+ const RETIRED_HOOKS = ['plan-guard.js', 'config-guard.js'];
1217
+
1218
+ function removeRetiredHooks(targetPath) {
1202
1219
  const settingsFile = path.join(targetPath, 'settings.json');
1203
1220
  if (!fs.existsSync(settingsFile)) return;
1204
1221
  try {
1205
1222
  const settings = JSON.parse(fs.readFileSync(settingsFile, 'utf8'));
1206
1223
  const pre = settings.hooks && settings.hooks.PreToolUse;
1207
1224
  if (!Array.isArray(pre)) return;
1208
- const kept = pre.filter(entry =>
1209
- !(entry.hooks || []).some(h => typeof h.command === 'string' && h.command.includes('plan-guard.js')));
1210
- if (kept.length === pre.length) return;
1225
+ const isRetired = h => typeof h.command === 'string' && RETIRED_HOOKS.some(hook => h.command.includes(hook));
1226
+ if (!pre.some(entry => (entry.hooks || []).some(isRetired))) return;
1227
+ // Drop only the retired hooks; an entry survives while it still holds the user's own hooks
1228
+ const kept = pre
1229
+ .map(entry => (entry.hooks || []).some(isRetired)
1230
+ ? { ...entry, hooks: entry.hooks.filter(h => !isRetired(h)) }
1231
+ : entry)
1232
+ .filter(entry => !Array.isArray(entry.hooks) || entry.hooks.length);
1211
1233
  if (kept.length) settings.hooks.PreToolUse = kept;
1212
1234
  else delete settings.hooks.PreToolUse;
1213
1235
  if (settings.hooks && !Object.keys(settings.hooks).length) delete settings.hooks;
1214
1236
  fs.writeFileSync(settingsFile, JSON.stringify(settings, null, 2));
1215
- log.info('Removed plan-guard hook from settings.json (native plan mode replaces it)');
1237
+ log.info('Removed retired guard hooks from settings.json');
1216
1238
  } catch (e) {}
1217
1239
  }
1218
1240
 
@@ -1227,6 +1249,25 @@ function removePlanningActiveMarker(dataDir) {
1227
1249
  } catch (e) {}
1228
1250
  }
1229
1251
 
1252
+ // Move .5/features/{name}/plan.md to .5/planning/{name}.md. Plans now live where native plan
1253
+ // mode saves them, and /5:implement finds them by their `feature` frontmatter. The .5/ data
1254
+ // is shared, so performUpdate() and performCodexUpdate() both run this.
1255
+ function movePlansToPlanningDir(dataDir) {
1256
+ const featuresDir = path.join(dataDir, 'features');
1257
+ if (!fs.existsSync(featuresDir)) return;
1258
+ const planningDir = path.join(dataDir, 'planning');
1259
+ try {
1260
+ for (const feature of fs.readdirSync(featuresDir)) {
1261
+ const planFile = path.join(featuresDir, feature, 'plan.md');
1262
+ const target = path.join(planningDir, `${feature}.md`);
1263
+ if (!fs.existsSync(planFile) || fs.existsSync(target)) continue;
1264
+ fs.mkdirSync(planningDir, { recursive: true });
1265
+ fs.renameSync(planFile, target);
1266
+ log.info(`Moved plan: features/${feature}/plan.md → planning/${feature}.md`);
1267
+ }
1268
+ } catch (e) {}
1269
+ }
1270
+
1230
1271
  // Perform update (preserves user-created files, updates .5/ data directory)
1231
1272
  function performUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
1232
1273
  log.header(`Updating from ${versionInfo.installed || 'legacy'} to ${versionInfo.available}`);
@@ -1248,10 +1289,13 @@ function performUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
1248
1289
  // Strip `context: fork` from generated skills — caused infinite loops
1249
1290
  removeContextForkFromSkills(targetPath);
1250
1291
 
1251
- // Native plan mode replaces the plan-guard hook and its marker file
1252
- removePlanGuardHook(targetPath);
1292
+ // Native plan mode replaces the plan-guard hook and its marker file; config-guard is retired
1293
+ removeRetiredHooks(targetPath);
1253
1294
  removePlanningActiveMarker(dataDir);
1254
1295
 
1296
+ // Plans moved from .5/features/{name}/plan.md to .5/planning/{name}.md
1297
+ movePlansToPlanningDir(dataDir);
1298
+
1255
1299
  // Flag v1 → v2 major upgrade so statusline can prompt for reconfigure
1256
1300
  const prevMajor = versionInfo.installed ? parseInt(versionInfo.installed.split('.')[0], 10) : 0;
1257
1301
  const newMajor = versionInfo.available ? parseInt(versionInfo.available.split('.')[0], 10) : 0;
@@ -1281,69 +1325,15 @@ function performUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
1281
1325
 
1282
1326
  // ── Codex install/update/uninstall ──────────────────────────────────────────
1283
1327
 
1284
- // Generate instructions.md for Codex (replaces hooks + settings.json)
1285
- function generateCodexInstructions(targetPath) {
1286
- const content = `# dev-workflow — Codex Instructions
1287
-
1288
- This file is managed by the dev-workflow installer. It provides Codex with
1289
- the context it needs to run the workflow skills correctly.
1290
-
1291
- ## Workflow Overview
1292
-
1293
- The workflow provides structured feature development:
1294
-
1295
- 1. **Plan** (\`$5-plan\`) — Requirements, discovery, and unified plan
1296
- 2. **Implement** (\`$5-implement\`) — Orchestrated implementation with inline verification
1297
- 3. **Review** (\`$5-review\`) — Code review
1298
-
1299
- ## Data Directory
1300
-
1301
- All workflow state lives in \`.5/\` at the project root:
1302
- - \`.5/config.json\` — Project configuration
1303
- - \`.5/features/{name}/plan.md\` — Unified plan
1304
- - \`.5/features/{name}/state.json\` — Implementation resume state
1305
-
1306
- ## Guard Rules
1307
-
1308
- During the planning phase ($5-plan), until the user approves the plan:
1309
- - Do NOT write files outside \`.5/\`
1310
- - Do NOT write source code — only the unified plan and scan cache
1311
-
1312
- ## Scope Discipline (replaces the dependency-guard Stop hook)
1313
-
1314
- Before you report any task as done — inside or outside the workflow skills — check the uncommitted diff of dependency manifests (\`package.json\`, \`requirements*.txt\`, \`pyproject.toml\`, \`go.mod\`, \`Cargo.toml\`, \`Gemfile\`, \`composer.json\`, \`pom.xml\`, \`build.gradle\`, \`*.csproj\`). For every added dependency: keep it and name it in your reply if the user asked for it; otherwise remove it with the package manager and use existing code, the standard library, a native platform feature, or an installed dependency instead. For a deeper check, run \`$5-lean-check\`.
1315
-
1316
- ## Configuration
1317
-
1318
- Run \`$5-configure\` after installation to set up your project.
1319
-
1320
- ## Codex Token Budget
1321
-
1322
- Workflow skills use \`gpt-5.4-mini\` with low reasoning for exploration, orchestration, and simple executors by default. They escalate to \`gpt-5.4\` with medium reasoning only for complex logic, security-sensitive work, data migrations, public API changes, final verification that needs logic review, or retries after a cheaper attempt fails.
1323
-
1324
- ## Templates & References
1325
-
1326
- Templates are in \`.codex/templates/\` and references in \`.codex/references/\`.
1327
- Skills reference these paths for output formatting.
1328
- `;
1329
-
1330
- fs.writeFileSync(path.join(targetPath, 'instructions.md'), content);
1331
- log.success('Generated instructions.md');
1332
- }
1333
-
1334
1328
  // Install commands as Codex skills
1335
1329
  function installCodexSkills(targetPath, sourcePath) {
1336
- const commandsSrc = path.join(sourcePath, 'commands', '5');
1337
1330
  const skillsDest = path.join(targetPath, 'skills');
1331
+ const files = getCodexCommandFiles(sourcePath);
1332
+ if (files.length === 0) return;
1338
1333
 
1339
- if (!fs.existsSync(commandsSrc)) return;
1340
-
1341
- const files = fs.readdirSync(commandsSrc).filter(f => f.endsWith('.md'));
1342
-
1343
- for (const file of files) {
1344
- const name = file.replace('.md', '');
1334
+ for (const { name, file } of files) {
1345
1335
  const skillName = `5-${name}`;
1346
- const content = fs.readFileSync(path.join(commandsSrc, file), 'utf8');
1336
+ const content = fs.readFileSync(file, 'utf8');
1347
1337
  const converted = convertClaudeCommandToCodexSkill(content, skillName);
1348
1338
 
1349
1339
  const skillDir = path.join(skillsDest, skillName);
@@ -1354,7 +1344,7 @@ function installCodexSkills(targetPath, sourcePath) {
1354
1344
  }
1355
1345
  log.success(`Installed ${files.length} workflow skills`);
1356
1346
 
1357
- // Also convert and install original workflow skills (configure-docs-index, configure-skills, generate-readme)
1347
+ // Also convert and install the workflow's own skills (configure-*, review styles)
1358
1348
  const managed = getWorkflowManagedFiles();
1359
1349
  for (const skill of managed.skills) {
1360
1350
  const skillSrc = path.join(sourcePath, 'skills', skill);
@@ -1428,9 +1418,6 @@ function performCodexFreshInstall(targetPath, sourcePath, isGlobal) {
1428
1418
  copyWorkflowHelperBins(targetPath);
1429
1419
  log.success('Installed bin/ (workflow helper binaries)');
1430
1420
 
1431
- // Generate instructions.md (replaces hooks + settings.json)
1432
- generateCodexInstructions(targetPath);
1433
-
1434
1421
  // Initialize version tracking (shared .5/ directory)
1435
1422
  initializeVersionJson(isGlobal);
1436
1423
 
@@ -1442,8 +1429,7 @@ function performCodexFreshInstall(targetPath, sourcePath, isGlobal) {
1442
1429
  log.info('This will:');
1443
1430
  log.info(' • Detect your project type and build commands');
1444
1431
  log.info(' • Set up ticket tracking conventions');
1445
- log.info(' • Generate comprehensive documentation');
1446
- log.info(' • Create project-specific skills');
1432
+ log.info(' • Add the workflow rules to AGENTS.md as one marked block, linking your repository standards');
1447
1433
 
1448
1434
  showCommandsHelp(isGlobal);
1449
1435
  }
@@ -1455,14 +1441,9 @@ function codexSelectiveUpdate(targetPath, sourcePath) {
1455
1441
  const skillsDest = path.join(targetPath, 'skills');
1456
1442
 
1457
1443
  // Remove workflow command skills (5-*)
1458
- const commandsSrc = path.join(sourcePath, 'commands', '5');
1459
- if (fs.existsSync(commandsSrc)) {
1460
- const files = fs.readdirSync(commandsSrc).filter(f => f.endsWith('.md'));
1461
- for (const file of files) {
1462
- const name = file.replace('.md', '');
1463
- const skillDir = path.join(skillsDest, `5-${name}`);
1464
- if (fs.existsSync(skillDir)) removeDir(skillDir);
1465
- }
1444
+ for (const { name } of getCodexCommandFiles(sourcePath)) {
1445
+ const skillDir = path.join(skillsDest, `5-${name}`);
1446
+ if (fs.existsSync(skillDir)) removeDir(skillDir);
1466
1447
  }
1467
1448
 
1468
1449
  // Remove utility skills
@@ -1489,9 +1470,6 @@ function codexSelectiveUpdate(targetPath, sourcePath) {
1489
1470
  // Update helper binaries used by runtime commands
1490
1471
  copyWorkflowHelperBins(targetPath);
1491
1472
  log.success('Updated bin/ helper binaries');
1492
-
1493
- // Regenerate instructions.md
1494
- generateCodexInstructions(targetPath);
1495
1473
  }
1496
1474
 
1497
1475
  // Codex update
@@ -1511,6 +1489,9 @@ function performCodexUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
1511
1489
  // The plan-guard marker is shared .5/ state; Codex has no settings.json hook to remove
1512
1490
  removePlanningActiveMarker(dataDir);
1513
1491
 
1492
+ // Plans moved from .5/features/{name}/plan.md to .5/planning/{name}.md
1493
+ movePlansToPlanningDir(dataDir);
1494
+
1514
1495
  // Flag v1 → v2 major upgrade so skills can prompt for reconfigure
1515
1496
  const prevMajor = versionInfo.installed ? parseInt(versionInfo.installed.split('.')[0], 10) : 0;
1516
1497
  const newMajor = versionInfo.available ? parseInt(versionInfo.available.split('.')[0], 10) : 0;
@@ -1547,17 +1528,21 @@ function codexUninstall() {
1547
1528
  return;
1548
1529
  }
1549
1530
 
1531
+ // Remove workflow files retired from the package, which the current source no longer lists
1532
+ for (const entry of LEGACY_REMOVED_FILES) {
1533
+ const fullPath = path.join(targetPath, entry);
1534
+ if (!fs.existsSync(fullPath)) continue;
1535
+ if (fs.statSync(fullPath).isDirectory()) removeDir(fullPath);
1536
+ else fs.unlinkSync(fullPath);
1537
+ log.info(`Removed legacy orphan: ${entry}`);
1538
+ }
1539
+
1550
1540
  // Remove workflow command skills (5-*)
1551
- const commandsSrc = path.join(getSourcePath(), 'commands', '5');
1552
- if (fs.existsSync(commandsSrc)) {
1553
- const files = fs.readdirSync(commandsSrc).filter(f => f.endsWith('.md'));
1554
- for (const file of files) {
1555
- const name = file.replace('.md', '');
1556
- const skillDir = path.join(targetPath, 'skills', `5-${name}`);
1557
- if (fs.existsSync(skillDir)) removeDir(skillDir);
1558
- }
1559
- log.success('Removed workflow skills');
1541
+ for (const { name } of getCodexCommandFiles(getSourcePath())) {
1542
+ const skillDir = path.join(targetPath, 'skills', `5-${name}`);
1543
+ if (fs.existsSync(skillDir)) removeDir(skillDir);
1560
1544
  }
1545
+ log.success('Removed workflow skills');
1561
1546
 
1562
1547
  // Remove utility skills
1563
1548
  const managed = getWorkflowManagedFiles();
@@ -1603,7 +1588,7 @@ function codexUninstall() {
1603
1588
  log.success('Removed workflow helper binaries');
1604
1589
  }
1605
1590
 
1606
- // Remove instructions.md
1591
+ // Remove instructions.md left by earlier versions (Codex never read it; AGENTS.md carries the rules)
1607
1592
  const instructionsPath = path.join(targetPath, 'instructions.md');
1608
1593
  if (fs.existsSync(instructionsPath)) {
1609
1594
  fs.unlinkSync(instructionsPath);