From dingduff
Verify every citation in a drafted legal memo against DingDuff-stored opinion and statute source files. Use after drafting a memo when the user asks to cite-check, citecheck, verify citations, verify quotes, check cites, or validate authorities. Produces cites.json, opens the interactive attorney review panel (or a standalone review.html), and records the attorney's verdicts in review.json.
How this skill is triggered — by the user, by Claude, or both
Slash command
/dingduff:dingduff-citation-checkThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
You orchestrate a propose-and-verify loop: YOU propose verbatim supporting
You orchestrate a propose-and-verify loop: YOU propose verbatim supporting quotes; a deterministic local script verifies them and computes anchors. A hallucinated quote cannot become a highlight — the script only accepts text that actually exists in the source file.
Privacy: verification runs entirely in this session. When the review panel
opens via citecheck_review, the memo transits the DingDuff server once as
tool arguments and is never stored or logged. The standalone review.html
fallback never leaves the machine at all. State this plainly if the user
asks.
python3 --version. If python3 is missing, stop and tell the user it
is required (macOS: xcode-select --install or brew install python3).<skill-dir> — the directory holding this skill's scripts/:
CLAUDE_PLUGIN_ROOT environment variable is set (the skill was
installed as a plugin), use
${CLAUDE_PLUGIN_ROOT}/skills/dingduff-citation-check.<skill-dir>/scripts/verify_anchors.py exists before proceeding.The markdown memo to be checked (usually the one just drafted). If multiple candidates exist, ask the user. Only markdown is supported in v1 — if the deliverable is .docx, cite-check the markdown draft before conversion.
Convention: source files live in sources/ under the project root, saved
there from opinion_store/statute_store download URLs. (Going forward,
always save those downloads into sources/.)
Also search the rest of the working folder for strays:
**Cluster ID:** <id> line.# <citation> and contain **Code:** and
**Section:** lines.If the same cluster is stored twice, use the newest file and tell the user.
Build the sources map:
cl-{cluster_id} (cluster id from the FILE's Cluster ID
line), with type, path, cluster_id, case_name, citation.stat-{filename stem}, with type, path, statute_id, code, section, jurisdiction. statute_id is the [jurisdiction]/[code]/[section]
identifier used with statute_store (e.g. TX/property/92.006,
US/18-usc/1001) — reconstruct it from the file's metadata block. The
review panel needs it to re-fetch the statute, so get it right.Read the memo end to end. Every citation instance gets its own entry — the
same case cited five times yields five entries, and Id., supra, and
short forms count. Resolve what each Id./short cite refers to by reading
context.
For each instance record:
id: c001, c002, … in memo order.cite_text: the citation EXACTLY as it appears in the memo.memo_context: ~40+ chars of surrounding memo text containing cite_text.
REQUIRED whenever cite_text appears more than once in the memo (always
required for Id. forms); the snippet itself must be unique in the memo.pin: the pin-cite page, if any (e.g. "461").proposition: one sentence stating what this citation is offered to
support — the claim the attorney will verify.support_type: "quotation" if the memo quotes the source, else
"paraphrase".anchors_proposed: 1–3 quotes copied VERBATIM from the stored source
file that support the proposition.Hard rules for quotes:
... only for genuine omissions; every segment around an ellipsis
must be at least ~10 characters, segments must appear in document order,
and they must be reasonably close together.## Citing Cases section or the file footer — only
the opinion body (the verifier rejects these)."no_quote_claimed": true with empty
anchors_proposed. Use sparingly — every no-quote citation is one the
attorney must verify entirely by hand.If a cited authority has no stored file, tell the user and offer to fetch it
now (opinion_store / statute_store → save into sources/). If the user
declines, still include the citation, with a source entry of
{"type": "opinion"|"statute", "missing": true, "case_name"/"citation": ...}
so it is tracked as unverifiable rather than silently dropped.
Write .cite-check/proposals.json (create the scratch dir):
{
"schema_version": 1,
"memo": { "path": "memo.md" },
"sources": {
"cl-12345": { "type": "opinion", "path": "sources/smith_v_jones_12345.md",
"cluster_id": "12345", "case_name": "Smith v. Jones",
"citation": "123 F.3d 456" },
"stat-tex_prop_code_92_006": { "type": "statute",
"path": "sources/tex_prop_code_92_006.md",
"statute_id": "TX/property/92.006",
"code": "Property Code", "section": "92.006" }
},
"citations": [
{ "id": "c001", "source": "cl-12345",
"cite_text": "Smith v. Jones, 123 F.3d 456, 461 (9th Cir. 1997)",
"pin": "461",
"memo_context": "The discovery rule controls. Smith v. Jones, 123 F.3d 456, 461",
"proposition": "The discovery rule governs accrual.",
"support_type": "paraphrase",
"anchors_proposed": [ { "quote": "the limitations period does not begin to run until ..." } ],
"no_quote_claimed": false }
]
}
Then run:
python3 <skill-dir>/scripts/verify_anchors.py \
--proposals .cite-check/proposals.json --out cites.json \
--generated-by "<model name> via /cite-check"
Exit codes: 0 all anchored → continue. 2 fatal → relay stderr and stop.
1 retryable failures → the stdout JSON report lists each failure with a
reason and a hint:
not_found: re-open the source near the hint text and re-copy verbatim.case_mismatch: the hint IS the exact source text — use it.only_in_citing_cases: you quoted the appendix; find body support.ambiguous_in_memo / memo_context_not_found / cite_text_not_in_context:
fix the memo_context snippet.segment_too_short / ellipsis_gap_too_large: quote more around the
ellipsis or drop it.Fix proposals and re-run. MAXIMUM 2 retries; anything still failing stays
anchor_failed in cites.json (the attorney sees it flagged red — that is
working as designed, not something to hide). source_missing entries are
not retryable.
Call the citecheck_review MCP tool with:
memo_text: the memo file content, passed VERBATIM (do not re-wrap,
reformat, or "clean up" — the panel verifies it against the memo's
SHA-256 from cites.json and flags any transcription drift).cites: the parsed content of cites.json.This renders the two-pane review panel in the conversation. Then ALWAYS build the standalone fallback too (cheap, local, and the only path on clients without app support):
python3 <skill-dir>/scripts/build_review.py --cites cites.json --out review.html
(add --review review.json if a prior review export exists). Check the
tool result's structuredContent.panel field: if it is "may_not_render",
LEAD with the fallback — tell the user to open review.html in a browser
rather than waiting for a panel that won't appear. Otherwise mention
review.html as the backup if no panel appears above.
Give a compact table: id · citation · source · status · match quality · warnings. Then explicitly call out, in prose:
anchor_failed citation and why,source_missing (unverifiable) citation,no_quote_claimed citation,multiple_matches, short_quote,
match_in_header, cluster_id_mismatch).Explain next steps: review each citation in the panel (j/k to move, 1–3 for verdicts), then click "Send review to Claude" (panel) or "Export review.json" (standalone).
When the attorney finishes, the panel sends a message containing a fenced
```json review.json block. Save it VERBATIM as review.json in the project
root (next to cites.json). Confirm the save and summarize the verdicts —
especially any rejected (‼️) or needs_attention (⚠️) citations, which need
memo revisions. After revising the memo, re-run /cite-check; verdicts whose
citation and proposition are unchanged carry forward automatically.
After review.json is saved, generate the printable audit record:
python3 <skill-dir>/scripts/build_audit.py --cites cites.json \
--review review.json --out cite-check-audit.html
Tell the attorney cite-check-audit.html is ready — it prints on landscape
letter paper and records, per citation: the source, the proposition, whether
the verifier anchored it, the attorney's verdict (✅ ⚠️ ‼️ ❓), the review
note, and the reviewer — plus an integrity footer (memo hash, verification
provenance). This is the firm's record that the work product was checked.
If the user wants the audit before any attorney review, run it without
--review (all rows show ❓).
Guides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub dingduff/dingduff-plugins --plugin dingduff