Quellcode durchsuchen

feat(skills): loop-ops iter1 — pattern-aware loop-init (vs upstream starters)

Closes the one dimension where upstream's loop-init led: it seeds per-pattern.
`loop-init --pattern ci-sweeper` now seeds the config with that pattern's
scope/goal/escalation (and, at L2+, its real gate verify/guard/worktree/land_via)
instead of only setting the `pattern:` field. Doctrine preserved: it still
scaffolds at L1 by default with a commented graduation block; a seeded L1 config
audits clean immediately, and a seeded L2 config audits AND doctors clean. Unknown
/custom patterns fall back to the generic placeholder template. Suite 81->87.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
0xDarkMatter vor 1 Monat
Ursprung
Commit
ed6e7bf739
3 geänderte Dateien mit 101 neuen und 3 gelöschten Zeilen
  1. 5 1
      skills/loop-ops/SKILL.md
  2. 81 2
      skills/loop-ops/scripts/loop-init.sh
  3. 15 0
      skills/loop-ops/tests/run.sh

+ 5 - 1
skills/loop-ops/SKILL.md

@@ -168,7 +168,11 @@ Writes `<dir>/<name>/` with four files from the bundled templates:
 `loop.config.yaml` ([assets/loop.config.template.yaml](assets/loop.config.template.yaml)),
 `STATE.md` ([assets/STATE.template.md](assets/STATE.template.md)), `run-log.md`, and
 `run.md` — the headless run prompt a scheduler feeds to `claude -p`
