omniconductor 0.5.0 → 1.0.1

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 (52) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/README.md +59 -19
  3. package/VISION.md +2 -2
  4. package/adapters/README.md +8 -8
  5. package/adapters/claude/README.md +3 -6
  6. package/adapters/claude/SUPPORTED-FEATURES.md +4 -4
  7. package/adapters/claude/metadata.json +39 -0
  8. package/adapters/claude/transform-spec.md +1 -1
  9. package/adapters/claude/transform.sh +208 -38
  10. package/adapters/codex/README.md +23 -27
  11. package/adapters/codex/metadata.json +35 -0
  12. package/adapters/codex/transform-spec.md +5 -6
  13. package/adapters/codex/transform.sh +284 -37
  14. package/adapters/copilot/README.md +26 -29
  15. package/adapters/copilot/metadata.json +36 -0
  16. package/adapters/copilot/transform.sh +126 -35
  17. package/adapters/cursor/README.md +31 -30
  18. package/adapters/cursor/metadata.json +35 -0
  19. package/adapters/cursor/transform.sh +117 -28
  20. package/adapters/gemini/README.md +14 -15
  21. package/adapters/gemini/metadata.json +36 -0
  22. package/adapters/gemini/transform.sh +312 -36
  23. package/adapters/windsurf/README.md +20 -19
  24. package/adapters/windsurf/metadata.json +36 -0
  25. package/adapters/windsurf/transform.sh +139 -55
  26. package/bin/doctor.js +257 -0
  27. package/bin/omniconductor.js +15 -2
  28. package/core/anti-patterns/frequent-rule-file-edit.md +1 -1
  29. package/core/anti-patterns/single-monolithic-rule-file.md +1 -1
  30. package/core/hooks/README.md +1 -0
  31. package/core/hooks/pretool-loop-guard.sh.template +177 -0
  32. package/core/recipes/README.md +6 -4
  33. package/core/recipes/loop-engineering.md +73 -0
  34. package/core/universal-rules/README.md +4 -4
  35. package/core/universal-rules/meta-discipline.md +4 -4
  36. package/core/universal-rules/spec-as-you-go.md +1 -1
  37. package/docs/ADAPTER-LIVE-VERIFICATION.md +73 -0
  38. package/docs/COMPARISON.md +133 -0
  39. package/docs/COMPATIBILITY-MATRIX.md +126 -0
  40. package/docs/DESIGN-DECISIONS.md +1268 -0
  41. package/docs/MANUAL-INSTALL.md +15 -15
  42. package/docs/PUBLICATION-POLICY.md +46 -0
  43. package/docs/PUBLISH-GUIDE.md +141 -0
  44. package/package.json +7 -1
  45. package/tools/check-adapter-metadata.sh +211 -0
  46. package/tools/check-stale-tokens.sh +130 -0
  47. package/tools/generate-adapter-docs.js +123 -0
  48. package/tools/live-verify.sh +195 -0
  49. package/tools/manifest-safety.sh +118 -0
  50. package/tools/stale-tokens.txt +32 -0
  51. package/tools/test-install-modes.sh +277 -0
  52. package/tools/validate-adapter-output.sh +1 -1
@@ -34,6 +34,7 @@ set -eu
34
34
 
35
35
  TARGET=""
36
36
  RECIPES=""
37
+ MODE="full"
37
38
  DRY_RUN="false"
38
39
  MEASURE_BASELINE="false"
39
40
  NO_PROMPT="false"
@@ -48,6 +49,7 @@ WIZARD_SHOW_ANTI_PATTERNS="false"
48
49
  while [ $# -gt 0 ]; do
49
50
  case "$1" in
50
51
  --recipes=*) RECIPES="${1#--recipes=}" ;;
52
+ --mode=*) MODE="${1#--mode=}" ;;
51
53
  --dry-run) DRY_RUN="true" ;;
52
54
  --measure-baseline) MEASURE_BASELINE="true" ;;
53
55
  --no-prompt) NO_PROMPT="true" ;;
@@ -60,6 +62,11 @@ Usage: bash adapters/claude/transform.sh <target-project> [options]
60
62
 
61
63
  Options:
62
64
  --recipes=A,B,C Comma-separated list of recipes to install
65
+ --mode=<m> Install preset (ADR-044): full (default) | minimal (rules + recipes
66
+ text + docs + CLAUDE.md; no agents/hooks/hookify) | strict (abort if
67
+ CLAUDE.md exists) | recipes-only (ONLY the selected recipe rule files;
68
+ requires --recipes=) | reflector-only (self-improvement loop standalone:
69
+ recipe + reflector agent + trajectory hook + /reflect)
63
70
  --dry-run Preview only — no files written
64
71
  --measure-baseline After install, measure cache token baseline (opt-in)
65
72
  --no-prompt Skip all interactive prompts; apply sensible defaults (CI-safe)
@@ -70,7 +77,7 @@ Options:
70
77
  manifest are preserved.
71
78
  --force Bypass uninstall safety checks (active worktrees, missing manifest)
72
79
 
73
- Recipes available: web-mobile-parity, i18n, monorepo, branch-strategy, auto-mock-data, coding-conventions, tdd, debugging, database-discipline, design-system, self-improvement, git-hygiene
80
+ Recipes available: web-mobile-parity, i18n, monorepo, branch-strategy, auto-mock-data, coding-conventions, tdd, debugging, database-discipline, design-system, self-improvement, git-hygiene, loop-engineering
74
81
  EOF
75
82
  exit 0
76
83
  ;;
