mcpbeat Sign in

Farm Tfcompat Bugs Agent Skill

Run a sustained bug-farming round — keep a full swarm hunting until N distinct OpenTofu-vs-pulumi-hcl divergences are proven, then ship each as its own draft PR containing only the failing test. Use when the user asks to "find 10 more bugs", "raise the next N issues", or run another bug-hunting round.

2k tokens
context cost
the whole folder, loaded on every use
1
files
instructions only
0
copies elsewhere
how many repositories repackaged it
4
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/pulumi/pulumi-hcl --skill farm-tfcompat-bugs

The instruction itself

9 sections, as written by the author

Farm: N proven divergences, N draft PRs

A round ends when N distinct, vetted divergences each have their own draft PR

containing only the failing test. This is the steady-state version of

swarm-tfcompat-bugs, which stops at one bug and

reports. Everything there about partitioning, exclusion lists, and the direction rule

still applies — read it first. This skill adds what only shows up when you run the swarm

to a quota, round after round: **sustained headcount, adjudication under duplicate

pressure, PR staging, and saturation accounting.**

The three jobs that are actually yours (the lead's): de-confliction, adjudication,

and shipping. Hunters never open PRs. You vet every candidate personally.

Round setup

  • git fetch && git pull master. Re-derive the exclusion list from *this* master:

git log since the last round, gh pr list --state all, gh issue list --state open,

and ls tests/tfcompat/testdata/cases. Last round's fixes are this round's exclusions.

  • **Read docs/terraform-compatibility.md and put its "Known Limitations" in every

hunter prompt verbatim.** That file is the owner's ruling on which divergences are

*accepted and documented* — unsupported terraform-block fields, the List<Object>

empty-vs-null limit, destroy-ordering of late-created instances, unsupported/extra

functions. A divergence listed there is settled, not a bug, no matter how cleanly it

reproduces. It grows every round (an owner closing one of your PRs by documenting it

lands here), so re-read it each round rather than trusting last round's copy.

  • Fence anything the user is actively working. If they have an open PR or a live

branch in an area, that whole area is off-limits — not just the specific bug. State the

fence as a positive constraint in every prompt ("your signal must be a value, type,

mark, or op *kind* — never op *order* and never a dependency edge"), because a negative

fence alone gets rounded down to "avoid that one test".

  • Carry the exhausted-domain list forward from previous rounds' memory notes and

fold it into the exclusion list. Domains that returned clean negatives twice are not

worth a third agent.

  • Partition into N disjoint domains, spawn all N in one message

(general-purpose, run_in_background: true, unique name).

What a hunter prompt needs beyond the swarm skill's list

  • WRITE ALL FILES TO THIS WORKTREE: <absolute path> on its own line. Without it

hunters write into the main checkout and you will hunt for their deliverables. This is

the single highest-value line in the prompt.

  • Rebuild before judging: make build, then

PATH="$PWD/bin:$PATH" go test ./tests/tfcompat/ -run 'Test(L1|L2)<Name>' -count=1 -v.

A stale bin/ produces failures that no longer exist on master.

  • Capture, don't eyeball: go test … > /tmp/<name>.txt 2>&1, then grep for

expected:|actual|Messages:|error:|does not contain. The harness diff carries ANSI and

wrapping that defeats a naive grep of scrollback.

  • Report negatives honestly, naming what was probed. A clean negative is a result —

it retires a domain. A fabricated bug costs more than an empty round.

Sustaining headcount

Hold N hunters *working* until the quota is met — the drain is real: some domains come

back clean, some candidates get rejected, and later bugs cost more than early ones.

Re-task with SendMessage, don't respawn. A hunter that just proved its domain clean

already knows the harness, the providers, and the rejection bar. Send it the new domain

plus the *updated* exclusion list (including whatever just got filed). A fresh Agent

call pays for all that context again.

Expect to re-task roughly half the swarm once or twice to reach 10. If a hunter needs a

third domain, the search space is telling you something — see Saturation.

Adjudication

**The bar: you personally reproduce it 3/3 deterministic FAIL, on freshly built binaries,

with -count=1.** Not the hunter's run — yours. A hunter FAIL that PASSes for you is a

stale-binary artifact; reject it and re-task.

Then walk the rejection classes. Every one of these has cost a real round:

| Reject when | Why |

|---|---|

| pulumi-hcl is *more lenient* than OpenTofu | Wrong direction; no migration depends on it |

| SDKv2 optional-attr null vs "" | Zero-value artifact of the shim, not a divergence |

| Computed field recomputed on update | Self-healing, by design |

| Plan-time unknown-refinement diff | Unobservable to a user |

| Secret / sensitive over-propagation | Pulumi's stickier marks are by design |

| Only difference is number representation | Deferred float64 family — flag it, don't file it |

| Signal is op *order* or a dependency edge | Fenced; belongs to the scheduling work |

| Structurally indistinguishable on the wire | E.g. MaxItemsOne empty-vs-absent block |

| Listed in docs/terraform-compatibility.md | Accepted, documented limitation — settled |

Verify every claimed duplicate before rejecting on it. gh issue view /

gh pr view the number. Issues get closed by a *different* PR than the one that names

them, and a "fixed in #X" that actually landed in #Y still fails on master — that is a

live bug, not a duplicate. Equally: a bug you remember being filed may be closed and

scoped to a path that doesn't cover your case.

Borderline goes in the PR, with the relationship named. If a candidate might be a

sibling of an open issue, or might be intended behavior in the Pulumi model, file it and

say so in the body. The owner folds or closes it in seconds; a silently dropped real bug

is gone. Do not let "possibly by design" become a rejection reason on your own authority.

Take evidence-backed pushback from hunters. A lead's exclusion can be wrong. When a

hunter comes back with an empirical probe contradicting a fence you set, verify it and

change the fence. One round's #430 exists only because a hunter refused a bad exclusion.

Shipping: one draft PR per bug

Stage from a detached worktree so the session tree stays untouched:

git worktree add --detach <staging> origin/master

Then per bug, in <staging>: branch off origin/master → copy only that bug's

tests/tfcompat/<case>_test.go + testdata/cases/<case>/ (plus its provider file if it

added one) → git add those exact paths → commit → push →

gh pr create --draft.

  • Test only. No fix, no changelog. CI failing is the point; say so in the body.
  • One bug per PR, off master, never stacked.
  • Body: the divergence in one line (OpenTofu does X, pulumi-hcl does Y), the repro

command, the captured failure output, and any flagged relationship to an open issue.

  • Never git add .; never touch the user's index in the session tree.

Closing the round

  • Verify all N PRs exist (gh pr list) and note any the user has already adopted or

retitled — that is the signal the round landed.

  • Clean both trees. Hunters leak files into the main checkout as well as the

worktree. git status --short both, rm/rm -rf the exact untracked scratch paths

(test files, case dirs, deferred/rejected candidates), then `git worktree remove

--force + git worktree prune the staging tree. Never git add/reset/rm --cached`.

  • Write the round memory note, linked to the previous round's. It must carry:

master SHA, the PR numbers, the rejections with their reasons, and the

domains proven clean — the next round starts from this note's exclusion list.

  • Report to the user: the PR table, the judgment calls you flagged, the rejections,

the exhausted domains, and cleanup status.

Saturation is a finding

Yield decays across rounds. When most hunters need re-tasking, when negatives repeat a

domain a third time, or when reaching the quota requires filing borderlines — say so

plainly in the closing report and name where the remaining yield is concentrated. "A

round 6 will likely return fewer than 10 without new surface landing first" is more

useful than ten thin PRs. Do not pad a round to hit N.

Checklist

  • [ ] Master pulled; exclusion list re-derived from this master + carried exhausted domains
  • [ ] User's active work fenced as a positive constraint, in every prompt
  • [ ] N disjoint domains, spawned in one message, each told the absolute worktree path
  • [ ] Every candidate vetted by *you* at 3/3 on freshly built binaries
  • [ ] Rejection classes walked; every claimed duplicate verified with gh
  • [ ] Borderlines filed with the relationship flagged, not dropped
  • [ ] One draft PR per bug, test-only, off master
  • [ ] Both trees clean, staging worktree removed, index untouched
  • [ ] Memory note written with PRs + rejections + clean domains
  • [ ] Saturation stated honestly

How to use it

Copy the folder

Take pulumi/farm-tfcompat-bugs from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.