docs: add a skill for AI coding agents, compile-checked in CI - #272
Merged
Conversation
Coding agents write terminal tests badly in predictable ways: a sleep where a wait belongs, a whole-screen snapshot taken mid-repaint, a 1x1 terminal, a (row, col) handed to a method that wants (col, row), wait_frame against an application that never emits synchronized updates, a bare program name under env_clear. skills/termlens/SKILL.md is the counter to each — the model in sixty seconds, twelve golden rules with the reason behind each, a setup section, four copy-paste recipes (a CLI --help snapshot, a ratatui navigation flow, overriding size and environment, targeted cell and style assertions), a failure-triage table quoting the crate's actual messages, an API cheat sheet, a pitfalls table and a finishing checklist. Written against 0.9.0. Every rule with a measurable claim was measured: stock ratatui 0.30.2 with crossterm emits no DEC 2026 updates (repaints() stays 0), so the skill sends agents to snapshot_after rather than wait_frame; the recipes ran green seven times in a row against a real ratatui binary named myapp; the instant-exit --help case ran 100 times with both wait orders; and a fresh Claude Code session in this checkout discovers the skill through the .claude/skills/termlens link. The README gains the one-line install and CONTRIBUTING's layout names the directory. The skill deliberately does not reference this repository's internal issue tracker or planning documents. Signed-off-by: Vyncint Ng <vyncint@icloud.com>
The skill is what an agent copies from, so a recipe that stops compiling
teaches the wrong API to everyone who installed it. The README's example is
already compile-checked for the same reason; the skill's four recipes get
the same guard. check-skill-snippets.sh extracts every block tagged exactly
```rust into a scratch consumer that owns a stub `myapp` binary — the shape
the recipes are written for, so termlens::bin!("myapp") resolves at compile
time — and runs cargo check --tests against the crate in the checkout. A
failure prints which snippet maps to which line of the skill.
It compiles and does not run: the stub is fn main() {}, and the recipes'
runtime claims were exercised against a real ratatui application when the
skill was written. Verified to fail on a renamed method. The job joins
required-green; it is a script step, so CONTRIBUTING §1's cargo list is
unchanged and gates-listed still passes.
Signed-off-by: Vyncint Ng <vyncint@icloud.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A skill for coding agents (Claude Code, Cursor, Copilot) that write tests with termlens, at
skills/termlens/SKILL.md, plus a CI guard that compiles every Rust block in it against the crate.What is in the skill
sleep(andsend_afteras the one sanctioned delay),snapshot_afterfor whole-screen snapshots, one predicate per instant,bin!for own binaries, the 2..=1000 geometry floor and ceiling, the two coordinate orders, finish the process and assert!alternate_screen(),wait_frameonly for applications that emit synchronized updates,termlens::Result<()>tests, snapshot theScreennot its text, the hermetic environment, cells and wide characters.--helpsnapshot with exit code; ratatui navigation and clean quit; overriding size, environment and deadline; targetedfind/cell/style/rect_text/cursorassertions including CJK.What was measured before writing it
repaints()stays 0 after a draw), so the skill sends agents tosnapshot_after, and names the exact timeout messagewait_frameproduces otherwise.myapp(list with highlight,j/k/q,--help,NO_COLOR): 5 tests, green 7 runs in a row, snapshots stable.--helpcase ran 100 times with both wait orders on an idle machine with no loss; the skill still recommends waiting on the last line first, and says why (the macOS teardown race under load, from DESIGN §2).claude -psession in this checkout reports the skill available and quotes its description, so the.claude/skills/termlenssymlink is discovered.The guard
.github/scripts/check-skill-snippets.shwrites each```rustblock to a scratch consumer owning a stubmyappand runscargo check --tests; on failure it prints which snippet is which line of the skill. Verified to fail on a renamed method. Newskilljob, inrequired-green. It compiles and does not run — the stub isfn main() {}.Not done, deliberately
references/split; at 450 lines it is dense on purpose.