@@ -92,12 +99,32 @@ if [ -z "$TARGET" ]; then
92
99
  exit 1
93
100
  fi
94
101
 
102
+ case "$MODE" in
103
+ full|minimal|strict|recipes-only|reflector-only) : ;;
104
+ *) echo "Error: unknown --mode '$MODE' (one of: full, minimal, strict, recipes-only, reflector-only)" >&2; exit 1 ;;
105
+ esac
106
+ if [ "$MODE" = "reflector-only" ]; then
107
+ if [ -n "$RECIPES" ] && [ "$RECIPES" != "self-improvement" ]; then
108
+ echo "NOTE: --mode=reflector-only ignores --recipes (installs self-improvement only)" >&2
109
+ fi
110
+ RECIPES="self-improvement"
111
+ fi
112
+ if [ "$MODE" = "recipes-only" ] && [ -z "$RECIPES" ] && [ "$UNINSTALL" != "true" ]; then
113
+ echo "Error: --mode=recipes-only requires --recipes=A,B,..." >&2
114
+ exit 1
115
+ fi
116
+
95
117
  # Resolve CONDUCTOR root (where this script lives: adapters/claude/).
96
118
  CONDUCTOR_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
97
119
  CORE_ROOT="$CONDUCTOR_ROOT/core"
98
120
  TOOLS_ROOT="$CONDUCTOR_ROOT/tools"
99
121
  [ -d "$CORE_ROOT" ] || { echo "Error: core/ not found at $CORE_ROOT" >&2; exit 1; }
100
122
 
123
+ # CONDUCTOR package version for the manifest — parsed at runtime from package.json
124
+ # so releases never drift the manifest (falls back to "unknown" on any error).
125
+ CONDUCTOR_VERSION="$(/usr/bin/sed -n -E 's/^[[:space:]]*"version"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/p' "$CONDUCTOR_ROOT/package.json" 2>/dev/null | /usr/bin/head -n 1)"
126
+ [ -n "$CONDUCTOR_VERSION" ] || CONDUCTOR_VERSION="unknown"
127
+
101
128
  if [ "$DRY_RUN" = "true" ]; then
102
129
  mkdir -p "$TARGET"
103
130
  fi
