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
@@ -30,7 +30,7 @@
30
30
  # core/recipes/*.md (selected) → <target>/AGENTS.md (each as "## Recipe — <name>")
31
31
  # core/docs-templates/*.md → <target>/docs/*.md (CURRENT_WORK, REMAINING_TASKS, etc.)
32
32
  # core/hooks/*.sh.template → SKIPPED (Reflector hook emitted via --recipes=self-improvement, ADR-032; other guards Claude-only, ADR-034)
33
- # core/roles/*.md → SKIPPED (Codex has no sub-agent dispatch)
33
+ # core/roles/*.md → SKIPPED (role emission is Claude-only today; Codex supports sub-agents natively — ADR-031)
34
34
  # adapters/claude/hookify-... → SKIPPED (Claude-only plugin)
35
35
  #
36
36
  # Single-file model: Codex reads ONE always-loaded rules file. Everything that
@@ -42,6 +42,7 @@ set -eu
42
42
 
43
43
  TARGET=""
44
44
  RECIPES=""
45
+ MODE="full"
45
46
  DRY_RUN="false"
46
47
  NO_PROMPT="false"
47
48
  UNINSTALL="false"
@@ -53,6 +54,7 @@ WIZARD_APPLY_RULES="true"
53
54
  while [ $# -gt 0 ]; do
54
55
  case "$1" in
55
56
  --recipes=*) RECIPES="${1#--recipes=}" ;;
57
+ --mode=*) MODE="${1#--mode=}" ;;
56
58
  --dry-run) DRY_RUN="true" ;;
57
59
  --no-prompt) NO_PROMPT="true" ;;
58
60
  --uninstall|--rollback) UNINSTALL="true" ;;
@@ -63,6 +65,10 @@ Usage: bash adapters/codex/transform.sh <target-project> [options]
63
65
 
64
66
  Options:
65
67
  --recipes=A,B,C Comma-separated list of recipes to append into AGENTS.md
68
+ --mode=<m> Install preset (ADR-044): full (default) | minimal (rules text +
69
+ docs only) | strict (abort if AGENTS.md exists) | recipes-only
70
+ (marked block appended to AGENTS.md; requires --recipes=) |
71
+ reflector-only (self-improvement loop standalone as a marked block)
66
72
  --dry-run Preview only — no files written
67
73
  --no-prompt Skip all interactive prompts; apply sensible defaults (CI-safe)
68
74
  --uninstall Revert a previous install using <target>/.conductor-manifest.json
@@ -75,11 +81,11 @@ Output (single-file Codex model):
75
81
  <target>/AGENTS.md Bundled intro + 5 universal rules + compressed workflow + recipes
