Skip to content

Commit 35e7967

Browse files
jet52claude
andcommitted
Rename ndcourts-mcp to ndlaw throughout prompts and labels
The MCP server renamed itself to ndlaw (FastMCP("ndlaw")); jetredline's prompt vocabulary, source-precedence tiers, and Via provenance labels still said "ndcourts-mcp", which is why run narration and cite-review badges showed the retired name. Renamed in SKILL.md, pass3b-citations.md, ndlaw_export.py prose/help, cite_review.py reviewer-guide text, and tests. Kept intentionally: DEFAULT_DB still points at ~/code/ndcourts-mcp/opinions.db (the repo directory's real name), the vendored jetcite ndcourts module (named for ndcourts.gov, not the MCP), and the cite-review HTML's acceptance of the legacy "ndcourts-mcp" via label so previously exported review states keep their MCP badge styling. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent bc219d6 commit 35e7967

5 files changed

Lines changed: 36 additions & 36 deletions

File tree

skills/jetredline/SKILL.md

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ $VENV_PYTHON $SKILL_DIR/extract_text.py --input <draft.docx> --output <TMPDIR>/<
344344
6b. **Delegate Pass 7** (dissent/concurrence cross-check) to a subagent if a dissent or concurrence was identified in Step 0 and `DOC_TYPE == opinion` — see Pass 7 below
345345
7. **Pass 2 routing:** If the opinion has **more than 30 paragraphs**, delegate Pass 2 to a subagent — see "Delegated Pass 2" below. Otherwise, perform Pass 2 in main context. **Pass 5** (analytical rigor) is always performed in main context. Pass 2 (when not delegated) and Pass 5 can proceed in parallel with subagents.
346346
8. Collect subagent results from Passes 1, 3, 4, 6, 7, and (if delegated) Pass 2 — **use the `TaskOutput` tool**, not Bash `tail`
347-
8a. **Caption mismatches → edits (closed-loop rule).** Check the Pass 3B results table for Caption Check mismatches. Generate a correcting tracked-change edit **only** when the *same* citation resolved to an official caption and the draft's name is a near-match typo of it (high `name_similarity`) — e.g., a comment "Official caption per 2023 ND 219: 'Tracey v. Tracey'". **Never** harmonize names across two *different* citations (different cite = presumptively different case), and do not auto-correct low-similarity or unresolved names — add a comment for human review instead. Include qualifying edits in the edits JSON alongside Pass 2/3A/5 edits. Likewise apply the **parallel-cite corrections** flagged by Pass 3B's parallel-cite check — add a missing N.W.2d/N.W.3d parallel to a *full* cite, or fix a wrong one, using the `formatted` value from ndcourts-mcp.
347+
8a. **Caption mismatches → edits (closed-loop rule).** Check the Pass 3B results table for Caption Check mismatches. Generate a correcting tracked-change edit **only** when the *same* citation resolved to an official caption and the draft's name is a near-match typo of it (high `name_similarity`) — e.g., a comment "Official caption per 2023 ND 219: 'Tracey v. Tracey'". **Never** harmonize names across two *different* citations (different cite = presumptively different case), and do not auto-correct low-similarity or unresolved names — add a comment for human review instead. Include qualifying edits in the edits JSON alongside Pass 2/3A/5 edits. Likewise apply the **parallel-cite corrections** flagged by Pass 3B's parallel-cite check — add a missing N.W.2d/N.W.3d parallel to a *full* cite, or fix a wrong one, using the `formatted` value from ndlaw.
348348
8b. **Treatment flags → comments.** If the Pass 3C overruling scan flagged any cited case for possible negative treatment, add a *comment* (not an edit) on each occurrence, quoting the citing context, for human review. Never auto-edit on a treatment signal.
349349
9. **If user requested tracked-changes .docx** (both or tracked-changes only): Produce tracked-changes .docx output using the batch edit workflow (see Step 9 details below)
350350
10. **If user requested analysis document** (both or analysis only): Produce the companion analysis document (incorporating all subagent results). If also producing .docx, create both outputs in the same response
@@ -356,22 +356,22 @@ python3 ~/.claude/skills/jetredline/provenance.py --file <stem>-ANALYSIS.md \
356356
Footer, e.g.: *Report generated by Claude Opus 4.8 (claude-opus-4-8) using jetredline v4.4.0 on 2026-06-05. AI-generated first draft for internal use; verify all citations and findings before relying.* Version and date are sourced deterministically by the script (version from frontmatter/`VERSION`, date from the system clock); you supply only `--model` from your runtime context — the script never guesses the model. The stamp is idempotent. **Stamp only the analysis document — never the tracked-changes `.docx`, which is the user's own opinion text and must not be altered with a footer.** In **audit mode** (no files written) and **web mode** (analysis returned inline, no filesystem), skip the script; in web mode you may append the same footer line manually as the report's last line.
357357
11. **Generate citation review HTML** (CLI and Cowork): After Pass 3 completes, generate an interactive citation review page for human verification.
358358