@@ -243,7 +270,7 @@ backup_if_exists() {
243
270
  # Manifest is generated using only POSIX shell (no jq dependency). Format:
244
271
  #
245
272
  # {
246
- # "version": "v0.2.0",
273
+ # "version": "v<CONDUCTOR package.json version>",
247
274
  # "install_timestamp": "2026-05-10T12:00:00Z",
248
275
  # "conductor_root": "/abs/path/to/conductor",
249
276
  # "recipes_enabled": ["monorepo", "i18n"],
@@ -267,6 +294,9 @@ MANIFEST_STAGE_PATH="" # set by init_manifest()
267
294
  MANIFEST_TS="" # ISO-8601 install timestamp (set by init_manifest)
268
295
  MANIFEST_LAST_BACKUP="" # backup_if_exists writes the backup path here; emit helpers read it
269
296
 
297
+ # shellcheck source=../../tools/manifest-safety.sh
298
+ . "$CONDUCTOR_ROOT/tools/manifest-safety.sh"
299
+
270
300
  init_manifest() {
271
301
  # Called once at install start (after wizard, before any emit).
272
302
  if [ "$DRY_RUN" = "true" ]; then
@@ -289,12 +319,13 @@ record_emit() {
289
319
  local had_backup="false"
290
320
  [ -n "$backup" ] && had_backup="true"
291
321
  # Escape backslashes and double quotes for JSON.
292
- local esc_path esc_src esc_backup
322
+ local esc_path esc_src esc_backup emitted_sha
293
323
  esc_path="$(printf '%s' "$relpath" | /usr/bin/sed 's/\\/\\\\/g; s/"/\\"/g')"
294
324
  esc_src="$(printf '%s' "$src" | /usr/bin/sed 's/\\/\\\\/g; s/"/\\"/g')"
295
325
  esc_backup="$(printf '%s' "$backup" | /usr/bin/sed 's/\\/\\\\/g; s/"/\\"/g')"
296
- printf ' {"path": "%s", "source": "%s", "had_backup": %s, "backup_path": "%s"},\n' \
297
- "$esc_path" "$esc_src" "$had_backup" "$esc_backup" >> "$MANIFEST_STAGE_PATH"
326
+ emitted_sha="$(conductor_sha256_file "$TARGET_ABS/$relpath")"
327
+ printf ' {"path": "%s", "source": "%s", "had_backup": %s, "backup_path": "%s", "sha256": "%s"},\n' \
328
+ "$esc_path" "$esc_src" "$had_backup" "$esc_backup" "$emitted_sha" >> "$MANIFEST_STAGE_PATH"
298
329
  }
299
330
 
300
331
  finalize_manifest() {
@@ -343,7 +374,9 @@ finalize_manifest() {
343
374
 
344
375
  /bin/cat > "$MANIFEST_PATH" <<EOF
345
376
  {
346
- "version": "v0.2.0",
377
+ "version": "v$CONDUCTOR_VERSION",
378
+ "adapter": "claude",
379
+ "mode": "$MODE",
347
380
  "install_timestamp": "$MANIFEST_TS",
348
381
  "conductor_root": "$CONDUCTOR_ROOT",
349
382
  "recipes_enabled": $recipes_json,
@@ -359,21 +392,19 @@ EOF
359
392
  # Wrappers around backup_if_exists / cp / write that also remember the backup path so the
360
393
  # next record_emit() call can reference it. Keeps emit-step changes minimal.
361
394
  backup_and_remember() {
362
- # backup_and_remember <dest>
363
- MANIFEST_LAST_BACKUP=""
364
- if [ -f "$1" ]; then
365
- if [ "$DRY_RUN" = "true" ]; then
366
- log "would back up existing $1 -> $1.conductor-backup-<ts>"
367
- MANIFEST_LAST_BACKUP=""
368
- else
369
- local ts
370
- ts="$(/bin/date +%Y%m%d-%H%M%S)"
371
- local backup="$1.conductor-backup-$ts"
372
- /bin/cp "$1" "$backup"
373
- log " backed up existing $1 -> $backup"
374
- # Store relative-to-target path for portability.
375
- MANIFEST_LAST_BACKUP="${backup#$TARGET_ABS/}"
376
- fi
395
+ conductor_manifest_backup_and_remember "$1"
396
+ }
397
+
398
+ # ----- framework detection (ADR-044 suggest, NEVER auto-switch) ----------
399
+
400
+ detect_coexisting_frameworks() {
401
+ local found=""
402
+ [ -d "$TARGET_ABS/.specify" ] && found="$found Spec-Kit"
403
+ { [ -d "$TARGET_ABS/_bmad" ] || [ -d "$TARGET_ABS/.bmad-core" ]; } && found="$found BMAD"
404
+ if [ -n "$found" ] && [ "$MODE" = "full" ]; then
405
+ log "NOTE: detected coexisting framework(s):$found"
406
+ log " Consider --mode=recipes-only or --mode=reflector-only to coexist without"
407
+ log " overlapping workflow rules (suggestion only — nothing was changed)."
377
408
  fi
378
409
  }
379
410
 
@@ -424,6 +455,7 @@ do_uninstall() {
424
455
  local restored=0
425
456
  local deleted=0
426
457
  local missing=0
458
+ local preserved=0
427
459
 
428
460
  # Iterate manifest entries by line. Tolerate trailing comma absence on last entry.
429
461
  while IFS= read -r line; do
@@ -433,16 +465,27 @@ do_uninstall() {
433
465
  *) continue ;;
434
466
  esac
435
467
  entries_count=$((entries_count + 1))
436
- local rel_path src had_backup backup_path
468
+ local rel_path src had_backup backup_path expected_sha
437
469
  rel_path="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"path": *"([^"]*)".*/\1/')"
438
470
  src="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"source": *"([^"]*)".*/\1/')"
439
471
  had_backup="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"had_backup": *(true|false).*/\1/')"
440
472
  backup_path="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"backup_path": *"([^"]*)".*/\1/')"
473
+ expected_sha="$(conductor_manifest_field "$line" sha256 2>/dev/null || true)"
441
474
 
442
475
  local abs_dest="$TARGET_ABS/$rel_path"
443
476
  local abs_backup=""
444
477
  [ -n "$backup_path" ] && abs_backup="$TARGET_ABS/$backup_path"
445
478
 
479
+ if [ -f "$abs_dest" ] && ! conductor_manifest_file_matches "$abs_dest" "$expected_sha"; then
480
+ if [ -z "$expected_sha" ]; then
481
+ log " WARNING: preserving $rel_path (legacy manifest has no checksum)"
482
+ else
483
+ log " WARNING: preserving user-modified $rel_path"
484
+ fi
485
+ preserved=$((preserved + 1))
486
+ continue
487
+ fi
488
+
446
489
  if [ "$had_backup" = "true" ] && [ -n "$abs_backup" ]; then
447
490
  if [ -f "$abs_backup" ]; then
448
491
  if [ "$DRY_RUN" = "true" ]; then
@@ -518,6 +561,7 @@ do_uninstall() {
518
561
  echo " Backups restored: $restored"
519
562
  echo " Files deleted: $deleted"
520
563
  echo " Backup-missing deletes: $missing"
564
+ [ "$preserved" -gt 0 ] && echo " User-modified files preserved: $preserved"
521
565
  echo "========================================================"
522
566
  }
523
567
 
@@ -565,6 +609,26 @@ if [ -d "$TARGET_ABS/.claude" ] || [ -f "$TARGET_ABS/CLAUDE.md" ]; then
565
609
  IS_ADOPTER_CASE="true"
566
610
  fi
567
611
 
612
+ detect_coexisting_frameworks
613
+
614
+ # --mode=strict: never overwrite an existing baseline, even with a backup (ADR-044).
615
+ if [ "$MODE" = "strict" ]; then
616
+ if [ -f "$TARGET_ABS/CLAUDE.md" ]; then
617
+ echo "Error (--mode=strict): $TARGET_ABS/CLAUDE.md already exists — strict mode aborts instead of overwriting a baseline." >&2
618
+ echo " Use --mode=full (timestamped backup + manifest-based restore), or move the file first." >&2
619
+ exit 3
620
+ fi
621
+ if [ -d "$TARGET_ABS/.claude/rules" ] && [ -n "$(/bin/ls -A "$TARGET_ABS/.claude/rules" 2>/dev/null)" ]; then
622
+ echo "Error (--mode=strict): $TARGET_ABS/.claude/rules/ already has files — strict mode never writes next to an existing rules surface." >&2
623
+ exit 3
624
+ fi
625
+ fi
626
+
627
+ # À-la-carte modes are non-interactive by design.
628
+ if [ "$MODE" != "full" ] && [ "$MODE" != "strict" ]; then
629
+ NO_PROMPT="true"
630
+ fi
631
+
568
632
  if [ "$IS_ADOPTER_CASE" = "true" ] && [ "$NO_PROMPT" = "false" ] && [ "$DRY_RUN" = "false" ]; then
569
633
  echo ""
570
634
  echo "========================================================"
@@ -593,7 +657,7 @@ if [ "$IS_ADOPTER_CASE" = "true" ] && [ "$NO_PROMPT" = "false" ] && [ "$DRY_RUN"
593
657
  # 3. Select recipes
594
658
  echo ""
595
659
  echo "Available recipes:"
596
- echo " web-mobile-parity, i18n, monorepo, branch-strategy, auto-mock-data, coding-conventions, tdd, debugging, database-discipline, design-system, self-improvement, git-hygiene"
660
+ echo " web-mobile-parity, i18n, monorepo, branch-strategy, auto-mock-data, coding-conventions, tdd, debugging, database-discipline, design-system, self-improvement, git-hygiene, loop-engineering"
597
661
  printf "Select recipes (comma-separated, or leave blank for none): "
598
662
  read -r _recipe_answer
599
663
  if [ -n "$_recipe_answer" ]; then
@@ -633,7 +697,9 @@ fi
633
697
  # Initialize manifest before any emit happens.
634
698
  init_manifest
635
699
 
636
- if [ "$WIZARD_APPLY_RULES" = "true" ]; then
700
+ if [ "$MODE" = "recipes-only" ] || [ "$MODE" = "reflector-only" ]; then
701
+ log "Step 1/6: universal-rules — skipped (--mode=$MODE is à la carte)"
702
+ elif [ "$WIZARD_APPLY_RULES" = "true" ]; then
637
703
  log "Step 1/6: universal-rules → .claude/rules/"
638
704
  mkdir_if_real "$TARGET_ABS/.claude/rules"
639
705
 
@@ -654,9 +720,16 @@ fi
654
720
 
655
721
  # ----- step 2: roles -----------------------------------------------------
656
722
 
657
- if [ "$WIZARD_APPLY_RULES" = "true" ]; then
723
+ if [ "$MODE" = "minimal" ]; then
724
+ log "Step 2/6: roles — skipped (--mode=minimal ships text only)"
725
+ elif [ "$WIZARD_APPLY_RULES" = "true" ]; then
658
726
  log "Step 2/6: roles → .claude/agents/"
659
- mkdir_if_real "$TARGET_ABS/.claude/agents"
727
+ # À la carte without self-improvement must not leave an empty .claude/agents/.
728
+ if [ "$MODE" != "recipes-only" ] && [ "$MODE" != "reflector-only" ]; then
729
+ mkdir_if_real "$TARGET_ABS/.claude/agents"
730
+ else
731
+ case ",$RECIPES," in *",self-improvement,"*) mkdir_if_real "$TARGET_ABS/.claude/agents" ;; esac
732
+ fi
660
733
 
661
734
  # Map each universal role to Claude-native agent frontmatter.
662
735
  declare_agent() {
@@ -683,12 +756,16 @@ EOF
683
756
  record_emit ".claude/agents/$role.md" "core/roles/$role.md" "$MANIFEST_LAST_BACKUP"
684
757
  }
685
758
 
759
+ if [ "$MODE" != "recipes-only" ] && [ "$MODE" != "reflector-only" ]; then
686
760
  declare_agent planner "Architecture, gap analysis, ADRs, trade-off decisions. No implementation code." opus
687
761
  declare_agent builder "Multi-file or cross-cutting code implementation (3+ files)." opus
688
762
  declare_agent reviewer "Plan validation before implementation. Read-only gatekeeper." opus
689
763
  declare_agent helper "Single-file or 1-2-file work where the pattern is established." sonnet
690
764
  declare_agent designer "UI / UX implementation. Visual components, design tokens, accessibility." sonnet
691
765
  declare_agent scribe "Documentation sync after implementation. No code edits." sonnet
766
+ else
767
+ log " (à la carte — the 6 universal role agents skipped)"
768
+ fi
692
769
  case ",$RECIPES," in *",self-improvement,"*)
693
770
  declare_agent reflector "Reads session trajectories; proposes atomic lesson deltas for human approval. No code, no auto-apply." opus ;;
694
771
  esac
@@ -699,7 +776,9 @@ fi
699
776
  # ----- step 3: recipes (opt-in) ------------------------------------------
700
777
 
701
778
  log "Step 3/6: recipes (opt-in) → .claude/rules/"
779
+ RECIPES_EMITTED=0
702
780
  if [ -n "$RECIPES" ]; then
781
+ mkdir_if_real "$TARGET_ABS/.claude/rules"
703
782
  IFS=',' read -ra RECIPE_LIST <<< "$RECIPES"
704
783
  for r in "${RECIPE_LIST[@]}"; do
705
784
  src="$CORE_ROOT/recipes/$r.md"
@@ -711,21 +790,72 @@ if [ -n "$RECIPES" ]; then
711
790
  backup_and_remember "$dest"
712
791
  copy_with_paths_frontmatter "$src" "$dest" "**"
713
792
  record_emit ".claude/rules/$r.md" "core/recipes/$r.md" "$MANIFEST_LAST_BACKUP"
793
+ RECIPES_EMITTED=$((RECIPES_EMITTED + 1))
714
794
  done
715
795
  else
716
796
  log " (no recipes selected — pass --recipes=name1,name2 to install)"
717
797
  fi
798
+ if [ "$MODE" = "recipes-only" ] && [ "${RECIPES_EMITTED:-0}" -eq 0 ] && [ "$DRY_RUN" != "true" ]; then
799
+ echo "Error: --mode=recipes-only resolved ZERO valid recipes from '--recipes=$RECIPES' — nothing to install (check the names)." >&2
800
+ /bin/rm -f "$MANIFEST_STAGE_PATH"
801
+ exit 1
802
+ fi
718
803
 
719
804
  # ----- step 4: hooks + settings.json -------------------------------------
720
805
 
806
+ INSTALLED_HOOKS=()
807
+
808
+ if [ "$MODE" = "minimal" ]; then
809
+ log "Step 4/6: hooks + settings.json — skipped (--mode=minimal ships text only)"
810
+ elif [ "$MODE" = "recipes-only" ] || [ "$MODE" = "reflector-only" ]; then
811
+ # À la carte: only the Reflector's trajectory hook (when self-improvement is selected).
812
+ case ",$RECIPES," in
813
+ *",self-improvement,"*)
814
+ log "Step 4/6: hooks — à la carte: stop-trajectory-log only (--mode=$MODE)"
815
+ mkdir_if_real "$TARGET_ABS/.claude/hooks"
816
+ src="$CORE_ROOT/hooks/stop-trajectory-log.sh.template"
817
+ dest="$TARGET_ABS/.claude/hooks/stop-trajectory-log.sh"
818
+ if [ -f "$src" ]; then
819
+ backup_and_remember "$dest"
820
+ substitute_template "$src" "$dest"
821
+ record_emit ".claude/hooks/stop-trajectory-log.sh" "core/hooks/stop-trajectory-log.sh.template" "$MANIFEST_LAST_BACKUP"
822
+ fi
823
+ SETTINGS_PATH="$TARGET_ABS/.claude/settings.json"
824
+ if [ -f "$SETTINGS_PATH" ]; then
825
+ log " $SETTINGS_PATH exists — add the Stop hook manually: \"\$CLAUDE_PROJECT_DIR\"/.claude/hooks/stop-trajectory-log.sh"
826
+ elif [ "$DRY_RUN" = "true" ]; then
827
+ log "would write minimal $SETTINGS_PATH (trajectory Stop hook only)"
828
+ else
829
+ /bin/cat > "$SETTINGS_PATH" <<'MINSETTINGS_EOF'
830
+ {
831
+ "$comment": "Minimal project settings generated by CONDUCTOR (à-la-carte mode): registers only the Reflector trajectory Stop hook.",
832
+ "hooks": {
833
+ "Stop": [
834
+ {
835
+ "hooks": [
836
+ { "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/stop-trajectory-log.sh" }
837
+ ]
838
+ }
839
+ ]
840
+ }
841
+ }
842
+ MINSETTINGS_EOF
843
+ log " wrote minimal $SETTINGS_PATH (trajectory Stop hook only)"
844
+ record_emit ".claude/settings.json" "<synthesized:minimal>" ""
845
+ fi
846
+ ;;
847
+ *)
848
+ log "Step 4/6: hooks — skipped (--mode=$MODE without self-improvement)"
849
+ ;;
850
+ esac
851
+ else
721
852
  log "Step 4/6: hooks → .claude/hooks/"
722
853
  mkdir_if_real "$TARGET_ABS/.claude/hooks"
723
854
 
724
855
  # Core hooks (always emitted when template exists). Optional hooks (cache-hit baseline, large-file
725
856
  # read guard) emit only if their templates are present in the CONDUCTOR core/ tree, allowing the
726
857
  # adapter to remain forward-compatible with P1.7 work in progress.
727
- INSTALLED_HOOKS=()
728
- for hook in pretool-agent-routing stop-session-log-check stop-r6-review-check stop-cache-hit-baseline-check pretool-large-file-read-guard pretool-commit-current-work-check pretool-commit-test-coverage-check stop-trajectory-log stop-git-hygiene-guard; do
858
+ for hook in pretool-agent-routing stop-session-log-check stop-r6-review-check stop-cache-hit-baseline-check pretool-large-file-read-guard pretool-commit-current-work-check pretool-commit-test-coverage-check stop-trajectory-log stop-git-hygiene-guard pretool-loop-guard; do
729
859
  src="$CORE_ROOT/hooks/$hook.sh.template"
730
860
  dest="$TARGET_ABS/.claude/hooks/$hook.sh"
731
861
  if [ ! -f "$src" ]; then
@@ -796,6 +926,12 @@ else
796
926
  "hooks": [
797
927
  { "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/pretool-large-file-read-guard.sh" }
798
928
  ]
929
+ },
930
+ {
931
+ "matcher": "*",
932
+ "hooks": [
933
+ { "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/pretool-loop-guard.sh" }
934
+ ]
799
935
  }
800
936
  ],
801
937
  "Stop": [
@@ -812,9 +948,10 @@ else
812
948
  }
813
949
  }
814
950
  SETTINGS_EOF
815
- log " wrote $SETTINGS_PATH ($(printf '%s' "${INSTALLED_HOOKS[*]}" | /usr/bin/wc -w | /usr/bin/tr -d ' ') hook(s) installed in .claude/hooks; settings.json registers 9 core hooks: 4 PreToolUse + 5 Stop)"
951
+ log " wrote $SETTINGS_PATH ($(printf '%s' "${INSTALLED_HOOKS[*]}" | /usr/bin/wc -w | /usr/bin/tr -d ' ') hook(s) installed in .claude/hooks; settings.json registers 10 core hooks: 5 PreToolUse + 5 Stop)"
816
952
  record_emit ".claude/settings.json" "<synthesized>" ""
817
953
  fi
954
+ fi
818
955
 
819
956
  # ----- step 4.5: hookify rule templates ----------------------------------
820
957
  #
@@ -827,7 +964,9 @@ fi
827
964
  # Forward-compat: silent skip if the hookify-templates directory is empty or missing.
828
965
 
829
966
  HOOKIFY_TEMPLATE_DIR="$CONDUCTOR_ROOT/adapters/claude/hookify-templates"
830
- if [ -d "$HOOKIFY_TEMPLATE_DIR" ]; then
967
+ if [ "$MODE" != "full" ] && [ "$MODE" != "strict" ]; then
968
+ log "Step 4.5/6: hookify rules — skipped (--mode=$MODE)"
969
+ elif [ -d "$HOOKIFY_TEMPLATE_DIR" ]; then
831
970
  log "Step 4.5/6: hookify rules → .claude/hookify.*.local.md"
832
971
  HOOKIFY_INSTALLED=0
833
972
  HOOKIFY_SKIPPED=0
@@ -860,7 +999,13 @@ if [ -d "$HOOKIFY_TEMPLATE_DIR" ]; then
860
999
  fi
861
1000
 
862
1001
  # ---- Step 4.6: self-improvement runtime artifacts (only when recipe selected) ----
863
- case ",$RECIPES," in
1002
+ if [ "$MODE" = "minimal" ]; then
1003
+ RECIPES_FOR_RUNTIME=""
1004
+ log "Step 4.6: self-improvement runtime — skipped (--mode=minimal ships text only)"
1005
+ else
1006
+ RECIPES_FOR_RUNTIME="$RECIPES"
1007
+ fi
1008
+ case ",$RECIPES_FOR_RUNTIME," in
864
1009
  *",self-improvement,"*)
865
1010
  log "Step 4.6: emitting self-improvement runtime (prune script + /reflect command)"
866
1011
  # prune script → .conductor/reflect/prune-lessons.sh
@@ -923,6 +1068,9 @@ esac
923
1068
 
924
1069
  # ----- step 5: docs templates --------------------------------------------
925
1070
 
1071
+ if [ "$MODE" = "recipes-only" ] || [ "$MODE" = "reflector-only" ]; then
1072
+ log "Step 5/6: docs templates — skipped (--mode=$MODE is à la carte)"
1073
+ else
926
1074
  log "Step 5/6: docs templates → docs/"
927
1075
  mkdir_if_real "$TARGET_ABS/docs"
928
1076
  mkdir_if_real "$TARGET_ABS/docs/specs"
@@ -956,8 +1104,13 @@ if [ -f "$CORE_ROOT/docs-templates/specs/_example.md" ]; then
956
1104
  fi
957
1105
  fi
958
1106
 
1107
+ fi
1108
+
959
1109
  # ----- step 6: synthesize CLAUDE.md --------------------------------------
960
1110
 
1111
+ if [ "$MODE" = "recipes-only" ] || [ "$MODE" = "reflector-only" ]; then
1112
+ log "Step 6/6: CLAUDE.md — skipped (--mode=$MODE is à la carte)"
1113
+ else
961
1114
  log "Step 6/6: synthesize CLAUDE.md"
962
1115
  CLAUDE_MD="$TARGET_ABS/CLAUDE.md"
963
1116
 
@@ -1044,6 +1197,8 @@ else
1044
1197
  fi
1045
1198
 
1046
1199
  # Finalize manifest now that all emits are complete (before optional baseline measurement).
1200
+ fi
1201
+
1047
1202
  finalize_manifest
1048
1203
 
1049
1204
  # ----- step 7 (optional): baseline measurement ---------------------------
@@ -1151,20 +1306,35 @@ echo ""
1151
1306
  echo "========================================================"
1152
1307
  echo " Done."
1153
1308
  echo " Target: $TARGET_ABS"
1154
- echo " Universal rules: 5"
1155
- case ",$RECIPES," in
1156
- *",self-improvement,"*) echo " Roles: 7 (incl. reflector)" ;;
1157
- *) echo " Roles: 6" ;;
1158
- esac
1309
+ echo " Mode: $MODE"
1310
+ if [ "$MODE" = "recipes-only" ] || [ "$MODE" = "reflector-only" ]; then
1311
+ echo " Universal rules: 0 (à la carte)"
1312
+ case ",$RECIPES," in
1313
+ *",self-improvement,"*) echo " Roles: 1 (reflector only)" ;;
1314
+ *) echo " Roles: 0" ;;
1315
+ esac
1316
+ else
1317
+ echo " Universal rules: 5"
1318
+ if [ "$MODE" = "minimal" ]; then
1319
+ echo " Roles: 0 (--mode=minimal)"
1320
+ else
1321
+ case ",$RECIPES," in
1322
+ *",self-improvement,"*) echo " Roles: 7 (incl. reflector)" ;;
1323
+ *) echo " Roles: 6" ;;
1324
+ esac
1325
+ fi
1326
+ fi
1159
1327
  echo " Recipes installed: ${RECIPES:-(none)}"
