agentsclimarketplace

Redgreen loop

Skill stid/lcd/skills/redgreen-loop

Autonomous build verb of LCD. Use when an LCD work-item (docs/lcd/work/<slug>/ or the conventions artifact-root) has failing tests to drive to green — after Deep-lane test-gen, or once a Standard-lane JOURNAL's STEPS reach failing tests. Iterates the test runner with bail, fixes the first failing test with minimum code, commits, repeats until green. Hard iteration cap and stuck escalation.From its SKILL.md

Install
npx -y skills add stid/lcd --skill redgreen-loop

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

8.1 KB, as published. Nobody here has run it

Red-Green Loop (LCD build verb)

Drives the inner TDD loop autonomously once failing tests exist (Deep-lane phase 4, or a Standard-lane JOURNAL whose STEPS reached failing tests), escalating via STUCK.md if it can't make progress. The edit boundary comes from the JOURNAL EDIT BOUNDARY (Deep lane keeps it in sync with plan.md's File structure) — that boundary bounds every edit the loop is allowed to make.

Resolve paths + toolchain

Resolve the artifact root from .claude/rules/lcd-conventions.md (artifact-root, default docs/lcd). Work item: <artifact-root>/work/<slug>/. Pick the test runner from the lockfile — you need a full-suite command, a bail command (stop on first failure), and a single-test filter:

Markersuitebailsingle test
bun.lockbbun testbun test --bailbun test --bail -t '<name>'
pnpm/yarn/npm<pm> test<pm> test … --bail<pm> test -- -t '<name>'
Cargo.tomlcargo testcargo testcargo test <name>
pyproject.toml/requirements.txtpytestpytest -xpytest -x -k '<name>'
go.modgo test ./...go test -failfast ./...go test -run '<name>' ./...

Project override: if .claude/rules/lcd-conventions.md exists, its <!-- lcd-conventions:v1 --> block defines bail / single-test / gate — use those over the lockfile defaults. Required when the bare <pm> test enters watch mode (vitest/jest), which would hang the loop.

Monorepo (zone-scoped) override: the block may also carry key[<path-prefix>]: variants (e.g. bail[packages/api]: …). When the EDIT BOUNDARY paths sit under such a prefix, use that zone's commands; longest matching prefix wins; the bare key is the fallback. If the boundary spans zones with different runners, run each zone's scoped command for its own paths.

Preconditions

Run only when ALL hold:

  1. The work-item exists with a JOURNAL (<artifact-root>/work/<slug>/JOURNAL.md); for Deep lane, spec.md/plan.md/tasks.md exist too. (STUCK.md is allowed but signals a prior halt — read it first and decide whether the situation changed.)
  2. The JOURNAL EDIT BOUNDARY lists every path the loop may edit (Deep: mirrors plan.md File structure). If it's empty, halt and ask for it.
  3. The scoped test run currently exits non-zero (there is something to fix).

If any precondition fails, halt and tell the user which phase/step to run.

Knobs (do not negotiate per-run)

KnobSetting
Iteration cap20 total iterations per invocation
Stuck detection(a) Same failing test + same assertion error twice consecutively, OR (b) the last fix diff is byte-identical to a prior attempt
EscalationWrite <artifact-root>/work/<slug>/STUCK.md. Halt; print the path
Commit policyOne commit per test that flips red→green. feat(<slug>): pass AC-N (SURFACE) or fix(<slug>): pass AC-N. On the branch's first commit, apply the versioning rule — but verify the manifest's current version on the branch first (git show $(git merge-base HEAD <default-branch>):<manifest>); don't assume a baseline chore: commit already bumped it
Edit boundaryThe loop may ONLY modify paths in the JOURNAL EDIT BOUNDARY. Out-of-plan edits abort the iteration immediately and do NOT count against the 20-cap. This is also enforced structurally: the plugin's PreToolUse hook (lcd-boundary-check.sh) denies out-of-boundary edits while the work-item is active — a denied edit means fix the target (or extend the boundary via lcd:refine), never fight the hook