76
82
  <target>/docs/*.md Universal doc templates (CURRENT_WORK, REMAINING_TASKS, ...)
77
83
 
78
- Recipes available: web-mobile-parity, i18n, monorepo, branch-strategy, auto-mock-data, coding-conventions, tdd, debugging, database-discipline, design-system, self-improvement, git-hygiene
84
+ 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
79
85
 
80
86
  What this adapter does NOT install (per ADR-004 honesty):
81
87
  - Hook guards (CONDUCTOR emits the Reflector hook when --recipes=self-improvement, ADR-032; other guards remain Claude-only, ADR-034)
82
- - Sub-agent personas (Codex has no sub-agent dispatch single session per task)
88
+ - Sub-agent personas (not yet emitted for Codex the tool supports sub-agents natively, ADR-031; agent emission is Phase 2)
83
89
  - Per-pattern rule scoping (Codex loads AGENTS.md whole — all rules always-on)
84
90
  - Hookify rule templates (Claude-only plugin)
85
91
  EOF
@@ -103,11 +109,31 @@ if [ -z "$TARGET" ]; then
103
109
  exit 1
104
110
  fi
105
111
 
112
+ case "$MODE" in
113
+ full|minimal|strict|recipes-only|reflector-only) : ;;
114
+ *) echo "Error: unknown --mode '$MODE' (one of: full, minimal, strict, recipes-only, reflector-only)" >&2; exit 1 ;;
115
+ esac
116
+ if [ "$MODE" = "reflector-only" ]; then
117
+ if [ -n "$RECIPES" ] && [ "$RECIPES" != "self-improvement" ]; then
118
+ echo "NOTE: --mode=reflector-only ignores --recipes (installs self-improvement only)" >&2
119
+ fi
120
+ RECIPES="self-improvement"
121
+ fi
122
+ if [ "$MODE" = "recipes-only" ] && [ -z "$RECIPES" ] && [ "$UNINSTALL" != "true" ]; then
123
+ echo "Error: --mode=recipes-only requires --recipes=A,B,..." >&2
124
+ exit 1
125
+ fi
126
+
106
127
  # Resolve CONDUCTOR root (where this script lives: adapters/codex/).
107
128
  CONDUCTOR_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
108
129
  CORE_ROOT="$CONDUCTOR_ROOT/core"
109
130
  [ -d "$CORE_ROOT" ] || { echo "Error: core/ not found at $CORE_ROOT" >&2; exit 1; }
110
131
 
132
+ # CONDUCTOR package version for the manifest — parsed at runtime from package.json
133
+ # so releases never drift the manifest (falls back to "unknown" on any error).
134
+ 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)"
135
+ [ -n "$CONDUCTOR_VERSION" ] || CONDUCTOR_VERSION="unknown"
136
+
111
137
  if [ "$DRY_RUN" = "true" ]; then
112
138
  mkdir -p "$TARGET"
113
139
  fi
@@ -154,20 +180,7 @@ derive_title() {
154
180
  # backup path in MANIFEST_LAST_BACKUP for the next record_emit. Honors DRY_RUN.
155
181
  # Origin: ADR-019 (Claude adapter pattern), mirrored per ADR-021.
156
182
  backup_and_remember() {
157
- MANIFEST_LAST_BACKUP=""
158
- if [ -f "$1" ]; then
159
- if [ "$DRY_RUN" = "true" ]; then
160
- log "would back up existing $1 -> $1.conductor-backup-<ts>"
161
- MANIFEST_LAST_BACKUP=""
162
- else
163
- local ts
164
- ts="$(/bin/date +%Y%m%d-%H%M%S)"
165
- local backup="$1.conductor-backup-$ts"
166
- /bin/cp "$1" "$backup"
167
- log " backed up existing $1 -> $backup"
168
- MANIFEST_LAST_BACKUP="${backup#$TARGET_ABS/}"
169
- fi
170
- fi
183
+ conductor_manifest_backup_and_remember "$1"
171
184
  }
172
185
 
173
186
  # ----- manifest tracking (ADR-020, mirrored per ADR-021) ------------------
@@ -179,6 +192,9 @@ MANIFEST_STAGE_PATH=""
179
192
  MANIFEST_TS=""
180
193
  MANIFEST_LAST_BACKUP=""
181
194
 
195
+ # shellcheck source=../../tools/manifest-safety.sh
196
+ . "$CONDUCTOR_ROOT/tools/manifest-safety.sh"
197
+
182
198
  init_manifest() {
183
199
  if [ "$DRY_RUN" = "true" ]; then
184
200
  log "would init manifest staging at $MANIFEST_PATH.staging"
@@ -197,12 +213,13 @@ record_emit() {
197
213
  local relpath="$1" src="$2" backup="${3:-}"
198
214
  local had_backup="false"
199
215
  [ -n "$backup" ] && had_backup="true"
200
- local esc_path esc_src esc_backup
216
+ local esc_path esc_src esc_backup emitted_sha
201
217
  esc_path="$(printf '%s' "$relpath" | /usr/bin/sed 's/\\/\\\\/g; s/"/\\"/g')"
202
218
  esc_src="$(printf '%s' "$src" | /usr/bin/sed 's/\\/\\\\/g; s/"/\\"/g')"
203
219
  esc_backup="$(printf '%s' "$backup" | /usr/bin/sed 's/\\/\\\\/g; s/"/\\"/g')"
204
- printf ' {"path": "%s", "source": "%s", "had_backup": %s, "backup_path": "%s"},\n' \
205
- "$esc_path" "$esc_src" "$had_backup" "$esc_backup" >> "$MANIFEST_STAGE_PATH"
220
+ emitted_sha="$(conductor_sha256_file "$TARGET_ABS/$relpath")"
221
+ printf ' {"path": "%s", "source": "%s", "had_backup": %s, "backup_path": "%s", "sha256": "%s"},\n' \
222
+ "$esc_path" "$esc_src" "$had_backup" "$esc_backup" "$emitted_sha" >> "$MANIFEST_STAGE_PATH"
206
223
  }
207
224
 
208
225
  finalize_manifest() {
@@ -249,8 +266,9 @@ finalize_manifest() {
249
266
 
250
267
  /bin/cat > "$MANIFEST_PATH" <<EOF
251
268
  {
252
- "version": "v0.2.0",
269
+ "version": "v$CONDUCTOR_VERSION",
253
270
  "adapter": "codex",
271
+ "mode": "$MODE",
254
272
  "install_timestamp": "$MANIFEST_TS",
255
273
  "conductor_root": "$CONDUCTOR_ROOT",
256
274
  "recipes_enabled": $recipes_json,
@@ -263,6 +281,92 @@ EOF
263
281
  log " wrote manifest $MANIFEST_PATH"
264
282
  }
265
283
 
284
+ # ----- marked append-blocks (ADR-044, --mode=recipes-only / reflector-only) ----
285
+ #
286
+ # Single-file tools can't take recipes as separate files, so à-la-carte modes
287
+ # APPEND a marked block to the existing baseline instead of overwriting it.
288
+ # The manifest records {"type": "block", "sha256": <hash of content>, "created_file"}.
289
+ # Uninstall strips the block only when its content hash still matches.
290
+
291
+ sha256_of() {
292
+ if command -v sha256sum >/dev/null 2>&1; then sha256sum | /usr/bin/awk '{print $1}'
293
+ else /usr/bin/shasum -a 256 | /usr/bin/awk '{print $1}'; fi
294
+ }
295
+
296
+ # append_block <abs_file> <block_name> <content_file> — sets BLOCK_SHA + BLOCK_CREATED.
297
+ append_block() {
298
+ local f="$1" name="$2" content="$3" rel entry expected_sha current_sha open_count close_count
299
+ local open="<!-- conductor:block $name -->" close="<!-- /conductor:block $name -->"
300
+ BLOCK_CREATED="false"; BLOCK_SHA=""
301
+ if [ "$DRY_RUN" = "true" ]; then
302
+ log "would append marked block '$name' to $f"
303
+ return
304
+ fi
305
+ # Content must never contain the marker syntax itself — a colliding line would
306
+ # truncate extraction AND stripping while the hash guard computes the same
307
+ # truncation on both sides (silent data loss). Refuse instead.
308
+ if /usr/bin/grep -qE '<!-- /?conductor:block ' "$content"; then
309
+ echo "Error: block content contains the conductor:block marker syntax — refusing to append." >&2
310
+ /bin/rm -f "${MANIFEST_STAGE_PATH:-}"
311
+ exit 1
312
+ fi
313
+ if [ ! -f "$f" ]; then
314
+ BLOCK_CREATED="true"
315
+ : > "$f"
316
+ else
317
+ rel="${f#$TARGET_ABS/}"
318
+ open_count="$(/usr/bin/grep -cF "$open" "$f" || true)"
319
+ close_count="$(/usr/bin/grep -cF "$close" "$f" || true)"
320
+ if [ "$open_count" -ne 0 ] || [ "$close_count" -ne 0 ]; then
321
+ if [ "$open_count" -ne 1 ] || [ "$close_count" -ne 1 ]; then
322
+ echo "Error: found an unpaired or duplicate '$name' CONDUCTOR marker in $f; refusing to change user content." >&2
323
+ /bin/rm -f "${MANIFEST_STAGE_PATH:-}"
324
+ exit 1
325
+ fi
326
+ entry="$(conductor_manifest_block_entry "$rel" "$name" 2>/dev/null || true)"
327
+ if [ -z "$entry" ]; then
328
+ echo "Error: '$name' marker in $f is not owned by this install manifest; refusing to replace user content." >&2
329
+ /bin/rm -f "${MANIFEST_STAGE_PATH:-}"
330
+ exit 1
331
+ fi
332
+ expected_sha="$(conductor_manifest_field "$entry" sha256 2>/dev/null || true)"
333
+ current_sha="$(/usr/bin/awk -v o="$open" -v c="$close" '$0==o{b=1;next} $0==c{b=0;next} b' "$f" | sha256_of)"
334
+ if [ -z "$expected_sha" ] || [ "$current_sha" != "$expected_sha" ]; then
335
+ echo "Error: managed '$name' block in $f was customized; refusing to overwrite it." >&2
336
+ /bin/rm -f "${MANIFEST_STAGE_PATH:-}"
337
+ exit 1
338
+ fi
339
+ # The manifest owns this one, unmodified block, so replacement is safe.
340
+ /usr/bin/awk -v o="$open" -v c="$close" '$0==o{inb=1; if (heldset && held ~ /^[[:space:]]*$/) heldset=0; next} $0==c{inb=0;next} inb{next} {if (heldset) print held; held=$0; heldset=1} END{if (heldset) print held}' "$f" > "$f.conductor-tmp"
341
+ /bin/mv "$f.conductor-tmp" "$f"
342
+ log " replaced existing block '$name' in $f"
343
+ fi
344
+ fi
345
+ { echo ""; echo "$open"; /bin/cat "$content"; echo "$close"; } >> "$f"
346
+ BLOCK_SHA="$(/usr/bin/awk -v o="$open" -v c="$close" '$0==o{b=1;next} $0==c{b=0;next} b' "$f" | sha256_of)"
347
+ log " appended block '$name' to $f (sha256 $(printf '%s' "$BLOCK_SHA" | /usr/bin/cut -c1-12)...)"
348
+ }
349
+
350
+ record_emit_block() {
351
+ if [ "$DRY_RUN" = "true" ] || [ "$UNINSTALL" = "true" ]; then return; fi
352
+ local relpath="$1" name="$2" sha="$3" created="$4"
353
+ printf ' {"path": "%s", "type": "block", "block": "%s", "sha256": "%s", "created_file": %s},\n' \
354
+ "$relpath" "$name" "$sha" "$created" >> "$MANIFEST_STAGE_PATH"
355
+ }
356
+
357
+ # ----- framework detection (ADR-044 — suggest, NEVER auto-switch) ----------
358
+
359
+ detect_coexisting_frameworks() {
360
+ local found=""
361
+ [ -d "$TARGET_ABS/.specify" ] && found="$found Spec-Kit"
362
+ { [ -d "$TARGET_ABS/_bmad" ] || [ -d "$TARGET_ABS/.bmad-core" ]; } && found="$found BMAD"
363
+ if [ -n "$found" ] && [ "$MODE" = "full" ]; then
364
+ log "NOTE: detected coexisting framework(s):$found"
365
+ log " Consider --mode=recipes-only or --mode=reflector-only to coexist without"
366
+ log " overlapping workflow rules (suggestion only — nothing was changed)."
367
+ fi
368
+ }
369
+
266
370
  # ----- uninstall flow (mirrored from Cursor/Claude adapter) ---------------
267
371
 
268
372
  do_uninstall() {
@@ -297,24 +401,72 @@ do_uninstall() {
297
401
  local restored=0
298
402
  local deleted=0
299
403
  local missing=0
404
+ local preserved=0
405
+ local blocks_removed=0
406
+ local blocks_kept=0
300
407
 
301
408
  while IFS= read -r line; do
302
409
  case "$line" in
410
+ *'"type": "block"'*)
411
+ entries_count=$((entries_count + 1))
412
+ local b_rel b_name b_sha b_created b_abs b_open b_close b_cur_sha
413
+ b_rel="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"path": *"([^"]*)".*/\1/')"
414
+ b_name="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"block": *"([^"]*)".*/\1/')"
415
+ b_sha="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"sha256": *"([^"]*)".*/\1/')"
416
+ b_created="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"created_file": *(true|false).*/\1/')"
417
+ b_abs="$TARGET_ABS/$b_rel"
418
+ b_open="<!-- conductor:block $b_name -->"
419
+ b_close="<!-- /conductor:block $b_name -->"
420
+ if [ ! -f "$b_abs" ] || ! /usr/bin/grep -qF "$b_open" "$b_abs"; then
421
+ log " skip block '$b_name' ($b_rel absent or markers removed)"
422
+ continue
423
+ fi
424
+ b_cur_sha="$(/usr/bin/awk -v o="$b_open" -v c="$b_close" '$0==o{b=1;next} $0==c{b=0;next} b' "$b_abs" | sha256_of)"
425
+ if [ "$b_cur_sha" = "$b_sha" ]; then
426
+ if [ "$DRY_RUN" = "true" ]; then
427
+ log " would strip block '$b_name' from $b_rel"
428
+ else
429
+ /usr/bin/awk -v o="$b_open" -v c="$b_close" '$0==o{inb=1; if (heldset && held ~ /^[[:space:]]*$/) heldset=0; next} $0==c{inb=0;next} inb{next} {if (heldset) print held; held=$0; heldset=1} END{if (heldset) print held}' "$b_abs" > "$b_abs.conductor-tmp"
430
+ /bin/mv "$b_abs.conductor-tmp" "$b_abs"
431
+ log " stripped block '$b_name' from $b_rel"
432
+ if [ "$b_created" = "true" ] && ! /usr/bin/grep -q '[^[:space:]]' "$b_abs"; then
433
+ /bin/rm -f "$b_abs"
434
+ log " deleted $b_rel (created by CONDUCTOR, now empty)"
435
+ fi
436
+ fi
437
+ blocks_removed=$((blocks_removed + 1))
438
+ else
439
+ log " WARNING: block '$b_name' in $b_rel was customized (hash mismatch) — left in place"
440
+ blocks_kept=$((blocks_kept + 1))
441
+ fi
442
+ continue
443
+ ;;
303
444
  *'"path":'*'"source":'*'"had_backup":'*)
304
445
  ;;
305
446
  *) continue ;;
306
447
  esac
307
448
  entries_count=$((entries_count + 1))
308
- local rel_path src had_backup backup_path
449
+ local rel_path src had_backup backup_path expected_sha
309
450
  rel_path="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"path": *"([^"]*)".*/\1/')"
310
451
  src="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"source": *"([^"]*)".*/\1/')"
311
452
  had_backup="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"had_backup": *(true|false).*/\1/')"
312
453
  backup_path="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"backup_path": *"([^"]*)".*/\1/')"
454
+ expected_sha="$(conductor_manifest_field "$line" sha256 2>/dev/null || true)"
313
455
 
314
456
  local abs_dest="$TARGET_ABS/$rel_path"
315
457
  local abs_backup=""
316
458
  [ -n "$backup_path" ] && abs_backup="$TARGET_ABS/$backup_path"
317
459
 
460
+ if [ -f "$abs_dest" ] && ! conductor_manifest_file_matches "$abs_dest" "$expected_sha"; then
461
+ if [ -z "$expected_sha" ]; then
462
+ log " WARNING: preserving $rel_path (legacy manifest has no checksum)"
463
+ else
464
+ log " WARNING: preserving user-modified $rel_path"
465
+ fi
466
+ preserved=$((preserved + 1))
467
+ continue
468
+ fi
469
+
318
470
  if [ "$had_backup" = "true" ] && [ -n "$abs_backup" ]; then
319
471
  if [ -f "$abs_backup" ]; then
320
472
  if [ "$DRY_RUN" = "true" ]; then
@@ -387,6 +539,10 @@ do_uninstall() {
387
539
  echo " Backups restored: $restored"
388
540
  echo " Files deleted: $deleted"
389
541
  echo " Backup-missing deletes: $missing"
542
+ [ "$preserved" -gt 0 ] && echo " User-modified files preserved: $preserved"
543
+ if [ "$blocks_removed" -gt 0 ] || [ "$blocks_kept" -gt 0 ]; then
544
+ echo " Blocks stripped: $blocks_removed (customized blocks left: $blocks_kept)"
545
+ fi
390
546
  echo "========================================================"
391
547
  }
392
548
 
@@ -421,6 +577,20 @@ if [ -f "$TARGET_ABS/AGENTS.md" ] || [ -d "$TARGET_ABS/.codex" ]; then
421
577
  IS_ADOPTER_CASE="true"
422
578
  fi
423
579
 
580
+ detect_coexisting_frameworks
581
+
582
+ # --mode=strict: never overwrite an existing baseline, even with a backup (ADR-044).
583
+ if [ "$MODE" = "strict" ] && [ -f "$TARGET_ABS/AGENTS.md" ]; then
584
+ echo "Error (--mode=strict): $TARGET_ABS/AGENTS.md already exists — strict mode aborts instead of overwriting a baseline." >&2
585
+ echo " Use --mode=full (timestamped backup + manifest-based restore), or move the file first." >&2
586
+ exit 3
587
+ fi
588
+
589
+ # À-la-carte modes are non-interactive by design.
590
+ if [ "$MODE" != "full" ] && [ "$MODE" != "strict" ]; then
591
+ NO_PROMPT="true"
592
+ fi
593
+
424
594
  if [ "$IS_ADOPTER_CASE" = "true" ] && [ "$NO_PROMPT" = "false" ] && [ "$DRY_RUN" = "false" ]; then
425
595
  echo ""
426
596
  echo "========================================================"
@@ -448,7 +618,7 @@ if [ "$IS_ADOPTER_CASE" = "true" ] && [ "$NO_PROMPT" = "false" ] && [ "$DRY_RUN"
448
618
 
449
619
  echo ""
450
620
  echo "Available recipes:"
451
- echo " web-mobile-parity, i18n, monorepo, branch-strategy, auto-mock-data, coding-conventions, tdd, debugging, database-discipline, design-system, self-improvement, git-hygiene"
621
+ 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"
452
622
  printf "Select recipes (comma-separated, or leave blank for none): "
453
623
  read -r _recipe_answer
454
624
  if [ -n "$_recipe_answer" ]; then
@@ -471,6 +641,10 @@ UNIVERSAL_RULES="workflow spec-as-you-go quality-gates operations meta-disciplin
471
641
 
472
642
  AGENTS_DEST="$TARGET_ABS/AGENTS.md"
473
643
 
644
+ INSTALLED_RECIPES=""
645
+
646
+ if [ "$MODE" != "recipes-only" ] && [ "$MODE" != "reflector-only" ]; then
647
+
474
648
  log "Step 1/2: AGENTS.md → $AGENTS_DEST"
475
649
  backup_and_remember "$AGENTS_DEST"
476
650
 
@@ -504,20 +678,24 @@ build_agents_md() {
504
678
  ## How to use this with Codex (한/영)
505
679
 
506
680
  **한국어** — Codex 는 *한 방(one-shot) 셸 작업* 에 강합니다. 스크립트 작성, 파일 일괄 변환, git 작업,
507
- "이 명령 실행하고 결과 보고" 류 작업이 최적입니다. 멀티 스텝 오케스트레이션(서브에이전트/훅)은
508
- Codex강점이 아니므로, 그런 작업은 사람이 순차 프롬프트로 분해하거나 Claude/Cursor 쓰세요.
681
+ "이 명령 실행하고 결과 보고" 류 작업이 최적입니다. Codex 서브에이전트/훅을 네이티브로 지원하지만
682
+ (ADR-031), CONDUCTOR Codex adapter 아직 이를 자동 생성하지 않으므로 (Phase 2), 멀티 스텝
683
+ 오케스트레이션은 순차 프롬프트로 분해하거나 CONDUCTOR 의 full-emission 인 Claude adapter 를 쓰세요.
509
684
  이 번들은 Codex 가 *인라인으로 생성하는 코드* 가 프로젝트 컨벤션을 따르도록 충분한 맥락을 줍니다.
510
685
 
511
686
  **English** — Codex shines at *one-shot shell tasks*: writing scripts, batch file transforms, git
512
- operations, and "run this command and report the output" work. Multi-step orchestration
513
- (sub-agents / hooks) is not Codex's strength decompose such work into sequential prompts, or
514
- reach for Claude/Cursor. This bundle gives Codex enough context that the code it generates inline
687
+ operations, and "run this command and report the output" work. Codex supports sub-agents and hooks
688
+ natively (ADR-031), but CONDUCTOR's Codex adapter does not emit them yet (Phase 2) — decompose
689
+ multi-step orchestration into sequential prompts, or use CONDUCTOR's full-emission Claude adapter.
690
+ This bundle gives Codex enough context that the code it generates inline
515
691
  follows your project conventions.
516
692
 
517
- > **Enforcement note (Codex)**: Codex has **no sub-agents, no hooks, and no per-pattern rule
518
- > scoping**. Every rule below is loaded *always* and is **self-policed** there is no automated
519
- > gate. Claude-only enforcement mechanisms cited in the rule text (Stop hooks, agent routing) do
520
- > NOT run on Codex; treat them as reminders. Pair this with a git pre-commit hook if you want a hard gate.
693
+ > **Enforcement note (Codex)**: Codex supports sub-agents, hooks, and per-task model routing
694
+ > natively (ADR-031), but CONDUCTOR's Codex adapter currently emits rule text (plus the Reflector
695
+ > loop) only full hook/agent emission is Phase 2. Every rule below is loaded *always* and is
696
+ > **self-policed** CONDUCTOR installs no automated gate here. Enforcement mechanisms cited in
697
+ > the rule text (Stop hooks, agent routing) are emitted for Claude only today; treat them as
698
+ > reminders. Pair this with a git pre-commit hook if you want a hard gate.
521
699
 
522
700
  ## ABSOLUTE rules (always-on summary)
523
701
 
@@ -574,7 +752,7 @@ more often than other tools** — but the gates that remain (Implementation →
574
752
  - **Review** — Stage A on the diff (correctness), Stage B before merge (block on HIGH-confidence issues).
575
753
  - **Spec** — update `docs/specs/<area>.md` to reflect actually-shipped behavior (spec-as-you-go).
576
754
 
577
- > On Codex, phase enforcement is **self-policed** (no Stop hooks). The rule text above is the reminder.
755
+ > On Codex, phase enforcement is **self-policed** (CONDUCTOR emits no Stop hooks here yet). The rule text above is the reminder.
578
756
 
579
757
  WORKFLOW
580
758
 
@@ -628,9 +806,71 @@ else
628
806
  log " wrote $AGENTS_DEST"
629
807
  fi
630
808
 
809
+ else
810
+ # ----- à-la-carte modes: marked block appended to AGENTS.md (ADR-044) ------
811
+ BLOCK_NAME="recipes"; [ "$MODE" = "reflector-only" ] && BLOCK_NAME="reflector"
812
+ log "Step 1/2: --mode=$MODE — '$BLOCK_NAME' marked block → $AGENTS_DEST (no full bundle)"
813
+ if [ "$DRY_RUN" = "true" ]; then
814
+ log "would append marked block '$BLOCK_NAME' (selected recipes: $RECIPES) to $AGENTS_DEST"
815
+ else
816
+ _blk="$(/usr/bin/mktemp "${TMPDIR:-/tmp}/conductor-block.XXXXXX")"
817
+ {
818
+ echo "# CONDUCTOR — à la carte (--mode=$MODE)"
819
+ echo ""
820
+ echo "> Installed by CONDUCTOR WITHOUT the universal-rule bundle. This is a managed"
821
+ echo "> block: --uninstall strips it when unmodified. Full workflow: --mode=full."
822
+ echo ""
823
+ IFS=',' read -ra _RECIPE_LIST <<< "$RECIPES"
824
+ for r in "${_RECIPE_LIST[@]}"; do
825
+ r="$(printf '%s' "$r" | /usr/bin/sed 's/^ *//; s/ *$//')"
826
+ [ -z "$r" ] && continue
827
+ src="$CORE_ROOT/recipes/$r.md"
828
+ if [ ! -f "$src" ]; then
829
+ echo "Warning: recipe '$r' not found at $src; skipping" >&2
830
+ continue
831
+ fi
832
+ echo "## Recipe — $r"
833
+ echo ""
834
+ strip_frontmatter "$src"
835
+ echo ""
836
+ INSTALLED_RECIPES="$INSTALLED_RECIPES $r"
837
+ done
838
+ } > "$_blk"
839
+ if [ -z "${INSTALLED_RECIPES// /}" ]; then
840
+ /bin/rm -f "$_blk"
841
+ echo "Error: --mode=$MODE resolved ZERO valid recipes from '--recipes=$RECIPES' — nothing to install (check the names)." >&2
842
+ /bin/rm -f "$MANIFEST_STAGE_PATH"
843
+ exit 1
844
+ fi
845
+ append_block "$AGENTS_DEST" "$BLOCK_NAME" "$_blk"
846
+ /bin/rm -f "$_blk"
847
+ record_emit_block "AGENTS.md" "$BLOCK_NAME" "$BLOCK_SHA" "$BLOCK_CREATED"
848
+ # Preserve OTHER à-la-carte blocks from a previous install (e.g. recipes-only
849
+ # then reflector-only): carry their manifest entries forward so uninstall can
850
+ # still strip them (ADR-044 review fix — cross-mode orphaned block).
851
+ if [ -f "$MANIFEST_PATH" ]; then
852
+ while IFS= read -r _prev; do
853
+ case "$_prev" in *'"type": "block"'*) : ;; *) continue ;; esac
854
+ _pname="$(printf '%s' "$_prev" | /usr/bin/sed -E 's/.*"block": *"([^"]*)".*/\1/')"
855
+ [ "$_pname" = "$BLOCK_NAME" ] && continue
856
+ if /usr/bin/grep -qF "<!-- conductor:block $_pname -->" "$AGENTS_DEST" 2>/dev/null; then
857
+ printf '%s\n' "$_prev" | /usr/bin/sed 's/,*$/,/' >> "$MANIFEST_STAGE_PATH"
858
+ log " preserved previous block '$_pname' in manifest"
859
+ fi
860
+ done < "$MANIFEST_PATH"
861
+ fi
862
+ fi
863
+ fi
864
+
631
865
  # ----- opt-in: self-improvement (Reflector) --------------------------------
632
866
 
633
- case ",$RECIPES," in
867
+ if [ "$MODE" = "minimal" ]; then
868
+ RECIPES_FOR_RUNTIME=""
869
+ log "Step: self-improvement runtime — skipped (--mode=minimal ships text only)"
870
+ else
871
+ RECIPES_FOR_RUNTIME="$RECIPES"
872
+ fi
873
+ case ",$RECIPES_FOR_RUNTIME," in
634
874
  *",self-improvement,"*)
635
875
  log "Step: self-improvement (Reflector) → .codex hook/skill/agent"
636
876
  if [ "$DRY_RUN" != "true" ]; then
@@ -678,6 +918,9 @@ esac
678
918
 
679
919
  # ----- step 2: docs templates --------------------------------------------
680
920
 
921
+ if [ "$MODE" = "recipes-only" ] || [ "$MODE" = "reflector-only" ]; then
922
+ log "Step 2/2: docs templates — skipped (--mode=$MODE is à la carte; docs ship with full/minimal)"
923
+ else
681
924
  log "Step 2/2: docs templates → docs/"
682
925
  mkdir_if_real "$TARGET_ABS/docs"
683
926
  mkdir_if_real "$TARGET_ABS/docs/specs"
@@ -712,6 +955,8 @@ if [ -f "$CORE_ROOT/docs-templates/specs/_example.md" ]; then
712
955
  fi
713
956
 
714
957
  # Finalize manifest after all emits.
958
+ fi
959
+
715
960
  finalize_manifest
716
961
 
717
962
  # ----- completion summary -------------------------------------------------
@@ -725,7 +970,9 @@ else
725
970
  fi
726
971
  echo " Target: $TARGET_ABS"
727
972
  echo " Adapter: codex"
728
- if [ "$WIZARD_APPLY_RULES" = "true" ]; then
973
+ if [ "$MODE" = "recipes-only" ] || [ "$MODE" = "reflector-only" ]; then
974
+ echo " AGENTS.md: marked à-la-carte block appended (no universal-rule bundle)"
975
+ elif [ "$WIZARD_APPLY_RULES" = "true" ]; then
729
976
  echo " AGENTS.md: intro + 5 universal rules + compressed workflow + memory note"
730
977
  else
731
978
  echo " AGENTS.md: intro + compressed workflow + memory note (universal rules skipped)"
@@ -734,7 +981,7 @@ echo " Recipes appended:${INSTALLED_RECIPES:- (none)}"
734
981
  echo ""
735
982
  echo " Skipped (per ADR-004 honesty):"
736
983
  echo " - Hooks: CONDUCTOR emits the Reflector hook when --recipes=self-improvement (ADR-032); other guards remain Claude-only (ADR-034)."
737
- echo " - Sub-agent personas: Codex has no sub-agent dispatchsingle session per task."
984
+ echo " - Sub-agent personas: not yet emitted for Codex (tool supports sub-agents nativelyADR-031; Phase 2)."
738
985
  echo " - Per-pattern scoping: Codex loads AGENTS.md whole — all rules are always-on."
739
986
  echo " - Hookify rule templates: Claude-only plugin."
740
987
  echo ""
@@ -743,6 +990,6 @@ echo "========================================================"
743
990
  echo ""
744
991
  echo "Next steps for the project:"
745
992
  echo " 1. Open $TARGET_ABS with Codex."
746
- echo " 2. Edit docs/CURRENT_WORK.md with your project's current state."
993
+ [ -d "$TARGET_ABS/docs" ] && echo " 2. Edit docs/CURRENT_WORK.md with your project's current state."
747
994
  echo " 3. (optional) Create .memory/ and add it to .gitignore — see the Memory section in AGENTS.md."
748
995
  echo " 4. Verify Codex cites project conventions when generating code (confirms AGENTS.md loaded)."
@@ -6,24 +6,21 @@ GitHub Copilot is a T2 target because:
6
6
  - Instructions live IN the repo, so all collaborators automatically share them.
7
7
  - Copilot's PR review feature provides a partial Stage B code-review analog tied to GitHub.
8
8
 
9
- It is **T2 (not T1)** because:
9
+ **Tool capability vs CONDUCTOR emission (ADR-031):** as of 2026 Copilot ships hooks (CLI + cloud + VS Code), 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 Copilot limitation.
10
10
 
11
- - No sub-agent dispatch.
12
- - ❌ No hooks for ABSOLUTE enforcement.
13
- - No per-call model routing (model picker in UI).
14
- - ❌ No built-in memory directory.
15
- - ⚠️ Slash commands limited.
11
+ **Tier**: T2 (see `docs/COMPATIBILITY-MATRIX.md` hooks + sub-agents + per-task model + commands all present; caveats: `applyTo:` glob scoping works, but the coding agent has no transcript API).
12
+
13
+ > 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
14
 
17
- **Tier**: T2 — Good support; rule scoping works well, enforcement is limited.
18
15
 
19
16
  ## Installation path
20
17
 
21
18
  ```bash
22
- # Install (the copilot adapter is implemented):
23
- bash /path/to/conductor/adapters/copilot/transform.sh /path/to/target [--dry-run]
19
+ # Recommended (npm, no clone):
20
+ npx omniconductor init --target=copilot <target-dir>
24
21
 
25
- # (planned / roadmap not yet available):
26
- # npx omniconductor init --target=copilot [target-dir]
22
+ # Or from a local clone:
23
+ bash /path/to/conductor/adapters/copilot/transform.sh /path/to/target [--dry-run] [--per-rule]
27
24
  ```
28
25
 
29
26
  ## What gets installed
@@ -31,13 +28,9 @@ bash /path/to/conductor/adapters/copilot/transform.sh /path/to/target [--dry-run
31
28
  ```
32
29
  <target>/
33
30
  ├── .github/
31
+ │ ├── copilot-instructions.md # 5 universal rules merged (repo-wide, default mode)
34
32
  │ └── instructions/
35
- ├── all.instructions.md # applyTo: '**' (always-loaded)
36
- │ ├── operations.instructions.md # applyTo: '**'
37
- │ ├── coding-conventions.instructions.md # applyTo: '**/*.{ts,tsx,js,jsx}'
38
- │ ├── token-economy.instructions.md # applyTo: '**'
39
- │ ├── spec-as-you-go.instructions.md # applyTo: 'docs/specs/**,**/*.md'
40
- │ └── model-routing.instructions.md # applyTo: '**'
33
+ └── <recipe>.instructions.md # per --recipes=, applyTo: from source paths
41
34
  └── docs/
42
35
  ├── CURRENT_WORK.md # Universal templates
43
36
  ├── REMAINING_TASKS.md
@@ -47,30 +40,34 @@ bash /path/to/conductor/adapters/copilot/transform.sh /path/to/target [--dry-run
47
40
  └── specs/_example.md
48
41
  ```
49
42
 
50
- ## Native features supported
43
+ - `--per-rule` splits the 5 universal rules into per-file `.github/instructions/<rule>.instructions.md` (`applyTo: '**'`) instead of the single merged file.
44
+ - `--recipes=self-improvement` additionally emits the Reflector loop: session-end trajectory hook config, `/reflect` command, reflector agent, prune script, and the `.conductor/reflect/` weekly runner (ADR-032/033).
45
+
46
+ ## Native features supported (emitted today)
51
47
 
52
- - ✅ Always-loaded baseline (`applyTo: '**'`).
53
- - ✅ Per-pattern rule scoping (`applyTo:` front-matter).
54
- - ✅ Instructions IN the repo (collaborator-shared).
48
+ - ✅ Always-loaded baseline (`.github/copilot-instructions.md`).
49
+ - ✅ Per-pattern rule scoping (`applyTo:` front-matter on recipe files).
50
+ - ✅ Instructions IN the repo (collaborator-shared) — one install covers VS Code, Cursor (Copilot ext), Windsurf (Copilot adapter), JetBrains, Neovim.
55
51
  - ✅ All universal rule TEXT.
56
52
  - ✅ All doc templates.
53
+ - ✅ Reflector loop (opt-in recipe).
57
54
  - ⚠️ Copilot PR review feature for Stage B (partial).
58
55
 
59
- ## Features NOT supported
56
+ ## Not emitted yet (Phase 2 — Copilot supports these natively, ADR-031/034)
60
57
 
61
- | Feature | Workaround |
58
+ | Feature | Interim workaround |
62
59
  |---|---|
63
- | Sub-agent dispatch | Human plays orchestrator role. |
64
- | Hooks | Pair with project-level pre-commit git hooks for enforcement. |
65
- | Per-call model routing | Pick model in Copilot Chat UI. |
66
- | Built-in memory directory | DIY at `.memory/` (gitignored). |
60
+ | Enforcement guard hooks | Self-police, or pair with project-level pre-commit git hooks. Only the Reflector session-end hook is emitted today. |
61
+ | The 6 role agents (sub-agent dispatch) | Copilot has native agents; CONDUCTOR doesn't emit its role definitions for Copilot yet. Human plays orchestrator. |
62
+ | Per-call model-routing config | Pick the model in Copilot Chat UI per task (Copilot supports per-task model selection). |
63
+ | 4-type memory pattern | Self-managed at `.memory/` (gitignored); Copilot's built-in managed memory is separate. |
67
64
  | Specialized review agents (Stage A) | Run review prompts manually in Copilot Chat. Use Copilot PR review for Stage B (best-effort). |
68
65
 
69
66
  ## After install — first steps
70
67
 
71
- 1. Commit `.github/instructions/` to your repo. All collaborators automatically pick up the rules.
68
+ 1. Commit `.github/copilot-instructions.md` (and `.github/instructions/` if you used recipes or `--per-rule`) to your repo. All collaborators automatically pick up the rules.
72
69
  2. Configure Copilot PR review for Stage B (in repo settings).
73
- 3. Customize the always-loaded section of `all.instructions.md` replace `{{PROJECT_NAME}}`.
70
+ 3. Skim `.github/copilot-instructions.md` and adjust recipe `applyTo:` globs to your repo layout if needed.
74
71
  4. Rename `docs/specs/_example.md` → `docs/specs/<your-area>.md`.
75
72
  5. Add `.memory/` to `.gitignore`. Create your first memory entry.
76
73