1160
1328
  echo " Hooks: ${#INSTALLED_HOOKS[@]} (${INSTALLED_HOOKS[*]:-none})"
1161
- echo " Settings: .claude/settings.json (permissions allowlist + hooks registry)"
1329
+ if [ -f "$TARGET_ABS/.claude/settings.json" ]; then
1330
+ echo " Settings: .claude/settings.json (permissions allowlist + hooks registry)"
1331
+ fi
1162
1332
  echo ""
1163
1333
  echo " Run \`claude\` (Claude Code restart) to activate new rules."
1164
1334
  echo "========================================================"
1165
1335
  echo ""
1166
1336
  echo "Next steps for the project:"
1167
1337
  echo " 1. Open $TARGET_ABS in Claude Code."
1168
- echo " 2. Edit docs/CURRENT_WORK.md with your project's current state."
1338
+ [ -d "$TARGET_ABS/docs" ] && echo " 2. Edit docs/CURRENT_WORK.md with your project's current state."
1169
1339
  echo " 3. Edit CLAUDE.md if you have project-specific orchestrator rules to add."
1170
1340
  echo " 4. Verify hook installation: ls -la $TARGET_ABS/.claude/hooks/"
@@ -1,20 +1,16 @@
1
- # Adapter — Codex (T3)
1
+ # Adapter — Codex (T2)
2
2
 
