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.
- package/CHANGELOG.md +68 -0
- package/README.md +59 -19
- package/VISION.md +2 -2
- package/adapters/README.md +8 -8
- package/adapters/claude/README.md +3 -6
- package/adapters/claude/SUPPORTED-FEATURES.md +4 -4
- package/adapters/claude/metadata.json +39 -0
- package/adapters/claude/transform-spec.md +1 -1
- package/adapters/claude/transform.sh +208 -38
- package/adapters/codex/README.md +23 -27
- package/adapters/codex/metadata.json +35 -0
- package/adapters/codex/transform-spec.md +5 -6
- package/adapters/codex/transform.sh +284 -37
- package/adapters/copilot/README.md +26 -29
- package/adapters/copilot/metadata.json +36 -0
- package/adapters/copilot/transform.sh +126 -35
- package/adapters/cursor/README.md +31 -30
- package/adapters/cursor/metadata.json +35 -0
- package/adapters/cursor/transform.sh +117 -28
- package/adapters/gemini/README.md +14 -15
- package/adapters/gemini/metadata.json +36 -0
- package/adapters/gemini/transform.sh +312 -36
- package/adapters/windsurf/README.md +20 -19
- package/adapters/windsurf/metadata.json +36 -0
- package/adapters/windsurf/transform.sh +139 -55
- package/bin/doctor.js +257 -0
- package/bin/omniconductor.js +15 -2
- package/core/anti-patterns/frequent-rule-file-edit.md +1 -1
- package/core/anti-patterns/single-monolithic-rule-file.md +1 -1
- package/core/hooks/README.md +1 -0
- package/core/hooks/pretool-loop-guard.sh.template +177 -0
- package/core/recipes/README.md +6 -4
- package/core/recipes/loop-engineering.md +73 -0
- package/core/universal-rules/README.md +4 -4
- package/core/universal-rules/meta-discipline.md +4 -4
- package/core/universal-rules/spec-as-you-go.md +1 -1
- package/docs/ADAPTER-LIVE-VERIFICATION.md +73 -0
- package/docs/COMPARISON.md +133 -0
- package/docs/COMPATIBILITY-MATRIX.md +126 -0
- package/docs/DESIGN-DECISIONS.md +1268 -0
- package/docs/MANUAL-INSTALL.md +15 -15
- package/docs/PUBLICATION-POLICY.md +46 -0
- package/docs/PUBLISH-GUIDE.md +141 -0
- package/package.json +7 -1
- package/tools/check-adapter-metadata.sh +211 -0
- package/tools/check-stale-tokens.sh +130 -0
- package/tools/generate-adapter-docs.js +123 -0
- package/tools/live-verify.sh +195 -0
- package/tools/manifest-safety.sh +118 -0
- package/tools/stale-tokens.txt +32 -0
- package/tools/test-install-modes.sh +277 -0
- package/tools/validate-adapter-output.sh +1 -1
|
@@ -26,13 +26,14 @@
|
|
|
26
26
|
# core/recipes/coding-conventions → <target>/.gemini/styleguide.md (Gemini style-guide convention; opt-in)
|
|
27
27
|
# core/docs-templates/*.md → <target>/docs/*.md (CURRENT_WORK, REMAINING_TASKS, etc.)
|
|
28
28
|
# core/hooks/*.sh.template → SKIPPED (Reflector hook emitted via --recipes=self-improvement, ADR-032; other guards Claude-only, ADR-034)
|
|
29
|
-
# core/roles/*.md → SKIPPED (Gemini
|
|
29
|
+
# core/roles/*.md → SKIPPED (role emission is Claude-only today; Gemini supports sub-agents natively — ADR-031)
|
|
30
30
|
#
|
|
31
31
|
# Gemini reality (per adapters/gemini/SUPPORTED-FEATURES.md):
|
|
32
32
|
# - Single always-loaded rule file (GEMINI.md). No per-pattern rule scoping.
|
|
33
|
-
# -
|
|
33
|
+
# - Gemini CLI supports sub-agents / hooks / per-call model routing natively
|
|
34
|
+
# (ADR-031), but this adapter does not emit them yet (Phase 2). CONDUCTOR
|
|
34
35
|
# emits the Reflector hook when --recipes=self-improvement (ADR-032); other
|
|
35
|
-
# guards remain Claude-only (ADR-034).
|
|
36
|
+
# guards remain Claude-only emission (ADR-034).
|
|
36
37
|
# The bundle below carries the rule TEXT honestly; Claude-only enforcement mechanisms
|
|
37
38
|
# are noted as self-policed for Gemini, never faked.
|
|
38
39
|
|
|
@@ -42,6 +43,7 @@ set -eu
|
|
|
42
43
|
|
|
43
44
|
TARGET=""
|
|
44
45
|
RECIPES=""
|
|
46
|
+
MODE="full"
|
|
45
47
|
DRY_RUN="false"
|
|
46
48
|
NO_PROMPT="false"
|
|
47
49
|
UNINSTALL="false"
|
|
@@ -53,6 +55,7 @@ WIZARD_APPLY_RULES="true"
|
|
|
53
55
|
while [ $# -gt 0 ]; do
|
|
54
56
|
case "$1" in
|
|
55
57
|
--recipes=*) RECIPES="${1#--recipes=}" ;;
|
|
58
|
+
--mode=*) MODE="${1#--mode=}" ;;
|
|
56
59
|
--dry-run) DRY_RUN="true" ;;
|
|
57
60
|
--no-prompt) NO_PROMPT="true" ;;
|
|
58
61
|
--uninstall|--rollback) UNINSTALL="true" ;;
|
|
@@ -63,6 +66,17 @@ Usage: bash adapters/gemini/transform.sh <target-project> [options]
|
|
|
63
66
|
|
|
64
67
|
Options:
|
|
65
68
|
--recipes=A,B,C Comma-separated list of recipes to install (appended into GEMINI.md)
|
|
69
|
+
--mode=<m> Install preset (ADR-044). One of:
|
|
70
|
+
full (default) everything this adapter emits today
|
|
71
|
+
minimal discipline text + session continuity only
|
|
72
|
+
(GEMINI.md + docs/; no styleguide, no Reflector runtime)
|
|
73
|
+
strict full, but ABORT (exit 3) if GEMINI.md already exists
|
|
74
|
+
(never overwrites a baseline, even with backup)
|
|
75
|
+
recipes-only ONLY the selected recipes, appended to GEMINI.md as a
|
|
76
|
+
marked block (requires --recipes=; block-aware uninstall)
|
|
77
|
+
reflector-only the self-improvement loop standalone (recipe text as a
|
|
78
|
+
marked block + Reflector runtime; least-conflicting with
|
|
79
|
+
other frameworks like Spec Kit / BMAD)
|
|
66
80
|
--dry-run Preview only — no files written
|
|
67
81
|
--no-prompt Skip all interactive prompts; apply sensible defaults (CI-safe)
|
|
68
82
|
--uninstall Revert a previous install using <target>/.conductor-manifest.json
|
|
@@ -71,7 +85,7 @@ Options:
|
|
|
71
85
|
manifest are preserved.
|
|
72
86
|
--force Bypass uninstall safety checks (active worktrees, missing manifest)
|
|
73
87
|
|
|
74
|
-
Recipes available: web-mobile-parity, i18n, monorepo, branch-strategy, auto-mock-data, coding-conventions, tdd, debugging, database-discipline, design-system, self-improvement, git-hygiene
|
|
88
|
+
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
|
|
75
89
|
|
|
76
90
|
Gemini single-file model:
|
|
77
91
|
- All 5 universal rules + selected recipes are bundled into one always-loaded GEMINI.md.
|
|
@@ -81,8 +95,8 @@ Gemini single-file model:
|
|
|
81
95
|
|
|
82
96
|
What this adapter does NOT install (per ADR-004 honesty + ADR-021):
|
|
83
97
|
- Hook guards (CONDUCTOR emits the Reflector hook when --recipes=self-improvement, ADR-032; other guards remain Claude-only, ADR-034)
|
|
84
|
-
- Sub-agent personas (Gemini
|
|
85
|
-
- Per-call model routing (
|
|
98
|
+
- Sub-agent personas (not yet emitted for Gemini — the tool supports sub-agents natively, ADR-031; agent emission is Phase 2)
|
|
99
|
+
- Per-call model routing (supported natively by Gemini CLI, ADR-031; not yet automated by CONDUCTOR)
|
|
86
100
|
- Built-in memory directory (DIY at .memory/ — see the note inside GEMINI.md)
|
|
87
101
|
EOF
|
|
88
102
|
exit 0
|
|
@@ -105,11 +119,31 @@ if [ -z "$TARGET" ]; then
|
|
|
105
119
|
exit 1
|
|
106
120
|
fi
|
|
107
121
|
|
|
122
|
+
case "$MODE" in
|
|
123
|
+
full|minimal|strict|recipes-only|reflector-only) : ;;
|
|
124
|
+
*) echo "Error: unknown --mode '$MODE' (one of: full, minimal, strict, recipes-only, reflector-only)" >&2; exit 1 ;;
|
|
125
|
+
esac
|
|
126
|
+
if [ "$MODE" = "reflector-only" ]; then
|
|
127
|
+
if [ -n "$RECIPES" ] && [ "$RECIPES" != "self-improvement" ]; then
|
|
128
|
+
echo "NOTE: --mode=reflector-only ignores --recipes (installs self-improvement only)" >&2
|
|
129
|
+
fi
|
|
130
|
+
RECIPES="self-improvement"
|
|
131
|
+
fi
|
|
132
|
+
if [ "$MODE" = "recipes-only" ] && [ -z "$RECIPES" ] && [ "$UNINSTALL" != "true" ]; then
|
|
133
|
+
echo "Error: --mode=recipes-only requires --recipes=A,B,..." >&2
|
|
134
|
+
exit 1
|
|
135
|
+
fi
|
|
136
|
+
|
|
108
137
|
# Resolve CONDUCTOR root (where this script lives: adapters/gemini/).
|
|
109
138
|
CONDUCTOR_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
110
139
|
CORE_ROOT="$CONDUCTOR_ROOT/core"
|
|
111
140
|
[ -d "$CORE_ROOT" ] || { echo "Error: core/ not found at $CORE_ROOT" >&2; exit 1; }
|
|
112
141
|
|
|
142
|
+
# CONDUCTOR package version for the manifest — parsed at runtime from package.json
|
|
143
|
+
# so releases never drift the manifest (falls back to "unknown" on any error).
|
|
144
|
+
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)"
|
|
145
|
+
[ -n "$CONDUCTOR_VERSION" ] || CONDUCTOR_VERSION="unknown"
|
|
146
|
+
|
|
113
147
|
if [ "$DRY_RUN" = "true" ]; then
|
|
114
148
|
mkdir -p "$TARGET"
|
|
115
149
|
fi
|
|
@@ -203,6 +237,9 @@ MANIFEST_STAGE_PATH=""
|
|
|
203
237
|
MANIFEST_TS=""
|
|
204
238
|
MANIFEST_LAST_BACKUP=""
|
|
205
239
|
|
|
240
|
+
# shellcheck source=../../tools/manifest-safety.sh
|
|
241
|
+
. "$CONDUCTOR_ROOT/tools/manifest-safety.sh"
|
|
242
|
+
|
|
206
243
|
init_manifest() {
|
|
207
244
|
if [ "$DRY_RUN" = "true" ]; then
|
|
208
245
|
log "would init manifest staging at $MANIFEST_PATH.staging"
|
|
@@ -221,12 +258,13 @@ record_emit() {
|
|
|
221
258
|
local relpath="$1" src="$2" backup="${3:-}"
|
|
222
259
|
local had_backup="false"
|
|
223
260
|
[ -n "$backup" ] && had_backup="true"
|
|
224
|
-
local esc_path esc_src esc_backup
|
|
261
|
+
local esc_path esc_src esc_backup emitted_sha
|
|
225
262
|
esc_path="$(printf '%s' "$relpath" | /usr/bin/sed 's/\\/\\\\/g; s/"/\\"/g')"
|
|
226
263
|
esc_src="$(printf '%s' "$src" | /usr/bin/sed 's/\\/\\\\/g; s/"/\\"/g')"
|
|
227
264
|
esc_backup="$(printf '%s' "$backup" | /usr/bin/sed 's/\\/\\\\/g; s/"/\\"/g')"
|
|
228
|
-
|
|
229
|
-
"
|
|
265
|
+
emitted_sha="$(conductor_sha256_file "$TARGET_ABS/$relpath")"
|
|
266
|
+
printf ' {"path": "%s", "source": "%s", "had_backup": %s, "backup_path": "%s", "sha256": "%s"},\n' \
|
|
267
|
+
"$esc_path" "$esc_src" "$had_backup" "$esc_backup" "$emitted_sha" >> "$MANIFEST_STAGE_PATH"
|
|
230
268
|
}
|
|
231
269
|
|
|
232
270
|
finalize_manifest() {
|
|
@@ -270,8 +308,9 @@ finalize_manifest() {
|
|
|
270
308
|
|
|
271
309
|
/bin/cat > "$MANIFEST_PATH" <<EOF
|
|
272
310
|
{
|
|
273
|
-
"version": "
|
|
311
|
+
"version": "v$CONDUCTOR_VERSION",
|
|
274
312
|
"adapter": "gemini",
|
|
313
|
+
"mode": "$MODE",
|
|
275
314
|
"install_timestamp": "$MANIFEST_TS",
|
|
276
315
|
"conductor_root": "$CONDUCTOR_ROOT",
|
|
277
316
|
"recipes_enabled": $recipes_json,
|
|
@@ -285,20 +324,98 @@ EOF
|
|
|
285
324
|
}
|
|
286
325
|
|
|
287
326
|
backup_and_remember() {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
327
|
+
conductor_manifest_backup_and_remember "$1"
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
# ----- marked append-blocks (ADR-044, --mode=recipes-only / reflector-only) ----
|
|
331
|
+
#
|
|
332
|
+
# Single-file tools can't take recipes as separate files, so à-la-carte modes
|
|
333
|
+
# APPEND a marked block to the existing baseline instead of overwriting it:
|
|
334
|
+
# <!-- conductor:block <name> -->
|
|
335
|
+
# ...content...
|
|
336
|
+
# <!-- /conductor:block <name> -->
|
|
337
|
+
# The manifest records {"type": "block", "sha256": <hash of content>, "created_file"}.
|
|
338
|
+
# Uninstall strips the block only when its content hash still matches (a customized
|
|
339
|
+
# block is left in place with a warning — backup ≠ silently destroying user edits).
|
|
340
|
+
|
|
341
|
+
sha256_of() {
|
|
342
|
+
if command -v sha256sum >/dev/null 2>&1; then sha256sum | /usr/bin/awk '{print $1}'
|
|
343
|
+
else /usr/bin/shasum -a 256 | /usr/bin/awk '{print $1}'; fi
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
# append_block <abs_file> <block_name> <content_file>
|
|
347
|
+
# Sets BLOCK_SHA + BLOCK_CREATED. Replaces the block if markers already exist.
|
|
348
|
+
append_block() {
|
|
349
|
+
local f="$1" name="$2" content="$3" rel entry expected_sha current_sha open_count close_count
|
|
350
|
+
local open="<!-- conductor:block $name -->" close="<!-- /conductor:block $name -->"
|
|
351
|
+
BLOCK_CREATED="false"; BLOCK_SHA=""
|
|
352
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
353
|
+
log "would append marked block '$name' to $f"
|
|
354
|
+
return
|
|
355
|
+
fi
|
|
356
|
+
# Content must never contain the marker syntax itself — a colliding line would
|
|
357
|
+
# truncate extraction AND stripping while the hash guard computes the same
|
|
358
|
+
# truncation on both sides (silent data loss). Refuse instead.
|
|
359
|
+
if /usr/bin/grep -qE '<!-- /?conductor:block ' "$content"; then
|
|
360
|
+
echo "Error: block content contains the conductor:block marker syntax — refusing to append." >&2
|
|
361
|
+
/bin/rm -f "${MANIFEST_STAGE_PATH:-}"
|
|
362
|
+
exit 1
|
|
363
|
+
fi
|
|
364
|
+
if [ ! -f "$f" ]; then
|
|
365
|
+
BLOCK_CREATED="true"
|
|
366
|
+
: > "$f"
|
|
367
|
+
else
|
|
368
|
+
rel="${f#$TARGET_ABS/}"
|
|
369
|
+
open_count="$(/usr/bin/grep -cF "$open" "$f" || true)"
|
|
370
|
+
close_count="$(/usr/bin/grep -cF "$close" "$f" || true)"
|
|
371
|
+
if [ "$open_count" -ne 0 ] || [ "$close_count" -ne 0 ]; then
|
|
372
|
+
if [ "$open_count" -ne 1 ] || [ "$close_count" -ne 1 ]; then
|
|
373
|
+
echo "Error: found an unpaired or duplicate '$name' CONDUCTOR marker in $f; refusing to change user content." >&2
|
|
374
|
+
/bin/rm -f "${MANIFEST_STAGE_PATH:-}"
|
|
375
|
+
exit 1
|
|
376
|
+
fi
|
|
377
|
+
entry="$(conductor_manifest_block_entry "$rel" "$name" 2>/dev/null || true)"
|
|
378
|
+
if [ -z "$entry" ]; then
|
|
379
|
+
echo "Error: '$name' marker in $f is not owned by this install manifest; refusing to replace user content." >&2
|
|
380
|
+
/bin/rm -f "${MANIFEST_STAGE_PATH:-}"
|
|
381
|
+
exit 1
|
|
382
|
+
fi
|
|
383
|
+
expected_sha="$(conductor_manifest_field "$entry" sha256 2>/dev/null || true)"
|
|
384
|
+
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)"
|
|
385
|
+
if [ -z "$expected_sha" ] || [ "$current_sha" != "$expected_sha" ]; then
|
|
386
|
+
echo "Error: managed '$name' block in $f was customized; refusing to overwrite it." >&2
|
|
387
|
+
/bin/rm -f "${MANIFEST_STAGE_PATH:-}"
|
|
388
|
+
exit 1
|
|
389
|
+
fi
|
|
390
|
+
# The manifest owns this one, unmodified block, so replacement is safe.
|
|
391
|
+
/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"
|
|
392
|
+
/bin/mv "$f.conductor-tmp" "$f"
|
|
393
|
+
log " replaced existing block '$name' in $f"
|
|
300
394
|
fi
|
|
301
395
|
fi
|
|
396
|
+
{ echo ""; echo "$open"; /bin/cat "$content"; echo "$close"; } >> "$f"
|
|
397
|
+
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)"
|
|
398
|
+
log " appended block '$name' to $f (sha256 $(printf '%s' "$BLOCK_SHA" | /usr/bin/cut -c1-12)...)"
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
record_emit_block() {
|
|
402
|
+
if [ "$DRY_RUN" = "true" ] || [ "$UNINSTALL" = "true" ]; then return; fi
|
|
403
|
+
local relpath="$1" name="$2" sha="$3" created="$4"
|
|
404
|
+
printf ' {"path": "%s", "type": "block", "block": "%s", "sha256": "%s", "created_file": %s},\n' \
|
|
405
|
+
"$relpath" "$name" "$sha" "$created" >> "$MANIFEST_STAGE_PATH"
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
# ----- framework detection (ADR-044 — suggest, NEVER auto-switch) ----------
|
|
409
|
+
|
|
410
|
+
detect_coexisting_frameworks() {
|
|
411
|
+
local found=""
|
|
412
|
+
[ -d "$TARGET_ABS/.specify" ] && found="$found Spec-Kit"
|
|
413
|
+
{ [ -d "$TARGET_ABS/_bmad" ] || [ -d "$TARGET_ABS/.bmad-core" ]; } && found="$found BMAD"
|
|
414
|
+
if [ -n "$found" ] && [ "$MODE" = "full" ]; then
|
|
415
|
+
log "NOTE: detected coexisting framework(s):$found"
|
|
416
|
+
log " Consider --mode=recipes-only or --mode=reflector-only to coexist without"
|
|
417
|
+
log " overlapping workflow rules (suggestion only — nothing was changed)."
|
|
418
|
+
fi
|
|
302
419
|
}
|
|
303
420
|
|
|
304
421
|
# ----- uninstall flow (mirrored from Cursor/Claude adapter) ---------------
|
|
@@ -335,24 +452,80 @@ do_uninstall() {
|
|
|
335
452
|
local restored=0
|
|
336
453
|
local deleted=0
|
|
337
454
|
local missing=0
|
|
455
|
+
local preserved=0
|
|
456
|
+
|
|
457
|
+
local blocks_removed=0
|
|
458
|
+
local blocks_kept=0
|
|
338
459
|
|
|
339
460
|
while IFS= read -r line; do
|
|
340
461
|
case "$line" in
|
|
462
|
+
*'"type": "block"'*)
|
|
463
|
+
# Marked append-block entry (ADR-044) — strip the block, hash-guarded.
|
|
464
|
+
entries_count=$((entries_count + 1))
|
|
465
|
+
local b_rel b_name b_sha b_created b_abs b_open b_close b_cur b_cur_sha
|
|
466
|
+
b_rel="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"path": *"([^"]*)".*/\1/')"
|
|
467
|
+
b_name="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"block": *"([^"]*)".*/\1/')"
|
|
468
|
+
b_sha="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"sha256": *"([^"]*)".*/\1/')"
|
|
469
|
+
b_created="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"created_file": *(true|false).*/\1/')"
|
|
470
|
+
b_abs="$TARGET_ABS/$b_rel"
|
|
471
|
+
b_open="<!-- conductor:block $b_name -->"
|
|
472
|
+
b_close="<!-- /conductor:block $b_name -->"
|
|
473
|
+
if [ ! -f "$b_abs" ]; then
|
|
474
|
+
log " skip block '$b_name' ($b_rel already absent)"
|
|
475
|
+
continue
|
|
476
|
+
fi
|
|
477
|
+
if ! /usr/bin/grep -qF "$b_open" "$b_abs"; then
|
|
478
|
+
log " skip block '$b_name' (markers already removed from $b_rel)"
|
|
479
|
+
continue
|
|
480
|
+
fi
|
|
481
|
+
# Hash via the same direct pipe as emit-time (a shell-variable roundtrip
|
|
482
|
+
# strips trailing newlines and breaks the comparison).
|
|
483
|
+
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)"
|
|
484
|
+
if [ "$b_cur_sha" = "$b_sha" ]; then
|
|
485
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
486
|
+
log " would strip block '$b_name' from $b_rel"
|
|
487
|
+
else
|
|
488
|
+
/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"
|
|
489
|
+
/bin/mv "$b_abs.conductor-tmp" "$b_abs"
|
|
490
|
+
log " stripped block '$b_name' from $b_rel"
|
|
491
|
+
if [ "$b_created" = "true" ] && ! /usr/bin/grep -q '[^[:space:]]' "$b_abs"; then
|
|
492
|
+
/bin/rm -f "$b_abs"
|
|
493
|
+
log " deleted $b_rel (file was created by CONDUCTOR and is now empty)"
|
|
494
|
+
fi
|
|
495
|
+
fi
|
|
496
|
+
blocks_removed=$((blocks_removed + 1))
|
|
497
|
+
else
|
|
498
|
+
log " WARNING: block '$b_name' in $b_rel was customized (hash mismatch) — left in place"
|
|
499
|
+
blocks_kept=$((blocks_kept + 1))
|
|
500
|
+
fi
|
|
501
|
+
continue
|
|
502
|
+
;;
|
|
341
503
|
*'"path":'*'"source":'*'"had_backup":'*)
|
|
342
504
|
;;
|
|
343
505
|
*) continue ;;
|
|
344
506
|
esac
|
|
345
507
|
entries_count=$((entries_count + 1))
|
|
346
|
-
local rel_path src had_backup backup_path
|
|
508
|
+
local rel_path src had_backup backup_path expected_sha
|
|
347
509
|
rel_path="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"path": *"([^"]*)".*/\1/')"
|
|
348
510
|
src="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"source": *"([^"]*)".*/\1/')"
|
|
349
511
|
had_backup="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"had_backup": *(true|false).*/\1/')"
|
|
350
512
|
backup_path="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"backup_path": *"([^"]*)".*/\1/')"
|
|
513
|
+
expected_sha="$(conductor_manifest_field "$line" sha256 2>/dev/null || true)"
|
|
351
514
|
|
|
352
515
|
local abs_dest="$TARGET_ABS/$rel_path"
|
|
353
516
|
local abs_backup=""
|
|
354
517
|
[ -n "$backup_path" ] && abs_backup="$TARGET_ABS/$backup_path"
|
|
355
518
|
|
|
519
|
+
if [ -f "$abs_dest" ] && ! conductor_manifest_file_matches "$abs_dest" "$expected_sha"; then
|
|
520
|
+
if [ -z "$expected_sha" ]; then
|
|
521
|
+
log " WARNING: preserving $rel_path (legacy manifest has no checksum)"
|
|
522
|
+
else
|
|
523
|
+
log " WARNING: preserving user-modified $rel_path"
|
|
524
|
+
fi
|
|
525
|
+
preserved=$((preserved + 1))
|
|
526
|
+
continue
|
|
527
|
+
fi
|
|
528
|
+
|
|
356
529
|
if [ "$had_backup" = "true" ] && [ -n "$abs_backup" ]; then
|
|
357
530
|
if [ -f "$abs_backup" ]; then
|
|
358
531
|
if [ "$DRY_RUN" = "true" ]; then
|
|
@@ -425,6 +598,10 @@ do_uninstall() {
|
|
|
425
598
|
echo " Backups restored: $restored"
|
|
426
599
|
echo " Files deleted: $deleted"
|
|
427
600
|
echo " Backup-missing deletes: $missing"
|
|
601
|
+
[ "$preserved" -gt 0 ] && echo " User-modified files preserved: $preserved"
|
|
602
|
+
if [ "$blocks_removed" -gt 0 ] || [ "$blocks_kept" -gt 0 ]; then
|
|
603
|
+
echo " Blocks stripped: $blocks_removed (customized blocks left: $blocks_kept)"
|
|
604
|
+
fi
|
|
428
605
|
echo "========================================================"
|
|
429
606
|
}
|
|
430
607
|
|
|
@@ -459,6 +636,24 @@ if [ -f "$TARGET_ABS/GEMINI.md" ] || [ -d "$TARGET_ABS/.gemini" ]; then
|
|
|
459
636
|
IS_ADOPTER_CASE="true"
|
|
460
637
|
fi
|
|
461
638
|
|
|
639
|
+
detect_coexisting_frameworks
|
|
640
|
+
|
|
641
|
+
# --mode=strict: never overwrite an existing baseline, even with a backup (ADR-044).
|
|
642
|
+
if [ "$MODE" = "strict" ]; then
|
|
643
|
+
for _sf in "GEMINI.md" ".gemini/styleguide.md"; do
|
|
644
|
+
if [ -f "$TARGET_ABS/$_sf" ]; then
|
|
645
|
+
echo "Error (--mode=strict): $TARGET_ABS/$_sf already exists — strict mode aborts instead of overwriting a baseline." >&2
|
|
646
|
+
echo " Use --mode=full (timestamped backup + manifest-based restore), or move the file first." >&2
|
|
647
|
+
exit 3
|
|
648
|
+
fi
|
|
649
|
+
done
|
|
650
|
+
fi
|
|
651
|
+
|
|
652
|
+
# À-la-carte modes are non-interactive by design (they never touch the universal-rule choice).
|
|
653
|
+
if [ "$MODE" != "full" ] && [ "$MODE" != "strict" ]; then
|
|
654
|
+
NO_PROMPT="true"
|
|
655
|
+
fi
|
|
656
|
+
|
|
462
657
|
if [ "$IS_ADOPTER_CASE" = "true" ] && [ "$NO_PROMPT" = "false" ] && [ "$DRY_RUN" = "false" ]; then
|
|
463
658
|
echo ""
|
|
464
659
|
echo "========================================================"
|
|
@@ -486,7 +681,7 @@ if [ "$IS_ADOPTER_CASE" = "true" ] && [ "$NO_PROMPT" = "false" ] && [ "$DRY_RUN"
|
|
|
486
681
|
|
|
487
682
|
echo ""
|
|
488
683
|
echo "Available recipes:"
|
|
489
|
-
echo " web-mobile-parity, i18n, monorepo, branch-strategy, auto-mock-data, coding-conventions, tdd, debugging, database-discipline, design-system, self-improvement, git-hygiene"
|
|
684
|
+
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"
|
|
490
685
|
printf "Select recipes (comma-separated, or leave blank for none): "
|
|
491
686
|
read -r _recipe_answer
|
|
492
687
|
if [ -n "$_recipe_answer" ]; then
|
|
@@ -520,6 +715,8 @@ if [ -n "$RECIPES" ]; then
|
|
|
520
715
|
IFS="$_old_ifs"
|
|
521
716
|
fi
|
|
522
717
|
|
|
718
|
+
if [ "$MODE" != "recipes-only" ] && [ "$MODE" != "reflector-only" ]; then
|
|
719
|
+
|
|
523
720
|
log "Step 1/3: GEMINI.md bundle → $GEMINI_DEST"
|
|
524
721
|
|
|
525
722
|
if [ -f "$GEMINI_DEST" ] && [ "$DRY_RUN" = "false" ]; then
|
|
@@ -547,19 +744,22 @@ else
|
|
|
547
744
|
**EN** — You are the lead orchestrator for **{{PROJECT_NAME}}**. You translate the
|
|
548
745
|
user's intent into a disciplined Plan → Architecture → Tasks → Implementation →
|
|
549
746
|
Review → Spec workflow. The universal rules below are your operating floor; every
|
|
550
|
-
turn inherits them. Gemini CLI
|
|
551
|
-
|
|
552
|
-
|
|
747
|
+
turn inherits them. Gemini CLI supports sub-agents and hooks natively (ADR-031),
|
|
748
|
+
but CONDUCTOR's Gemini adapter currently emits rule text (plus the Reflector loop)
|
|
749
|
+
only — full hook/agent emission is Phase 2 — so these rules are **self-policed**:
|
|
750
|
+
you follow them by reading them, not because an emitted hook blocks you.
|
|
553
751
|
|
|
554
752
|
**KO** — 당신은 **{{PROJECT_NAME}}** 의 리드 오케스트레이터입니다. 사용자의 의도를
|
|
555
753
|
Plan → Architecture → Tasks → Implementation → Review → Spec 워크플로로 옮깁니다.
|
|
556
|
-
아래 universal rule 은 모든 턴이 상속하는 기본 규칙입니다. Gemini CLI 는
|
|
557
|
-
|
|
754
|
+
아래 universal rule 은 모든 턴이 상속하는 기본 규칙입니다. Gemini CLI 는 sub-agent 와
|
|
755
|
+
hook 을 네이티브로 지원하지만 (ADR-031), CONDUCTOR 의 Gemini adapter 는 현재 rule 텍스트
|
|
756
|
+
(+ Reflector loop) 만 생성합니다 (hook/agent 자동 생성은 Phase 2) — 따라서 이 규칙들은
|
|
558
757
|
**자기 규율(self-policed)** 로 지켜야 합니다.
|
|
559
758
|
|
|
560
759
|
> **Note (Gemini)**: Claude Code enforces parts of these rules with PreToolUse / Stop
|
|
561
|
-
> hooks and sub-agent dispatch. Gemini CLI has
|
|
562
|
-
>
|
|
760
|
+
> hooks and sub-agent dispatch. Gemini CLI has those surfaces natively too (ADR-031),
|
|
761
|
+
> but CONDUCTOR does not emit hooks/agents here yet (Phase 2). Where a rule mentions a
|
|
762
|
+
> Claude-only mechanism, treat it as self-policed: read the rule, follow it.
|
|
563
763
|
|
|
564
764
|
## ABSOLUTE rules (summary) / 절대 규칙 요약
|
|
565
765
|
|
|
@@ -699,8 +899,68 @@ FOOTER_EOF
|
|
|
699
899
|
fi
|
|
700
900
|
record_emit "GEMINI.md" "<synthesized:5-universal-rules+workflow>" "$MANIFEST_LAST_BACKUP"
|
|
701
901
|
|
|
902
|
+
else
|
|
903
|
+
# ----- à-la-carte modes: marked block appended to GEMINI.md (ADR-044) ------
|
|
904
|
+
BLOCK_NAME="recipes"; [ "$MODE" = "reflector-only" ] && BLOCK_NAME="reflector"
|
|
905
|
+
log "Step 1/3: --mode=$MODE — '$BLOCK_NAME' marked block → $GEMINI_DEST (no full bundle)"
|
|
906
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
907
|
+
log "would append marked block '$BLOCK_NAME' (selected recipes: $RECIPES) to $GEMINI_DEST"
|
|
908
|
+
else
|
|
909
|
+
_blk="$(/usr/bin/mktemp "${TMPDIR:-/tmp}/conductor-block.XXXXXX")"
|
|
910
|
+
{
|
|
911
|
+
echo "# CONDUCTOR — à la carte (--mode=$MODE)"
|
|
912
|
+
echo ""
|
|
913
|
+
echo "> Installed by CONDUCTOR WITHOUT the universal-rule bundle. This is a managed"
|
|
914
|
+
echo "> block: --uninstall strips it when unmodified. Full workflow: --mode=full."
|
|
915
|
+
echo ""
|
|
916
|
+
IFS=',' read -ra RECIPE_LIST <<< "$RECIPES"
|
|
917
|
+
for r in "${RECIPE_LIST[@]}"; do
|
|
918
|
+
r="$(printf '%s' "$r" | /usr/bin/sed 's/^ *//; s/ *$//')"
|
|
919
|
+
[ -z "$r" ] && continue
|
|
920
|
+
src="$CORE_ROOT/recipes/$r.md"
|
|
921
|
+
if [ ! -f "$src" ]; then
|
|
922
|
+
echo "Warning: recipe '$r' not found at $src; skipping" >&2
|
|
923
|
+
continue
|
|
924
|
+
fi
|
|
925
|
+
echo "## Recipe — $r"
|
|
926
|
+
echo ""
|
|
927
|
+
emit_rule_body "$src"
|
|
928
|
+
echo ""
|
|
929
|
+
INSTALLED_RECIPES="$INSTALLED_RECIPES $r"
|
|
930
|
+
done
|
|
931
|
+
} > "$_blk"
|
|
932
|
+
if [ -z "${INSTALLED_RECIPES// /}" ]; then
|
|
933
|
+
/bin/rm -f "$_blk"
|
|
934
|
+
echo "Error: --mode=$MODE resolved ZERO valid recipes from '--recipes=$RECIPES' — nothing to install (check the names)." >&2
|
|
935
|
+
/bin/rm -f "$MANIFEST_STAGE_PATH"
|
|
936
|
+
exit 1
|
|
937
|
+
fi
|
|
938
|
+
append_block "$GEMINI_DEST" "$BLOCK_NAME" "$_blk"
|
|
939
|
+
/bin/rm -f "$_blk"
|
|
940
|
+
record_emit_block "GEMINI.md" "$BLOCK_NAME" "$BLOCK_SHA" "$BLOCK_CREATED"
|
|
941
|
+
# Preserve OTHER à-la-carte blocks from a previous install (e.g. recipes-only
|
|
942
|
+
# then reflector-only): carry their manifest entries forward so uninstall can
|
|
943
|
+
# still strip them (ADR-044 review fix — cross-mode orphaned block).
|
|
944
|
+
if [ -f "$MANIFEST_PATH" ]; then
|
|
945
|
+
while IFS= read -r _prev; do
|
|
946
|
+
case "$_prev" in *'"type": "block"'*) : ;; *) continue ;; esac
|
|
947
|
+
_pname="$(printf '%s' "$_prev" | /usr/bin/sed -E 's/.*"block": *"([^"]*)".*/\1/')"
|
|
948
|
+
[ "$_pname" = "$BLOCK_NAME" ] && continue
|
|
949
|
+
if /usr/bin/grep -qF "<!-- conductor:block $_pname -->" "$GEMINI_DEST" 2>/dev/null; then
|
|
950
|
+
printf '%s\n' "$_prev" | /usr/bin/sed 's/,*$/,/' >> "$MANIFEST_STAGE_PATH"
|
|
951
|
+
log " preserved previous block '$_pname' in manifest"
|
|
952
|
+
fi
|
|
953
|
+
done < "$MANIFEST_PATH"
|
|
954
|
+
fi
|
|
955
|
+
fi
|
|
956
|
+
fi
|
|
957
|
+
|
|
702
958
|
# ----- step 2: .gemini/styleguide.md (opt-in: coding-conventions) ---------
|
|
703
959
|
|
|
960
|
+
if [ "$MODE" != "full" ] && [ "$MODE" != "strict" ]; then
|
|
961
|
+
# À la carte: the marked block is the sole carrier (no side files); minimal ships text only.
|
|
962
|
+
WANT_STYLEGUIDE="false"
|
|
963
|
+
fi
|
|
704
964
|
log "Step 2/3: .gemini/styleguide.md (opt-in via --recipes=coding-conventions)"
|
|
705
965
|
if [ "$WANT_STYLEGUIDE" = "true" ]; then
|
|
706
966
|
STYLE_SRC="$CORE_ROOT/recipes/coding-conventions.md"
|
|
@@ -732,7 +992,13 @@ fi
|
|
|
732
992
|
|
|
733
993
|
# ----- self-improvement (opt-in: self-improvement recipe) ------------------
|
|
734
994
|
|
|
735
|
-
|
|
995
|
+
if [ "$MODE" = "minimal" ]; then
|
|
996
|
+
RECIPES_FOR_RUNTIME=""
|
|
997
|
+
log "Step: self-improvement runtime — skipped (--mode=minimal ships text only)"
|
|
998
|
+
else
|
|
999
|
+
RECIPES_FOR_RUNTIME="$RECIPES"
|
|
1000
|
+
fi
|
|
1001
|
+
case ",$RECIPES_FOR_RUNTIME," in
|
|
736
1002
|
*",self-improvement,"*)
|
|
737
1003
|
log "Step: self-improvement (Reflector) → .gemini hooks/command/agent"
|
|
738
1004
|
if [ "$DRY_RUN" != "true" ]; then
|
|
@@ -781,6 +1047,9 @@ esac
|
|
|
781
1047
|
|
|
782
1048
|
# ----- step 3: docs templates --------------------------------------------
|
|
783
1049
|
|
|
1050
|
+
if [ "$MODE" = "recipes-only" ] || [ "$MODE" = "reflector-only" ]; then
|
|
1051
|
+
log "Step 3/3: docs templates — skipped (--mode=$MODE is à la carte; docs ship with full/minimal)"
|
|
1052
|
+
else
|
|
784
1053
|
log "Step 3/3: docs templates → docs/"
|
|
785
1054
|
mkdir_if_real "$TARGET_ABS/docs"
|
|
786
1055
|
mkdir_if_real "$TARGET_ABS/docs/specs"
|
|
@@ -815,6 +1084,8 @@ if [ -f "$CORE_ROOT/docs-templates/specs/_example.md" ]; then
|
|
|
815
1084
|
fi
|
|
816
1085
|
|
|
817
1086
|
# Finalize manifest after all emits.
|
|
1087
|
+
fi
|
|
1088
|
+
|
|
818
1089
|
finalize_manifest
|
|
819
1090
|
|
|
820
1091
|
# ----- completion summary -------------------------------------------------
|
|
@@ -824,14 +1095,19 @@ echo "========================================================"
|
|
|
824
1095
|
echo " Done."
|
|
825
1096
|
echo " Target: $TARGET_ABS"
|
|
826
1097
|
echo " Adapter: gemini"
|
|
827
|
-
echo "
|
|
1098
|
+
echo " Mode: $MODE"
|
|
1099
|
+
if [ "$MODE" = "recipes-only" ] || [ "$MODE" = "reflector-only" ]; then
|
|
1100
|
+
echo " GEMINI.md: marked à-la-carte block appended (no universal-rule bundle)"
|
|
1101
|
+
else
|
|
1102
|
+
echo " GEMINI.md: 1 bundled file (5 universal rules + workflow, always-loaded)"
|
|
1103
|
+
fi
|
|
828
1104
|
echo " Style guide: $([ "$WANT_STYLEGUIDE" = "true" ] && echo ".gemini/styleguide.md emitted" || echo "(not emitted — select coding-conventions)")"
|
|
829
1105
|
echo " Recipes installed:${INSTALLED_RECIPES:- (none)}"
|
|
830
1106
|
echo ""
|
|
831
1107
|
echo " Skipped (per ADR-004 honesty):"
|
|
832
1108
|
echo " - Hooks: CONDUCTOR emits the Reflector hook when --recipes=self-improvement (ADR-032); other guards remain Claude-only (ADR-034)."
|
|
833
|
-
echo " - Sub-agent personas: Gemini
|
|
834
|
-
echo " - Per-call model routing:
|
|
1109
|
+
echo " - Sub-agent personas: not yet emitted for Gemini (tool supports sub-agents natively — ADR-031; Phase 2)."
|
|
1110
|
+
echo " - Per-call model routing: supported natively by Gemini CLI (ADR-031); not yet automated by CONDUCTOR."
|
|
835
1111
|
echo " - Built-in memory: DIY at .memory/ (see the note inside GEMINI.md)."
|
|
836
1112
|
echo ""
|
|
837
1113
|
echo " Activation: open $TARGET_ABS with Gemini CLI — it loads GEMINI.md automatically."
|
|
@@ -839,6 +1115,6 @@ echo "========================================================"
|
|
|
839
1115
|
echo ""
|
|
840
1116
|
echo "Next steps for the project:"
|
|
841
1117
|
echo " 1. Replace {{PROJECT_NAME}} in GEMINI.md (and .gemini/styleguide.md if present)."
|
|
842
|
-
echo " 2. Edit docs/CURRENT_WORK.md with your project's current state."
|
|
1118
|
+
[ -d "$TARGET_ABS/docs" ] && echo " 2. Edit docs/CURRENT_WORK.md with your project's current state."
|
|
843
1119
|
echo " 3. Add .memory/ to .gitignore if you adopt the DIY memory pattern."
|
|
844
1120
|
echo " 4. Rename docs/specs/_example.md → docs/specs/<your-area>.md."
|
|
@@ -6,15 +6,12 @@ Windsurf (the AI-IDE) is a T3 target because:
|
|
|
6
6
|
- It supports a directory of additional rules at `.devin/rules/*.md` (preferred; legacy `.windsurf/rules/` is still read).
|
|
7
7
|
- Its workflow is similar to Cursor's but with less per-pattern scoping.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
**Tool capability vs CONDUCTOR emission (ADR-031):** as of 2026 Windsurf / Devin Desktop ships hooks (12 events — but **no session/stop events**, the one real Stop-style-enforcement gap), sub-agent dispatch (Devin Local), custom agents, per-task model routing, commands, and built-in 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). Real tool-side caveats: no glob rule-scoping (all `.devin/rules/*.md` load together) and no desktop scheduler.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
-
|
|
14
|
-
- ❌ No per-call model routing.
|
|
15
|
-
- ❌ No built-in memory directory.
|
|
11
|
+
**Tier**: T3 (see `docs/COMPATIBILITY-MATRIX.md` — the missing session/stop hook events keep it below T2).
|
|
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**: T3 — Basic. Rule TEXT installs and groups well, but enforcement and scoping are minimal.
|
|
18
15
|
|
|
19
16
|
## Installation path
|
|
20
17
|
|
|
@@ -39,11 +36,12 @@ bash adapters/windsurf/transform.sh <target> --uninstall
|
|
|
39
36
|
├── .windsurfrules # Always-loaded baseline (orchestrator manual + ABSOLUTE rules)
|
|
40
37
|
├── .devin/ # Preferred rules dir (legacy .windsurf/rules/ still read)
|
|
41
38
|
│ └── rules/
|
|
42
|
-
│ ├──
|
|
43
|
-
│ ├── coding-conventions.md
|
|
44
|
-
│ ├── token-economy.md
|
|
39
|
+
│ ├── workflow.md
|
|
45
40
|
│ ├── spec-as-you-go.md
|
|
46
|
-
│
|
|
41
|
+
│ ├── quality-gates.md
|
|
42
|
+
│ ├── operations.md
|
|
43
|
+
│ ├── meta-discipline.md
|
|
44
|
+
│ └── <recipe>.md # per --recipes=
|
|
47
45
|
└── docs/
|
|
48
46
|
├── CURRENT_WORK.md # Universal templates
|
|
49
47
|
├── REMAINING_TASKS.md
|
|
@@ -53,22 +51,25 @@ bash adapters/windsurf/transform.sh <target> --uninstall
|
|
|
53
51
|
└── specs/_example.md
|
|
54
52
|
```
|
|
55
53
|
|
|
56
|
-
|
|
54
|
+
- `--recipes=self-improvement` additionally emits the Reflector loop: trajectory hook config (`.windsurf/hooks.json`, riding `post_cascade_response_with_transcript` — Windsurf has no session/stop event), the `/reflect` workflow (`.windsurf/workflows/reflect.md`), a reflector persona rule (`.devin/rules/reflector.md`, `trigger: manual`), prune script, and the `.conductor/reflect/` weekly runner (ADR-032/033).
|
|
55
|
+
|
|
56
|
+
## Native features supported (emitted today)
|
|
57
57
|
|
|
58
58
|
- ✅ Always-loaded baseline (`.windsurfrules`).
|
|
59
59
|
- ✅ Directory-based rule loading (`.devin/rules/`; legacy `.windsurf/rules/` still read).
|
|
60
60
|
- ✅ All universal rule TEXT.
|
|
61
61
|
- ✅ All doc templates.
|
|
62
|
+
- ✅ Reflector loop (opt-in recipe).
|
|
62
63
|
|
|
63
|
-
##
|
|
64
|
+
## Not emitted yet (Phase 2 — Windsurf supports most of these natively, ADR-031/034)
|
|
64
65
|
|
|
65
|
-
| Feature |
|
|
66
|
+
| Feature | Interim workaround |
|
|
66
67
|
|---|---|
|
|
67
|
-
| Per-pattern rule scoping | All rules in `.devin/rules/` load together. No glob filtering. |
|
|
68
|
-
|
|
|
69
|
-
|
|
|
70
|
-
| Per-call model
|
|
71
|
-
|
|
|
68
|
+
| Per-pattern rule scoping | All rules in `.devin/rules/` load together. No glob filtering (tool-side). |
|
|
69
|
+
| Enforcement guard hooks | Windsurf has hooks but **no session/stop events** (tool-side gap) — Stop-style enforcement isn't possible; self-police or pair with pre-commit git hooks. |
|
|
70
|
+
| The 6 role agents (sub-agent dispatch) | Devin Local has native sub-agents; CONDUCTOR doesn't emit its role definitions yet. Human plays orchestrator. |
|
|
71
|
+
| Per-call model-routing config | Pick the model per task via the tool's own model selection. |
|
|
72
|
+
| 4-type memory pattern | Self-managed at `.memory/` (gitignored); the tool's built-in memory is separate. |
|
|
72
73
|
|
|
73
74
|
## After install — first steps
|
|
74
75
|
|