name: citation-auditor description: Audit a markdown file by chunking it, extracting claims with structured output, routing each claim to verifier skills, aggregating verdicts, and rendering annotated markdown. argument-hint: "<file.md>" disable-model-invocation: true
Audit the markdown file at $0.
Invocation Contexts
This skill has two roles in this repo:
- Standalone
/audit(default): user-triggered via/audit <file.md>on an existing markdown file. Uses inline mode — per-claim badges injected into the body plus a per-claim audit report at the end. Does not altercheckpoint.json,verification-audit.json, or any WF1 artifact. - WF1 native verifier backend: Step 3 may reuse the verifier pool under
.claude/skills/verifiers/, but it must not use this skill's markdown renderer as a DOCX review output. Native WF1 results must go throughcitation-checker/scripts/adapt-citation-auditor.pyandmerge-verification-audits.pyso the final artifact remainsworking/verification-audit.json.
There is no automatic Step 10 in this repo. WF1 remains an 8-step review pipeline.
Procedure
Confirm
$0exists and is a markdown file. If it does not, stop and ask for a valid path.Run:
python -m citation_auditor chunk "$0" --max-tokens 3000Parse stdout as JSON with the schema
{ "chunks": [...] }.For each chunk, extract only factual, citation-bearing claims using structured output with this schema:
text: stringsentence_span: { start: integer, end: integer }claim_type: factual | citation | quantitative | temporal | othersuggested_verifier: string | null
Do not extract speculation, forecasts, rumors, advocacy, or soft prediction language such as:
전망이다예상된다업계 관계자에 따르면가능성이 있다Unless the sentence also contains a concrete verifiable factual assertion that stands on its own.
Keep claim offsets chunk-relative. Do not convert them to document offsets yourself.
Route each claim to verifier skills:
- If
suggested_verifieris set and exactly matches a loaded verifier skill name, use it. - Otherwise test the claim text against each verifier skill frontmatter
patternsusing case-insensitive regex matching and use every match. - If nothing matches, fall back to
general-web.
- If
For each
(claim, verifier)pair, use the Task tool to dispatch a subagent that loads that verifier skill and receives the claim JSON.Require each verifier subagent to return only this JSON:
{ "label": "...", "rationale": "...", "supporting_urls": ["..."], "authority": 0.0 }supporting_urlsmay contain either clickable source URLs or plain-language source references when no stable URL exists. Preserve them verbatim and do not invent clickable URLs for non-linkable sources such as precedent search-result IDs.Build aggregate input JSON locally. The exact top-level shape is
{ "verdicts": [ <bundle>, ... ] }where each<bundle>covers one(chunk, claim)pair and holds all verifier candidates for that claim. Do not invent other top-level keys.Exact schema (copy this structure):
{ "verdicts": [ { "chunk": { "index": 0, "text": "<full chunk text>", "segments": [ { "chunk_start": 0, "chunk_end": 44, "document_start": 0, "document_end": 44 } ] }, "claim": { "text": "<claim sentence>", "sentence_span": { "start": 64, "end": 268 }, "claim_type": "citation", "suggested_verifier": "us-law" }, "candidates": [ { "claim": { "text": "<same claim as above>", "sentence_span": { "start": 64, "end": 268 }, "claim_type": "citation", "suggested_verifier": "us-law" }, "verifier_name": "us-law", "authority": 0.9, "label": "contradicted", "rationale": "<Korean rationale from verifier>", "evidence": [ { "url": "https://..." } ] } ] } ] }Rules:
- One bundle per
(chunk, claim)pair. If the same claim has two verifiers, put both candidates inside the same bundle'scandidatesarray — do NOT create a second bundle for the same claim. - The top-level
claiminside each bundle is the canonical claim; each candidate'sclaimmust match it verbatim. evidenceitems require a non-emptyurlstring. If the verifier returnedsupporting_urls: [], emit"evidence": []— do not emit[{"url": ""}].labelmust be one ofverified/contradicted/unknown.authoritymust match the verifier skill's declared authority value.
- One bundle per
Write that JSON to a temp file and run:
python -m citation_auditor aggregate <tmpfile>Write the aggregate output to a temp file and run:
- Standalone
/audit:python -m citation_auditor render "$0" <aggfile>(inline mode is default). - Do not use
render --mode=appendfor WF1 DOCX review output.
- Standalone
Return only the final annotated markdown unless the user explicitly asked for intermediate JSON.
If claim extraction validation fails, retry once with a repair prompt. If it still fails, skip that chunk and note it briefly.
If a verifier subagent returns invalid JSON, drop that candidate instead of inventing a verdict.
If a line was skipped because it is a forecast, opinion, rumor, or unattributed speculation, treat that as expected behavior rather than an extraction failure.
If the user asks why a forecast or opinion line was not audited, explain that this plugin audits verifiable factual claims and citations, not predictions or commentary.