3
- OpenAI Codex (the modern shell-driven agent — not the deprecated original Codex API) is a T3 target because:
3
+ OpenAI Codex (the modern shell-driven agent — not the deprecated original Codex API) is a T2 target because:
4
4
 
5
- - It supports a single project rules file at `AGENTS.md` (project root — the established cross-agent convention).
6
- - It excels at shell-driven scripting and one-shot tasks.
5
+ - It supports a single project rules file at `AGENTS.md` (project root — the established cross-agent convention), auto-loaded on session start.
6
+ - It excels at shell-driven scripting and agentic terminal work.
7
7
 
8
- It is **T3** because:
8
+ **Tool capability vs CONDUCTOR emission (ADR-031):** as of 2026 Codex ships hooks (default-on), sub-agent dispatch, custom agents, per-task model routing, commands, and built-in managed memory. What is limited today is what CONDUCTOR **emits** for it — rule text + docs + the opt-in Reflector loop; the enforcement guard hooks, role agents, and model-routing config are Phase-2 emission (ADR-034). That is a CONDUCTOR gap, not a Codex limitation. Real tool-side caveat: rules scope by nested-file hierarchy, not glob — the adapter bundles everything into one `AGENTS.md`.
9
9
 
10
- - No per-pattern rule scoping.
11
- - ❌ No sub-agent dispatch.
12
- - No hooks.
13
- - ❌ No per-call model routing.
14
- - ❌ No built-in memory directory.
15
- - ⚠️ Limited multi-step orchestration capability vs Claude/Cursor.
10
+ **Tier**: T2 (see `docs/COMPATIBILITY-MATRIX.md`). Live-verified via the automated headless probe (`tools/live-verify.sh` current status in `docs/ADAPTER-LIVE-VERIFICATION.md`).
11
+
12
+ > Enumerable facts about this adapter (output paths / tier / capabilities / live verification / headless CLI) are machine-readable in [`metadata.json`](./metadata.json) and CI-checked against `transform.sh` + the validator (ADR-040).
16
13
 
