From collie
Main loop orchestrator for collie. Drives the 'run → observe → triage → deep-verify → fix → rerun' self-iteration pipeline. Called by commands/autoiter.md on every ralph-loop session restart. Implements a persistent state machine (§3.5) across ralph-loop session restarts: fresh-start → Stage 0 (Discovery planmode) → Stage 1 (kickoff) → Stage 2 (run trigger) → Stage 3 (observe + auto-recovery) → Stage 4a (Triage) → Stage 4b (Deep Verify) → Stage 5.0 (fix-plan) → Stage 5.1 (flow) → Stage 5.2 (G6 diff audit + rerun) → Stage 6 (rollback + stop check). Completion signal: <promise>Collie: AUTOITER DONE</promise> (emitted ONLY by the §3.5 terminal branch after ralph-loop restart, NEVER inline).
How this skill is triggered — by the user, by Claude, or both
Slash command
/collie:autoiterThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Drives the iterative improvement pipeline: run trigger → observe → triage → deep-verify → gated fix → rerun → stop check. Invoked by `commands/autoiter.md` on every ralph-loop session restart.
Drives the iterative improvement pipeline: run trigger → observe → triage → deep-verify → gated fix → rerun → stop check. Invoked by commands/autoiter.md on every ralph-loop session restart.
Completion signal: <promise>Collie: AUTOITER DONE</promise>
Sentinel rule: Emitted ONLY by the §3.5 terminal branch. NO other stage emits it inline.
digraph autoiter {
rankdir=TB;
node [shape=box, style=rounded];
entry [label="SKILL entry\n§3.5 state machine"];
nested_check [label="Nested-call check\n(COLLIE_AUTOITER_ACTIVE?)"];
fail_fast [label="fail-fast escalate\n(do NOT rm current-run)", shape=ellipse];
no_current_run [label="current-run missing?", shape=diamond];
fresh_start [label="Fresh start:\ngenerate runId\nwrite current-run"];
stage0 [label="Stage 0\nDiscovery & Lock\n(planmode)"];
ralph_restart [label="ExitPlanMode\n→ ralph-loop restart"];
run_spec_missing [label="run-spec.md missing?", shape=diamond];
recovery [label="Recovery chain:\nlast-plan.json→plan file\n→plan-source→cp run-spec.md"];
recovery_fail [label="Recovery failed\nrm current-run", shape=ellipse];
worktree_prepare [label="Create worktree\nautoiter-prepare (if needed)\ninit state.json(iter=1)"];
read_state [label="Read state.json"];
terminal [label="status=terminal:\nrm current-run\nemit sentinel", shape=ellipse];
stage1 [label="Stage 1 Kickoff"];
stage2 [label="Stage 2 Run Trigger\n(background)"];
stage3 [label="Stage 3 Observe"];
blocker [label="Blocking issue?\nauto-recovery ladder", shape=diamond];
blocker_fail [label="Write escalated → return\n(§3.5 handles)", shape=ellipse];
stage4a [label="Stage 4a Triage\n(opus, reverse suspicion)"];
stage4b [label="Stage 4b Deep Verify\n(opus, adversarial, parallel)"];
stage50 [label="Stage 5.0 Fix Plan\n(G7 check first)"];
g7_fail [label="G7 deadlock\nescalated → return", shape=ellipse];
stage51 [label="Stage 5.1 flow"];
stage52 [label="Stage 5.2 G6 Diff Audit"];
g6_fail [label="G6 fail\nescalated → return", shape=ellipse];
stage53 [label="Stage 5.3 Rerun + scalar"];
stage6 [label="Stage 6 Rollback + Stop Check"];
stop [label="Stop: write terminal state\nreturn (§3.5 handles sentinel)", shape=ellipse];
next_iter [label="iter++\nstate=running → Stage 1"];
entry -> nested_check;
nested_check -> fail_fast [label="COLLIE_AUTOITER_ACTIVE set"];
nested_check -> no_current_run [label="not nested"];
no_current_run -> fresh_start [label="yes"];
no_current_run -> run_spec_missing [label="no"];
fresh_start -> stage0;
stage0 -> ralph_restart;
ralph_restart -> entry [label="next session §3.5 re-entry"];
run_spec_missing -> recovery [label="yes"];
recovery -> recovery_fail [label="chain fails"];
recovery_fail -> fresh_start [label="fresh start"];
recovery -> worktree_prepare [label="success"];
worktree_prepare -> stage1;
run_spec_missing -> read_state [label="no"];
read_state -> stage1 [label="status=running"];
read_state -> stage6 [label="status=iter_done"];
read_state -> terminal [label="status=terminal"];
stage1 -> stage2;
stage2 -> stage3;
stage3 -> blocker;
blocker -> stage4a [label="no blocking issues"];
blocker -> blocker_fail [label="ladder exhausted"];
stage4a -> stage4b;
stage4b -> stage50;
stage50 -> g7_fail [label="G7 deadlock"];
stage50 -> stage51 [label="ok"];
stage51 -> stage52;
stage52 -> g6_fail [label="audit FAIL"];
stage52 -> stage53 [label="PASS"];
stage53 -> stage6;
stage6 -> stop [label="SC1-SC5 met"];
stage6 -> next_iter [label="continue"];
next_iter -> stage1;
}
⛔ 主 session 是协调器,不是执行器。
仅以下 5 类操作允许 inline,逻辑上是单点动作:
nohup bash 启动 trigger(单行命令)fix-plan.md(仅汇总 4b deep-verify 输出,禁止读源码)git diff HEAD~1..HEAD --name-only(单行 git,结果不解析)~/.collie/autoiter/... 下的 status / progress / state)mkdir -p iter-N/)每次需要执行操作时,主 agent 按以下基准自主裁定 inline vs dispatch + model:
裁定步骤:
~/.claude/CLAUDE.md 中的"Agent 模型选择速查"+"Subagent 派发策略"两节Agent 模型选择速查(节选自用户 CLAUDE.md):
Explore → haiku(文件搜索、代码分析、只读探索)general-purpose 轻量 → haiku(文档生成、简单分析)general-purpose 标准 → sonnet(代码实现、中等复杂度)general-purpose 复杂 → opus(架构决策、复杂重构)code-reviewer → sonnetPlan → opus(架构设计、规划)典型应用例子(参考,非强制;具体 stage 由主 agent 实时裁定):
任何其他 stage 的 inline / dispatch + model 选择由主 agent 实时裁定,plan 不硬编码。
PROJECT_ID=$(node -e "const s=require('./hooks/_state.js'); console.log(s.projectId())")
CURRENT_RUN_FILE=$(node -e "const s=require('./hooks/_state.js'); console.log(s.currentRunFile('$PROJECT_ID'))")
If COLLIE_AUTOITER_ACTIVE environment variable is set → this is a nested call from inside another /auto or /autoiter session.
Action: call scripts/escalate.sh "nested_loop_call" "$PROJECT_ID" then stop immediately. Do NOT rm current-run (the outer run owns it).
If not nested: set export COLLIE_AUTOITER_ACTIVE=1 for all subprocesses in this session, then proceed.
~/.collie/autoiter/{project-id}/current-run does NOT exist → Fresh start:
runId: YYYYMMDD-HHMMSS-{shortSessionId} (use date +%Y%m%d-%H%M%S + first 6 chars of $CLAUDE_SESSION_ID or random hex)mkdir -p ~/.collie/autoiter/{project-id}/Post-planmode recovery path:
runId = $(cat $CURRENT_RUN_FILE)~/.collie/state/{sessionId}/last-plan.json → get plan file pathplan-source field valuerm $CURRENT_RUN_FILE → go to Branch Amkdir -p ~/.collie/autoiter/{project-id}/{runId}/
# ⛔ NEVER use Write or Edit — cp only (prevents LLM rewriting content)
cp "$PLAN_SOURCE" ~/.collie/autoiter/{project-id}/{runId}/run-spec.md
git worktree add .worktrees/autoiter-{runId} -b autoiter/{runId}
echo "$(pwd)/.worktrees/autoiter-{runId}" > ~/.collie/autoiter/{project-id}/{runId}/worktree-path
skip_prepare from run-spec.mdskip_prepare=false AND prepare-report.md does NOT exist:
Skill('collie:autoiter-prepare') with: run_spec_path, report_path, project_id, run_id, worktree_pathAskUserQuestion "Prepare failed: [X]. Fix material and retry, or abort?"state.json.status="escalated" → return (§3.5 terminal handles on next restart)state.json:
{
"runId": "<runId>",
"iter": 1,
"status": "running",
"should_continue": true,
"stop_reason": null,
"last_scalar": null,
"baseline_scalar": null,
"promise_signal": "Collie: AUTOITER DONE"
}
Read state.json:
| status | action |
|---|---|
"running" | Re-enter Stage 1 kickoff (idempotent: skip write if kickoff.md already exists) |
"iter_done" | Proceed to Stage 6 stop check |
"converged" / "budget_exhausted" / "escalated" | Terminal: rm current-run → print [autoiter {runId}] All done — status={status} → emit <promise>Collie: AUTOITER DONE</promise> → stop |
| missing | Treat same as Branch B (run-spec.md missing path) |
Only reached on fresh start from Branch A.
Call EnterPlanMode.
Dispatch haiku subagent using system prompt from skills/autoiter/references/discovery-prompt.md. Input: project root. Output:
success_criterion type (all_green / scalar_threshold / convergence_delta / custom)primary_goal (correctness / optimization / both)Collect all 5 in one batch:
primary_goal? (correctness / optimization / both)iter_rollback_policy? (default: kind_aware)Write to planmode system-prompt-specified plan file (do NOT override path). Top 3 lines must be:
<!-- plan-source: <planmode plan file absolute path> -->
<!-- plan-kind: autoiter-stage0 -->
<!-- plan-executor: collie:autoiter -->
Body YAML:
task: <user prompt verbatim>
primary_goal: <Q3>
trigger:
kind: shell|replay|dataset
invocation: "<shell command>"
expected_output: "stdout stream / junit xml / custom parser"
scalar_extraction: "<grep/regex/jq path>"
success_criterion:
type: all_green|scalar_threshold|convergence_delta|custom
threshold: <Q2 value>
budget:
max_iterations: 5
max_tokens: unlimited
max_wallclock_min: unlimited
overfit_guards: [G1, G2, G3, G4, G5, G6, G7, G8]
iter_rollback_policy: kind_aware
skip_prepare: false
Call ExitPlanMode. This is the ONLY exit from Stage 0.
ralph-loop restarts the session. §3.5 Branch B (recovery path) handles everything after.
⛔ 每次进入 Stage 1(iteration 起始)必须先做这一步,再做原 Step 1。
上一 iter 的 [iter-{N-1} stage-*] 任务先标 completed(正常结束)或 deleted(被 rollback)
TaskCreate 6 次建立本 iter 锚点:
[iter-N stage-1] Kickoff(git HEAD + baseline)[iter-N stage-2] Run trigger(subprocess background + Monitor/tail)[iter-N stage-3] Observe(ISSUE 收集 + auto-recovery 阶梯)[iter-N stage-4] Triage + Deep Verify(4a/4b opus)[iter-N stage-5] Fix Plan + flow + G6 audit + Rerun(5.0/5.1/5.2/5.3)[iter-N stage-6] Rollback + Stop CheckN 从 state.json 读取
TaskUpdate [iter-N stage-1] in_progress,进入原 Step 1
Self-anchor:长 dispatch(subagent 返回 > 200 字符或耗时 > 30s)后,主 agent 必须先 TaskList 确认当前 anchor 与 SKILL 当前 stage 一致;漂移 → STOP + escalate stage_anchor_drift。Stage 切换时 TaskUpdate 切 completed/in_progress 后再进入下一 stage。
All Stage 1+ work runs inside the worktree. Read worktree-path to get the absolute path.
WORKTREE=$(cat ~/.collie/autoiter/{project-id}/{runId}/worktree-path)
ITER_DIR=~/.collie/autoiter/{project-id}/{runId}/iter-{N}
mkdir -p $ITER_DIR/fixes
Write iter-N/kickoff.md (skip if already exists — idempotency):
# Kickoff — iter-N
git_head: <git rev-parse HEAD>
baseline_metric: <state.last_scalar or "none (first iter)">
iter_goal: <based on progress.md DEFERRED pool if iter > 1>
timestamp: <ISO-8601>
Observability:
status.md: iter N/M · Stage 1 · Kickoff · preparing triggeruser-log.md: ## iter-N · <ts>\nKickoff. HEAD: <sha>. Baseline scalar: <val>.[autoiter {runId}] iter-N Stage 1 → Kickofftimeout_min = min(max_wallclock_min / max_iterations, 30)
# "unlimited" in either field → use 30 min
# Bash run_in_background=true
cd $WORKTREE
timeout ${timeout_min}m bash -c "<trigger.invocation>" \
> $ITER_DIR/raw.log 2>&1
echo "EXIT_CODE:$?" >> $ITER_DIR/raw.log
ToolSearch query="select:Monitor"
Monitor available: Subscribe to stdout stream in real-time. Record observations to iter-N/raw.log.
Monitor NOT available (fallback):
ScheduleWakeup delaySeconds=60 on each poll cycleraw.logEXIT_CODE: line appears in raw.logObservability:
status.md: iter N/M · Stage 2 · Running trigger · <elapsed>s elapsed[autoiter {runId}] iter-N Stage 2 → trigger running (timeout: {timeout_min}min)⚠️ 本 stage 内每次执行操作前请按 §Section 0 裁定基准选择 inline / dispatch + model。fix 应用属"执行"型,参考速查表选 sonnet。
Parse raw.log. For each issue:
## ISSUE-{nnn}
- title: <one-line summary>
- evidence: <log excerpt, max 5 lines>
- severity: 1-5
- first_seen_ts: <monotonic>
- blocking: true|false
Non-blocking issues → record and continue to Stage 4a.
Triggered when blocking: true or exit code non-zero.
Step 1: Kill subprocess:
kill -TERM <pid>; sleep 5; kill -KILL <pid> 2>/dev/null || true
Step 2: Assess complexity → choose start model:
Step 3: Recovery loop, max 3 attempts:
raw.log + run-spec.md; output: root_cause + fix_patch)Step 4: All 3 attempts fail → unrecoverable:
iter-N/blocker-report.md (each attempt: model, root_cause, fix_applied, result)status.md: iter N/M · Stage 3 · BLOCKED · auto-recovery ladder exhausteduser-log.mdscripts/escalate.sh "blocker_unrecoverable" "$RUN_ID"$COLLIE_AUTOITER_NOTIFY_CMD set: bash -c "$COLLIE_AUTOITER_NOTIFY_CMD" with env COLLIE_AUTOITER_EVENT=blocker_unrecoverable, COLLIE_AUTOITER_RUN_ID, COLLIE_AUTOITER_STATUS_FILEstate.json.status = "escalated"Observability:
status.md: iter N/M · Stage 3 · Observing · {n} issues found[autoiter {runId}] iter-N Stage 3 → {n} issues recorded, {m} blockingDispatch single opus subagent.
System prompt requirements (G3):
observations.md (anchor prevention)Inputs: iter-N/observations.md + run-spec.md + progress.md
Output: iter-N/triage.md
## ISSUE-{nnn}
verdict: Real | Discarded | Unclear
confidence: 1-5
rationale: <adversarial reasoning>
| condition | action |
|---|---|
| confidence ≥ 3, verdict Real/Unclear | Proceed to Stage 4b |
| confidence ≤ 2, verdict Real/Unclear | Write to progress.md DEFERRED pool, tag triage_low_confidence; skip Stage 4b |
| Discarded (any confidence) | Drop silently; do NOT write to DEFERRED |
Observability:
status.md: iter N/M · Stage 4a · Triage · {n_real} Real, {n_deferred} DEFERRED[autoiter {runId}] iter-N Stage 4a → triage complete ({n} → {m} to Deep Verify)For each issue that passed G8 Triage gate, dispatch ONE opus subagent in parallel.
System prompt requirements (G3):
observations.mdOutput: iter-N/fixes/FIX-{nnn}.md
id: FIX-{nnn}
kind: correctness | optimization | mixed
severity: 1-5
fix_confidence: 1-5
root_cause: "<text — must be non-empty>"
reproduction_test: |
<runnable test reproducing issue BEFORE fix>
fix_outline: "<what to change, where>"
why_root_cause: "<adversarial justification>"
dependencies: [FIX-xxx, ...]
uncertainty_tag: triage_unclear | none
| condition | action |
|---|---|
fix_confidence ≤ 2 | DEFERRED pool, tag deep_verify_low_confidence; exclude from Stage 5.0 |
root_cause empty | DEFERRED pool, tag g2_incomplete; exclude from Stage 5.0 |
reproduction_test empty | DEFERRED pool, tag g2_incomplete; exclude from Stage 5.0 |
fix_confidence ≥ 3 AND both fields non-empty | Eligible for Stage 5.0 |
Observability:
status.md: iter N/M · Stage 4b · Deep Verify · {n} FIX in verification[autoiter {runId}] iter-N Stage 4b → {n} issues in parallel Deep Verify⚠️ 本 stage 是 §Section 0 例外项 #2(受约束 inline)。仅汇总 4b deep-verify 输出到 fix-plan.md,禁止读源码。如需补充信息 → 按裁定基准 dispatch。
const { jaccard, bucketize } = require('./skills/autoiter/lib/jaccard.js');
// currentTasksText: concatenated task subject strings from current iter FIX-*.md files
// prevTasksText: concatenated task subject strings from iter-(N-1)/fix-plan.md (empty string if iter=1)
const ratio = jaccard(currentTasksText, prevTasksText); // returns [0.0, 1.0]
const bucket = bucketize(ratio); // returns 1-5
See skills/autoiter/references/overfit-guards.md §G7 for bucket thresholds.
If bucket >= 4 AND consecutiveDelta0 >= 2:
iter-N/summary.md: Jaccard ratio + bucketstate.json.status = "escalated"scripts/escalate.sh "loop_no_progress" "$RUN_ID"$COLLIE_AUTOITER_NOTIFY_CMD set: notify with COLLIE_AUTOITER_EVENT=deadlockOnly FIX entries with fix_confidence ≥ 3 AND non-empty root_cause AND non-empty reproduction_test are eligible.
Write iter-N/fix-plan.md using skills/autoiter/references/fix-plan-template.md:
<!-- plan-source: <absolute path to iter-N/fix-plan.md> -->
<!-- plan-topic: autoiter-iter-N-fixes -->
<!-- plan-executor: collie:flow -->
dependencies fields; independent FIX = same batch)root_cause → Why, fix_outline → How, reproduction_test → VerifyNone — iter-local change if no shared-state impact)run-spec.md — do NOT re-deriveObservability:
status.md: iter N/M · Stage 5.0 · Building fix-plan · {n} FIX eligible[autoiter {runId}] iter-N Stage 5.0 → fix-plan.md built ({n} FIX)Skill('collie:flow')
Input: iter-N/fix-plan.md. Runs full pipeline: TDD → implement → review → simplify → regression → [collie-final-review].
⚠️ git diff --name-only 是 §Section 0 例外项 #3(inline 取文件清单不解析内容)。审计 diff 内容属"执行+分析"型,按裁定基准 dispatch。
Execute immediately after flow returns.
git diff HEAD~1..HEAD --name-only
For each changed file: verify it appears in fix-plan.md Task list "Key files", OR is a mechanical consequence of a listed fix (auto-generated file, build artifact).
If any diff line is NOT traceable to any FIX entry:
state.json.status = "escalated"scripts/escalate.sh "g6_diff_audit_failed" "$RUN_ID"If audit passes → proceed to Stage 5.3.
See skills/autoiter/references/overfit-guards.md §G6 for full audit rules.
Observability:
[autoiter {runId}] iter-N Stage 5.2 → G6 diff audit PASS (or FAIL)⚠️ 启动 rerun bash 是 §Section 0 例外项 #1(inline)。raw.log 解析 / scalar 提取属"执行+分析"型,按裁定基准 dispatch。
cd $WORKTREE
bash -c "<trigger.invocation>" > $ITER_DIR/rerun.log 2>&1
Parse scalar from rerun.log using run-spec.trigger.scalar_extraction.
Write iter-N/summary.md:
# Summary — iter-N
scalar_before: <state.last_scalar>
scalar_after: <new_scalar>
scalar_delta: <new - before>
convergence: yes|no
decision: continue | stop_converged | stop_cap | stop_budget
fixes_applied: [FIX-001, FIX-002, ...]
Update state.json: { "last_scalar": <new_scalar>, "status": "iter_done" }
Observability:
status.md: iter N/M · Stage 5.3 · Rerun done · scalar={new} (was {old}, Δ={delta})user-log.md: narrative of this iter's outcome[autoiter {runId}] iter-N Stage 5.3 → rerun done, scalar={new}⚠️ "是否 rollback"决策 inline;执行 rollback 命令属"执行"型 + 涉及 ❌ 第 5 条(inline git reset),必须按裁定基准 dispatch。
MUST consult skills/autoiter/references/stop-criterion.md for the authoritative rollback matrix before executing any revert. The inline table below is a quick-reference summary only; the reference document governs all edge cases.
Full matrix in skills/autoiter/references/stop-criterion.md. Summary:
primary_goal | scalar_delta | action |
|---|---|---|
correctness | any | Never whole-iter rollback. Keep correctness FIX. Per-FIX revert optimization if scalar degrades. |
optimization | degrades | Per-FIX revert all kind=optimization; force-keep kind=correctness |
optimization | flat/improves | Keep all |
both | degrades + ≥50% optimization FIX | Per-FIX revert optimization; keep correctness |
both | degrades + ≥80% correctness FIX | Keep all (crash-fix priority) |
both | degrades + 50-80% correctness | Per-FIX revert optimization; keep correctness |
both | flat/improves | Keep all |
Per-FIX revert:
git revert --no-commit <commit-sha> # repeat for each optimization FIX being reverted
git commit -m "chore: revert optimization FIX(es) due to scalar regression (iter-N)"
Append rollback_log section to iter-N/summary.md for each reverted FIX.
Full spec in skills/autoiter/references/stop-criterion.md.
| ID | Condition | Terminal status |
|---|---|---|
| SC1 | iter >= max_iterations | budget_exhausted |
| SC2 | all_green reached OR scalar >= threshold | converged |
| SC3 | Last 2 iters: |scalar_delta| ≤ ε (ε=0 for int 1-5; ε=0.01×|baseline| for continuous) | converged |
| SC4 | tokens_used >= max_tokens OR elapsed >= max_wallclock_min | budget_exhausted |
| SC5 | stop-steps-counter.js triggered (same error ×3 or no file changes ×5) | escalated |
If any stop condition true:
iter-N/summary.md decision fieldstatus.md: DONE · {reason} · scalar={final} (baseline={base}, Δ={total})user-log.md$COLLIE_AUTOITER_NOTIFY_CMD set: bash -c "$COLLIE_AUTOITER_NOTIFY_CMD" with COLLIE_AUTOITER_EVENT=autoiter_done (or escalated/budget_exhausted)state.json.status = <terminal status>rm current-run + sentinel on next ralph-loop restart.[autoiter {runId}] Stage 6 → STOP ({reason})If continue:
state.json.iter = N+1, status = "running"[autoiter {runId}] Stage 6 → continue to iter-{N+1}At every stage transition and iter boundary, update ALL of:
status.md (overwrite): iter N/M · Stage X · <description> · scalar=<val>user-log.md (append): human-readable narrative[autoiter {runId}] iter-N Stage X → ...$COLLIE_AUTOITER_NOTIFY_CMD set:
COLLIE_AUTOITER_EVENT=<event> \
COLLIE_AUTOITER_RUN_ID=<runId> \
COLLIE_AUTOITER_STATUS_FILE=<path/to/status.md> \
bash -c "$COLLIE_AUTOITER_NOTIFY_CMD"
Terminal events: autoiter_done, escalated, budget_exhausted, blocker_unrecoverable, prepare_failed, deadlock<promise>Collie: AUTOITER DONE</promise> emitted ONLY by §3.5 terminal branch. Never from Stage 3/5/6 inline.cp in Branch B recovery; never modified after creation.rm current-run THEN emit sentinel (crash-safe ordering).kind=correctness with explicit reproduction_test new-file addition. See overfit-guards.md §G1.prepare-report.md already exists, skip prepare entirely.COLLIE_AUTOITER_ACTIVE check prevents /autoiter inside /auto or another /autoiter.skills/autoiter/references/overfit-guards.md — G1-G8 rules (enforced at Stage 3 / Stage 5.0 / Stage 5.2)skills/autoiter/references/stop-criterion.md — SC1-SC5 + full rollback matrixskills/autoiter/references/fix-plan-template.md — Stage 5.0 templateskills/autoiter/references/discovery-prompt.md — Stage 0.2 Discovery subagent system promptskills/autoiter/references/iter-prompt.md — per-iter observation guidanceskills/autoiter/lib/jaccard.js — G7 token-set Jaccard similarity (zero external deps)npx claudepluginhub lkv1988/collie-harness --plugin collieGuides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.