-([assets/run.template.md](assets/run.template.md)).
+([assets/run.template.md](assets/run.template.md)). Pass a known `--pattern`
+(pr-babysitter, ci-sweeper, dependency-sweeper, …) and the config is **seeded** with that
+pattern's scope/goal/escalation — and, at L2+, its gate — so you get a near-ready config to
+review, not blank placeholders (it audits clean immediately). Doctrine holds: it still
+scaffolds at L1 by default with a graduation block.
 
 ```bash
 # Create .loops/pr-babysitter/ with config + STATE.md + run-log.md + run.md from templates:

+ 81 - 2
skills/loop-ops/scripts/loop-init.sh

@@ -114,6 +114,44 @@ case "$TIER" in
   L3)    PMODE="bypassPermissions" ;;
 esac
 
+# ── pattern presets ─────────────────────────────────────────────────────────
+# Seed a near-ready config for a known --pattern (the user reviews, doesn't start
+# from blank placeholders). Doctrine: always scaffold at the chosen tier; report/
+# propose/draft patterns carry no gate (VERIFY_SEED empty), code-changing ones do.
+SEEDED=0; SCOPE_SEED=""; GOAL_SEED=""; ESCAL_SEED=""; VERIFY_SEED=""; GUARD_SEED=""
+case "$PATTERN" in
+  daily-triage) SEEDED=1
+    SCOPE_SEED="src/**"
+    GOAL_SEED="Sweep the backlog/issues/alerts and write the day's STATE.md priority list; report only."
+    ESCAL_SEED="everything - a human decides what to action; this loop never changes code" ;;
+  pr-babysitter) SEEDED=1
+    SCOPE_SEED="src/**"
+    GOAL_SEED="Watch open PRs; flag stuck/failing/conflicted; post a summary comment at most; never merge."
+    ESCAL_SEED="a human reviews and merges; never merge to main" ;;
+  ci-sweeper) SEEDED=1
+    SCOPE_SEED="src/**"
+    GOAL_SEED="Detect red CI; classify the failure; at L2 propose a fix in a worktree; never auto-merge to main."
+    ESCAL_SEED="flaky/infra failures, anything touching deploy/secrets, ambiguous root cause"
+    VERIFY_SEED="npm test"; GUARD_SEED="npm run typecheck" ;;
+  dependency-sweeper) SEEDED=1
+    SCOPE_SEED="package.json"
+    GOAL_SEED="Patch-only dependency bumps behind the release cooldown + guard; open a PR; never minor/major."
+    ESCAL_SEED="minor/major bumps, guard failures, any flagged advisory"
+    VERIFY_SEED="npm test"; GUARD_SEED="npm run build && npm test" ;;
+  changelog-drafter) SEEDED=1
+    SCOPE_SEED="CHANGELOG.md"
+    GOAL_SEED="Summarize merged PRs since the last tag into RELEASE_NOTES_DRAFT.md; never publish a release."
+    ESCAL_SEED="the human edits and publishes; never run gh release create" ;;
+  post-merge-cleanup) SEEDED=1
+    SCOPE_SEED="src/**"
+    GOAL_SEED="Find merged-deletable branches / stale flags / orphaned artifacts; report; never delete unmerged work."
+    ESCAL_SEED="anything ambiguous; never delete a branch with unmerged commits" ;;
+  issue-triage) SEEDED=1
+    SCOPE_SEED="src/**"
+    GOAL_SEED="Classify new issues and suggest labels + priority; propose only; never close or set priority unattended."
+    ESCAL_SEED="priority calls, dupe-closing, anything needing product judgment" ;;
+esac
+
 TARGET_DIR="$DIR/$NAME"
 CFG_OUT="$TARGET_DIR/loop.config.yaml"
 STATE_OUT="$TARGET_DIR/STATE.md"
@@ -162,6 +200,47 @@ render_run() {
     "$RUN_TPL"
 }
 
+# Seeded config for a known pattern. L1 stays report-only (gate fields are a
+# commented graduation block); L2/L3 emit verify/guard/worktree/land_via — using
+# the pattern's gate if it has one, else a <fill:…> placeholder the audit will flag.
+render_seeded_config() {
+  cat <<EOF
+# loop.config.yaml - $PATTERN (seeded by loop-init at $TIER; REVIEW before scheduling)
+# Full field semantics: skills/loop-ops/references/state-spine.md
+name: $NAME
+pattern: $PATTERN
+tier: $TIER
+permission_mode: $PMODE
+cadence: $CADENCE
+goal: "$GOAL_SEED"
+scope:
+  - "$SCOPE_SEED"
+escalation: "$ESCAL_SEED"
+budget_tokens: 200000
+kill_switch: ".loops/$NAME/PAUSED exists, OR the loop-pause label is set"
+EOF
+  if [[ "$TIER" == "L1" ]]; then
+    cat <<EOF
+
+# ── graduate to L2 (assisted): set tier: L2, uncomment + fill, re-run loop-audit + loop-doctor --live ──
+# verify: "${VERIFY_SEED:-<fill: the gate command, e.g. npm test>}"
+# guard: "${GUARD_SEED:-<fill: a must-always-pass command>}"
+# worktree: true
+# land_via: fleet-ops
+EOF
+  else
+    cat <<EOF
+verify: "${VERIFY_SEED:-<fill: the gate command for this loop>}"
+guard: "${GUARD_SEED:-<fill: a must-always-pass command>}"
+worktree: true
+land_via: fleet-ops
+EOF
+  fi
+}
+
+# Pick the seeded renderer for a known pattern, else the generic template.
+emit_config() { if [[ "$SEEDED" -eq 1 ]]; then render_seeded_config; else render_config; fi; }
+
 # ── dry-run: print and stop ─────────────────────────────────────────────────
 if [[ "$DRY_RUN" -eq 1 ]]; then
   printf '%s\n' "$CFG_OUT"
@@ -174,7 +253,7 @@ if [[ "$DRY_RUN" -eq 1 ]]; then
     term_panel_vert
     term_panel_close "nothing written" ""
   } >&2
-  render_config
+  emit_config
   exit "$EX_OK"
 fi
 
@@ -188,7 +267,7 @@ write_atomic() {  # write_atomic <dest> <content>
   mv -f "$tmp" "$dest" || { rm -f "$tmp"; printf 'error: failed to move into place: %s\n' "$dest" >&2; exit 1; }
 }
 
-write_atomic "$CFG_OUT"   "$(render_config)"
+write_atomic "$CFG_OUT"   "$(emit_config)"
 write_atomic "$STATE_OUT" "$(render_state)"
 write_atomic "$LOG_OUT"   "$(render_log)"
 write_atomic "$RUN_OUT"   "$(render_run)"

+ 15 - 0
skills/loop-ops/tests/run.sh

@@ -115,6 +115,21 @@ bash "$INIT" --dir "$SB/loops" >/dev/null 2>&1; expect_exit "missing --name -> 2
 bash "$INIT" --name BadName --dir "$SB/loops" >/dev/null 2>&1; expect_exit "non-kebab name -> 2" 2 $?
 bash "$INIT" --name x --tier L9 --dir "$SB/loops" >/dev/null 2>&1; expect_exit "bad tier -> 2" 2 $?
 
+# pattern-seeding: a known pattern seeds a near-ready, audit-clean config
+bash "$INIT" --name seed-l1 --pattern ci-sweeper --tier L1 --cadence 15m --dir "$SB/seed" >/dev/null 2>&1
+seedcfg="$(cat "$SB/seed/seed-l1/loop.config.yaml")"
+expect_has "seeded config carries the pattern goal" "Detect red CI" "$seedcfg"
+expect_has "seeded L1 leaves a graduation block" "graduate to L2" "$seedcfg"
+bash "$AUDIT" "$SB/seed/seed-l1/loop.config.yaml" >/dev/null 2>&1; expect_exit "seeded L1 audits clean -> 0" 0 $?
+# at L2 the pattern's gate is filled (not commented) and audits clean
+bash "$INIT" --name seed-l2 --pattern ci-sweeper --tier L2 --cadence 15m --dir "$SB/seed" >/dev/null 2>&1
+l2cfg="$(cat "$SB/seed/seed-l2/loop.config.yaml")"
+case "$l2cfg" in *$'\nverify: "npm test"'*) ok "seeded L2 fills the gate";; *) no "seeded L2 did not fill the gate";; esac
+bash "$AUDIT" "$SB/seed/seed-l2/loop.config.yaml" >/dev/null 2>&1; expect_exit "seeded L2 audits clean -> 0" 0 $?
+# an unknown pattern falls back to the generic placeholder template (not ready)
+bash "$INIT" --name seed-x --pattern custom --tier L1 --dir "$SB/seed" >/dev/null 2>&1
+case "$(cat "$SB/seed/seed-x/loop.config.yaml")" in *"<one sentence"*) ok "unknown pattern uses generic template";; *) no "unknown pattern did not use template";; esac
+
 # ── loop-audit: a freshly-init'd config is NOT ready (placeholders) -> 10 ───
 echo "-- loop-audit --"
 bash "$INIT" --name raw --pattern custom --tier L1 --dir "$SB/loops" >/dev/null 2>&1