17
- **Tier**: T3 — Basic. Rule TEXT installs but most CONDUCTOR mechanism doesn't apply.
18
14
 
19
15
  ## Installation path
20
16
 
@@ -39,37 +35,37 @@ bash adapters/codex/transform.sh <target> --uninstall # revert (man
39
35
  └── specs/_example.md
40
36
  ```
41
37
 
42
- ## Native features supported
38
+ - `--recipes=self-improvement` additionally emits the Reflector loop: session-end trajectory hook config (`.codex/hooks.json`), `/reflect` command, reflector agent, prune script, and the `.conductor/reflect/` weekly runner (ADR-032/033).
39
+
40
+ ## Native features supported (emitted today)
43
41
 
44
42
  - ✅ Always-loaded baseline (`AGENTS.md`).
45
43
  - ✅ All universal rule TEXT.
46
44
  - ✅ All doc templates.
45
+ - ✅ Reflector loop (opt-in recipe).
47
46
  - ✅ Strong shell-task execution (Codex's primary strength).
48
47
 
49
- ## Features NOT supported
48
+ ## Not emitted yet (Phase 2 — Codex supports these natively, ADR-031/034)
50
49
 
51
- | Feature | Workaround |
50
+ | Feature | Interim workaround |
52
51
  |---|---|
53
- | Per-pattern rule scoping | All rules always-loaded. |
54
- | Sub-agent dispatch | Human plays orchestrator (or breaks task into sequential prompts). |
55
- | Hooks | Pair with project pre-commit git hooks. |
56
- | Per-call model routing | Single model per Codex invocation. |
57
- | Built-in memory directory | DIY at `.memory/`. |
58
- | Multi-step orchestration | Limited — Codex shines at one-shot shell tasks. For multi-step, use Claude/Cursor. |
52
+ | Per-pattern rule scoping | All rules always-loaded in one `AGENTS.md` (Codex scopes by nested-file hierarchy, not globs). |
53
+ | Enforcement guard hooks | Self-police, or pair with project pre-commit git hooks. Only the Reflector session-end hook is emitted today (`--recipes=self-improvement`). |
54
+ | The 6 role agents (sub-agent dispatch) | Codex has native sub-agents; CONDUCTOR doesn't emit its role definitions for Codex yet. Human plays orchestrator. |
55
+ | Per-call model-routing config | Pick the model per invocation via Codex's own model selection. |
56
+ | 4-type memory pattern | Self-managed at `.memory/` (gitignored); Codex's built-in managed memory is separate. |
59
57
 
60
58
  ## Best fit use cases
61
59
 
62
- - Shell scripts.
63
- - One-shot file transformations.
64
- - Quick git operations.
65
- - "Run this command and tell me the output" tasks.
60
+ - Shell-driven agentic work and scripting.
61
+ - One-shot file transformations and quick git operations.
62
+ - Headless automation (`codex exec` — the Reflector weekly runner uses it).
66
63
 
67
64
  ## After install — first steps
68
65
 
69
66
  1. Verify Codex reads `AGENTS.md` (auto-loaded from project root on session start).
70
67
  2. Customize `AGENTS.md` for your project as needed.
71
68
  3. Add `.memory/` to `.gitignore`.
72
- 4. Use Codex for shell tasks; rely on Claude/Cursor for multi-step orchestration.
73
69
 
74
70
  ## Quirks / known issues
75
71
 
@@ -84,4 +80,4 @@ bash adapters/codex/transform.sh <target> --uninstall # revert (man
84
80
  - ✅ `SUPPORTED-FEATURES.md`
85
81
  - ✅ `transform-spec.md`
86
82
  - ✅ `transform.sh` (implemented — single-file `AGENTS.md` bundle, recipes, dry-run, manifest-based uninstall)
87
- - `notes.md` (real-Codex install verification deferred)
83
+ - Live-verified (auto-probe `tools/live-verify.sh` see `docs/ADAPTER-LIVE-VERIFICATION.md`)
@@ -0,0 +1,35 @@
1
+ {
2
+ "_comment": "Single source for enumerable adapter facts (ADR-040). CI asserts transform.sh / validator / matrix agree with this file. Update HERE first; docs follow.",
3
+ "tool": "codex",
4
+ "display_name": "Codex",
5
+ "tier": "T2",
6
+ "outputs": [
7
+ { "path": "AGENTS.md", "kind": "always_loaded", "validated": true },
8
+ { "path": "docs/CURRENT_WORK.md", "kind": "docs", "validated": false }
9
+ ],
10
+ "reflector_outputs": [
11
+ { "path": ".codex/hooks.json", "note": "Stop trajectory hook config (recipe-gated)" },
12
+ { "path": ".conductor/reflect", "note": "runner + brief + scheduling (recipe-gated)" }
13
+ ],
14
+ "install": { "ala_carte": "block" },
15
+ "legacy_paths": [".codex/codex.md"],
16
+ "capabilities": {
17
+ "tool_native": {
18
+ "hooks": "yes",
19
+ "sub_agents": "yes",
20
+ "model_routing": "yes",
21
+ "commands": "yes",
22
+ "glob_scoping": "no",
23
+ "scheduler": "local"
24
+ },
25
+ "conductor_emitted": {
26
+ "rules": "full",
27
+ "guard_hooks": "none",
28
+ "reflector_loop": "recipe",
29
+ "role_agents": "none",
30
+ "model_routing": "none"
31
+ }
32
+ },
33
+ "live_verification": { "status": "verified", "date": "2026-07-09", "cli": "codex-cli 0.144.0", "note": "headless probe listed 4/5 rules + read-CURRENT_WORK-first" },
34
+ "headless_cli": { "command": "codex", "invocation": "codex exec" }
35
+ }
@@ -41,7 +41,7 @@ adapters/codex/_native/codex.md.tpl # Header template (Codex-flavor
41
41
  └── specs/_example.md
42
42
  ```