359-
**11a. Refresh ND authority text + direct URLs from ndlaw (zero token cost).** Run the export script first — it pulls each cited ND opinion's authoritative text and the court's direct opinion URL (`https://www.ndcourts.gov/supreme-court/opinions/<id>`) from the ndlaw corpus into `~/refs`, plus a metadata map for the review page. It auto-selects a backend: a local `opinions.db` (`NDLAW_DB` env or the default dev path), else a deployed ndcourts-mcp instance over Streamable HTTP (`NDLAW_URL` + `NDLAW_AUTH` env, or `--url`/`--auth`; for Claude Code users the URL and Basic-Auth header are in their MCP config — `claude mcp get ndlaw`). The script speaks to the server directly, so no opinion text passes through model context.
359+
**11a. Refresh ND authority text + direct URLs from ndlaw (zero token cost).** Run the export script first — it pulls each cited ND opinion's authoritative text and the court's direct opinion URL (`https://www.ndcourts.gov/supreme-court/opinions/<id>`) from the ndlaw corpus into `~/refs`, plus a metadata map for the review page. It auto-selects a backend: a local `opinions.db` (`NDLAW_DB` env or the default dev path), else a deployed ndlaw instance over Streamable HTTP (`NDLAW_URL` + `NDLAW_AUTH` env, or `--url`/`--auth`; for Claude Code users the URL and Basic-Auth header are in their MCP config — `claude mcp get ndlaw`). The script speaks to the server directly, so no opinion text passes through model context.
360360
```bash
361361
$VENV_PYTHON ~/.claude/skills/jetredline/ndlaw_export.py \
362362
--opinion <opinion_md_path> \
363363
--refs-dir ~/refs \
364364
--meta-out <TMPDIR>/sources.json
365365
```
366-
Exit 2 means no backend was reachable (typical in Cowork, where neither the corpus DB nor `NDLAW_URL` exists). **Fall back to a scribe subagent riding the in-context MCP connection** — if ndcourts-mcp tools are available:
366+
Exit 2 means no backend was reachable (typical in Cowork, where neither the corpus DB nor `NDLAW_URL` exists). **Fall back to a scribe subagent riding the in-context MCP connection** — if ndlaw tools are available:
367367

368368
1. From the cite JSON, list the corpus-eligible authorities that still lack refs text: case entries (not `pin_cite`, not `is_repeat`) whose `normalized` is an ND neutral cite (`YYYY ND N`) or N.W.-family reporter cite, with `local_exists` false.
369369
2. Launch **one** subagent (Task tool, `model: haiku`, subagent_type `general-purpose`) with that list and these instructions: for each citation, call `lookup_opinion(<cite>)` and record `case_name`, `url`, `url_source`, `date_filed`, and `citations`; then page through `get_opinion_text(<cite>, offset=..., limit=50000)` until `has_more` is false and **Write the concatenated text verbatim** (do not summarize, reformat, or strip the frontmatter block) to the refs path: `~/refs/opin/ND/<year>/<year>ND<n>.md` for `YYYY ND N`; `~/refs/opin/NW2d/<vol>/<page>.md` for `V N.W.2d P` (analogously `NW3d`, `NW`). Finally Write `<TMPDIR>/sources.json` mapping **every** citation form from `citations` to `{"case_name", "url", "url_source", "date_filed", "via": "ndlaw"}`, and return only a tally ("N exported, M not in corpus") — never opinion text.
370370
3. The token cost stays inside the subagent's isolated context (and within the subscription); main context must never page opinion text through its own tool results just to embed it.
371371

