| name | skill-authoring |
| tier | meta |
| description | Write each verification rule into a Claude Code skill folder following the official skill format. Use when converting extracted rules into skill folders, when iterating on existing rule skills after testing, or when the developer user wants to capture domain knowledge as a skill. Each skill folder must be self-contained with business logic in SKILL.md, code in scripts/, regulation context in references/, and sample data in assets/. Also use the bundled skill-creator for the full eval/iterate workflow. |
Skill Authoring
Each verification rule becomes a skill folder. The skill must be self-contained: anyone (or any agent) reading just this folder should have everything needed to verify compliance with that one rule.
Skill Folder Structure
Follow the official Claude Code skill format strictly. See references/skill-format-spec.md for the complete specification.
rule-skills/
rule-001-capital-adequacy/
SKILL.md # The verification logic and methodology
scripts/
check.py # Deterministic checks (regex, calculations)
references/
regulation.md # Original regulation text, verbatim
interpretation.md # Expert notes on how to interpret edge cases
assets/
samples.json # Annotated sample extractions with expected results
corner_cases.json # Known edge cases with their resolutions
Not every rule needs all of these. A simple threshold check might only need SKILL.md and a script. A complex semantic rule might need detailed references and many samples. Start minimal, add as needed during testing.
Filename case matters. Use uppercase SKILL.md (matching the meta-skill convention you see in template/skills/). On Linux filesystems this is case-sensitive; engine path-matching, audit scripts, and downstream tooling all assume uppercase. Do not write skill.md, Skill.md, or any other case variant.
Granularity: 1 rule = 1 skill directory (default)
Default to one rule per skill directory. Group rules into the same file ONLY when they meet BOTH:
- They share the same evidence (same section / same table / same field) โ so locating one locates all.
- They fail together โ when one fails, the others almost always fail too (e.g., siblings in a required-fields list where the table itself is missing).
When grouping, name the file with the explicit range so downstream consumers (workflow-run, dashboards, finalization) can parse rule coverage by filename:
- โ
check_r013_r017.py (R013, R014, R015, R016, R017 โ same disclosure table, fail together)
- โ
check_r001_r050_r078.py (different chapters, even if topically related โ keep separate)
Anti-pattern: the unified runner
If you find yourself writing a single unified_qc.py (or batch_runner.py, or master_check.py) that handles all rules in one Python file, stop. That means your per-rule skills are wrong, not that the architecture is wrong. Fix the skills.
A failure pattern worth flagging: an agent writes a unified runner like unified_qc.py to bypass individual skills it doesn't trust. The result is cascading errors โ a single rule's failure corrupts every other rule's verdict, easily producing 15%+ error rates across thousands of production checks. The unified runner feels productive locally and is a global mistake. It also stalls the phase model: with no individual check.py files landing on disk, the engine can't credit the work toward milestone completion.
If individual skills aren't running cleanly, the right response is to identify which ones break and fix them, not consolidate. The whole pipeline (extraction โ skill_testing โ distillation โ production_qc) assumes one rule = one verifiable artifact.
Anti-pattern: stub SKILL.md OR stub check.py
Each rule_skill folder MUST have BOTH a substantive SKILL.md AND a substantive check.py (or check.py that imports + calls a workflow that does the real work). One side being a stub breaks the contract.
Variant 1: stub SKILL.md (a templated ~20-line scaffold with ๆฃๆฅ้ป่พ: N/A or equivalent) paired with a real check.py (regex methodology embedded in code). SKILL.md is supposed to be the human-readable methodology document. A reader scanning the rule folder for "what does this verify and why" gets nothing. The methodology has been pushed entirely into check.py comments โ works for the engine, loses the deliverable framing.
Variant 2: substantive SKILL.md (real methodology, PASS/FAIL criteria, source cross-refs) paired with stub check.py (a thin scaffold returning {"verdict": "NOT_APPLICABLE", "evidence": "Check requires worker LLM execution"}). The real check logic lives in workflows/<rule_id>/workflow.py โ but check.py doesn't import or call it. A user running python rule_skills/R01-01/check.py document.txt gets NOT_APPLICABLE on every input, which is misleading.
Variant 3 (legacy): stub check.py returning {"pass": null, "method": "stub"} paired with an otherwise-real SKILL.md. Methodology described but never executable.
Variant 4 (the "monolithic verify engine" stub): per-rule SKILL.md is a thin 20-35 line scaffold ("see verify_engine.py"), per-rule check.py is a thin shim that imports + calls a single monolithic rule_skills/verify_engine.py (or similar root-level file) that holds all 15-20 rules' verification logic in one ~750-LOC file. Each per-rule check.py looks like from rule_skills.verify_engine import check_R01_01; return check_R01_01(doc). This passes the "check.py is not literally a stub" surface check but inverts the canonical per-rule granularity: per-rule files contain no rule-specific reasoning, the monolith holds everything, and the read-this-skill-to-understand-this-rule workflow fails for everyone (developer user, future auditor, downstream agent). The contract says skills are KC's unit of per-rule granularity for a reason. Centralizing all check logic into one big file may look efficient but loses the per-rule auditability that's the whole point. If you find yourself writing verify_engine.py with 15+ check functions and stub SKILL.md/check.py per rule, stop โ keep the methodology in each rule's SKILL.md (substantive) and either inline the check logic or use the canonical per-rule check.py + workflow_v1.py pattern.
The contract:
- โ DO: SKILL.md describes WHAT to check + WHY + WHEN to flag it. Substantive โ typically 50-300 lines, not a 20-line template.
- โ DO: check.py implements the check. EITHER substantive direct logic OR
from workflows.<rule_id>.workflow_v1 import verify + delegate. Returns concrete verdicts.
- โ DON'T: stub SKILL.md with methodology in check.py comments (variant 1).
- โ DON'T: substantive SKILL.md with check.py that returns NOT_APPLICABLE without delegating to a workflow (variant 2).
- โ DON'T: stub check.py returning null verdict (variant 3, legacy).
The engine may refuse phase advance if too many check.py files are stub-shaped. Better to author them substantively now.
Writing SKILL.md
Frontmatter
---
name: rule-001-capital-adequacy
description: Verify that the capital adequacy ratio reported in the document meets the regulatory minimum of 8%. Use when checking capital adequacy compliance in bank financial reports. Check the capital adequacy section or table for the reported ratio and compare against the threshold.
---
- name: Must match the directory name exactly. Use lowercase, hyphens, no spaces. Prefix with the rule ID from your catalog.
- description: Write it as if explaining to another coding agent when they should use this skill. Be specific about what the rule checks, where to look in the document, and what constitutes pass/fail. Be pushy โ include trigger keywords.
Body Content
The body should cover:
-
What this rule checks โ one paragraph explaining the rule in plain language. Include the regulatory source and intent.
-
Where to look โ which section, chapter, table, or part of the document contains the relevant information. Be specific. "The capital adequacy ratio is typically found in Chapter 2, Section 'Key Regulatory Metrics' or in the summary table on page 1."
-
What to extract โ the specific entities needed. "Extract the reported capital adequacy ratio as a percentage." Define the expected format and any normalization needed.
-
How to judge โ the logic for pass/fail. "The ratio must be >= 8.0%. If the ratio is missing, flag as MISSING rather than FAIL." For semantic judgments, describe the criteria in natural language.
-
Edge cases โ known tricky situations. "Some reports express the ratio as a decimal (0.12) rather than a percentage (12%). Normalize before comparing."
-
Comment format โ what to say when the rule fails. Keep it concise and actionable. "Capital adequacy ratio is X%, which is below the regulatory minimum of 8%."
Length and Style
- Keep SKILL.md under 500 lines. Most rules should be 100-200 lines.
- Explain the WHY behind the rule, not just the mechanics. Understanding intent helps handle edge cases.
- Write in imperative form: "Extract the ratio" not "The ratio should be extracted."
- If detailed regulation text is long, put it in
references/regulation.md and reference it from SKILL.md.
Pipeline Node Design
When a skill's workflow has multiple steps, decompose into nodes where each node does one thing well. Each node's difficulty should be well within the model's capability โ don't cram location + extraction + judgment into a single LLM call.
Pre-processing (text cleaning, format normalization) and post-processing (output parsing, value normalization) are separate nodes, not embedded in the LLM prompt. This keeps prompts clean and makes each step independently testable.
Writing Scripts
Scripts in scripts/ handle deterministic operations:
- Regex patterns for entity extraction (dates, amounts, ratios, identifiers).
- Calculation logic for threshold checks, ratio computations, cross-field validation.
- Format normalization (Chinese numerals โ digits, date format standardization, unit conversion).
Scripts should be self-contained Python files that can be imported or executed. Include clear input/output documentation in the script's docstring.
Do not put LLM prompts in scripts. LLM interactions belong in the SKILL.md body or in the workflow (later phase).
Strip reviewer annotations before keyword matching
Sample documents often carry reviewer-annotation footers (้ขๆๅฝไธญ็น: ..., ๆ ๆณจ: ..., Expected: ...) that mark the ground-truth verdict for testing. If your check.py uses keyword/regex matching against the document body, these annotations will leak into the match โ producing false-positive PASS on violation samples (your rule "finds" the disclosure keyword inside the annotation itself, not the actual document content).
The canonical helper ships at workflows/common/utils.py and is auto-populated into every workspace at engine init:
from workflows.common.utils import strip_annotations
def check(document_text):
text = strip_annotations(document_text)
Recognized prefixes (Chinese + English variants): ้ขๆๅฝไธญ็น, ้ขๆ็ปๆ, ้ขๆๅคๅฎ, ้ขๆ้ช่ฏ, ๆ ๆณจ, ๅฎกๆ ธๆ ๆณจ, Expected, expected, EXPECTED, Annotation, annotation. Pass extra_prefixes=("..."ใ"...") if your project uses different labels.
A recurring failure mode worth flagging: a non-trivial fraction of rules have standalone check.py false-positive PASS on violation samples because the regex matches the ้ขๆๅฝไธญ็น: ... annotation footer instead of the document body. KC ships the helper as a template file so this trap is one import away from being avoided.
Writing References
references/ holds content that the coding agent reads on demand:
- regulation.md: The original regulation text, verbatim. Include the source, date, and version. This is the ground truth that the rule is derived from.
- interpretation.md: Expert notes from the developer user or from the coding agent's own analysis. "When the regulation says 'adequate disclosure', in practice this means the section must be at least 2 paragraphs and cover risks A, B, and C."
Keep references factual and sourced. They are evidence, not instructions.
Writing Assets
assets/ holds data that supports testing and edge case handling:
- samples.json: Annotated examples. Each entry: the input (extracted text or entity), the expected result (pass/fail/missing), and the expected comment. Build this incrementally as you test.
- corner_cases.json: Edge cases that the standard logic does not handle. Each entry: description, detection pattern, resolution, and confidence threshold. See the
corner-case-management skill for the methodology.
Authoring methodology (from skill-creator core)
This section folds in the universal authoring patterns from Anthropic's upstream skill-creator. Apply them on top of the KC-specific layout above when drafting any new rule skill.
Capture intent before drafting
Before writing any skill, get clear on four questions:
- What should this skill enable Claude (or check.py) to do? โ A single concrete capability, not a category.
- When should it trigger? โ What user phrases / document contexts should match its description.
- What's the expected output format? โ verdict + comment + evidence shape; or for non-check skills, the deliverable shape.
- Do we need test samples? โ If the rule has objective pass/fail criteria (almost all KC rules do), yes. Build
assets/samples.json incrementally as edge cases appear.
If the conversation already contains worked examples (a user pointed at a passage and said "this is non-compliant"), extract answers from history first โ don't ask the user to repeat themselves.
Frontmatter and progressive disclosure
Skills load in three tiers; budget each tier for what it has to carry:
- Metadata (name + description) โ always in the agent's context. ~100 words. This is the primary triggering mechanism โ make it specific and slightly "pushy" (Claude tends to under-trigger skills). Include trigger keywords, rule ID, the regulation it derives from, and the document location it expects to find evidence in.
- SKILL.md body โ loaded when the skill triggers. Target 100โ300 lines for typical rules, hard ceiling 500. Explain the WHY behind the rule, not just the mechanics.
- Bundled resources (scripts/, references/, assets/) โ loaded only when the body explicitly points to them. Big regulation excerpts and sample corpora belong here, not inline.
If SKILL.md is approaching 500 lines, that's the cue to push detail down into references/ and leave a pointer like "See references/edge-cases.md for the full enumeration of corner cases."
Writing style
- Imperative over passive. "Extract the ratio" not "the ratio should be extracted."
- Explain why, not just what. Today's LLMs have good theory of mind โ a one-line "the regulation flags this to protect retail investors" makes a downstream agent generalize correctly to a case you didn't enumerate.
- Be wary of all-caps MUSTs and NEVERs. If you find yourself reaching for them, that's usually a sign the underlying reasoning hasn't been made explicit. Reframe and explain.
- Be specific about location. "Look in Chapter 2, Section 'Key Regulatory Metrics' or the summary table on page 1" beats "look in the financial disclosures somewhere."
Test samples before scripts
After drafting SKILL.md, write 2โ3 realistic sample inputs into assets/samples.json with their expected verdicts BEFORE you finalise check.py. The samples ground the script: every regex or keyword you add should be there to make a specific sample produce its expected verdict. Writing scripts in the abstract โ without samples โ almost always produces over-fitted code that fails on the first real document.
Iterate, don't perfect
A rule skill rarely lands correctly on the first draft. Plan for at least one revision after testing surfaces problems. Don't pile on defensive MUSTs to handle every edge case โ generalize the methodology. If three samples each needed a different one-off fix, that's a signal the underlying rule statement is too narrow.
If your skill needs more sophisticated methodology than this section covers โ formal eval loops with quantitative benchmarks, blind A/B comparison between skill versions, or description-optimization runs โ consult skill-creator.
Iteration
Skills evolve through testing. After each test iteration:
- Update SKILL.md if the logic needs adjustment.
- Add failing cases to
assets/samples.json.
- Add newly discovered edge cases to
assets/corner_cases.json.
- Update
references/interpretation.md with new insights.
- Log what changed and why.
Use the bundled skill-creator skill if you want to run the full eval/iterate workflow with quantitative benchmarks.
Bilingual Skills
Write skills in the language matching the LANGUAGE setting in .env. If rules and documents are in Chinese, write the SKILL.md body in Chinese using proper financial/regulatory terminology. The frontmatter (name, description) stays in English for system compatibility.