43
43
 
44
- ## `.codex/codex.md` composition (in order)
44
+ ## `AGENTS.md` composition (in order)
45
45
 
46
46
  1. **Header from `_native/codex.md.tpl`** — bilingual (한/영) intro adapted for Codex (one-shot model, shell-task strength).
47
47
  2. **ABSOLUTE rules section** — R1-R8 minus Claude-only sub-agent enforcement. R-prefix renumbered.
@@ -60,9 +60,8 @@ Same as Gemini adapter — strip front-matter, concatenate, replace tool-specifi
60
60
 
61
61
  | Case | Adapter behavior |
62
62
  |---|---|
63
- | `.codex/` doesn't exist | Create it. |
64
- | Existing `.codex/codex.md` | Skip; report "SKIP (exists)". |
65
- | `.codex/codex.md` exceeds Codex context budget | Warn; document trim strategy in `notes.md`. |
63
+ | Existing `AGENTS.md` | Back up, then write (manifest-tracked; `--uninstall` restores). |
64
+ | `AGENTS.md` exceeds Codex context budget | Warn; document trim strategy in `notes.md`. |
66
65
 
67
66
  ## Idempotency check
68
67
 
@@ -71,14 +70,14 @@ Re-run reports "SKIP (exists)" for everything.
71
70
  ## Verification commands (P3.5 will fill)
72
71
 
73
72
  ```bash
74
- test -f "<target>/.codex/codex.md" || echo "MISSING codex.md"
73
+ test -f "<target>/AGENTS.md" || echo "MISSING AGENTS.md"
75
74
 
76
75
  # Run Codex in <target>; verify it follows ABSOLUTE rules + universal conventions.
77
76
  ```
78
77
 
79
78
  ## P3.5 Codex version compatibility check
80
79
 
81
- - Confirm `.codex/codex.md` IS the canonical project-rules location.
80
+ - Confirm `AGENTS.md` IS the canonical project-rules location. (Confirmed — live-verified; current status in `docs/ADAPTER-LIVE-VERIFICATION.md`.)
82
81
  - Confirm Codex auto-loads it on session start.
83
82
  - Confirm Codex follows the rule TEXT in its inline code generation.
84
83