372372
If MCP tools are also unavailable, skip `--sources-meta` below and fall through silently (never stall on this step) — or, at most, build a minimal `sources.json` from one cheap `lookup_opinion` call per unique ND case (URL + case name only) if a stray connection allows it.
373373

374-
**11b. Generate the page.** Write a `via.json` mapping each citation (as written, or its normalized form) to the tier from the Pass 3B **Via** column — e.g. `{"2024 ND 156": "ndcourts-mcp", "445 U.S. 684": "CourtListener", "N.D.C.C. § 14-05-24": "local"}`:
374+
**11b. Generate the page.** Write a `via.json` mapping each citation (as written, or its normalized form) to the tier from the Pass 3B **Via** column — e.g. `{"2024 ND 156": "ndlaw", "445 U.S. 684": "CourtListener", "N.D.C.C. § 14-05-24": "local"}`:
375375
```bash
376376
$VENV_PYTHON ~/.claude/skills/jetredline/cite_review.py \
377377
--opinion <opinion_md_path> \
@@ -433,7 +433,7 @@ The script operates directly on the .docx ZIP archive — no unpack/pack pipelin
433433

434434
**9c. Check the output.** Parse the JSON summary from apply_edits.py. If any edits failed, report them.
435435

436-
**9d. Citation hyperlinks (optional).** When the user asks for clickable / linked citations, add `hyperlink` edits to the same `edits.json` — one per citation, anchored to the citation text, using the verified URL (prefer ndcourts-mcp `absolute_url`, else the CourtListener URL, else the `url` from `cite_check.py`):
436+
**9d. Citation hyperlinks (optional).** When the user asks for clickable / linked citations, add `hyperlink` edits to the same `edits.json` — one per citation, anchored to the citation text, using the verified URL (prefer ndlaw `absolute_url`, else the CourtListener URL, else the `url` from `cite_check.py`):
437437
```json
438438
{ "type": "hyperlink", "para": 12, "anchor": "2024 ND 45", "url": "https://www.ndcourts.gov/..." }
439439
```
@@ -459,25 +459,25 @@ For each delegated pass performed inline (1, 3B, 4, 6, 7 — and 2's entry forma
459459

460460
**Context limits:** Without subagents, very long documents (50+ paragraphs) may approach context limits. If this occurs, prioritize: Pass 2 → Pass 5 → Pass 3A → Pass 1 → Pass 3B → Pass 4 → Pass 6 → Pass 7. Inform the user which passes were completed.
461461

462-
## Legal-Research MCP Servers (ndcourts-mcp, CourtListener)
462+
## Legal-Research MCP Servers (ndlaw, CourtListener)
463463

464464
Two optional MCP servers improve citation verification when connected. **They are augmentation, not replacement** — every check below degrades gracefully to the existing pipeline (`cite_check.py` + `~/refs/` + `WebFetch` + web search). Never fail or stall a task because an MCP server is absent or returns no data.
465465

466-
**Availability:** Before relying on a server, check whether its tools are present in your tool set (e.g. an `ndcourts-mcp` tool such as `verify_citation`, or a CourtListener tool such as `verify_citations`). If a tool is not available, skip silently to the next tier.
466+
**Availability:** Before relying on a server, check whether its tools are present in your tool set (e.g. an `ndlaw` tool such as `verify_citation`, or a CourtListener tool such as `verify_citations`). If a tool is not available, skip silently to the next tier.
467467

468468
**Source precedence — apply at every case-citation check; fall through on a miss:**
469-
1. **ndcourts-mcp** (primary, North Dakota cases) — local ND opinion corpus. Deterministic, no network.
470-
2. **CourtListener MCP** (secondary) — case data ndcourts-mcp lacks: federal and out-of-state authorities, and ND opinions missing from the ND corpus.
469+
1. **ndlaw** (primary, North Dakota cases) — local ND opinion corpus. Deterministic, no network.
470+
2. **CourtListener MCP** (secondary) — case data ndlaw lacks: federal and out-of-state authorities, and ND opinions missing from the ND corpus.
471471
3. **Existing pipeline** (fallback) — `cite_check.py` / `~/refs/` / `WebFetch` / web search. Always available in CLI mode; the only path when no MCP server is connected.
472472

473473
**Out of scope for both servers:** authoritative text of statutes, court rules, the constitution, and NDAC — these always resolve through the existing pipeline.
474474

475-
**ndcourts-mcp tools and the fields used below:**
475+
**ndlaw tools and the fields used below:**
476476
- `verify_citation(query, expected_case_name=...)``found`, `canonical_case_name`, `formatted` (full Redbook cite), `cites_redbook`, `absolute_url`; when `expected_case_name` is supplied, also `name_matches` (bool) and `name_similarity` (0–1). Catches wrong volume/page/year and name drift.
477477
- `verify_quotation(citation, quote)``verbatim` (bool), `paragraph` (pinpoint ¶, generally 1997+), `differences` (word-level diff), `closest_text`. Typography-tolerant (curly/straight quotes, dashes, whitespace).
478478
- `detect_overruled_in_draft(draft_text)``flagged` (cited cases with possible negative/distinguished treatment, each with `treatment_entries` + citing context), `clear`, `unresolved`. **Advisory only.**
479479

480-
**Cardinal caution:** ndcourts-mcp is a research aid, not an authoritative text; treatment signals and the `antecedent_name` heuristic are best-effort. Use them to *flag for human review*, never to auto-edit on the signal alone.
480+
**Cardinal caution:** ndlaw is a research aid, not an authoritative text; treatment signals and the `antecedent_name` heuristic are best-effort. Use them to *flag for human review*, never to auto-edit on the signal alone.
481481

482482
## Editing Instructions
483483

@@ -530,7 +530,7 @@ When the opinion exceeds 30 paragraphs, delegate Pass 2 to a Task subagent (suba
530530

531531
### Pass 3: Citation Check (Delegated to Subagent)
532532

533-
Pass 3 has three parts: (A) Bluebook format checking, in main context; (B) substantive citation verification, delegated to a subagent; and (C) a negative-treatment / overruling scan, in main context. Parts B and C use the ndcourts-mcp / CourtListener servers as the primary source when available — see "Legal-Research MCP Servers" above — and fall back to local files plus web verification otherwise.
533+
Pass 3 has three parts: (A) Bluebook format checking, in main context; (B) substantive citation verification, delegated to a subagent; and (C) a negative-treatment / overruling scan, in main context. Parts B and C use the ndlaw / CourtListener servers as the primary source when available — see "Legal-Research MCP Servers" above — and fall back to local files plus web verification otherwise.
534534

535535
#### Part A: Format Check (Main Context)
536536

@@ -556,10 +556,10 @@ Pass 3B verifies ALL North Dakota citations — cases, statutes, constitution, c
556556

557557
> Read `~/.claude/skills/jetredline/references/pass-instructions/pass3b-citations.md` and follow it. The opinion file is at `[opinion_path]`; write the passages ledger to `<TMPDIR>/passages.json`. Here is the extracted citation list: [numbered list — ¶, citation text, proposition, quoted text if any, signal].
558558
559-
**Returns:** the results table (`¶ | Citation | Type | Caption Check | Quote Check | Supports? | Via | Source Link | Notes`), a summary line with counts by type, the lookup-methods tally for case citations (`ndcourts-mcp / CourtListener / local / web / not found`), and an ND web-fallback note. The subagent also writes `<TMPDIR>/passages.json` (the passages ledger embedded in the citation-review HTML). Carry the tally and note into the analysis document alongside the results table. The instructions enforce the closed-loop case-name rule (correct same-cite typos only; never harmonize different citations) — Step 8a depends on the resulting Caption Check column and `name_similarity` values.
559+
**Returns:** the results table (`¶ | Citation | Type | Caption Check | Quote Check | Supports? | Via | Source Link | Notes`), a summary line with counts by type, the lookup-methods tally for case citations (`ndlaw / CourtListener / local / web / not found`), and an ND web-fallback note. The subagent also writes `<TMPDIR>/passages.json` (the passages ledger embedded in the citation-review HTML). Carry the tally and note into the analysis document alongside the results table. The instructions enforce the closed-loop case-name rule (correct same-cite typos only; never harmonize different citations) — Step 8a depends on the resulting Caption Check column and `name_similarity` values.
560560

561561
**Web mode:** No shell, Python, or `~/refs/` — but the MCP servers, if connected, are the primary way to verify case citations here.
562-
1. **If ndcourts-mcp / CourtListener tools are available, use them first**, following Step 1.5 of `references/pass-instructions/pass3b-citations.md` (read it from project knowledge — verify_citation for caption/existence/name drift, verify_quotation for quotes); run Part C's `detect_overruled_in_draft` too. This closes the gap where case citations otherwise can't be verified without a filesystem.
562+
1. **If ndlaw / CourtListener tools are available, use them first**, following Step 1.5 of `references/pass-instructions/pass3b-citations.md` (read it from project knowledge — verify_citation for caption/existence/name drift, verify_quotation for quotes); run Part C's `detect_overruled_in_draft` too. This closes the gap where case citations otherwise can't be verified without a filesystem.
563563
2. For ND citations the MCP servers don't cover, use WebFetch on the official URL (build it from the citation, or run `cite_check.py` if any shell is available).
564564
3. For ND case citations, use web search to locate the opinion on ndcourts.gov or Google Scholar.
565565
4. Verify quotes and substantive support as described above.
@@ -570,15 +570,15 @@ Pass 3B verifies ALL North Dakota citations — cases, statutes, constitution, c
570570

571571
A proofreading pass that flags cited cases later opinions may have overruled, superseded, abrogated, or distinguished. jetredline has no other "still good law?" check, so this is purely additive.
572572

573-
**If the `detect_overruled_in_draft` tool is available** (ndcourts-mcp), call it once on the full draft text:
573+
**If the `detect_overruled_in_draft` tool is available** (ndlaw), call it once on the full draft text:
574574
- Pass the draft opinion/memo text as `draft_text`.
575575
- From the result, take `flagged` (each entry has the cited case, a treatment signal, and `treatment_entries` with the citing opinion and sentence-local context). `clear` and `unresolved` are informational.
576576
- For each flagged case, queue a **comment** (handled in Step 8b) on each occurrence in the draft, quoting the citing context and the citing opinion. **Never** convert a treatment signal into a tracked-change edit.
577577
- In the analysis document, add a short "Negative-treatment check" subsection: list flagged cases with their signal and citing opinion, and note that `unresolved` cites (federal, out-of-state, or not in the ND corpus) were **not** checked.
578578

579579
**Caution:** Signals are sentence-local heuristics, not a verdict — a citing sentence may use a treatment word about a *different* case. Always present them as "possible negative treatment — verify," and read the cited opinion before relying on it. An absent flag is not assurance a case is good law.
580580

581-
**If the tool is unavailable:** skip this part and note in the analysis document: "Automated negative-treatment check not run (ndcourts-mcp unavailable); citations were not screened for subsequent history." Do not attempt to substitute web search for a citator here.
581+
**If the tool is unavailable:** skip this part and note in the analysis document: "Automated negative-treatment check not run (ndlaw unavailable); citations were not screened for subsequent history." Do not attempt to substitute web search for a citator here.
582582

583583
### Pass 4: Fact Check (Delegated to Subagent)
584584

@@ -671,7 +671,7 @@ For memos: Does the memo correctly identify the standard *and* apply it consiste
671671

672672
In multi-issue documents where each issue has a different standard, verify each standard is applied to the correct issue.
673673

674-
#### Statutory-Construction Cross-Check (when ndcourts-mcp is available)
674+
#### Statutory-Construction Cross-Check (when ndlaw is available)
675675

676676
When the draft construes an N.D.C.C. section or a court rule as a point of decision, call `find_opinions_construing(<authority>)` and scan the returned `results[].opinions` for ND opinions construing the same provision. Use it as an advisory aid: if a recent or obviously on-point construction is missing from the draft's analysis, note it for the author's consideration (do not assert it is controlling). Skip silently if the tool is unavailable. For a key *cited* precedent whose holding the draft leans on, `case_summary(<cite>)` (disposition + `syllabus_points`) can confirm what the case actually held — this aids the substantive-support assessment; it does **not** feed the draft's own Case Highlight, since the draft is not in the corpus.
677677

0 commit comments

Comments
 (0)