The loop

iteration = 0
while iteration < 20:
    iteration += 1

    output = run(BAIL_CMD)                     # 1. run suite, stop on first failure
    if exit_code == 0: break                   #    all green → done

    failing_name  = parse_first_failing_test(output)   # 2.
    failing_error = parse_first_assertion_error(output)

    if failing_name == prev_name and failing_error == prev_error:   # 3. stuck (a)
        write_stuck_md(slug, …, "repeat-failure"); halt
    prev_name, prev_error = failing_name, failing_error

    target = pick_target_from_edit_boundary(failing_name)  # 4. read test, then AC in spec/JOURNAL
    diff   = generate_minimum_diff(target, failing_test, failing_error)  # 5.

    if diff in attempted_diffs:                # 6. stuck (b)
        write_stuck_md(slug, …, "repeat-diff"); halt
    attempted_diffs.append(diff)

    if any_path_in(diff) not in edit_boundary: # 7. edit-boundary check
        log("out-of-plan edit; aborting iteration without counting"); iteration -= 1; continue

    apply_diff(diff)                           # 8.
    if run(SINGLE_TEST_CMD for failing_name).exit_code != 0:
        revert_diff(diff); continue            #    didn't fix → try a different approach

    commit(f"feat({slug}): pass {failing_name}")   # 9. one commit per red→green flip
    update_journal_now_and_steps()                 #    keep the resume anchor current

if iteration == 20 and exit_code != 0:
    write_stuck_md(slug, …, "iteration-cap"); halt

Budget-aware variant (under Workflow only)

When this loop runs inside a Workflow script, the script also has a token budget via budget.remaining(), so the guard becomes the lower of {20 iterations, budget exhausted, stuck}. The 20-iteration cap is otherwise unchanged:

// inside a Workflow script — budget is NOT reachable from the in-loop skill
let iteration = 0
while (iteration < 20 && (!budget.total || budget.remaining() > 30_000)) {
    iteration += 1
    // ... same red→green body (bail, fix first failure, single-test gate, commit) ...
}
// halt reason: iteration-cap | budget-exhausted | stuck — write STUCK.md, then escalate

budget only exists inside a Workflow; in the plain skill the cap + stuck detection stay the sole bounds.

Implementation tactics

  • Read the test first, then the AC. The test is the contract; the AC body (spec.md, or the JOURNAL ACs for Standard lane) is the why. If the test asks for something the AC didn't promise, stop — fix the test rather than implement the wrong thing.
  • Minimum code only. If the test asserts response.version === string, the impl is a one-line return { version: VERSION } — not a refactor, not validation. The audit catches missing surfaces; resist scope creep.
  • Use existing primitives. Grep (start from MAP Zones) before adding a helper.
  • Keep the JOURNAL current. After each green commit, tick the STEP and update NOW.Next-action — this is what makes a mid-loop context reset resumable via /lcd:resume.

Writing STUCK.md

Start from the LCD package's templates/STUCK.md and fill in: exact failing test name (as the runner printed it); the full assertion error block; the last three attempted diffs (unified format); the edit boundary (copy from the JOURNAL); a last attempted timestamp. Then halt. Don't use AskUserQuestion — the user may be away. STUCK.md plus the JOURNAL is enough for a cold pickup.

When to stop early (not via STUCK)

  • All scoped tests pass AND the full suite is green → success. Report iterations used.
  • The user interrupts with a redirect → halt immediately.

Quality gate before declaring done

  • Final full-suite run exits 0.
  • Per-fix commits exist (one per test that flipped).
  • No unacknowledged STUCK.md.
  • JOURNAL NOW.Next-action updated, and the iterations used recorded as a JOURNAL LOG line (e.g. red-green: green in 4 iterations, 0 reverts) — the work-item's closeout reads it. Suggest /lcd:audit <slug> next (if a surface was declared).

Keep looking

Skills are one crate of 627,801. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.