skill
CHA
CHA (Cyclic Hostile Adversarial Harnessing) — Cross-checking LLM pipeline for deep code debugging
Set up
Skills are installed by placing their folder where your agent loads skills.
The download comes from github.com/jysvai/CHA itself, not from our server, so what you get is exactly what its author published.
Install instructions come from the README
README
synced Oct 21, 2026CHA — Cyclic Hostile Adversarial Harnessing
한국어 문서: README.ko.md
A release-gate loop for coding agents. Not a linter, not a prompt pack — a process that keeps running until the issue count is zero, and that refuses to believe anything it has not executed.
The one rule that makes the rest work: a claim is not a defect until you have run it.
Why this exists
A coding agent reviewing its own work is the least reliable reviewer you can pick. It wrote the code, it read the same comments, it shares the same blind spots — and when it is unsure, it produces a fluent, confident, wrong answer.
The usual patches don't hold:
| Patch | Why it fails |
|---|---|
| "Review your own diff" | Same model, same context, same blind spot. |
| A second pass from the same model | Correlated errors. It agrees with itself. |
| A stricter linter | Finds shapes, not lies. A comment that contradicts its code is green. |
| More tests | A test that asserts nothing is also green. Nobody notices. |
CHA fixes this by splitting the roles across platforms and never letting a claim through unexecuted:
- A different platform reviews (Gemini, Codex, GPT — any second eye). Different training, different failure modes, uncorrelated hallucinations.
- Only one agent writes code (Claude). Edits stay serialized, so a fix is never half-applied by two writers.
- Every claim is adjudicated by execution. In the measured run, 57 claims → 22 true. Roughly 6 in 10 confident findings were wrong, and reading alone would not have told you which.
- Every fix is proved red first, then green.
- Every fix gets a mutant: break the fixed line on purpose and confirm a test goes red. If it stays green, the fix is unguarded and someone will delete it.
- A false warning is a defect. Code that cries wolf costs the same as code that is silent.
What you get
Each benefit is bought by one device in the loop, and each comes with the number that showed the device working. Measured, not promised.
| You get | Because | Measured |
|---|---|---|
| An AI reviewer you can use without trusting it. | It reviews from another platform, read-only, and every claim is settled by running it. | deel 57 → 22 true · the game 67 settled → 22 true. The false ones never touched the code. |
| Proof of what each fix fixed. | The red test comes first, and its output is kept. | CHA on itself: 10 fail / 2 pass before a line was touched. |
| A test that goes red if a fix is deleted later. | Every fix gets a mutant: the fixed line, broken on purpose. | The game: 20 of 92 mutants leaked on their first run, each a check that guarded nothing. |
| A green that means something was measured. | Unmeasurable counts as failure, and the gate reports numbers, never the word "pass". | deel: 24 mutants hiding behind a green build: 2 leaked, 22 measuring nothing. |
| Nothing lost quietly. | Every second-eye run is classified: truncated, quota, blocked on a tool, empty. | The game's record said "lost 0". It was lost 2, both refusals saved as answers. |
| No half-applied fixes. | One writer, and the reviewer's read-only boundary is checked, not declared. | deel: 3 half-applied fixes, every one the two-writer shape. |
| The same false claim costs you once. | An append-only record that files every false verdict with its counter-evidence. | deel: 2,745 lines of record, none deleted. |
What it costs is in the FAQ: adjudication grows with the number of claims, and the full sweep with mutants × test time.
Measured on a real codebase
CHA was not designed on a whiteboard. It was extracted from the release review of deel — a zero-dependency Node CLI coding agent.
| Source under review | 171 files · 77,607 lines |
| Tests | 154 files · 75,499 lines |
| Test results at the last gate | 12,596 pass · 0 fail · 1 skip · 156/156 files exit clean |
| Mutants registered | 1,179 across 138 source files / 119 test files |
| Last full mutation sweep | 1,149 mutants · 2h46m · 1,125 caught · 2 leaked · 22 unmeasurable — all 24 resolved |
| Gates run | 39 |
| Second-eye briefings in the last round | 39 |
| Claims raised → confirmed by execution | 57 → 22 |
| Fixes landed in that round | 19 |
| Cumulative record | 2,745 lines, never deleted |
| Commits | 434 |
Every figure above is the state at gate 39 (2026-09-16). Later rounds move them — this is a snapshot of one measured moment, not a running total. The loop has not stopped.
The 24 that the green build was hiding. The full sweep found 2 mutants that no test caught, and 22 whose anchors had drifted — they were in the list, named, counted as present, and measuring nothing. That last category is the dangerous one: it is invisible in both a red run and a green run.
Measured on a second domain: a Roblox game
The loop was run on something with nothing in common with deel: a multiplayer Roblox horror game written in Luau, unreleased at the time, on a machine with no Luau runtime. The only thing that could run was a static check over the source. The game is private, so its code is not quoted, only the numbers and the shapes of the defects.
| Source under review | 58 Luau files · 24,401 lines |
| Gate at the end | 23 checks green (4 static · 18 red tests · 1 rig geometry), re-run 2026-09-22 |
| Defects recorded | 21 in logic, security and lifecycle · 7 in the character model |
| Mutants | 92, all caught at the end · 20 leaked the first time they ran |
| Second eye | gemini-3.8-flash-high via agy, read-only · 30 briefings → 27 answered · 3 lost |
| Claims raised → settled by execution | 128 → 67 settled → 22 true · 45 false (58 never adjudicated) |
The false rate held across domains. 67% of the settled claims were false; on deel it was 61%. Different language, different reviewer, different kind of program, and still six or seven confident findings in ten were wrong in ways reading could not reveal.
The domain changed what the defects looked like, not their classes. A nil hole in a Luau table dropped the player's own body out of a raycast filter. A NaN sent from the client passed a type check and math.clamp and permanently broke that player's saves. The engine's respawn path skipped the cleanup that the ending path ran. A cylinder mesh rendered a disc because the engine forces width equal to length, which no amount of reading the source shows.
Mutation mattered more where nothing runs. One in five mutants leaked the first time it ran. Each leak was a check that went red on the defect and green on the fix and still guarded nothing.
The run's own record miscounted twice, in both directions. "Lost 0" was really 2 lost: a tool refusal saved as the answer. A round's "82% false" was really 68%: sixteen claims counted twice. What CHA took back from it is 1.3.0: Lua support, a call-site index in every briefing, refusal files read as not answered, and a declared reviewer. Details: docs/en/09-results.md.
Run against itself
CHA has been pointed at its own repository for three rounds, one per release since 1.1.0. Every claim was settled by running it before anything was edited.
| Rounds | 3 · 2026-09-18 (1.1.0) · 2026-09-20 (1.2.0) · 2026-09-22 (1.3.0) |
| Claims settled by execution | 49 → 33 참 · 4 거짓 · 12 못 잼 |
| Fixes landed | 30, red test first |
| Mutants registered | 49 · last full sweep 49 잡음 · 0 샜음 · 0 못 잼, 25m32s |
| Tool tests | 67 checks · round 1 started from 12, the first this repository had |
The state at gate 4 (2026-09-22). The tool tests were re-run on 2026-10-07:
67 pass / 0 fail / 0 skip.
Round 1 found eight defects in its own tools. Before a line was touched, the
suite went 10 fail / 2 pass. The ones worth naming: a mutation whose test was killed at the timeout was
scored 잡음, so an unmeasured line sat on the healthy side of the table. A
mutant list written the way the FAQ offers lost its entries while still
showing them in the file. secondEye.maxRetries: "six" made the queue send
nothing and report success. --max 20kb removed the cap and shipped a 41.9KB
briefing under the line cap NaNKB. All four are this repository's own defect
classes, living in the tools built to find them.
Breaking the fixes on purpose found two more: a test that could not tell two reasons apart, and a control flaky one run in four — invisible until the timeout fix stopped scoring slowness as success.
Round 2 ported the four devices the live deel loop had and this repository
did not, and found eleven defects doing it. Four were one shape: something the
repository said about itself that no code made true. secondEye.mode: "read-only" and writer: "claude-only" were read by nothing, while the
architecture diagram drew them as a boundary. One more was found only by
looking at the machine: the sweep had leaked 76 runaway processes, and the
timings it printed were measured inside load it was creating.
Round 3 brought back what the game run taught: 14 claims → 11 참 · 3 거짓. All three false ones came from this side. One of them, a plausible agy command line already written into the draft of the setup docs, would have shipped. Only a live run told it apart from the working one.
The rounds, with the command next to every number: .cha/record.md.
The loop
Nothing ships while the count is above zero, and nothing ships without an explicit human go-ahead.
Step by step, with each one's entry and exit condition: docs/en/02-loop.md.
How the pieces connect
Everything that can write is on one side of a line: the plugin, the tools, the .cha/ files, and the single agent that edits code. The second eye is on the other side, on another platform, with a pinned model id and no write tools, no shell, and no repository access. Briefing text crosses one way, claim text crosses back, and nothing else crosses at all.
That line is not about trust. Two writers produce edits whose interaction nobody has read — one moves a guard, the other moves the thing it guarded, both test suites pass separately, and the defect lives in between. Every half-applied fix in the measured rounds had that shape: a header describing behaviour that only one of two call sites implemented. It happened three times.
Install
# 1. Add this repo as a plugin marketplace
/plugin marketplace add jysvai/CHA
# 2. Install
/plugin install cha@cha
Or point Claude Code at a local clone:
git clone https://github.com/jysvai/CHA ~/cha
/plugin marketplace add ~/cha
/plugin install cha@cha
Then, in the repo you want to review:
/cha-init
That writes .cha/ (config, cumulative record, mutant list) and tells you what your second eye needs.
Full setup — including the second-eye CLI, quota handling, and what to do when you have no second platform — is in docs/en/01-setup.md.
Commands
| Command | What it does |
|---|---|
/cha-init | Scaffold .cha/ in the current repo and detect the gate commands. |
/cha-hunt <path> | First-eye pass over a slice. Produces suspicions, not verdicts. |
/cha-brief <path> | Cut a file into ≤20KB briefings with the five defect classes and .cha/house.md attached. |
/cha-review2 | Send every pending briefing to the second eye, one at a time, quota-aware. |
/cha-gauge <briefing> | Run one briefing N times and report how often the second eye actually answers. |
/cha-judge <tag> | Adjudicate one answer by execution. Writes true/false/unmeasurable with evidence. |
/cha-fix <id> | Red test first, then the fix, then the mutant. Refuses to reorder. |
/cha-mutate [filter] | Run the mutant sweep — all of them, or one file. |
/cha-gate | Run the full gate and refuse to report green on anything unmeasured. |
/cha-record | Append this round to the cumulative record. |
/cha-status | Where the loop is: pending briefings, unjudged answers, unguarded fixes. |
Skills
Skills load automatically when the work matches. You can also invoke them by name.
| Skill | Loaded when |
|---|---|
cha-loop | Running or resuming the loop; deciding what step is next. |
cha-briefing | Cutting source into second-eye briefings. |
cha-adjudication | Judging a claim — the execution-first rules and the verdict format. |
cha-mutation | Writing, repairing, and sweeping mutants. |
cha-red-test | Proving a failure before fixing it. |
cha-record | The cumulative record format and what must never be dropped. |
Agents
| Agent | Role |
|---|---|
cha-hunter | Read-only first eye. Produces suspicions with file:line, never fixes. |
cha-adjudicator | Runs the claim. Returns a verdict with the command and its output. |
cha-mutant-smith | Lifts the exact source line, builds the mutant, verifies it is caught. |
Where the claims went
Every claim is split by execution, not by reading — and the split is not close.
The five defect classes
Every briefing carries these. They are the classes that survived every round — the ones a linter cannot see and a same-model review will not name:
- A rule that never matches real input.
/(1b|2b|3b)/markedqwen2.5-coder:32b— a 32B model — as "too small", because32bcontains2b. - Silent failure. A sheet that could not be read was skipped with
catch { continue; }and the result still said "read everything". - A test that does not guard. Named
"rejects non-numeric counts", asked only about'many', and let'3',null,trueand[]straight through. - Comment contradicts code. The header said "a line with no
okis not counted as a success"; the code counted it as one, and the failure rate came out lower than reality. - Trust-boundary leak.
--offlinewas checked after the connection had already knocked on the external address three times, with the key attached.
Details and the real diffs: docs/en/09-results.md.
What CHA refuses to do
- It does not fix what it could not measure. Four findings in the last round were platform-locked (Unix-only, or needed Excel installed). They were recorded as unmeasurable, not guessed at. Inventing a fix for an unrun claim is the same failure mode CHA exists to stop.
- It does not let the reviewer write code. The second eye is read-only and one writer holds the pen — and both are checked rather than declared. A command carrying a permission-skipping flag stops the run; a patch that comes back in an answer is removed before the answer is filed, and the removal is written into the answer.
- It does not let an empty answer look like a clean file. Every second-eye run is classified — truncated, blocked on a tool, quota, disconnected, empty — and the kind decides the next move. A truncated answer is re-asked smaller, never re-asked identically.
- It does not report green on anything it did not run. An unmeasurable mutant fails the sweep. Silence is not success.
- It does not ship on its own. Tag and push happen after a human says so, with the review scope reported first.
Portfolio page
A single self-contained page in Korean and English: what you get, the loop, the numbers from all three runs, and the defect classes.
jysvai.github.io/CHA · the source is site/index.html, published as it is by every push that touches it.
Documentation
| 00 — Why | The failure mode this exists to stop. |
| 01 — Setup | Install, second-eye CLI, quota, no-second-platform fallback. |
| 02 — The loop | Each step, its entry and exit condition. |
| 03 — Harness tuning | What actually had to be tuned, and what broke first. |
| 04 — Briefing | Why 20KB, what goes in, .cha/house.md, what must never go in. |
| 05 — Second eye | Serialization, quota backoff, model pinning, the enforced read-only boundary, the failure kinds, and measuring the reviewer itself. |
| 06 — Adjudication | Execution-first rules, verdict format, the 57→22 number. |
| 07 — Mutation | Anchors, drift, the unmeasurable category. |
| 08 — Gate & record | What the gate covers and why the record is never deleted. |
| 09 — Results | The measured run, with the actual defects. |
| 10 — FAQ | Cost, time, small repos, CI. |
Korean documentation lives in docs/ko/.