Engineering best practices that AI coding agents actually apply — 40+ skills, from secure coding and cloud to compliance and UX writing. BUILD + AUDIT modes.
Overview
Your assistant is brilliant — it just doesn't know your standards, and it forgets the ones it does know as the task grows long. SOTA-skills fixes both, and the fix is : from a bare "build X" prompt, best-practice coverage climbs from — the model stops silently dropping tests, rate limiting, structured logging, and TLS (see every number →). It works by being a : route in only the rules a task needs, re-state them every turn, and re-check them last before shipping — so the guidance survives a long context instead of fading into it. That's why it beats a bigger prompt instead of becoming one. Native on Claude Code; works with Antigravity CLI, Codex, and any agent that reads AGENTS.md. Those agents get the skills and an always-on directive, but not the per-turn re-statement, which is a Claude Code hook (per-agent detail), and no lift has yet been measured through them.
README
SOTA Engineering Skills
Make your AI coding assistant build and audit like your most senior engineer.
Your assistant is brilliant — it just doesn’t know your standards, and it forgets the ones it does know as the task grows long. SOTA-skills fixes both, and the fix is measured: from a bare “build X” prompt, best-practice coverage climbs from ~59% to ~98% (+0.39) — the model stops silently dropping tests, rate limiting, structured logging, and TLS (see every number →).
It works by being a loop, not a prompt dump: route in only the rules a task needs,
re-state them every turn, and re-check them last before shipping — so the guidance
survives a long context instead of fading into it. That’s why it beats a bigger prompt
instead of becoming one. Native on Claude Code; works with Antigravity CLI, Codex, and any
agent that reads AGENTS.md. Those agents get the skills and an always-on directive, but not
the per-turn re-statement, which is a Claude Code hook
(per-agent detail), and no lift has yet been measured through them.
Under the hood: 43 skills (347 files, ~89k lines) of state-of-the-art 2026
practice, each instruction file under 500 lines so only the matching rules load —
the cap applies to skills/** alone, never to README/CHANGELOG/docs/ — every fast-moving
claim web-verified against a primary source as of the last full sweep (the root
LAST-VERIFIED stamp). Between sweeps an upstream can still move under a claim, so the
router’s own operating principle 1 stands: re-verify anything version- or CVE-sensitive at
use time.
Two commands to install:
/plugin marketplace add martinholovsky/SOTA-skills
/plugin install sota-skills@sota-skills
Or clone + link (best if you want a local checkout to read, hack on, or pin).
Skills are discovered from .claude/skills/ (per project) or ~/.claude/skills/
(personal, all projects). Clone the repo, then run the installer — it symlinks
every skill (and your profile, if you have one):
git clone https://github.com/martinholovsky/SOTA-skills && cd SOTA-skills
./scripts/install.sh # personal: ~/.claude/skills (all projects)
./scripts/install.sh --project DIR # one project: DIR/.claude/skills
./scripts/install.sh --target all # also ~/.agents/skills (Copilot, Codex, Cursor, Gemini CLI) + Antigravity's own dirs
./scripts/install.sh --copy # copy instead of symlink (pin a snapshot)
./scripts/install.sh --mcp # optional: register the read-only MCP server for other agents
The installer colour-codes what it did (✓ done · ↻ changed or act on this ·
· no-op) and drops to plain ASCII when the output is not a terminal, on a
non-UTF-8 locale, on TERM=dumb, or with NO_COLOR set — --color=always|never|auto
(or --no-color) overrides the detection either way.
Then describe the task in plain language — routing loads the right skills; the stack comes from your profile or the skills’ defaults (naming one is optional):
Design a multi-tenant invoicing service.
Run a full audit of this repo — severity, effort, and fix on every finding.
More install options: Installation · more prompts: Using it.
Five slash commands ship with the library — four bracket a working session, the fifth is
the heavy escalation. scripts/install.sh links them into ~/.claude/commands/, so they work
in any project, not just this one:
| When | What it does | |
|---|---|---|
/sota-resume |
start of a session | Finds the open work — every tracker, checkbox and TODO marker, swept with a controlled search — classifies it (ready · needs a decision · deferred · not an item · already done and never ticked off, or made unnecessary by a control that already covers the gap), shows you the table, then executes what you agree to against the project’s own CI. |
/sota-close |
end of a session | The closure pass: retract first, record open items where the next session will trip over them, update what the session made false, re-derive every number from its source, say what is not done and blocked on whom, then commit the evidence. |
/sota-audit |
work finished, or a codebase you did not write | Audits what is in front of you against the library: agrees and pins the scope (a diff’s callers included), maps the trust boundaries, runs the scanners that are installed, maps every surface to its owning skills and says which rules files nobody opened, walks each Audit checklist item by item, then fixes what you agree to. |
/sota-deep-audit |
a milestone, an inheritance, a go/no-go | The heavy pass, and expensive: the same standard as /sota-audit, run so you can trust the result without trusting the auditor — the full threat model reconstructed from the code (DFD, tested assumptions, a control-presence matrix), then the audit fanned across independent agents, re-measures the numbers past decisions rest on, and hands every serious finding to a refuter that did not find it. |
/sota-report |
end of a session | Writes a gitignored field report on where the guidance failed, was absent, was wrong — or was right and did not fire. Prints a gh issue create line; it never posts anything itself. |
They take free-text arguments (/sota-close focus on the migration branch). Full detail:
slash commands.
Contents
- Standards & practices baked in · What the audit hunts that a scanner can’t · How the numbers are kept honest
- Skills · Coverage & non-goals
- Installation · Always-on routing · Updating
- Using it — slash commands (
/sota-resume·/sota-audit·/sota-deep-audit·/sota-close·/sota-report) - Optional setup & integrations — badge, gates, other agents, status line, plugin extras
- Structure · How it works · Conventions
- Found a gap? Tell us · Contributing · License
Deeper docs: Find it fast (docs index) · Does it work? (measured results) · Why it works · Why some lifts expire and others don’t · Keeping rules applied as context fills · Roadmap · Agent-loop evals — tools, hidden tests, no model judge (separate repo)
Standards & practices baked in
Findings name the control they violate — not just “this looks wrong”:
- Security — OWASP Top 10 (2025), ASVS, API & LLM Top 10; findings cite CWE IDs. Disabled TLS certificate and SSH host-key verification are each stated once, with a detector per library read from that library’s own source
- OWASP, item by item — 19 OWASP projects compared with the library one item at a time (7,439 items, 2026-09-25); every one of the 847 gap themes was adopted, found covered, or recorded with a reason (ADOPTION-LOG). New ground includes anti-automation and abuse of value-granting flows, browser response hardening (Fetch Metadata, HSTS rollout), file uploads, SBOM content, dependency adoption, vulnerability remediation beyond the score, tag manager governance, the JVM web layer, and audit reports that carry reproduction steps and a finding lifecycle. Where a rule is detectable in code or config it ships an audit probe tested on a known-bad and a known-good fixture
- Languages — all 9 language skills (Rust → Ruby, below) get the same rigor; formal standards where they exist: SEI CERT (C, C++, Java), MISRA C/C++, ANSSI Rust. Each is also gap-checked against its ecosystem’s own scanner registry (all nine, by 2026-09-24 — LANGUAGE-TIER)
- Supply chain — SLSA, Sigstore, in-toto, SBOM (CycloneDX/SPDX), NIST SSDF
- Cloud & identity — CIS Benchmarks, NIST 800-207 zero trust, NIST 800-63-4, OAuth 2.1, FAPI 2.0, passkeys, SPIFFE
- Privacy & compliance — GDPR, CCPA/CPRA, HIPAA, PCI DSS 4.x, SOC 2, ISO 27001, EU AI Act, NIS2, DORA
- Government & regulated — NIST CSF 2.0, 800-53, 800-171/CMMC, FedRAMP, EU Cyber Resilience Act, IEC 62443, ISO/IEC 29147 & 30111 (vulnerability disclosure and the handling process behind it)
- Threats, detection & AI/ML — STRIDE, LINDDUN, MITRE ATT&CK & ATLAS, NIST 800-61, NIST AI RMF
- Frontend, mobile & testing — WCAG 2.2 AA, Core Web Vitals, OWASP MASVS & WSTG
Named standards are the floor. Most of the library is the practice layer no regulation writes down: cancellation & backpressure, retries with jitter, circuit breakers, outbox/saga, double-entry ledgers and the reconciliation that proves an integration is complete rather than merely correct, zero-downtime migrations, measure-first performance, API evolvability, per-language idioms, SLOs, test-suite health — and the ones that only show up once something is already running: triaging a vulnerability report a stranger sent you (reproduce before you rate it, check the cited code even exists, and decide the regulatory clock explicitly, because it starts at awareness), and why a skill can stop triggering with nothing about it changed (a length cap is enforced either by skipping or by silent truncation, and a shared listing budget means a neighbour’s bloat eats the trigger words you wrote).
Measured, not asserted — library vs. an unguided model (same model, no library); clean, blind-judged, stable across samples (results & method →). Every number below names the model it was measured on, because a lift can be overtaken by model progress and then reads as current when it is historical — that happened to the defect-avoidance row on 2026-08-21 and is stated there rather than quietly left standing:
-
Completeness +0.39 — and it did not expire. Re-measured 2026-08-21 on the current flagship
claude-sonnet-5: 0.62 → 1.00, +0.38 — unchanged. From a bare “build X” prompt, best-practice coverage goes ~59% → ~98% (7 tasks): the model stops silently dropping tests, rate limiting, structured logging, and TLS. Web search likely can’t recover this (an agent won’t search “should I add rate limiting”). Not model-specific, and not stale: a different-family model (openai/gpt-5.1) shows +0.44 on the same tasks (cross-model →), andclaude-sonnet-5— four months newer than the model this was established on — still shows +0.38 (2026-08-21 →). Why this one lasted while defect-avoidance did not: newer models stopped writing known-bad patterns, butsonnet-5unguided still omits tests in 7 of 7 tasks, transport in 5, rate limiting in 5. Knowledge gaps close with model progress; salience gaps do not. -
How much of that is just asking? Most of it — not all. A pre-registered placebo arm with no library, told only to “ship production-complete code and self-review it”, reaches 0.86 (2026-10-08,
sonnet-4.6): 69% of the lift. The library’s own +0.125 sits in the controls a model leaves out even when told to be thorough: transport enforcement, rate limiting, CSRF, request size limits, session invalidation. On generic completeness, asking nearly suffices (PLACEBO →). -
Freshness +0.53 → +0.30 — it erodes, and we measured that rather than assuming either way. Current-2026 facts (RFCs, CVEs, EOLs) 0.44 → 0.97 on
claude-sonnet-4.6, where an unguided model is confidently wrong. Re-measured 2026-08-25 onclaude-sonnet-5: 0.69 → 0.99, +0.30. The pre-registered prediction was that a training cutoff is a gap model progress cannot close — refuted: the newer model answers 8 of these facts unaided that its predecessor could not, because its cutoff advanced into a fixed case set. Ten of 32 remain outside it, and that is the surviving lift. So freshness is a third shape — neither expired like defect-avoidance nor flat like completeness. And the same day we proved the cause was the instrument, not the library: a fresh 10-case freshness set built from recent facts, each verified against its primary source and chosen by a rule fixed before any model ran, reads 0.33 → 1.00, +0.67 on the same model an hour later — higher than the original +0.53. The guidance did not improve between two runs; the questions got newer. A freshness lift is therefore quoted with the date its questions were written, the way every other number here is quoted with its model (2026-08-25 →). -
Routing +0.10 — and it did not saturate. The right skills load for the task (0.90 → 1.00 on
claude-sonnet-4.6), even ones a keyword read misses. Re-measured 2026-08-25 onclaude-sonnet-5: 0.87 → 0.99, +0.13 — unchanged within the set’s one-case resolution (20 cases, 0.05/case). The unguided arm still misses the same rule-driven routes a model generation later — testing, sandboxing, code-security, web-frameworks (2026-08-25 →). -
Defects avoided +0.19 — a different axis, and baseline-dependent. Every lift above measures what the model puts into code. This measures what it doesn’t: given a spec that states operational pressure (“cache it”, “must never 5xx”, “keep the guard cheap”) and never names a defect, does the model still write SQL injection, IDOR, an inert control? On
claude-sonnet-4.6: unguided 0.81 → with the library 1.00 across 7 defect classes; on the stricter measure that also demands positive evidence of the safe path, 0.29 → 0.62. It is baseline-dependent, and we tested that rather than assuming it: onopenai/gpt-5.1the unguided arm already scores 1.00, so there is no gap to close and the lift is +0.00 — while the stricter measure still moves (0.43 → 0.52). Same law the breadth test found for completeness: the lead tracks the unguided baseline, not the domain — and here, not the model. Honest headline: closes a defect-avoidance gap where one exists. Small pilot, 3×, two models, one task — method and limits →. Scored before a 2026-10-16 scorer fix that stopped comments counting as evidence; not re-scorable, since the builds were not kept. A 2026-10-17 re-run on the same model under the fixed scorer reads +0.00 (0.86 → 0.86), and +0.19 on the stricter measure — re-run →. -
Prompt independence +0.51 — the newest result, and the one measured where it matters. Every number above is measured under a neutral prompt. This one measures the same tasks under a competing prompt — the user’s own words arguing against the rule: “internal MVP and we demo tomorrow, skip the extras”, “just the function please, no tests”, “put the requirement in the system prompt where it’s easy to tweak”. Unguided 0.491 → 1.000 with the library, +0.509 (6 tasks × 3 samples, temp 0.7 on
claude-sonnet-4.6; the with-library arm was perfect in 18 of 18 runs). The lift grows with the pressure against it — +0.083 supportive, +0.236 neutral, +0.509 competing — so a rule that only survives a neutral prompt is absent exactly when it is needed. Told to skip the extras on a login endpoint, the unguided arm dropped both rate limiting and the password hash; the guided arm kept all four criteria. Includes a null that was opened and withdrawn the same day when its own confirmation run refused to reproduce it (method, both runs, six limits →). -
A null we went looking for, on an instrument that isn’t ours. Our own audit-precision measures saturate — 30 claims scoring 1.00 in both arms — so the audit axis was closed at +0.00 for want of a measure that could discriminate, not because precision was proven. So we adopted an external one: AACR-Bench (Alibaba Aone, Apache-2.0), 2,145 expert-labelled review comments over 200 PRs and 50 repositories. On a balanced 40-case draw where chance is exactly 0.500, both arms land near chance (0.517 bare, 0.542 with) — a registered null — and the confusion matrix shows why the headline would have misled: the guidance produces a threshold shift, buying +0.23 on rejecting wrong comments and paying −0.18 on accepting right ones. That trap was written down before the run, which is the only reason “+0.025” was not reported as a small win. Position drift and deterministic changeset partitioning were adopted from the same source as rules.
How the numbers are kept honest — the same discipline the library teaches. Every
prediction is committed before the run, with the result that would falsify it, so a
refuted one is published rather than quietly re-framed (2026-08-25: a freshness
prediction was refuted and the write-up leads with it). And case sets are built by a
rule fixed before any model runs — never from the cases a model got wrong, which is
selection bias and guarantees whatever gap you go on to report. That rule is now
part of the library itself (sota-llm-engineering rules/01 §8), because the temptation
is real: when an ageing set stops discriminating, the still-failing cases are sitting
right there.
And not just vs. an unguided model — head-to-head against the most popular guidance libraries on backend build tasks, SOTA-skills leads on completeness (content-only, blind-judged; wins or ties all 21 cases, loses none):
A five-domain breadth test shows when this edge holds: SOTA-skills leads the field wherever a base model ships incomplete code — production backend in any language and complex/security-sensitive frontend (~+10 pts) — and ties where the base model is already near-complete (simple UI, templated infra). The lead tracks task difficulty, not the domain — we measure it and say so. Full breadth result, consolidated table, method & honest limits →
And a result we will not dress up. Two outside assessments named
obra/superpowers as the methodological competitor,
so we ran it (2026-09-08, pinned SHA, 7 cases): SOTA 0.987, unguided 0.637,
Superpowers 0.599. In the chart above it sits at 60% against an unguided band of
58–64% — the same arm measured in the two runs, since temp-0 is not deterministic — so it
lands inside the baseline rather than above it. The band is one row on purpose: an earlier
version drew two “unguided model” bars and, though accurate, it read as a bug. That is −0.04 versus no guidance at all, against a ±0.03 noise
floor — so on this rubric the two are indistinguishable, and the honest reading is about the
instrument, not the project. Superpowers is process guidance; these cases score a built
artifact’s domain coverage. A low score is evidence about fit to this measure. It shows
the two libraries are not substitutes; it does not settle whether a methodology beats a
corpus, and we have no instrument that would.
Method and limits →
What the audit hunts that a scanner can’t
Thirty classes of defect survive every linter, SAST rule, and CVE scanner, because in each one the code isn’t wrong. The library hunts them as explicit passes (this said “Eleven” for seventeen days — correct when written on 2026-08-27 and fifteen classes behind by the time anyone recounted at the v1.41.2 cut. Recount the list, never restate this number: the first correction written here was itself stale within the hour, because the same change added three more classes below):
Finding them is the cheap half — and we can prove it. Across nine instruments, a frontier model recognises these classes unaided: audit lift +0.00, published below rather than buried. The expensive half is not writing them in the first place. On a model that does write them, the library stops it: 0.81 → 1.00. On one that already doesn’t (
gpt-5.1, unguided 1.00) there is nothing to close — we ran that second model and report the +0.00 too (2026-08-21).Qualified 2026-09-12, against ourselves. “Recognises these classes unaided” was measured on instruments that scored 1.00 in both arms — which is what a measure looks like when it cannot tell the arms apart. On an external one that can (AACR-Bench), judging whether a real review comment is correct puts a frontier model near chance in both arms. The audit lift is still +0.00, now across ten instruments; what is not supported is the stronger reading that finding these things is easy.
- Controls that are inert — a safeguard whose success and whose total failure look
identical from outside: a swallowed enforcement exception, a ruleset that loads zero
rules, presence decided by
exists()rather than a loaded artifact, a CI gate whose every run is skipped (and on GitHub a skipped job reports Success to branch protection), a policy engine left inAudit/warn/report-only since the day it shipped, a report whose word “verified” traces to no line that can fail, silent truncation on the way out of a generator — an unset token cap returns a fragment that a swallowed parse error publishes as a valid empty result — a test that still passes when the control’s body is replaced with a no-op, a write-back controller loggingupdated=1 errors=0every cycle for fifteen minutes while pushing no commit at all — its log describes the update it decided on, not the write landing. The same shape one layer down: a count that is computed and still false, because it was derived from an intermediate the function discards and emitted before thereturnthat dropped it. No function can attest to its own return value — every emission site has a suffix that can drop the result after the line is written — so the claim belongs in the consumer, derived from the value received. Where a job runs unattended, its log is the only witness, so the probe is to change what the function returns and read the output, not to re-run the tests. (rules/10, rules/14, kubernetes rules/04 §7) - Pins nothing watches, and watchers that can never report — a version embedded in a
build-tool invocation (
RUN xcaddy build v2.11.4 --with [email protected], a Bazel arg, ago install tool@version) is unwatchable by construction: Renovate sees aRUNline, and Dependabot has no regex manager at all — so pinning it converts an unreviewed drift into an unreviewed freeze, and both states are silent. The usual answer is a bespoke watcher, which then inherits the publishing conventions of whatever it watches: one queryingreleases/latesttakes a permanent 404 from a project that ships git tags and no releases, skips that entry every run forever, and leaves a list that still reads as complete. Same family, one layer down: in Gorequireis a floor, not a ceiling — under Minimal Version Selection the graph’s highest requirement wins, so “we pinned it” is simply false for anything another module also requires. (devsecops rules/03, rules/09, golang rules/07) - The agent’s own tooling as an attack surface — three surfaces the ordinary checks miss.
A coding agent invoked in CI is a CI actor holding your token: it takes instructions
from whatever text it is handed, and the usual
env:fix for expression injection is a shell defence that does nothing for a sink which interprets the value — it just removes the${{ }}reviewers grep for. The developer’s agent session transcript is a credential store nobody inventories, holding whatever the harness loaded, including files it read on its own initiative and mislabelled. And any tool that sweeps such text must never persist raw: store a digest plus a structural skeleton, because shape-based redaction is an enumeration and a bare 64-character hex key has no shape to match. (devsecops rules/01 §1.5a, secrets rules/04 §7, secrets rules/03 §2.1) - Controls the compiler removed — a safeguard that is correct in the source and absent
from the binary. Wiping is the known case (
memsetis dead-store-eliminated); the same applies to constant-time arithmetic, where strength reduction is an optimiser courtesy, so constant time is a property of the emitted code, verified across every architecture and optimisation level you ship —-Osand-Ozincluded. Two instruments answer it, and neither stands in for the other: Valgrind memcheck taint flags every branch on the secret, and dudect’s t-test times the running binary. (code-security rules/22 §1.1) - A signing step that picks its input by name. On a public repo a fork’s
pull_requestrun uploads into the base repo’s artifact store, so “sign the newest artifact named X” can sign a fork’s bytes — and the REST list reads the producer asnull, so a provenance filter over it passes everything. (devsecops rules/02 §2.5.2) - A defect that starts where the gates stop. Formatters, linters and most SAST end at the
compiled artifact; a loader, verifier, dynamic linker, capability check or admission
controller runs after it, and that whole depth is unprobed while every gate is green. Four
gates passed an eBPF object the kernel then refused to load, because a warn-by-default style
lint had suggested an owned argument that spent 52 bytes of a 512-byte stack — on a
constrained target a lint’s premise can be false, and the word “mechanical” is a
classification applied before the analysis that would justify it. A gate can also stop
short by default: ShellCheck does not report an unset ALL-CAPS name, so a
set -utypo passes the lint andbash -nand dies at run time; the optional checkcheck-unassigned-uppercasereports it, and this repo’s CI enables it. (devsecops rules/09 §2a, shell rules/03 §7, rust rules/07 §1a) - A version recalled instead of looked up. Not a stale pin — a measurement of someone else’s artifact, which never feels like a version decision. A recalled release number arrives with no felt uncertainty, so every rule that triggers on doubt is structurally unable to fire. The fix is a fact that cannot be recalled: record the EOL date beside the version. A row past its EOL is removed, not corrected — an unsupported branch can answer the opposite of the current one, not merely a staler version of it. (devsecops rules/03 §3.9)
- A finding sourced to whoever sells the remedy. Security claims arrive disproportionately from vendors of the fix, and such a source is not disqualified by that — it is unblinded by it. Independent sources converging is evidence; sources converging on the conclusion that sells their own product is one hypothesis held by several interested parties. Name the interest in the finding, prefer a test you run yourself, and label it a design argument rather than a measurement until someone runs it. (sota/rules/03 §2)
- A green light from the wrong stage. A pipeline with more than one stage has more than
one success signal, and the earliest is the one that looks like a summary — it is a count
and it renders first. A metrics collector reporting
1 targethad matched a selector and gathered nothing for days; the very next field readhealth=down. Discovery is not collection, and the same split is enumerate-vs-process, connect-vs-authenticate, resolve-vs-fetch, schedule-vs-execute. Accept the downstream artefact — the series, the row, the record — never the pipeline’s own readiness. And prove a repair with an output delta, not a green light: in that case three affirmative signals were already green while nothing was collected, and only0 → 54 seriestold the two states apart. (rules/14 §4b) - A safety net deleted because nobody had needed it yet. The deletion proof for a dependency is remove it and the build still passes. For anything whose job was to be available rather than called, that proof returns the same green either way, because being unreached is what a healthy fallback looks like. A cache, mirror, warm standby or break-glass path needs a second piece of evidence — the successor named, and measured working now. Field case: the replacement mirror was 3.3 hours fresh, so the deletion was right; had it been stale the correct action was the opposite one. (rules/10 §3a)
- A status that is true, about the wrong subject. Not a wrong answer — a correct one describing something other than what the reader assumed, which no amount of care applied to the value can catch. Field-reported, six in one session, every one literally true: “exit code 0” was the wrapper’s and arrived 17 seconds into a 41-minute run; “no advisories for this package” was true of the database that was opened, which had zero rows; “the harness returned no result” was true of a container that never started, and the alternative reading was a conclusion about the target; “38,861 passed” was true of the tree fifty minutes earlier. The rule is one clause long: when a check reports OK, name what the OK is about. (sota/rules/03 §2)
- The ad-hoc command you typed to check something. Unlinted, unreviewed, run against the
system under test — and it can report a false absence or destroy what it was inspecting. A sweep
reads as clean because the searcher silently excludes things: measured on one tree with
four matches,
rgdefaults found 1, agrepthat turned out to be a wrapper function found 3, explicit flags found 4. And a verification command that copied 40 GB into a container filled the host and corrupted the runtime — the check never ran. A count taken from a listing tool has the same shape without any bug at all:gh pr listanswers with the first 30 of 330, exit 0 and empty stderr, because a default page size is policy rather than a defect — so a result whose size equals the cap is a page until proven otherwise. Blast radius is not only disk, either: an unbounded backgrounded loop, or a wrapper that invokes a command its own directory shadows, fills the per-user process table, and every tool fails at once including the ones you would use to diagnose it. Two unrelated causes produce that one signature and only parentage separates them. Two more shapes where the command is correct: an extraction or fetch into a blob you have never opened cannot be positive-controlled at all, because nothing is yet known to be in it — so it must print a denominator (bytes, members, total files) beside the zero, or0reads as a fact about the subject whentarsimply could not open the archive. And the selector can name a different population member than the question did:sort -V | tail -1is the newest, not the default, and returned a backports kernel for a release that ships another one — nothing truncated, exit 0, no rule broken. And a sweep that writes can destroy what it inspects in a waygit statusshows as one character: an in-place sweep (perl -pi,sed -i) across a path list silently replaces a symlink with a regular file — exit 0, target untouched. Measured across four implementations, and the danger is the platform split: only BSD sed refuses, so a macOS developer sees the safe behaviour and CI (GNU, BusyBox) does not. That one-liner converted this repository’s own tracked symlinks. And a guard tested in zsh can pass what bash rejects: zsh leavesBASH_REMATCHunset, so empty-eqempty accepted43/44as “N/N checks passed”. (rules/06, rules/03 §3a) - Controls that block everything — the mirror image, and the one every other pass
here looks past. An enforcement control (cap, quota, filter, allowlist, sandbox
policy) can be tightened until it refuses the legitimate case too, and it passes the
same tests: a security suite asserts refusal, refusal is exactly what an over-tight
control produces, and the mutation probe above only ever installs the permissive
no-op, so it looks in one direction. The fix is an allow arm — a representative
legitimate case that must complete through the control, never against the bare
environment, because proving the machine can do the work says nothing about whether
your control permits it. Worked instance: a memory budget set with
RLIMIT_ASrefuses the runaway allocation exactly as intended, and also kills every Go or JVM process at startup, since those runtimes reserve gigabytes of address space they never touch (measured: 1.17 GiB reserved against 2.3 MiB resident). Its host-hardening twin: forcing AppArmor’s shippedflags=(unconfined)profiles into complain mode broke rootless Podman, because those profiles exist to grant a permission, not to skip a policy. (rules/12 §1a, sandboxing rules/02) - Layers that were never layers — the same test applied to an architecture diagram rather than a function. A second-opinion classifier drawn from the same model family as the system it guards shares its blind spots by construction (common-cause failure), and one that only ever sees what the primary already flagged uncertain cannot, even in principle, catch what the primary got confidently wrong. A TEE bought to fix records that were never emitted is answering a liveness question no hardware guarantee covers. Both are counted in a threat model and neither reaches the case it is counted for. (rules/08 §1, rules/18 §1)
- Stages that report success while doing nothing — found by the cheap signals
rather than by reading every line: a step returning “nothing found” far faster
than its claimed work allows, a gate that never prints how many items it
examined (
0 checked, 0 failed, exit 0), a size-gated branch no fixture crosses, a cache key narrower than the behaviour it gates, a control written as anassertthat-O/NDEBUG/a missing-eadeletes in production. When a tool’s correct output cannot be stated at all — the test oracle problem, which is why “it found 0” goes unchallenged — a metamorphic check pins how the output must change: a fixture with N known items, and an assertion that the count moves when the input does. (rules/11, rules/13) - A field that is always empty, and the seam nobody could have diffed. A
defaulted read —
.get(key, default)on a dict you did not construct — turns a key-name disagreement into a plausible constant, and when the producer is a model choosing field names from a distribution there is no change event to test against: the prompt and the reader can both be correct while the response uses a synonym. The only sound detector is at runtime — diff the keys the model returned against the keys anything consumed, and log the ones nothing read. (rules/13) - A search that never ran, reported as a clean tree. In zsh — macOS’s interactive
shell, and the one these checklists get pasted into — an unquoted glob in a flag value
(
grep --include=*.md) trips the defaultNOMATCHand aborts the command, where bash would pass the word through and run it. Its stdout and exit status are those of a real no-match: empty output, exit 1. zsh’sno matches foundstill reaches stderr (the command’s own2>/dev/nulldoes not cover it), so a script reading$outor$?, or a sweep with stderr dropped around it, reports a clean tree. The sweep you read as “nothing is stale” may never have executed. A second route reaches the same false-clean: in zsh an unquoted expansion does not word-split, sofiles=$(git ls-files '*.md'); grep -l X $filespasses the whole newline-joined list as one impossible filename and it searched nothing — and the remedy is separator-specific, since the${=var}fix for a space-separated flag string is itself wrong for a file list. Found the hard way in this repo, where the rule was already written and the skill was never loaded: a routing gap, fixed in the trigger rather than the text. (rules/01 §3 and §3a) - A watcher that cannot say “the thing I was watching is gone”. Done/not-done cannot express “I could not tell”, and once you add that you find you also need GONE — terminal and knowable, not unknown. Collapse it and the watch either invents a success or never ends. It is the row people delete while fixing the other bug: one rewrite replaced an explicit “no longer exists” branch with a blindness counter, which then reported “cannot read for 20min” about a job that had simply been garbage-collected. (rules/15 §2.2a)
- A measurement whose rows came from somewhere else. When tests and production write to one shared sink, every aggregate over it merges two populations — and the danger is not the false positive but the destroyed true finding, because the contaminated number carries the larger n and so reads as the more rigorous one. (rules/11, rules/05)
- Your own scorer, gate or benchmark doing none of the above — a whole file turns the lens around: anything whose output decides whether something is OK is a control too. A broken feature produces a complaint; a broken instrument produces a number, and numbers get quoted. So give it a known-bad input it must fail and a known-good one it must pass, bound what it reads, and never trust a number from an instrument you haven’t watched produce a wrong answer on purpose. The sharpest case is a guard that is an instance of what it guards — a coverage test whose scope is narrower than the population and whose predicate the defect satisfies, so it passes on exactly what it exists to catch. An instrument also fails by going red for a reason that is not a regression: a floor measured on one population and asserted over a pool fires with no code change once the denominator gains a new corpus, language or tenant — and dilution is the one cause a pooled metric cannot distinguish from the cause its author imagined. And the probe that proves a test can fail has a second half nobody writes down: hand-mutating a control to a no-op puts a real defect into production source, so the revert is part of the technique — verify it against the working tree, never against an exit status a wrapper will report as a clean pass. A known-bad also rots without anyone touching it, and in the direction nobody watches: a mutation pinned to a delta — append one line, add one file — breaches a threshold only from the subject’s current slack, so improving the subject disarms the probe. Measured here: shrinking an always-loaded file from 199 lines to 169 silently made the probe guarding its 200-line cap inert, and every standard safeguard passed — the literal matched, the mutation took, the tree was dirty. Pin the mutation to the threshold, and re-run the known-bads after a refactor, not only after a check changes. The remedy every mature discipline reached independently — the proof test, the clinical positive control, aviation built-in test, adversary emulation — is one move: a negative control, a committed known-bad the gate must reject on every run, verified per target rather than once, because a tripwire that fires for 2 of 20 targets looks identical to full coverage. Worth knowing that no mainstream framework asks for this: NIST SSDF and the EU CRA require a record that a scan ran, OpenSSF Scorecard’s SAST check detects only that a tool is configured, and SLSA will sign provenance for a scanner set to scan zero files. A passing compliance check is evidence of process, not of protection. And a negative control answers only whether the gate can fail — never whether it still covers you: a refactor into a nested module, a second manifest or a sidecar image moves code out of a gate’s scope with no diff to the workflow file, so watch the number of units each gate enumerated and treat a drop as a failure. (rules/15, devsecops rules/05)
- Absence encoded as a value — the in-band sentinel: a number whose domain
includes an “absent/unknown/error” marker (
-1,0,"",9999-12-31). It type-checks and no linter flags it:-1is truthy, so theif x:presence check everyone reaches for admits it, and because the sentinel carries an ordering it loses every<and wins every>— one missing operand makes a guard skip silently in one direction and fire spuriously in the other, from a single input. The tell is not the constant but the asymmetric guard: one operand filtered against the sentinel and the other, in the same comparison, not — because that filtering is applied per site, so it lands only where the author happened to be thinking about it. (architecture rules/02 §8a, with a per-language row measured on each toolchain) - Dependencies declared but never reached — the inert-dependency sweep: packages, modules, and plugins wired in and inert, installed and pinned and scanned and never run. Proven by deleting them in a scratch copy and running the real build, lint, and full suite, with exit codes and before/after transitive counts reported: a grep is not proof, and no tool’s silence is either. (rules/10)
- Decisions that stopped being right — the datastore picked for scale that never arrived, the rewrite justified by a benchmark that no longer reproduces. Every expensive-to-reverse decision is classified JUSTIFIED / STALE / UNJUSTIFIED / UNVERIFIABLE, and any number one rests on is re-measured this session.
- Findings that don’t survive contact — every Critical/High gets an independent pass
prompted to kill it, working from the code rather than the write-up and defaulting
to REFUTED when the evidence is ambiguous. Refutations are recorded, so the next
auditor doesn’t re-raise them — and swept before they’re dropped, because the
refuted pattern routinely closes somewhere the audit’s scope didn’t cover. A severity
also has to name its chain (reach → primitive → boundary crossing → channel), and
on a diff it is rated against the code the change replaced: filing a High against a
hardening fix teaches authors that hardening attracts findings. The refuter also gets
less than the finder had — no execution, no writes — with only the artifact
crossing over (the PoC, the failing command, the
file:line), never your write-up; and it returns a number against a threshold fixed before the findings were seen, because a paragraph of hedging is a judgement you then re-judge. (findings §1, §4, §4a) - A result you saw once — where the evidence is a behaviour (a crash, a race, a
timing bypass, anything an agent or a sampled model produced), it is reproduced N of
N and both numbers are reported:
1/1and3/3are typeset identically and mean different things. On a repeat audit the yield curve is read too — count falling while difficulty rises. A flat count wave after wave is a statement about the audit, not the code. (findings §2, methodology §4) - A control that works, on some of the sites it’s credited with — not inert, not
missing: a real containment check guarding one channel of five, a
disable_tools=Truepassed at 2 call sites of 6, a path guard on 9 target walks of 61. Every signal is a working control’s signal, because on the guarded subset it is one. The audit move is a census — enumerate the protected operation, mark each call site, report the ratio — and the API fix is that a parameter selecting a trust boundary defaults to the closed side. The population has a second axis, the principals it runs as:pam_faillockreturns success when it cannot open its tally, so a 0700 tally directory recorded no lock-screen failures (PAM runs as the user there) while every root-run test passed. (code-security rules/14 §6) - Security prose the code no longer keeps — “containment is applied at every target walk” (it was 9 of 61); “no function-calling, no shell — this RCE mechanism is NOT APPLICABLE” (tools were on by default). Each had been true when written. Most such claims are universally quantified and therefore falsifiable by counting, and a wrong NOT APPLICABLE is the worst case: it cancels the next reader’s own investigation. (code-security rules/14 §7)
- Your own tool, ingesting somebody else’s repository — scanners, SAST wrappers,
review bots and agentic analysers run on a maintainer’s machine with that identity’s
credentials, and the target is the attacker. Four legs, usually owned by four people:
staging that dereferences symlinks out of the tree, “static” analysis that evaluates
target-controlled build metadata, an LLM step spawned with tools live and the parent’s
cwd, and egress left on by default. “Buildless” is no defence: measured on CodeQL 2.27.3, Rust--build-mode=noneran a target’srustc-wrapper,build.rsand proc macro, andcargo metadata,treeandfetcheach ran a repository’srustc-wrapper. (sandboxing rules/05 §7, rust rules/07 §4a) - Absence claims — “no hardcoded secrets remain” is the one finding nobody can falsify: a narrow search and a true absence produce identical output. Any absence claim needs a widened search plus a second independent method, with the search stated. (findings §2, §4)
- Controls keyed to a neighbouring setting — the predicate reads a proxy that agrees with the real dependency right up until someone configures the two apart, three files away. A coupling defect: the control’s own site never changes, so neither per-file review nor a per-gate probe can see it — the signature is a control that silently stops at the moment it starts mattering. Field-reported 2026-08-26 with two shell shapes that fail the same way: a process substitution whose producer failed (its exit status is unreachable, so zero lines reads as success) and an “append” to a keyed store that is really an upsert, silently deleting the link target of a hash chain on the second run. The audit for this class is the proxy question, which the usual falsification question cannot answer: is this the thing I actually depend on, or something that currently agrees with it — and who can change one without the other, and would I find out? A control that is correctly enforcing the wrong predicate is not inert, so “would anything observable differ?” answers yes while the control is still wrong.
Where this is not backed by a number: the measured lift is in BUILD (completeness, freshness). Nine audit instruments across four designs sit at +0.00, and a tenth read a registered null too — recognition (snippets, cross-file repo, precision), procedure (does the model actually mutate the control and re-run the build), question-set (an unscoped “audit this repository”, with defect classes outside the standard repertoire), and, since 2026-08-14, a real repository at a real vulnerable commit — the one design a synthetic fixture provably could not stand in for, because a planted defect is a deviation from its filler and agents find deviations without security reasoning. That last one is the strongest form of the test and it closed the question: across 16 real BOLA sites in Harbor v2.5.1 both arms recalled 15/16, and across 59 blinded findings both scored precision 1.00. A frontier model handed the code is already at ceiling — on synthetic code, on real code, and when you stop telling it what to look for. The audit half is justified by gap analysis and by real defects it found in this repo — not by a measured lift, and it is reported that way rather than implied. This paragraph once said there would be no tenth accuracy instrument. One was built on 2026-09-12 (COMMENT-TRIAGE) and read a registered null. A different dependent variable (time-to-find, report usability, reach for a non-expert) is still untested. Two numbers landed 2026-09-10, both pre-registered before any call. The router’s terminal self-audit (BUILD step 4) is no longer only a mechanism: under 400 lines of competing rules prose, removing it costs −0.05, and it recovers +0.062 — SE 0.019, 95% CI [+0.024, +0.099], the first interval here excluding zero on that step (GATE-ABSORPTION). And the conflict rate between two skills loaded together — the one failure mode with a real incident behind it — measured 0.176 verified against 0.353 judge-reported, which refuted our own prior that conflicts are rare. The gap between those two numbers is the story: 3 of 11 reported conflicts quoted sentences that were not in the files named, and the judge could not see the router, which is where conflict resolution lives (CONFLICT-RATE).
Every null, the retraction, and the pre-registered predictions that were wrong →
How the numbers are kept honest
The measurement discipline is the part that is hard to copy, so it is worth stating plainly. Every item below is in the repo, not a claim about it:
- Nulls are published, not buried. Eleven +0.00 rows (counted 2026-09-24) sit on the scoreboard next to the +0.39 — including the ones that say, in our own words, that the audit half of this library adds nothing a good model doesn’t already do. That null is why the defect-avoidance result above matters: we went looking for value where our own measurements said there wasn’t any, and reported both. (This line read “seven” until 2026-08-21 — it was understating the count.)
- A lift was retracted. An early +0.07 on inert-control detection did not reproduce when the sample grew from 15 to 49 cases. It was withdrawn and the retraction is documented rather than quietly dropped.
- Routing is re-measured on a clock, not only on a diff.
scripts/routing-baseline.shre-runs the description classifier locally, and a monthly job goes red when that stamp is older than 3 months, because a model release can move routing with no change here. - The gates are proven able to fail.
scripts/check-negative-controls.shruns in CI as its own job: it injects a known-bad per invariant into a disposable git worktree and requires the intended check to be the one that complains — a non-zero exit for any other reason is reported as a false pass, not a catch. A passing gate proves the tree is clean; only this proves the gate still works. - Predictions are pre-registered. Before the 2026-07-30 audit experiments ran, the expected numbers and ranges were committed and pushed (PRE-REGISTRATION.md). Both predictions turned out wrong — one by three times its own lower bound — and are reported as wrong.
- The scorers are themselves tested. A mutation probe once replaced a scoring
function with
return 1.0and nothing noticed; the golden tests that now run in CI were watched to fail against that exact mutation first. - The eval runners carry a duration baseline. Each run records to a local ledger
and the next run of the same runner prints the delta —
[run-completeness elapsed 12.3s over 7 cases | previous 380.0s — 30.9x faster]— because “finished far faster than the work allows” is a comparison, and a duration without its denominator says nothing. A swing over 5× is flagged for a human; nothing is gated on time. That ledger was itself a shared sink until 2026-09-02 —--selftestruns and aborts landed in it in the same shape as measurements (46 of 60 rows), which had quietly disarmed the comparison for the most-run runner. Runs now mark completion, and only a completed run can be a baseline. - The library is applied to itself, and it finds things. Its own
dead-path rules caught this repo’s CI gates passing over zero files — green,
exit 0, examining nothing — and the fix was verified by re-running the mutation.
The same lens later caught this repo’s secret scan:
gitleaksprints179 commits scanned, and nobody read it. In a shallow clone it scans 1 of 179, printsno leaks found, and exits 0 — a green scan over 0.5% of history, with one CI setting the only thing preventing it. CI now asserts the scope. Two more, both 2026-09-04. Two releases had shipped and were never tagged — a CHANGELOG entry, a version bump, a merge, and no tag: unreachable bygit tag, and invisible because the one version gate checked only that a tag is never ahead ofVERSION. And an eval runner had been a dead runner for six days — its ablation target moved to another file in a split, so its guard refused every run. The guard was right; what failed is that the smoke harness rendered it as a blandok, the same string it prints for a runner that merely wants arguments.
The point is not that every number is flattering. It is that you can tell which ones are load-bearing, because the ones that aren’t are labelled.
Skills
| Skill | Covers |
|---|---|
sota |
Master router: operating principles, task→skill routing, full-audit workflow + audit methodology (tool matrix, evidence standard, report template) |
sota-architecture |
Styles & ADRs, DDD, distributed systems, resilience, scalability, cloud-native, anti-patterns |
sota-code-security |
Injection, authn/authz, crypto, web security, resource safety, data exposure, LLM appsec |
sota-threat-modeling |
STRIDE/LINDDUN, DFDs & trust boundaries, threat catalogs, risk rating, model reconstruction |
sota-skill-security |
The supply chain of things that tell an agent what to do: provenance & pinning, review-before-install, the instruction trust boundary, precedence & shadowing, capability minimisation |
sota-secrets-management |
Lifecycle & workload identity, storage backends, app patterns, leak detection, credential types |
sota-sandboxing |
Isolation boundaries, seccomp/Landlock/capabilities, containers/microVMs, parsers, AI-agent sandboxing |
sota-performance |
Measure-first methodology, algorithms, memory, I/O & network, caching, Web Vitals |
sota-async-concurrency |
Concurrency models, races/deadlocks, primitives, event-loop hygiene, cancellation, backpressure |
sota-api-design |
REST/HTTP, versioning, GraphQL, gRPC, websockets/SSE/realtime, webhooks, API security & ops |
sota-devsecops |
Pipeline hardening, SLSA/Sigstore provenance, dependencies/SBOM, container builds, IaC, admission control — including the trap where a bot PR (Dependabot/Renovate) branches inside the repo, satisfies every “trusted run” condition, and still gets no repository secrets, so a secret-dependent gate either goes permanently red or quietly scans less than it claims |
sota-databases |
Modeling & engine choice, zero-downtime migrations, indexes, transactions, reliability, security, pgvector/Qdrant, SurrealDB |
sota-frontend-design |
Typography/color, layout, design systems, UX patterns, WCAG 2.2 accessibility, motion design, visual craft |
sota-web-frameworks |
React 19/Next.js + Vue 3/Nuxt 4: Server Components & Server Actions, RSC/client boundary, caching (use cache/PPR/ISR), hydration correctness, SSR state serialization, Nitro routes, framework CVEs |
sota-observability |
Structured logging, metrics, OpenTelemetry tracing, SLOs & alerting, operational readiness |
sota-testing |
Test strategy & design, doubles/test data, contract testing, e2e, property/fuzzing/mutation, suite health, deadline tests that assert wall-clock (the one carve-out to “never assert durations” — a timeout has no other oracle) |
sota-llm-engineering |
Evals, prompt/context engineering, RAG, agents & tools, LLM production engineering, data lifecycle — incl. sizing context with the provider’s own token counter rather than another vendor’s tokenizer, which under-counts by up to 54% on markdown-dense text — and evaluating generated code: the grader as an attack target, the unbiased estimator if you report pass@k, held-out suites |
sota-ml-engineering |
Production ML/MLOps (classical, not LLM): training→serving→monitoring, feature stores/registries, leakage & train/serve skew, ML Test Score eval, deployment & rollback, drift/retraining, ML security & governance |
sota-cloud-infrastructure |
Accounts/landing zones, cloud IAM, VPC/DNS/CDN setup, compute selection, storage, FinOps, resilience & DR |
sota-kubernetes |
Cluster platform security: RBAC & escalation, admission control, GitOps controllers, operators/CRDs, etcd, Helm supply chain, multi-tenancy, Talos/k3s |
sota-identity-access |
IdP ops (OIDC/SAML/SCIM), RBAC/ABAC/ReBAC design, joiner-mover-leaver, privileged access & break-glass, SPIFFE, phishing-resistant MFA, AD/Kerberos/ADCS hardening |
sota-network-security |
Zero-trust & segmentation, NetworkPolicy depth, service mesh/mTLS, egress control, WAF/edge, DNS/TLS/PKI & cert lifecycle, CAA account binding, email auth (SPF/DKIM/DMARC) |
sota-confidential-computing |
TEEs (SEV-SNP/TDX/CCA, enclaves, confidential GPUs), remote attestation & attest-then-release, confidential K8s (CoCo), FHE/MPC/ZKP |
sota-detection-engineering |
Detection-as-code (Sigma/YARA/Falco), SIEM & telemetry coverage, alert tuning/SOAR, threat hunting & intel, deception, incident response, AD attack detection |
sota-data-engineering |
Pipelines & orchestration, streaming/CDC, lakehouse & Parquet, data quality/contracts, governance |
sota-privacy-compliance |
Data inventory, privacy by design, consent & user rights, GDPR/CCPA/HIPAA/PCI/AI Act, SOC 2/ISO 27001, breach readiness |
sota-security-compliance |
Control-frameworks-as-code: NIST CSF 2.0, 800-53, 800-171/CMMC, SSDF, FedRAMP, EU Cyber Resilience Act (SBOM/CVD/updates), ISA/IEC 62443 (OT zones & security levels) |
sota-mobile |
Platform/stack choice, offline-first & push, mobile security, performance budgets, store releases, Swift in apps (the language is sota-swift) |
sota-cli-ux |
Command/flag design, output & exit-code contracts, lifecycle behavior, distribution |
sota-shell-scripting |
Bash safety baseline, robustness, script security, CI/entrypoint/Makefile scripts, and PowerShell — pwsh CI steps and deploy scripts, where $ErrorActionPreference is not the set -e it looks like — and zsh silently rewriting "$rev:path" as a colon modifier |
sota-docs-workflow |
Documentation architecture, API docs & changelogs, code review/PR workflow, commits & releases |
sota-ux-writing |
Voice/tone & plain language (ISO 24495-1), microcopy, error & feedback messages, accessible/localizable interface text |
sota-copywriting |
Positioning & value props, headlines/landing pages/CTAs, SEO content (E-E-A-T, spam policies), claims & legal trust (FTC, email law) |
sota-rust |
Ownership/API design, errors & panics, unsafe discipline, tokio, supply chain, subprocess execution (std::process::Command), performance, CI |
sota-golang |
Errors, package design, goroutine safety, net/http hardening, security, pprof, CI |
sota-c-cpp |
RAII/idioms, memory safety & sanitizers, undefined behavior, security (CERT/MISRA, hardening flags), concurrency, CMake/clang-tidy/fuzzing CI, performance |
sota-jvm |
Java/Kotlin idioms, null/immutability API design, concurrency (virtual threads, JMM, coroutines), security (deserialization/JNDI/XXE/crypto), GC/JFR/GraalVM, Maven/Gradle supply chain & CI |
sota-python |
uv/ruff/typing, idioms, asyncio, security, performance, FastAPI/Django/pytest |
sota-javascript-typescript |
Strict TS, idioms, async, Node hardening, security, bundle/React performance, testing |
sota-dotnet |
C#/.NET idioms (records, NRT, patterns, spans), disposal/DI design, async (ConfigureAwait/cancellation), security (EF/Dapper, deserialization, ASP.NET Core auth, crypto), GC/Span/AOT, NuGet supply chain & analyzers/CI |
sota-php |
strict_types & modern idioms (enums, readonly, match), OWASP security (PDO, output escaping, uploads/LFI, unserialize/Phar, sessions), Composer supply chain, PHPStan/Psalm, OPcache/FPM/JIT |
sota-ruby |
Idioms & typing (RBS/Sorbet), security (SQLi, ERB escaping, strong params, Marshal/YAML.load, ReDoS), Bundler supply chain, RuboCop/Brakeman, GVL/Ractors/YJIT |
sota-swift |
Swift on any target — Swift 6 data-race safety, optionals & errors, ARC & unsafe code, security (CryptoKit, Codable, SQLKit, TLS), Vapor/Hummingbird defaults, SwiftPM supply chain (plugins & macros, SBOM) |
Every garbage-collected language skill also covers its escape hatch into raw memory: JNI/FFM/Unsafe, ctypes/cffi, native addons, unsafe/P/Invoke, PHP FFI, Fiddle. The class is stated once in sota-code-security rules/06 §3, and each language skill carries its own detectors.
Several hazards recur in every language, so each is stated once as a shared class in sota-code-security, with a detector for each language in that shared rule:
- SSH host-key verification;
- temp-file and permission hygiene;
- an LDAP bind used as a login check;
- XML built from strings;
- native library search paths.
Each language skill was also gap-checked against an external, tool-backed list of that language’s security checks: Bandit, gosec, cppcheck, Brakeman, ANSSI, find-sec-bugs, eslint-plugin-security, Psalm and the .NET analyzers. A concept matrix (scripts/gen-concept-matrix.py) keeps universal topics such as numeric precision and money covered in all nine.
Coverage & non-goals
Deliberately not covered: Scala/Elixir, standalone C (inside sota-c-cpp), platform-engineering/IDP depth. File a skill request issue. A language with no skill still routes: the router applies the domain skills and says no language skill covers it.
Installation
Both commands are shown at the top — the plugin (/plugin, auto-updates on
version bump) or clone + link (./scripts/install.sh, a local checkout to
read, hack on, or pin). A few details on the clone path:
- Skills are discovered from
.claude/skills/(per project) or~/.claude/skills/(personal, all projects);install.shsymlinks every skill and your profile. --project DIRscopes the skills to one repo (the slash commands still go to~/.claude/commands, on purpose: they are run about work in another project);--copypins a snapshot instead of linking.- Other agents need
--target all. Copilot CLI, Codex, Gemini CLI and Antigravity do not document~/.claude/skills;--target allalso links~/.agents/skills(Copilot, Codex, Cursor, Gemini CLI) and Antigravity’s own~/.gemini/config/skills/~/.gemini/antigravity-cli/skillswhere it is installed, and--routingthen mirrors the directive — ending in the router’s absolute path, for an agent with no skills loader — into each installed agent’s global file. With no flag, the installer offers this when it detects one of them. Paths, sources and what is still unverified: docs/MULTI-AGENT.md. - On Windows without Developer Mode, the install is a copy. Git Bash’s
ln -scopies silently when a symlink is refused; the installer now detects that and says so — re-run it after everygit pull, or enable Developer Mode and re-run for live links. Run as an elevated administrator, it links: 43 of 43 skills were real symlinks on Windows 11 with Git for Windows 2.56 (measured 2026-10-22). The no-privilege copy path above follows the Git for Windows and MSYS2 docs, and was not measured. - Prefer no script? Symlink
skills/*/into~/.claude/skills/andcommands/*.mdinto~/.claude/commands/by hand. You then skip what the script adds beyond links: the update-reminder hook, the routing-hook, code-rules-hook, zsh EQUALS hook and listing-budget offers, and the reach check.
The plugin (or --copy) installs the skills; a few extras (routing reminder,
status line, pre-commit gates, AGENTS.md) aren’t auto-enabled — see
Optional extras for plugin users. On first
run the plugin shows a one-time notice pointing there.
An install is personal, not repo-resident
Installing once makes the skills apply in every project you open, new ones included — there is nothing to run per repo, and a brand-new repo is covered the moment you start work in it. But the install resolves against your home directory: a teammate’s clone and a CI runner see none of it.
So for a repo shared with anyone, decide explicitly:
./scripts/install.sh --project . # repo-resident: .claude/skills/ in the repo
./scripts/install.sh --project . --copy # ...pinned snapshot, not symlinks to your paths
— or leave it personal and put the install step in CONTRIBUTING.md so a
contributor can reproduce it. What must not stay personal is the gates: a
secret scan that lives only in your shell doesn’t run on anyone else’s commit.
Wire those into the repo with init-gates.sh.
And the things no install can supply per repo — gates, LICENSE, .gitignore, an
agent file, and the order to create them in — are the day-zero list in
sota-docs-workflow rules/01 §10.
The router raises it once, unprompted, the first time it meets a repo that has
none of them.
Updating
Plugin install: updates ship when the version bumps — /plugin update sota-skills@sota-skills (or /plugin marketplace update sota-skills).
Do not assume auto-update covers you. Per the
Claude Code docs
(checked 2026-07-30): “Third-party and local development marketplaces have
auto-update disabled by default” — this is a third-party marketplace, so unless you
turned it on (/plugin → Marketplaces → the entry → Enable auto-update),
nothing updates on its own. Even with it enabled, the check runs after your session
starts “with a random delay of up to ten minutes”, and the running session keeps the
versions it loaded at launch, so a refresh lands on /reload-plugins or your next
launch — never mid-turn. Run /plugin update when you want a known-current library.
An occasional nudge, with no telemetry. Nothing pushes updates on either path,
so a SessionStart hook (scripts/update-reminder.sh) mentions — at most once
every 14 days — that your copy
has been sitting for a while, and how to check. It makes no network request. It
cannot tell whether a new version exists, only how long since it last spoke: the
useful part was the reminder, and a real check from every session start would turn a
documentation library into something that reports when and how often you work. You
run the check. Installed by install.sh (clone) and by the plugin’s own hook; silence
it with SOTA_UPDATE_REMINDER_DAYS=0, or set your own interval in days. The one thing it
can know locally it says every session: a copied install (no symlinks, e.g. Git Bash
without Developer Mode) is stamped with its release, and once git pull moves the checkout past
it, the hook names the stale copy and the re-install command. A second local fact, said once: a default-on
hook script that a git pull brought to a clone install and nothing registered (the code-rules
hook, or the zsh EQUALS hook when the agent’s shell is zsh), since only install.sh --routing
writes settings.json. A fresh install stays silent: it was just offered every hook.
Which version am I on? scripts/install.sh --version reports the release, the
checkout (git describe), whether your remote is ahead as of the last fetch, and
whether the skills are symlinked (update live) or a pinned --copy snapshot. Quote
it in a bug report — otherwise a report about a rule’s behaviour can’t be tied to the
release that produced it.
Clone install: because linking is symlink-based, existing skills update the moment you pull — the symlinks already point at the live files:
git -C /path/to/SOTA-skills pull
To also pick up newly added skills (a pull alone won’t link a brand-new skill directory) and prune links to removed ones — pull and re-link at once:
./scripts/update.sh # git pull --ff-only, then re-link
./scripts/install.sh --update # the same thing — update.sh is a thin alias
It’s idempotent: re-running only links what’s new and prunes what’s gone, and
never touches symlinks it didn’t create (--copy snapshots don’t auto-update —
re-run to refresh). With always-on routing enabled, a re-run also refreshes
the managed routing directive and reminder hook in place when their wording
changes upstream — prompting first, backing up, touching only the managed
block; a hook you customized is left untouched.
What an update does not refresh: the gates in your own repos. update.sh
re-links skills and re-syncs this checkout’s own hooks; it never reaches a repo you
ran init-gates.sh in, so those gates stay at the release
that generated them. Re-run init-gates.sh there — it rewrites only its own managed
block, so it is safe to repeat. This matters most for hook types: pre-commit
writes .git/hooks/ at install time, so a config that gains a
pre-push stage installs nothing on its own and the new gate silently never runs
(verified on pre-commit 4.6.0). verify-setup.sh check 9a reports exactly that —
a declared stage with no hook file — which check 9 cannot see, because a different
hook being present makes it read “installed”.
The skill listing budget — raise it, or most of these descriptions never reach the model
Claude Code reserves a per-turn character budget for the skill listing and computes it as
(context tokens x 4) x skillListingBudgetFraction, where the fraction defaults to
0.01. On a 200k-context model that is 8,000 characters for every skill you have
installed, from every source. This library’s 42 descriptions are about 38,240 of it —
and the budget is shared, so what matters is your machine’s total. On the machine this was
found on, the engine counted 65 skills / 47,324 characters against an 8,000 budget: our
42 plus 23 built-in skills that are compiled into the binary and invisible to any script.
Over budget, entries are ranked by recent usage and the ones that do not fit are
rendered as a bare - name with no description at all — so they carry no trigger
vocabulary and cannot be auto-selected on what they do. It is not a tail-trim: it is
all-or-nothing per skill. A skill you have never used ranks zero and is dropped first,
which is a discovery ratchet — invisible because unused, unused because invisible.
Measured 2026-09-11 by reading the shipped claude binary (2.1.268), not inferred from
behaviour, and confirmed live: roughly 20 of these 42 skills were listed name-only in the
session that found it.
Claude Code does notice — and tells nobody. Forcing the condition and reading the log it
wrote gives [WARN] Skill listing over budget: 65 skills, 47324 chars > 8000 budget — descriptions will be truncated. That line goes to ~/.claude/debug/ and appears nowhere
else, which is exactly why a whole session can run on a crippled listing unnoticed.
Since then (code.claude.com/docs/en/skills, re-read 2026-10-20): the docs name two places to
look in a session. /doctor estimates the listing’s context cost and its biggest
contributors. The Skills row in /context reports the listing’s size after the budget is
applied, so it matches what the model receives (before v2.1.196 it counted every description
in full). The docs also say the over-budget warning is written to the debug log; they do not
say whether /doctor shows it. Not re-measured here.
Why it still works anyway, and what actually breaks. The sota router is used every
session, so it ranks near the top and keeps its description — and a name-only skill is
still invocable by name, which is exactly what the router’s routing table does. That is
why always-on routing below is the recommended path and not a nicety: it is the mitigation.
What is genuinely lost is direct auto-selection of a domain skill when the router has not
fired, which is most likely for the skills you have never used.
scripts/install.sh offers to fix this, on install and on --update, in the same
shape as everything else it touches.
-
It measures what the listing actually holds, not what the installer just linked: personal skills, your account’s synced claude.ai skills, every enabled plugin, and the project’s own.
scripts/skill-listing-sources.shdoes this for all three checks (installer,verify-setup.sh, the plugin hook). It adds 25% for the built-in skills, which are compiled in and not on disk. -
It sizes the budget for the context window you actually run. The budget scales with the window, and 1M context gives five times the budget of 200K. Only a live session knows the window exactly, so the checks use, in order:
- the window
scripts/statusline.shlast observed, which it records; CLAUDE_CODE_DISABLE_1M_CONTEXT=1, which forces 200K;- a
[1m]model setting.
Otherwise the window is unknown and 200K is assumed. The model name alone can’t rule 1M out, because several current models run 1M natively with no suffix.
- the window
-
When it fits, it does nothing and says so. When it doesn’t, it asks before writing, backs the file up, writes through a symlink so dotfiles stay in charge, and never lowers a value you already set. For this library’s skills alone that is about 0.07 at 200K, or 0.02 at a known 1M window (measured at 42 skills).
-
It warns if the library is installed twice (a clone and the plugin). Every skill is then listed twice, and the fix is to remove one copy, not to raise the budget.
To set it by hand instead, in ~/.claude/settings.json:
{ "skillListingBudgetFraction": 0.07 }
Be aware of what you are buying: the listing is sent every turn, so this reserves ~7% of
the context window for it. skillListingMaxDescChars (default 1536) is a separate per-skill
cap — no description here exceeds it, so it does not apply.
Plugin users get told, because a plugin cannot fix this itself. Verified against the
2.1.268 binary: the settings precedence is
["userSettings","projectSettings","localSettings","flagSettings","policySettings"] — there
is no plugin scope — and a plugin contributes skills, hooks, agents, commands and MCP
servers only. So the plugin ships a SessionStart hook
(scripts/plugin-budget-check.sh). It measures the same sources as the installer and
compares them against the budget at your session’s window; a [1m] model in the hook’s
input counts as proof of 1M. It says so with the numbers, the window it assumed and the
exact setting when they do not fit, and separately when the library is installed twice. It does not write your settings: that reserves a share of every context window, so it is
your call. It speaks once per (size, fraction) pair — silent once fixed, and audible again if
you install more skills.
To check your own install: scripts/verify-setup.sh reports it as check 1b, with the
arithmetic, the per-source breakdown and the window it used, and a double install as 1g. By hand: look at the skill
list Claude is given and count entries that are a bare name with no text after the colon.
Any such skill is installed, correct, and unreachable except by name.
Always-on routing (recommended)
Skill descriptions are matched per prompt, so routing is opt-in and depends on how you phrase the request. To make the skills apply to every session regardless of wording, pin the routing instruction where Claude Code always sees it.
The quick path: ./scripts/install.sh offers to set this up for you after
linking the skills — interactive and dotfiles-aware: it detects an existing
or symlinked ~/.claude/CLAUDE.md / settings.json, asks before touching
anything (recommended answer pre-filled), backs up first, writes through a
symlink so dotfiles stay in charge, and uses managed markers so re-runs refresh
the managed block in place and never duplicate it. Use --routing to force,
--no-routing to skip, --yes for non-interactive. Or wire the three layers
by hand:
Three layers, strongest last:
1. A stack profile. Copy the template, fill in your stack, and symlink it
into ~/.claude/ so the router finds it in every project (not just this repo):
cp profiles/example.md.template profiles/.md # edit it — profiles/*.md is git-ignored
mkdir -p ~/.claude/profiles
ln -sfn "$(pwd)/profiles/.md" ~/.claude/profiles/.md
2. A global directive. ~/.claude/CLAUDE.md is loaded into every session,
every project. Add a routing mandate so the skills apply without trigger words:
# Global engineering directive
Always, on every answer: (1) **validate before you assert** — verify any claim
about code, system state, config, versions, or facts against a primary source
(read the file / run the command / fetch official docs) before answering or
proposing, and label anything unverified as such; (2) **keep docs current** —
when you change code/behavior/config, update the affected docs (README,
CHANGELOG, comments, runbooks, AGENTS.md) in the same change, unprompted.
For any task that builds, designs, refactors, debugs, reviews, or audits code —
in any language or repo — consult the `sota` router skill first, load the
matching `sota-*` skills, and apply their rules before acting. This holds even
when I never say "SOTA" or "audit". Treat `~/.claude/profiles/.md` as the
BUILD default and AUDIT baseline, and stop-and-ask on security-relevant choices.
3. (Optional) A per-prompt reminder. A directive read many turns ago can
fade from a long context; a UserPromptSubmit hook in ~/.claude/settings.json
re-injects it on every prompt. install.sh --routing writes exactly this, and
--update offers to refresh the wording when a release changes it:
{
"hooks": {
"UserPromptSubmit": [
{ "hooks": [ { "type": "command",
"command": "echo 'sota standing rules (every answer): (1) VALIDATE — check any claim about code, system state, config, versions or facts against a primary source before asserting it, and label anything unverified. (2) KEEP DOCS CURRENT — update affected docs in the same change. (3) ROUTE BEFORE YOU ACT — if the turn touches code, a diff, a config or a build/CI file, invoke the sota skill FIRST and apply the matching sota-* skills. Reading a file counts. If you have already read code this session without routing, route now. Routing is per task SHAPE, not per session: if the work has changed shape since you last routed — different layer or language, or from building to verifying — route again. Treat ~/.claude/profiles as the stack baseline; stop and ask on security-relevant choices.'" } ] }
]
}
}
Each rule is a numbered imperative of equal weight. That is not cosmetic: in a real session where routing was the third clause of a run-on sentence, rules (1) and (2) were obeyed every turn and the routing clause was dropped every turn — same text, same repetition, opposite outcome. Rule (3)'s last sentence makes the trigger recoverable: a long session often becomes a code task without any single prompt saying so, and routing late beats not routing.
If you hand-edit the wording, keep the phrase sota-* skills in it — that is
the marker install.sh uses to recognise the hook as its own. Reword past it and
your hook stops receiving updates, and a later --update adds a second one
beside it instead of refreshing it.
No mechanism in the skills forces a model to run a skill — the three layers feed it instructions it chooses to follow, making routing reliable, not phrasing-dependent.
Advisory vs enforced — read this before calling the library “only advisory”
That sentence is about the skills, and it is often read as “nothing here can enforce anything”. Three corrections, each re-checked 2026-10-02:
- The host can enforce, and some of it ships here. Claude Code hooks are not advice: a
Stophook can block the turn from ending,PreToolUsecan deny or rewrite any tool call (hooks docs), and the Agent SDK exposes the same loop with hooks and permissions programmatically.scripts/verified-done-hook.pyuses that: an opt-in Stop hook that refuses “done” on a changed tree until a verification command has passed on exactly that tree (router principle 6, enforced).scripts/zsh-equals-hook.py, on by default in the plugin, is a PreToolUse hook that refuses a zsh command carrying an unquoted=wordbefore it runs (sota-shell-scriptingrules/06 §1), a reflex the written rule did not stop. The git hooks fromscripts/init-gates.shand CI are enforcement on every host, whatever the agent. - The router is not an always-on 43 KB blob. Only each skill’s frontmatter
descriptionis in every turn’s listing; the router’s body loads when the skill is invoked (CONTEXT-MANAGEMENT). - The evals measure guidance, not an agent loop. Every runner script in
evals/is a chat-completion call with the rules in the prompt; no tools run and nothing the model writes is executed. So the lifts here are real for that condition. The agent-loop condition is measured in a separate repo, sota-agent-evals: Claude Agent SDK sessions with tools, scored by hidden tests in a no-network container with no model judge. Its v2 run (2026-10-02) was clean and read not supported on near-saturated cases. v3 (2026-10-08) hit the ceiling in every arm, and its library arms never invoked a skill: 0 of 166 library runs since v2. That arm installed skills without the routing layerinstall.shadds. v4 (2026-10-09) added it: 20/20 runs then invoked the library, but the router is mostly where they stopped (3/20 went further, 0/20 read a rules file). Pass rates were at the ceiling in both arms, so whether the rules help is still unmeasured (v4 report)) (evals/README).
What stays advisory is everything a hook cannot check mechanically: whether a rule was applied well. The line is “can a program decide it from the tree or the tool log”, not “skills vs harness”.
With the hook in place, re-typing the same instruction adds nothing mechanically. Rule (1) is already prepended to every prompt you send, so “always validate your claims” is a second copy of text the model has just received. What is not redundant is naming the technique instead of the goal — “re-read the state, don’t trust your summary”, “verify at the remote”, “run it rather than reason about it”. The failure mode this library keeps finding is never forgot to care; it is checked the wrong artefact, and only the specific phrasing redirects that. Operating principle 7 is the generic form of it. (Reported from a session using the library, 2026-08-18: an observation about mechanism, not a measured effect — nobody can run the counterfactual.)
Using it
With always-on routing set up (above), you don’t name anything — describe the task in plain language and the right skills load automatically (see How it works). Name a skill or rule only to force a specific skill, scope to one rule file, or stack an exact combo.
Building — plain prompts; routing picks the skills:
Design a multi-tenant invoicing service — stack from my profile, or propose one.
Add a RAG search feature over our docs, and write the evals first.
Scaffold the GitHub Actions pipeline for this repo: SHA-pinned actions, OIDC, SBOM + signing.
We handle CUI on this service — what does that require of the architecture and data stores?
Auditing — say the mode (“audit”, “review”, “harden”):
Run a full audit of this repo. Static analysis only, current commit, report with a prioritized roadmap.
Audit this PR before I merge it.
Sweep the repo and git history for secrets — rotate-first recommendations.
Threat-model this service from the code: DFD, trust boundaries, STRIDE.
Audit our Kubernetes manifests and Dockerfiles. Severity + effort on every finding.
Why is checkout slow? Profile first — no guessing.
Review our agent’s MCP setup for tool poisoning, rug pulls, and shadowing.
Naming a skill or rule (optional — to force or scope):
Add a websocket endpoint per
sota-api-designrules/05 (auth-at-upgrade, backpressure).
Is this migration zero-downtime safe? Check
sota-databasesrules/02 (expand/contract, lock-aware DDL).
Review test-suite health against
sota-testingrules/07 (flaky policy, coverage ratchets, speed budgets).
Audit this PR against
sota-code-security+sota-golangbefore merge.
Maintaining the library:
Refresh the library — re-verify fast-moving claims against current primary sources, apply fixes, and update the root
LAST-VERIFIEDstamp.
Create profiles/.md for my stack: .
Add a new skill for , same structure: SKILL.md + rules/ under 500 lines each, claims web-verified.
Tips:
- Say the mode if ambiguous — “audit/review/harden” vs “build/add/design”; skills key off those verbs.
- Scope audits explicitly — which commit/branch, static-only or may-run-tools, time budget (“crown jewels only”). The methodology file asks otherwise.
- Ask for the report format — default audit output is executive summary → findings by severity → roadmap by risk-reduction-per-effort → positive notes.
- Re-verify version-sensitive facts — web-check before pinning any version.
Slash commands
scripts/install.sh (and therefore scripts/update.sh) links every file in
commands/ into ~/.claude/commands/, so they work in any project, not just
this one. verify-setup.sh check 1d compares what is installed against what the checkout
ships — a git pull refreshes existing links and creates none, so a newly added command stays
silently uninstalled until you re-run the installer.
| Command | Run it when | What it does |
|---|---|---|
/sota-report |
at the end of a session, in your own project | Writes a gitignored field report on where the guidance failed, was absent, wrong, or right and did not fire — stamped with the version that produced it. Then writes a short generalised extract and prints a gh issue create line. It never posts anything. |
/sota-resume |
at the start of a session, or when picking a project back up | Finds the open work: sweeps every tracker, checkbox and TODO marker with a controlled search (a clean “nothing found” is exactly the answer a skipped symlink tree, a --replace flag or a 30-row default page produces), classifies it — ready · needs a decision · deliberately deferred · not an item · already done and never ticked off, or made unnecessary by a control that already covers the gap — shows you the table, then executes what you agree to, one item at a time, against the project’s own CI entry point. |
/sota-audit |
when a piece of work is finished, or on arriving in a codebase you did not write | Audits the code against the library rather than for defects in general, so the dominant finding is a rule that owns real surface area and was never applied — and behind it, a control that is present and enforces nothing. Agrees the scope first (every candidate printed with its denominator, because the wrong scope returns clean rather than an error), pins every finding and dismissal to a commit, covers a diff’s callers and importers, maps the trust boundaries before any severity is rated, runs the installed scanners (secrets over full history, dependencies, SAST, IaC and CI) and reports the missing ones as not reached, asks before running a codebase’s own tests, build or install scripts when you did not write it (that is its code running as you), routes from the surfaces in the tree rather than from whatever happened to be loaded, prints a coverage table per rules file naming the ones nobody opened, walks each Audit checklist item by item (met · not met · not applicable, with the reason), expands each serious finding to the full evidence block with a reproduction, asks the questions that need a decision in one batch, then fixes what you agree to — verified against the finding, not just the suite. |
/sota-deep-audit |
at a milestone, on inheriting a codebase, or before a go/no-go | The heavy pass, and the one to reach for deliberately rather than by default. It checks against the same standard as /sota-audit and buys five things one context cannot: independence (every serious finding goes to an agent that did not find it, working from the code rather than the finder’s write-up), scale (a repo too large to hold at once is partitioned across agents, each with its own context, where /sota-audit partitions within one), decisions re-measured rather than reconstructed (where a past choice rests on a number, that number is produced again this session), a forward look at whether the plan is still right, and the full threat-model reconstruction where /sota-audit builds a boundary map (below). Four lenses — decisions & results · code and architecture · security posture · strategy. It states the plan and the fan-out split before spending anything, and writes files only if you ask. |
/sota-close |
at the end of a session, before you walk away | The closure pass: retract first (every claim that proved wrong, corrected everywhere it reached), record open items where the next session will actually trip over them, update the docs and agent files the session made false (step 3a: re-read every doc that describes a file the session changed, bounded to those docs), re-derive every number from its source, state plainly what is not done and what is blocked on whom, then commit the evidence and confirm the push landed. |
/sota-resume and /sota-close are the two ends of the same session: one picks the open work
up, the other puts it down where the next session will find it. Neither needs the other to have
run — most projects scatter their open work across files written by people who are not here.
Both load what they cite: a step 0 invokes sota-shell-scripting and reads its rules/06
before the first sweep, because a citation loads nothing — and invariant 40 fails any command
that cites a skill’s rules file without saying to load it.
All five take free-text arguments to steer them (/sota-close focus on the migration branch).
They are prompts, not scripts: the text is in commands/*.md and nowhere else, so you can read
exactly what your session is being told to do before you run it.
Why the threat model runs first — light in /sota-audit, full in /sota-deep-audit. A
finding’s severity rests on the chain it closes, and a chain crosses a trust boundary, so both
commands map the boundaries before rating anything. /sota-audit builds the light version:
entry points, the authn/authz checkpoint on each, the asset it reaches, and the assumptions that
implies, each checked against the code. /sota-deep-audit reconstructs the whole model. That is a pass of its own, and it goes before the lenses rather than inside the security one,
because a finding rated without trust boundaries is rated in a vacuum. It extracts entry points,
stores, actors and the boundaries the system actually has from the code rather than the docs,
then writes down the assumptions that implies — services trust the gateway’s headers, that
bucket is private — and tests each against the code that makes it true. No evidence is not
“probably fine”; it is a broken assumption, and those are usually the Criticals. What comes out is
a control-presence matrix: Present · Partial · Absent · N/A · Unverifiable, each carrying the
evidence its state demands — file:line for Present, both sides for Partial, and the searches
you ran for Absent, so a reviewer can re-run them. Partial is the most important state. One
authorization-checked endpoint proves the team knows the pattern; the seventeen unchecked ones are
the finding, and they tell you the remediation is adoption rather than invention. The pass also
reads the negative space — exclusion lists, skip-auth decorators, count = 0, disabled tests
with security in the name — because a control someone switched off is a stronger finding than one
never built. Full procedure: sota-threat-modeling rules/06.
Why /sota-close is a command rather than a habit. The end of a session is when the
context has usually been compacted at least once, so “what happened” is reconstructed from
your assistant’s own earlier prose about the work rather than from the work — the weakest
check available. Everything the command asks for is executed against an artifact instead: git diff, git log -S, the file on disk, the command run again. The ordering is load-bearing
too — retraction comes first because every later step writes, and anything still wrong gets
propagated into a doc, a commit message or a hand-off where the next session reads it as
established.
Optional setup & integrations
Beyond the skills themselves — all opt-in, none required to use the library.
Badge
Built or audited a project with the library? Ship the attribution
:
[](https://github.com/martinholovsky/SOTA-skills)
Enforcing the gates
Routing makes the model apply the rules; to make them stick regardless of who
(or what) commits, wire them as git hooks. scripts/init-gates.sh generates a
SOTA-aligned .pre-commit-config.yaml for whatever languages it finds in the
target repo:
cd /path/to/your/project
/path/to/SOTA-skills/scripts/init-gates.sh # add --dry-run to preview first
It detects Python / Go / Rust / JS-TS / shell by manifest and extension, then
writes the exact tools each skill prescribes — ruff·mypy·pytest·pip-audit,
gofumpt·golangci-lint·govulncheck, clippy·cargo-audit, eslint·tsc· audit,
shellcheck·shfmt, plus gitleaks everywhere. Fast checks (lint, format, secrets)
run on commit; heavy ones (type-check, tests, vuln scans) run on push —
the split sota-python rules/01 §6 and sota-devsecops rules/05 require, so
commits stay quick.
It is idempotent: re-run it after adding a language and it rewrites only the
block between its # >>> sota-gates >>> markers, leaving any hooks you added
yourself in place. The hooks call your project’s own toolchain, so install the
per-language tools it lists on exit (and pre-commit install if the script
couldn’t).
Then check it actually took. init-gates.sh sets things up; nothing
verifies the result, and “configured” and “working” render identically — a
config file with no installed hook is not a control, and a CI job whose every
run is skipped is a gate on paper.
/path/to/SOTA-skills/scripts/verify-setup.sh # read-only; --runs N widens the CI sample
/path/to/SOTA-skills/scripts/verify-setup.sh --reach-only # section A only: is the library reaching this machine?
/path/to/SOTA-skills/scripts/verify-setup.sh --no-color # plain rows; also honours NO_COLOR and TERM=dumb
install.sh (and therefore update.sh) runs the --reach-only half itself at the end
of every run, because “linked 42 skills” is what the installer did and reachability
is what the agent gets — and the two diverge silently, since a git pull updates
every existing symlink and can create none. Pass --no-verify to skip it.
It reports skills reachability, the routing hook, the profile symlink, a licence
under any name, which gates exist, whether a hook is installed rather than
merely configured, and — from real run conclusions — whether CI has ever
executed and ever rejected anything. Its section F adds one fact about the
machine rather than the repo: what your default searcher silently skips. Every
searcher excludes something quietly — a symlinked directory, a .gitignore’d path, a
dot-directory — and the failure mode is a clean absence, which is exactly the answer
a sweep was hoping to prove. It runs a four-match fixture under $TMPDIR and names the
exclusions as INFO; nothing fails for them, because rg skipping ignored files is a
feature. The one thing that can fail is the positive control — a searcher that
cannot find the plain file is broken, and its absences are not evidence. It changes nothing and exits 1 on any
FAIL. Anything it could not observe is marked UNVERIFIED, never passed: on
this repo the reject-history check reads UNVERIFIED at the default sample and
turns up a real rejection at --runs 200, which is why the sample size is
printed. docs/VERIFY-SETUP.md carries the other half — a
paste-in prompt for the judgement calls a script can’t make: whether the agent
file’s content is meaningful and whether its claims are still true.
Add --docs-gate to also install a pre-commit hook that blocks a commit which
changes code but updates no docs (README/CHANGELOG/docs//*.md) — so docs
stay current without you having to ask. It writes a small helper to
.sota/docs-gate.sh; it’s heuristic (a docstring-only edit inside a code file
will trip it) and bypassable with SKIP=sota-docs-gate git commit, which is why
it’s opt-in.
Other AI agents (Codex, Copilot, Gemini, …)
The skill content is plain Markdown — any model reads it. To make the skills
themselves discoverable by Copilot CLI, Copilot in VS Code, Codex, Cursor, Gemini
CLI or Antigravity, install with ./scripts/install.sh --target all — it links
~/.agents/skills, which all but Antigravity read, plus Antigravity’s own skills
directories where it is installed, and --routing writes the directive into each one’s global
instructions file (table and sources: docs/MULTI-AGENT.md). To
route a project’s agent through the library, generate an AGENTS.md (the cross-tool open standard
read by Codex, Cursor, Copilot, Antigravity CLI, Windsurf, Zed, and more):
Or over MCP. scripts/sota-mcp-server.py serves the same files read-only as MCP tools (list_skills, get_skill, get_rules_file), resources and prompts, for an agent that would rather call tools than read a skills folder. ./scripts/install.sh --mcp registers it for Copilot, Codex, Gemini CLI, Antigravity and Cursor where they are installed; verify-setup.sh shows where it is missing. It does not route: the agent’s model picks from the descriptions, as it does with skills (docs/MULTI-AGENT.md).
cd /path/to/your/project
/path/to/SOTA-skills/scripts/gen-agents-md.sh # add --dry-run to preview
It writes a thin AGENTS.md that carries the operating principles and points the
agent at the installed skills/ tree — the index is built from each skill’s
frontmatter so it stays in sync, and the agent reads the relevant rules/*.md on
demand (no rule text is duplicated). Idempotent via a managed block, like the
others; --skills-dir/--output override the defaults. Claude Code keeps using
the native Skills install above. This repo itself follows the standard:
AGENTS.md is canonical; CLAUDE.md/GEMINI.md are symlinks.
Different tools read different filenames. Claude Code reads AGENTS.md natively since
v2.1.277, but by default only when no CLAUDE.md or CLAUDE.local.md exists, so one
personal CLAUDE.local.md silently stops it; older versions (and, before v2.1.281, some
sessions such as Bedrock) read CLAUDE.md only. Either way the symptom is the model
getting worse, not a missing file. Every run therefore reports the state of
the two sibling entry points, and --siblings writes them when they are absent:
/path/to/SOTA-skills/scripts/gen-agents-md.sh --siblings
# ./CLAUDE.md -> @AGENTS.md (Claude Code's native import)
It is not a copy — AGENTS.md stays the single source of truth — and the import is
preferred to ln -s AGENTS.md CLAUDE.md because on Windows creating a symlink
needs Administrator or Developer Mode, so a symlink is not portable.
For Claude Code a pointer is still the portable choice.
GEMINI.md is opt-in behind --legacy-gemini, because Antigravity CLI —
which replaces Gemini CLI, retired for individuals on 2026-06-18 — reads
AGENTS.md natively. (Measured 2026-09-10: Gemini CLI 0.59.0 now exits with
IneligibleTierError … migrate to the Antigravity suite, and Antigravity’s own
bundled docs list “Directory-Based Rules (GEMINI.md / AGENTS.md)”.)
An existing CLAUDE.md/GEMINI.md is never touched — but it is never silently
accepted either. The script inspects it and says what to change, because a file
that never mentions AGENTS.md is a file that will not work with this library:
| what it finds | what it says |
|---|---|
| absent | MISSING + the exact line to add (or writes it with --siblings) |
already imports/links AGENTS.md |
ok, left alone |
| your own content, no mention of it | ACTION — add @AGENTS.md as the first line; your file is not modified |
only the bare text AGENTS.md |
ACTION — a symlink checked out as a plain file (core.symlinks=false, or Windows without Developer Mode); it instructs nothing |
| a dangling symlink | ACTION — repoint it |
For Gemini there is a route with no pointer file at all: set context.fileName in
.gemini/settings.json to ["AGENTS.md", "GEMINI.md"] — it accepts a list. And
whichever you choose, confirm it loaded rather than assuming: /context in
Claude Code (under Memory files), /memory show in Gemini CLI.
Status line (optional)
scripts/statusline.sh is a Claude Code status line that shows which skills
you’ve actually used this session — not just how many are installed:
Opus 4.8 │ ctx 63% │ my-service ⎇ main │ skills▸ code-security, testing (2)
Claude Code’s status-line input doesn’t expose loaded skills, but it passes the
transcript path; the script reads back the Skill invocations recorded there,
falling back to a count of installed skills before any are used. It also records the
context window Claude Code reports (context_window.context_window_size) in
~/.claude/sota-skills-data/context-window, rewriting it only when the value changes. That
is the one exact source for the skill-listing budget checks, since nothing outside a live
session can know the window. Wire it up in settings.json (requires jq):
"statusLine": { "type": "command", "command": "/path/to/SOTA-skills/scripts/statusline.sh" }
Optional extras (for plugin users)
The plugin installs the skills and, since 2026-10-08, the always-on routing reminder as its
own UserPromptSubmit hook, on by default. Without it the skills were not used: across 166
agent runs with every skill installed and no routing layer, the model invoked a SOTA skill
zero times (sota-agent-evals v3).
Turn it off with SOTA_ROUTING_HOOK=off (for example in settings.json "env"). If you also
installed the installer’s hook, the plugin’s stays silent, so the reminder is never doubled.
Since ROADMAP 73 (m) it also ships the code-rules hook, on by default
(scripts/code-rules-hook.py, a PostToolUse hook on Edit|Write|MultiEdit). After the agent
writes code, it names the rules file for what that code does: an outbound fetch → SSRF, a CSV
writer → formula injection, an archive → Zip Slip, a handler → rate limiting. It tells the agent
those rules are part of the task, so it builds them instead of handing them back as a question.
It moved outcomes when measured: rule tests 0.698 with no hook → 0.906 with it
(sota-agent-evals v10).
It costs about +68% per agent task (v10: $0.615 vs $0.366 a run), its trigger table was written by an author who had read the
cases that measured it (in-sample), and it needs python3. On fresh tasks it did not move outcomes: on
cases-v5, 20 tasks sampled from OWASP ASVS and written blind to the library, the hook plus the router’s
table left cited rule tests at 0.667 in both arms while reach rose 8/20 → 13/20 (v14, NULL,
+38% cost). Agents read the named rule and handed it back as a decision, citing the precise spec. With one sentence of
competing pressure added to every prompt (“internal demo tomorrow … skip the extras”), the same two arms read 0.567 → 0.767
(v15, INCONCLUSIVE: 3 cases up, 0 down, p = 0.125, +49% cost). Turn it off with SOTA_CODE_RULES_HOOK=off.
install.sh --routing offers the same hook to clone installs; with both, each file is named once.
The router carries the same table as text (“What your code does: the rules file to read”), for
hosts that cannot run a hook. The exception is rows marked hook-only (HOOK_ONLY in the script, since
2026-10-22): new triggers reach the hook first and enter the router once their reach is measured. The
router is at its 500-line cap, and its rows are what the reach numbers were measured on.
Three host-config rows (containers and seccomp, AppArmor/SELinux, PAM) also read YAML, .j2,
.conf, .service and .toml files, so an Ansible role or a Compose file is covered. Every other
row reads code only: over 161,783 local config files, all rows together fired on 40%, almost
always falsely. Measured without the hook, it got agents to the right rules file in
14 of 20 runs, against 6, and rule tests rose 0.679 → 0.792
(sota-agent-evals v13; in-sample, like the hook’s own numbers).
Since 2026-10-21 it also ships the zsh EQUALS hook, on by default (scripts/zsh-equals-hook.py,
a PreToolUse hook on Bash). zsh rewrites an unquoted word starting with = to a command’s path
and aborts the rest of the line on one that names no command, so cat a; echo ===; grep x b prints
a and a == not found that reads like the end of the output, and the grep never runs. The hook
refuses that command before it runs and tells the agent how to quote it (sota-shell-scripting
rules/06 §1). A written rule did not stop the habit: a field report records the rule read and
broken 60 seconds later. Over one operator’s 43,875 agent Bash calls, it refused the 344 that zsh
had cut and nothing else (in-sample: the lexer was corrected on that corpus). It adds nothing to
the context unless it fires, does nothing unless the agent’s shell is zsh (CLAUDE_CODE_SHELL, else $SHELL), costs about 85 ms per Bash call
and needs python3. Turn it off with SOTA_ZSH_EQUALS_HOOK=off; install.sh --routing offers it
to clone installs.
The plugin does not touch your global config or status line. To match the clone experience, opt in to any of these; the scripts ship with the plugin, under its cache dir:
- Status line — point
settings.jsonstatusLineat the bundledscripts/statusline.sh(see Status line). - Pre-commit gates / AGENTS.md — run the bundled
scripts/init-gates.shorscripts/gen-agents-md.shagainst a project (see Enforcing the gates and Other AI agents).
The quickest path: just ask Claude to “set up the SOTA optional extras” — the first-run notice prompts for exactly this, and Claude will walk you through them.
Structure
skills/
sota/ # master router — start here
SKILL.md # routing, operating principles, workflows
rules/
01-audit-methodology.md # how to run an audit: scoping, tooling, triage
02-build-workflow.md # the four BUILD steps and where they are mirrored
03-audit-findings.md # severity, evidence, refutation, reporting
04-library-map.md # the library map — which rules/NN holds what.
# Offloaded out of the router 2026-09-02:
# 16,997 -> 13,415 tokens per load, measured
sota-/
SKILL.md # when to use, BUILD/AUDIT workflows,
# severity conventions, rules index, top-10
rules/
NN-.md # ≤ 500 lines each (the cap), ends with an Audit checklist
...
profiles/
.md # personal stack defaults consulted by router
Every skill works in two modes:
- BUILD — apply the rules while designing/writing code.
- AUDIT — review existing code; findings are emitted as
file:line | rule violated | severity (Critical/High/Medium/Low/Info) | effort (trivial/small/medium/large) | fix.
Three cross-cutting pieces live outside the domain skills:
skills/sota/rules/01-audit-methodology.md— how to run an audit: scoping, a verified static-analysis tool matrix, triage discipline, and audit hygiene.skills/sota/rules/03-audit-findings.md— what happens to what it finds: the severity model (a Critical/High must name its exploit chain leg by leg), the evidence standard, the decision-ledger pass, adversarial refutation, and the report template (executive summary → findings → roadmap by risk-reduction-per-effort).profiles/— per-user stack profiles: the default in BUILD mode, the expected baseline in AUDIT mode — keeping the library generic and shareable.
How it works
Claude Code matches your prompt against each skill’s frontmatter description
and loads what’s relevant automatically — you don’t have to name a skill.
Naming one (or the sota router) just makes the routing explicit. From there:
- The skill’s
SKILL.mdloads first (workflows, severity conventions, an index of itsrules/files). Only the rules files matching your task are read — never the whole library. - BUILD mode applies the rules while writing code and self-checks the diff against each loaded rules file’s Audit checklist before presenting it.
- AUDIT mode hunts violations and reports findings as
file:line | rule | severity | effort | fix. A full audit runs seven passes: recon → threat model → per-domain passes → silent-control pass (does each control confirmed to exist actually do anything?) → decision-ledger review → findings → refute before reporting. Scoping, evidence standard, severity model and report structure come fromsota/rules/03-audit-findings.md(scoping and tooling fromrules/01); the report ends in a roadmap sequenced by risk-reduction-per-effort. A verdict carried over from an earlier audit is bound to the commit it was made at and expires when that code changes, so a “fixed” finding that reappears stays open as a possible regression, never a duplicate (sota/rules/05§4); the threat-model pass also mines version control for past security fixes and hunts each fixed class across the rest of the code (sota-threat-modelingrules/06). - If
profiles/.mdexists, its stack choices are BUILD defaults and the AUDIT baseline (deviations get flagged).
It scales the rigour to the stakes, and names the level it chose. A spike, a one-off script or a local experiment gets built and labelled as a prototype, with one line on what was left out — the full treatment is not applied to throwaway code. But anything reachable by an untrusted caller, or touching money, credentials or another tenant’s data, gets it whether or not the request said “quick”. The load-bearing half is the labelling: an unnamed shortcut is not a prototype, so proportionality is something the library grants out loud rather than something it does silently (operating principle 9).
Conventions
- Every rules file ends with an Audit checklist (yes/no questions, often with grep/lint patterns to hunt violations).
- Severity scale everywhere: Critical (exploitable/data loss) · High (fix this sprint) · Medium (bounded impact) · Low (hygiene) · Info (observations, no direct risk). Each finding also carries an effort estimate (trivial/small/medium/large) so remediation can be sequenced by risk-reduction-per-effort.
- Each SKILL.md carries a top-10 non-negotiables list — apply these unconditionally; load detailed rules files only as the task demands.
- Borderline severities state the deciding assumption; unconfirmed findings are marked “needs verification”, never asserted.
- A negative claim needs more proof than a positive one. “No instances of X” and “I only looked one way” are indistinguishable from the outside, so an absence claim requires a widened search plus a second independent method, and the search actually run is stated.
- A positive observation must show effect, not existence — the request it rejected, the log line it emitted, the test that fails when it’s disabled. An inert control praised as a strength is the worst reporting error available.
- Publishing under someone else’s name raises the evidence bar. A finding for the person who asked is cheap to retract; the same claim posted as them — a pull request review comment, an issue, a commit message upstream — is public, attributed and permanent. Verify by execution rather than inference, say what you did not test, and never publish on someone’s behalf without their approval of the final text.
Found a gap? Tell us — it’s the only signal we get
This library has no telemetry. Nothing reports back, by design. That also means a wrong rule, a stale version claim, or a task with no owning skill stays in the library for everyone until a human says so.
If a skill was wrong, outdated, or missing when you needed it: open an issue (bad-guidance / skill-request templates — both take about a minute). Dangerous or security-sensitive guidance goes to a private advisory instead.
The assistant will usually flag these itself: the router tells it to surface a one-line note when the library lets you down, rather than papering over it.
Sending more than a one-liner? Run /sota-report at the end of a working session
in your own project. It asks that session to write up where the guidance failed, in the shape
this library can act on, to a gitignored FIELD-REPORT-*.local.md — a field report carries a
reproducer rather than a citation, which is why it is the highest-yield input here. The
prompt front-loads the four checks that decide whether a report is actionable, each one a
mistake actually made during intake.
It stamps the report with the version that produced it (report against what you actually
used — never update and re-run, since that puts a fresh stamp on old behaviour), writes a
gitignored FIELD-REPORT-*.local.md, and writes a short, generalised extract for
publishing — finding, mechanism, whether the rule was already loaded, what
caught it, proposed rule. It never posts anything: this repo is public and issues cannot
be un-published, so it prints a ready gh issue create --body-file … line and stops. You read
the file, then run it — or use the
field report template
if you have no gh. That template is how the library hears from anyone but its maintainer.
An old version is not a reason not to report. Measured over a month, 66% of rules files
were untouched — a stale report is usually about text that still ships, and triage is one
git log on the file it cites (docs/FIELD-REPORT-PROMPT.md).
scripts/install.sh (and therefore scripts/update.sh) installs the command into
~/.claude/commands/ alongside the others; verify-setup.sh check 1c
reports whether it is actually reachable. The reasoning behind each check is in
docs/FIELD-REPORT-PROMPT.md; the prompt itself lives in
commands/sota-report.md and nowhere else.
If it saved you time, a ⭐ helps other engineers find it.
Contributing
See CONTRIBUTING.md. The short version: keep skills generic,
verify fast-moving claims against primary sources, keep skill files
(skills/**) ≤ 500 lines — that cap keeps incremental rule loading working and
does not apply to README/CHANGELOG/docs/, which are read by humans — and end
each rules file with an audit checklist — exactly one, since appending a
section’s bullets under a fresh heading strands them where a reader has already
stopped. 41 invariants enforce this in scripts/check-invariants.sh
(pre-commit + CI — the one-line-each table with the incident behind each one is
docs/INVARIANTS.md), covering line caps, checklist placement and uniqueness,
description limits, version and count drift, router completeness,
internal link resolution, every rules file being reachable from its skill’s index,
a single [Unreleased] CHANGELOG entry, the LAST-VERIFIED stamp moving only
with a sweep, a rendered assets/*.png never being older than the *.html it
comes from, every scoreboard row declaring its sample size, a release
declaring the front door terms its new capabilities landed on, a release
that edits a skill description declaring a routing check — a description is
the whole auto-load classifier, so changing one competes for every neighbour’s
traffic — every § reference resolving, every check having a known-bad, every
shipped CHANGELOG version carrying a git tag and its own link reference, every
eval runner being named in the harness’s own README, the roadmap’s open set
agreeing with itself, every eval case set declaring how its cases were chosen,
no audit-checklist bullet being stranded inside a code fence, no absence reported
through a stderr-suppressed || echo — cmd 2>/dev/null || echo "missing X" fires on
every non-zero exit, so it manufactures findings about other people’s code, and it
shipped in nine of these skills until a field report caught it — no grep probe whose
--include filters out the very file it names, no version pin on a claim about what is
current (a “latest release is X.Y” rots silently; the rules say “latest stable” and keep
version numbers for boundaries such as “fixed in”), and every top-level area
declaring which gates cover it, because enforcement density is uneven and an ungated area
looks exactly like a covered one (the Coverage by area table in
docs/CONVENTIONS-LEDGER.md) — plus gitleaks
(full-history scan in CI; per-commit via the pre-commit hook).
What the invariants deliberately do not check is whether a rule is true. They are
structural; an external audit found 19 wrong statements with all of them green. The
measurable slice is behaviour against the library before your change —
evals/run-prompt-independence.py builds its comparison arm from git show :, so
it reads the real prior text rather than a mirror that drifts. When a prose edit is worth that
run, and the four shapes that are not:
docs/PROSE-REGRESSION.md.
Separately, scripts/check-claims.sh re-runs the library’s
executable claims — the ones a rule’s advice actually rests on — on both Linux and
macOS every CI run, because several are platform splits and one runner can only confirm
its own half. A measurement nobody re-runs rots silently, and it rots in the direction of the
recommendation: sota-shell-scripting rules/05 §3b shipped with GNU sed marked not
verified because the binary was absent locally, and measuring it inverted the advice.
The harness refuted one of its own on its first run. Ideas taken from outside the repo are recorded with a
verdict and reason in docs/ADOPTION-LOG.md, so a
rejection isn’t re-litigated. Security issues and conduct:
SECURITY.md, CODE_OF_CONDUCT.md.
License
© 2026 Martin Holovsky. Two licences, split by what the file is:
- Content — skills, rules, docs, eval cases and everything else not listed below — is CC BY 4.0, Creative Commons Attribution 4.0 International. Use, adapt, and share freely (including commercially); just give attribution: “SOTA Engineering Skills by Martin Holovsky, CC BY 4.0.”
- Code — every
*.shand*.pyfile,hooks/hooks.jsonand.github/workflows/*— is Apache-2.0 (from 2026-10-02; earlier releases shipped it under CC BY 4.0). CC licences are not designed for software; Apache-2.0 adds the patent grant and the warranty disclaimer code needs.
profiles/ holds personal stack profiles and is git-ignored except
profiles/example.md.template — copy that to profiles/.md and edit it;
your real profile stays local and is never committed.
Recommended Tools
Try a different keyword or remove a filter.
Install
npx skillfish add martinholovsky/sota-skills