PACER_PLUGIN_SPEC_V1.1.md
Current Specs/Connector and Integration Specs/PACER_PLUGIN_SPEC_V1.1.md
# PACER Plugin — Reference Implementation V1.1
**Date:** 2026-04-27
**Version:** 1.1
**Supersedes:** PACER_PLUGIN_SPEC.md (V1.0, 2026-04-11)
**Status:** Specification — reference implementation of the Q Plugin System
**Plugin ID:** `pacer`
**Category:** Legal
**Has Tab:** Yes — case monitoring dashboard
**Has Service:** Yes — programmatic case monitoring (no LLM)
**Dependencies:** PACER account, CourtListener API (free), Q Plugin System Architecture R2, DOC72 R5.73, DOC73 V1.4.1 + Corpus Source Bindings Proposal V1 (forthcoming absorption), DOC24 R2.5, DOC3
---
## V1.1 Changes from V1.0
V1.1 is a scope-narrow revision addressing items surfaced during the 2026-04-27 architectural review. Bug-level architectural rewires (EC-as-sole-writer event flow, DOC25 ingestion contract for CM/ECF, content-type registration completeness, DOC21/DOC22 surface registration, dangling §7.2 cross-reference to PACER_INTEGRATION_SPEC.md) are deferred to V1.2 for separate red-team. V1.1 should NOT be treated as a final implementation-ready spec; V1.2 is required before build.
V1.1 adds or modifies:
- §1 manifest: multi-credential `requires_auth` array (PACER + CourtListener), explicit `data_sources` declaration.
- NEW §1.5 Data Sources & Capabilities (PACER paid, CourtListener / RECAP free, CM/ECF email free).
- NEW §4.2 Search Backend Selection (CourtListener-first, PACER fallback). Original §4.2 / §4.3 renumbered to §4.3 / §4.4.
- §5.1 `smartRetrieveDocument()` function definition (the RECAP-first retrieval core that V1.0 referenced but did not define).
- NEW §7.3 Corpus Membership per DOC73 Corpus Source Bindings Proposal V1.
- §10 cross-reference to Q Plugin System Architecture R2 §8 (plugin settings surface — the universal pattern PACER inherits).
- §13 Phase 1 line corrected from "PACER MCP server" to "PACER plugin tool surface registered with EC, exposed externally through the single ELNOR MCP gateway."
- §13 effort estimates recalibrated for Claude-Code-driven build (8–14 hours clock time across all phases, not 13–19 hours human-developer time).
---
## 1. Plugin Manifest
```json
{
"plugin_id": "pacer",
"display_name": "PACER Federal Courts",
"description": "Federal court document access, case monitoring, docket tracking, party research, deadline extraction, and judicial analytics.",
"version": "1.0.0",
"author": "ELNOR System",
"icon": "Scale",
"category": "legal",
"has_tab": true,
"tab_component": "plugins/pacer/PacerTab",
"tab_label": "PACER Monitor",
"tab_icon": "Scale",
"requires_auth": [
{
"type": "credentials",
"provider": "pacer",
"fields": ["username", "password"],
"required": true,
"description": "Federal PACER account for authoritative live docket access. Required."
},
{
"type": "api_token",
"provider": "courtlistener",
"fields": ["api_token"],
"required": false,
"description": "Free CourtListener API token for RECAP-first retrieval and free legal research. Highly recommended — typically reduces PACER spend 70–90%."
}
],
"requires_internet": true,
"data_sources": ["pacer", "courtlistener_recap", "cm_ecf_email"],
"doc72_domains": ["litigation", "legal", "federal_court"],
"doc24_triggers": [
"court filing", "docket", "case number", "federal case",
"motion", "complaint", "court order", "opinion", "PACER",
"litigation history", "party search", "expert witness",
"Daubert", "scheduling order", "deadline", "trial date",
"new filings", "case status", "judge"
]
}
```
**Note (V1.2 obligation):** the `doc24_triggers` array is currently freeform strings. DOC24 R2.5 owns the tag vocabulary as ONE system (primary_tag / hedge_mode / force_level). V1.2 must clarify whether these are intent-detection keywords (different layer) or DeliveryDirective primary_tags, and align accordingly.
---
## 1.5 Data Sources & Capabilities
The plugin uses three input streams, prioritized by cost:
| Source | What | Cost | Auth | Coverage |
|--------|------|------|------|----------|
| **CourtListener / RECAP** | Free archive of PACER documents donated by other users, plus CourtListener's own opinion database, judge data, and citation network. | Free | API token (free signup at courtlistener.com) | Most published opinions; PACER documents previously fetched by anyone in the RECAP community; coverage growing daily |
| **PACER** (paid) | The official US federal court live system. All federal dockets, all filings, real-time. | $0.10/page, capped at $3/doc; $30/quarter waiver | PACER username + password | Comprehensive — federal courts only |
| **CM/ECF email links** | When you're counsel of record, CM/ECF emails a free single-use link for each filing. Time-limited, typically same-day. | Free | Listed on filing notification list per case | Cases where ELNOR is on the notification list |
**Capability: RECAP-first retrieval.** For every document request, the plugin checks CourtListener / RECAP first. If found, the document is fetched free. If not, falls back to direct PACER (charged). Optionally, paid PACER pulls are contributed back to RECAP — reducing cost for Will's future requests AND for the legal community. Implementation in §5.1 `smartRetrieveDocument()`.
**Capability: Free docket monitoring.** For dockets already tracked by RECAP, CourtListener can supply docket updates without a PACER charge. Direct PACER is used only for cases not yet in RECAP, or for the most recent entries RECAP hasn't picked up yet. This is the bedrock cost-saver for the watch-list workflow at §2.
**Capability: Free legal research.** CourtListener's Opinion Search and Citation Lookup APIs are free. Used for judge analytics (§10 KNOWLEDGE GRAPH), expert-witness prior-testimony lookups, and cross-case research without touching PACER. PACER has no dedicated opinion search; opinions live inside dockets.
**Realistic cost profile.** For a typical securities-litigation watch list of 15–25 active cases with 6-hour monitoring, expected RECAP coverage of 60–85% drives PACER spend below the $30/quarter free threshold for most quarters. Heavy fact-gathering periods (depositions, MTD opposition cycles) push spend up; the cost gate at §9.2 is what keeps that bounded.
---
## 2. PACER Tab — Case Monitoring Dashboard
### 2.1 Overview
The PACER tab is a case monitoring dashboard. It shows all watched cases, recent filings, alerts, cost tracking, and provides tools for search and document retrieval. It replaces CourtDrive as the case monitoring interface.
### 2.2 Tab Layout
```
┌─────────────────────────────────────────────────────────────────────────┐
│ PACER Monitor [🔍 Search PACER] [+ Add Case] [⚙] │
├────────────────────────────────────────────────┬────────────────────────┤
│ │ │
│ WATCHED CASES │ DETAIL PANEL │
│ ┌─────────────────────────────────────────┐ │ │
│ │ Filter: [All ▾] [Active ▾] [_______] │ │ (Click a case to │
│ ├─────────────────────────────────────────┤ │ view details here) │
│ │ │ │ │
│ │ ● White v. Brooge Energy C.D.Cal │ │ │
│ │ 2:24-cv-01234 │ │ │
│ │ 3 new · Checked 6h ago · 📁 Firm/Bro │ │ │
│ │ │ │ │
│ │ ● Narayanan v. Marex S.D.N.Y │ │ │
│ │ 1:24-cv-09876 │ │ │
│ │ 0 new · Checked 6h ago · 📁 Firm/Nar │ │ │
│ │ │ │ │
│ │ ● Henderson v. Paramount LASC* │ │ │
│ │ BC587659 (state - manual) │ │ │
│ │ — · Manual only · 📁 Firm/Henderson │ │ │
│ │ │ │ │
│ │ ○ In re Acme Securities S.D.N.Y │ │ │
│ │ 1:22-cv-04567 (closed) │ │ │
│ │ Archived · Last: 90d ago │ │ │
│ │ │ │ │
│ └─────────────────────────────────────────┘ │ │
│ │ │
│ RECENT ACTIVITY │ │
│ ┌─────────────────────────────────────────┐ │ │
│ │ Today │ │ │
│ │ 📄 Brooge: Motion to Dismiss (22p) │ │ │
│ │ 📄 Brooge: Declaration of Jones (8p) │ │ │
│ │ 📄 Brooge: Proposed Order (3p) │ │ │
│ │ Yesterday │ │ │
│ │ 📄 Narayanan: Scheduling Order (4p) │ │ │
│ └─────────────────────────────────────────┘ │ │
│ │ │
│ COST THIS QUARTER: $14.30 / $30.00 free │ │
│ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 47% │ │
│ │ │
└────────────────────────────────────┴────────────────────────────────────┘
```
### 2.3 Detail Panel (Right Side)
When you click a watched case, the right panel shows the full case detail:
```
┌──────────────────────────────────────────┐
│ White v. Brooge Energy Ltd. │
│ 2:24-cv-01234 · C.D. Cal. │
│ Judge: Hon. John F. Walter │
│ Filed: 2024-03-15 · Status: Open │
│ Our role: Counsel of Record │
│ │
│ ┌─ MONITORING ──────────────────────┐ │
│ │ Schedule: [Every 6 hours ▾] │ │
│ │ Last check: Apr 11, 7:01 AM │ │
│ │ Next check: Apr 11, 1:01 PM │ │
│ │ [Check Now] [Pause] [Remove] │ │
│ └───────────────────────────────────┘ │
│ │
│ ┌─ SAVE LOCATION ──────────────────┐ │
│ │ 📁 OneDrive - Schall Firm / │ │
│ │ Cases / Brooge / PACER Docs │ │
│ │ [Change Folder] │ │
│ └───────────────────────────────────┘ │
│ │
│ ┌─ PROJECT LINK ───────────────────┐ │
│ │ 🔗 Brooge Energy (Project) │ │
│ │ [Change] [Unlink] │ │
│ └───────────────────────────────────┘ │
│ │
│ ┌─ AGENT INSTRUCTIONS ─────────────┐ │
│ │ ☑ Enabled │ │
│ │ │ │
│ │ Rule 1: │ │
│ │ When: New document downloaded │ │
│ │ If: type matches "motion|order| │ │
│ │ opinion" │ │
│ │ Then: "Summarize filing. Extract │ │
│ │ deadlines. Add to calendar. │ │
│ │ If MTD, compare with complaint │ │
│ │ and flag weaknesses." │ │
│ │ [Edit] [Delete] │ │
│ │ │ │
│ │ Rule 2: │ │
│ │ When: New document downloaded │ │
│ │ If: type matches "expert report| │ │
│ │ declaration" │ │
│ │ Then: "Analyze expert's │ │
│ │ methodology. Search PACER for │ │
│ │ their prior testimony. Flag │ │
│ │ inconsistencies." │ │
│ │ [Edit] [Delete] │ │
│ │ │ │
│ │ [+ Add Rule] │ │
│ └───────────────────────────────────┘ │
│ │
│ ┌─ CORPUS CONTRIBUTION ────────────┐ │
│ │ (See §7.3 — DOC73 Corpus Source │ │
│ │ Bindings) │ │
│ │ │ │
│ │ Feed filings to corpus(es): │ │
│ │ ☑ securities_mtd_oppositions │ │
│ │ Filter: opposition briefs only │ │
│ │ ☐ firm_brief_bank │ │
│ │ Filter: all substantive filings │ │
│ │ [+ Add binding] │ │
│ └───────────────────────────────────┘ │
│ │
│ ┌─ DOCKET (247 entries) ───────────┐ │
│ │ Filter: [All ▾] [___________] │ │
│ │ │ │
│ │ #247 Motion to Dismiss 4/11 │ │
│ │ 📥 Downloaded · 22 pages │ │
│ │ 📝 Summary available │ │
│ │ [Open] [Summarize] [...] │ │
│ │ │ │
│ │ #246 Declaration of Jones 4/11 │ │
│ │ 📥 Downloaded · 8 pages │ │
│ │ [Open] [Summarize] [...] │ │
│ │ │ │
│ │ #245 Notice of Appearance 4/10 │ │
│ │ ○ Not downloaded (trivial) │ │
│ │ [Download] │ │
│ │ │ │
│ │ #244 Scheduling Order 4/8 │ │
│ │ 📥 Downloaded · 4 pages │ │
│ │ 📝 3 deadlines extracted │ │
│ │ [Open] [View Deadlines] [...] │ │
│ │ │ │
│ │ [Load more...] │ │
│ └───────────────────────────────────┘ │
│ │
│ ┌─ COST ───────────────────────────┐ │
│ │ This case: $8.40 total │ │
│ │ Documents: 34 downloaded │ │
│ │ From RECAP (free): 12 │ │
│ │ From PACER (paid): 22 │ │
│ └───────────────────────────────────┘ │
│ │
│ ┌─ ALERTS ─────────────────────────┐ │
│ │ ☑ Toast notification on new filing│ │
│ │ ☑ Include in morning briefing │ │
│ │ ☑ Push to Apple Reminders │ │
│ │ ☐ Email alert │ │
│ │ │ │
│ │ Alert filter: │ │
│ │ ☑ Motions ☑ Orders ☑ Opinions │ │
│ │ ☐ Certificates ☐ Notices of │ │
│ │ Appearance ☐ Routine filings │ │
│ └───────────────────────────────────┘ │
│ │
│ ┌─ ERRORS ─────────────────────────┐ │
│ │ No errors. Last 5 checks clean. │ │
│ └───────────────────────────────────┘ │
│ │
└──────────────────────────────────────────┘
```
The CORPUS CONTRIBUTION block is V1.1's only structural addition to the detail panel. It's surfaced inline because corpus binding is most often configured at the same time as the case is added (e.g., "this is a securities MTD case, feed its opposition briefs to my brief bank"). The picker is populated from the user's existing corpora plus a "[+ Create new corpus]" option that hands off to DOC73's corpus admin UI. See §7.3 for the data flow.
---
## 3. Adding Cases
### 3.1 Manual Add
Click [+ Add Case] in the tab header. Modal:
```
┌─ Add PACER Case ─────────────────────────────┐
│ │
│ Court: [Central District of California ▾] │
│ Case Number: [2:24-cv-01234 ] │
│ │
│ — OR — │
│ │
│ Search: [Brooge Energy ] │
│ [Search PACER] │
│ │
│ Results: │
│ ○ White v. Brooge Energy, 2:24-cv-01234 │
│ C.D. Cal. · Filed 2024-03-15 · Open │
│ ○ Pension Fund v. Brooge, 1:23-cv-09876 │
│ S.D.N.Y. · Filed 2023-08-01 · Closed │
│ │
│ ┌─ Configuration ───────────────────────┐ │
│ │ Our role: [Counsel of Record ▾] │ │
│ │ Schedule: [Every 6 hours ▾] │ │
│ │ Save folder: [📁 Choose...] │ │
│ │ Link to project: [Brooge Energy ▾] │ │
│ │ Feed corpus: [None ▾] │ │
│ │ ☑ Download new filings automatically │ │
│ │ ☑ Extract deadlines from orders │ │
│ │ ☑ Include in morning briefing │ │
│ └───────────────────────────────────────┘ │
│ │
│ [Cancel] [Add Case] │
└───────────────────────────────────────────────┘
```
### 3.2 Auto-Detection from OneDrive
When a new case folder appears in the firm OneDrive (e.g., a new matter is opened), Elnor can detect it and suggest adding a PACER monitor:
1. DOC16 file watcher detects new folder in `OneDrive/Cases/`.
2. Elnor scans the folder for a complaint or initial filing.
3. Extracts case number and court from the complaint. **(LLM step — flagged for V1.2 to specify cost, DOC25 ingestion contract reference, and confidence threshold.)**
4. Notification: "New case folder detected: 'Brooge Energy.' Found complaint with case number 2:24-cv-01234 (C.D. Cal.). Add to PACER monitoring? [Yes] [No] [Configure]"
5. If Yes → auto-creates the watched case entry with sensible defaults.
This is an optional feature — requires DOC16 file watching to be active.
### 3.3 From Chat
"Elnor, start monitoring the Brooge case on PACER"
Elnor asks for the case number if not known, searches PACER (via `smartRetrieveDocument` and PCL fallback as needed), confirms the case, and adds it to the watch list with default settings. Elnor then opens the PACER tab to show the new entry.
---
## 4. PACER Search
### 4.1 Search Bar in Tab Header
The [🔍 Search PACER] button opens a search panel at the top of the tab:
```
┌─ PACER Search ──────────────────────────────────────────────────┐
│ │
│ Search type: ● Cases ○ Parties ○ Opinions │
│ │
│ [Case search fields:] │
│ Court: [All Courts ▾] or [Specific: C.D. Cal. ▾] │
│ Party name: [Brooge Energy ] │
│ Case number: [ ] │
│ Date filed: [From: ___________] [To: ___________] │
│ Nature of suit: [Securities (890) ▾] │
│ Case status: [All ▾] │
│ │
│ Backend: [CourtListener (free) ▾] │
│ ☐ Include PACER live data not yet in RECAP (+est. cost) │
│ │
│ [Search] Est. cost: $0.00 (CourtListener-only) │
│ │
│ Results (4 cases found): │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ White v. Brooge Energy Ltd. 2:24-cv-01234 C.D.Cal │ │
│ │ Filed: 2024-03-15 · Open · Judge: Walter │ │
│ │ [View Docket] [Add to Watch List] [Download Complaint] │ │
│ ├────────────────────────────────────────────────────────────┤ │
│ │ Pension Fund v. Brooge Energy 1:23-cv-09876 S.D.N.Y │ │
│ │ Filed: 2023-08-01 · Closed · Dismissed │ │
│ │ [View Docket] [Add to Watch List] [Download Opinion] │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────┘
```
### 4.2 Search Backend Selection
Searches default to CourtListener (free), with PACER as fallback for results not in RECAP:
- **Cases search:** CourtListener's docket search covers most federal dockets in RECAP, free. Falls back to PACER's PCL (Case Locator) only if "include cases not yet in RECAP" is toggled. The most recent ~24–48 hours of new dockets may only exist in PACER.
- **Parties search:** CourtListener's RECAP party search is free. Paid PCL party search is opt-in.
- **Opinions search:** CourtListener-only and free. PACER has no dedicated opinion search; opinions live inside dockets. For legal research, CourtListener's opinion DB is the better source regardless.
- **Citation Lookup:** CourtListener-only and free. Used by the knowledge graph (§7) and by agent instructions for cross-case research.
The search UI shows estimated cost before each search — defaults to $0.00 (CourtListener-only) and only rises if "include PACER live data" is toggled. PACER fallback is logged in the cost dashboard at §9 so the source mix is visible.
When a CourtListener search returns zero hits AND the user has not opted into PACER fallback, the results panel shows an explicit "0 results in RECAP — try PACER live data? (est. cost: $0.10–$0.30)" prompt rather than silently returning empty. This avoids the failure mode where a user concludes "no such case" when the case is simply too recent for RECAP.
### 4.3 Scheduled Searches
Beyond case monitoring, you can set up recurring searches:
```
┌─ Scheduled Searches ────────────────────────────┐
│ │
│ Search 1: "New securities fraud filings" │
│ Query: Nature of suit = 890, Filed = last 7 days │
│ Court: All │
│ Schedule: Weekly, Sunday 8 AM │
│ Action: List results in PACER tab + notify │
│ Feed corpus: securities_mtd_oppositions │
│ (filter: opposition_brief on each result) │
│ [Edit] [Delete] [Run Now] │
│ │
│ Search 2: "Cases mentioning 'Schall Law Firm'" │
│ Query: Party search for "Schall Law" │
│ Court: All │
│ Schedule: Monthly, 1st, 8 AM │
│ Action: List results + notify if new │
│ Feed corpus: (none) │
│ [Edit] [Delete] [Run Now] │
│ │
│ [+ Add Scheduled Search] │
└───────────────────────────────────────────────────┘
```
Scheduled searches can carry corpus bindings independently of any watched-case binding. This is the natural home for one-shot bulk loads — e.g., "all S.D.N.Y. securities MTD oppositions filed 2020–2026, contribute to securities_mtd_oppositions corpus" — by setting Schedule to "One-time" with a date range query and a corpus binding.
### 4.4 Via Chat
"Elnor, search PACER for any new securities fraud cases filed in the Central District this month"
Elnor calls the plugin's search tools with the right parameters, returns results in chat, and offers to add any to the watch list, download specific documents, or contribute matches to a corpus.
---
## 5. Monitoring Service (Programmatic)
### 5.1 Service Architecture
The monitoring service is a **programmatic Node.js function** — no LLM, no tokens. It runs on a configurable schedule per case.
```typescript
// plugins/pacer/PacerMonitorService.ts
interface MonitorResult {
case_id: string;
new_entries: DocketEntry[];
documents_downloaded: string[]; // Local paths
errors: string[];
cost_incurred: number; // Cents
checked_at: string; // ISO timestamp
}
async function runMonitorCycle(): Promise<MonitorResult[]> {
const watchedCases = await getWatchedCases();
const results: MonitorResult[] = [];
for (const wc of watchedCases) {
if (!wc.enabled) continue;
if (!isDue(wc)) continue; // Respect per-case schedule
try {
// 1. Authenticate with PACER (or use cached token)
const token = await getPacerToken();
// 2. Fetch new docket entries (RECAP-first when possible)
const newEntries = await fetchNewDocketEntries(
token, wc.court, wc.case_number, wc.last_docket_entry
);
if (newEntries.length === 0) {
await updateLastChecked(wc.case_id);
continue;
}
// 3. Filter: which entries to auto-download?
const toDownload = newEntries.filter(entry =>
wc.auto_download && isSubstantiveFiling(entry)
);
// 4. Download documents (RECAP-first per smartRetrieveDocument)
const downloaded: string[] = [];
for (const entry of toDownload) {
const doc = await smartRetrieveDocument(
wc.case_number, wc.court, entry.number
);
// Save to configured folder
const savePath = path.join(wc.save_folder, formatFileName(entry, doc));
await fs.copyFile(doc.path, savePath);
downloaded.push(savePath);
}
// 5. Update state
await updateWatchedCase(wc.case_id, {
last_docket_entry: Math.max(...newEntries.map(e => e.number)),
last_checked: new Date().toISOString(),
});
// 6. Log result
results.push({
case_id: wc.case_id,
new_entries: newEntries,
documents_downloaded: downloaded,
errors: [],
cost_incurred: calculateCost(downloaded),
checked_at: new Date().toISOString(),
});
// 7. Send notification (programmatic — no LLM)
if (newEntries.length > 0 && wc.alerts.toast) {
sendToast(`${wc.case_name}: ${newEntries.length} new filings`);
}
// 8. Emit intake events for EC. EC routes per agent-instruction
// rules AND per DOC73 Corpus Source Bindings (§7.3) — the plugin
// does NOT directly queue agent tasks or directly write entity
// nodes. EC is sole writer.
// (V1.2 obligation: define the exact intake event payload and
// content-type registration — see §7.3 forward-reference.)
for (const entry of newEntries) {
await emitIntakeEvent({
source_kind: "pacer.watched_case",
source_id: wc.case_id,
content_type: classifyFilingContentType(entry),
payload: {
case: wc,
entry: entry,
document_path: downloaded.find(d => d.includes(`doc_${entry.number}`)) ?? null,
},
});
}
} catch (err) {
results.push({
case_id: wc.case_id,
new_entries: [],
documents_downloaded: [],
errors: [err.message],
cost_incurred: 0,
checked_at: new Date().toISOString(),
});
// Alert on error
sendToast(`PACER error for ${wc.case_name}: ${err.message}`, "error");
}
}
return results;
}
// ─── RECAP-first retrieval (referenced from runMonitorCycle and from
// manual download flows) ────────────────────────────────────────────
async function smartRetrieveDocument(
caseNumber: string,
court: string,
docketEntryNumber: number
): Promise<{
path: string;
source: 'cache' | 'recap' | 'pacer' | 'ecf-email';
cost_cents: number;
}> {
// 1. Local cache (already downloaded for this firm)
const cached = await checkLocalCache(caseNumber, court, docketEntryNumber);
if (cached) return { path: cached, source: 'cache', cost_cents: 0 };
// 2. CourtListener / RECAP (free)
try {
const recapDoc = await courtListener.fetchDocument({
court, case_number: caseNumber, entry_number: docketEntryNumber,
});
if (recapDoc) {
const localPath = await saveToCache(recapDoc);
return { path: localPath, source: 'recap', cost_cents: 0 };
}
} catch (err) {
logCourtListenerError(err); // Soft fail; fall through to PACER
}
// 3. Direct PACER fallback (paid) — guarded by cost gate (§9.2)
await assertCostGateAllows({ court, caseNumber, entry: docketEntryNumber });
const pacerDoc = await pacer.fetchDocument({
court, case_number: caseNumber, entry_number: docketEntryNumber,
});
const localPath = await saveToCache(pacerDoc);
// 4. Contribute back to RECAP if enabled (fire-and-forget)
if (settings.contributeToRecap) {
courtListener.uploadToRecap(localPath, {
court, case_number: caseNumber, entry_number: docketEntryNumber,
}).catch(err => logRecapUploadError(err));
}
return {
path: localPath,
source: 'pacer',
cost_cents: Math.min(pacerDoc.pages * 10, 300), // $0.10/page, capped at $3
};
}
```
**Note on EC-as-sole-writer (V1.2 obligation):** V1.0's `runMonitorCycle` directly called `queueAgentTask()` and implied direct DOC72 writes. V1.1 replaces those calls with a single `emitIntakeEvent()` call per new entry. The plugin's job ends at emitting the event; EC handles routing to DOC23 task queue, DOC72 entity creation, and DOC73 corpus binding (§7.3). The exact intake event schema, content-type registration (per DOC20 §6.18.2), and event-to-EC transport contract are V1.2 deliverables. V1.1 establishes the boundary; V1.2 specifies the plumbing.
### 5.2 Filing Type Classification (No LLM)
Determining whether a filing is "substantive" (worth downloading) vs "routine" (notice of appearance, certificate of service) is done programmatically using keyword matching on the docket text:
```typescript
const SUBSTANTIVE_PATTERNS = [
/motion/i, /order/i, /opinion/i, /complaint/i, /answer/i,
/memorandum/i, /brief/i, /declaration/i, /report/i,
/judgment/i, /ruling/i, /stipulation/i, /settlement/i,
/expert/i, /deposition/i, /discovery/i, /subpoena/i,
/class certification/i, /summary judgment/i,
];
const ROUTINE_PATTERNS = [
/certificate of service/i, /notice of appearance/i,
/consent to.*magistrate/i, /corporate disclosure/i,
/summons/i, /civil cover sheet/i,
];
function isSubstantiveFiling(entry: DocketEntry): boolean {
const text = entry.text.toLowerCase();
if (ROUTINE_PATTERNS.some(p => p.test(text))) return false;
if (SUBSTANTIVE_PATTERNS.some(p => p.test(text))) return true;
return false; // Default: don't download unknown types
}
```
A separate `classifyFilingContentType(entry)` returns the registered content type (e.g., `legal.pacer.filing.opposition_brief`, `legal.pacer.filing.motion_to_dismiss`, `legal.pacer.filing.scheduling_order`) used by §7.3 corpus binding filters and by intake event registration. The content-type registry per DOC20 §6.18.2 is a V1.2 obligation.
No AI needed for either classification. It's fast and free. The user can customize the patterns in Settings if needed.
### 5.3 Schedule Options Per Case
Each watched case has its own schedule:
| Schedule | Use Case |
|----------|----------|
| Every 2 hours | Your active cases where you're counsel of record — need to know quickly |
| Every 6 hours | Active cases you're monitoring but not actively litigating |
| Daily | Research cases, competitor monitoring |
| Weekly | Closed cases you're archiving, or tangentially related cases |
| Manual only | State court cases (PACER doesn't cover), or paused cases |
---
## 6. CM/ECF Email Auto-Capture
### 6.1 How It Works
When you're counsel of record on a federal case, CM/ECF sends email notifications with a free document link every time something is filed. This link expires (typically same-day).
The PACER plugin can intercept these emails (via DOC16 email processing) and auto-download the free document before the link expires:
1. DOC16 email processor detects CM/ECF notification (sender: `ecf_notification@...uscourts.gov`).
2. Extracts case number, docket entry number, and document URL.
3. Passes to PACER plugin.
4. Plugin downloads the document using the free link (no PACER charge).
5. Saves to the case's configured folder.
6. Updates the watch list state.
7. Emits intake event (per §5.1) — EC routes through DOC25 ingestion contract for the Knowledge-side write and through DOC73 corpus bindings (§7.3) where applicable.
**(V1.2 obligation:** §6 currently elides whether the CM/ECF flow goes through DOC25's ingestion contract for the Knowledge-side write or only writes to the Body / OneDrive side. V1.2 must draw the line explicitly. As written here, step 7's intake event goes through the standard EC pipeline, which means DOC25 applies — but the spec text needs to make that obligation visible.)
### 6.2 This Is Essentially What CourtDrive Does
CourtDrive's core value proposition is auto-capturing these free CM/ECF emails. This feature replicates that functionality inside ELNOR, without the CourtDrive subscription.
### 6.3 Requirements
- DOC16 email processing must be active.
- Elnor's email account (`elnor@schallfirm.com`) must be listed on the CM/ECF notification list for each case **(V1.2 obligation: confirm this account is provisioned, or specify the alternative — Will's email monitored with CM/ECF notifications forwarded/processed)**.
---
## 7. DOC72 Knowledge Integration
### 7.1 What Gets Stored
The PACER plugin emits intake events (§5.1 step 8); EC writes the resulting DOC72 nodes. Two tiers, by trigger:
**Programmatic (no LLM, always runs):**
- Case entity nodes — created when a case is added to the watch list.
- Filing entity nodes — created when documents are downloaded (basic metadata only: title, date, pages, type, registered content type).
- Party / judge entity nodes — extracted from case summary data (deterministic).
**AI-driven (LLM, only when agent instructions trigger):**
- Filing summaries — LLM reads the document and generates a summary.
- Legal issue extraction — LLM identifies legal theories, arguments, holdings.
- Deadline extraction — LLM parses court orders for dates and obligations.
- Expert witness analysis — LLM analyzes expert reports for methodology, prior testimony.
- Cross-case relationships — LLM identifies connections between cases.
**(V1.2 obligation:** the plugin emits intake events; EC writes the nodes. Per DOC72 R5.73 + the surface-intake-contracts pattern (DOC72 §20A), `intake.pacer` must be a defined surface intake contract with declared output nodes, output edges, content-type-registered payloads, and trigger commands. V1.2 drafts the contract, either as a forward-reference inside this plugin spec or as a separate DOC72 addendum proposal.)
### 7.2 Entity Schemas
(V1.0 referenced `PACER_INTEGRATION_SPEC.md §5` for full schemas. That file does not exist in the spec registry as of 2026-04-27. **V1.2 obligation:** either draft the entity schemas inline here, or draft `PACER_INTEGRATION_SPEC.md` as a separate document and re-link.)
### 7.3 Corpus Membership (per DOC73 Corpus Source Bindings Proposal V1)
The PACER plugin participates in DOC73's corpus source binding contract (see `DOC73_CORPUS_SOURCE_BINDINGS_PROPOSAL_V1.md` in the addenda folder, forthcoming absorption into DOC73 V1.5). Two source kinds are exposed:
- `pacer.watched_case` — a watched case from §2 / §3 of this spec.
- `pacer.scheduled_search` — a scheduled search from §4.3 of this spec.
Both can be bound to one or more `knowledge_corpus` targets, with optional `content_type_filter` narrowing contribution to specific filing kinds (e.g., only opposition briefs, only orders, only expert reports).
**UI integration — per-case detail panel (already shown in §2.3):**
```
┌─ CORPUS CONTRIBUTION ───────────────────┐
│ Feed filings to corpus(es): │
│ ☑ securities_mtd_oppositions │
│ Filter: opposition briefs only │
│ ☐ firm_brief_bank │
│ Filter: all substantive filings │
│ [+ Add binding] │
└─────────────────────────────────────────┘
```
**UI integration — scheduled search configuration:** the same picker is available, particularly relevant for one-shot bulk loads (e.g., "all S.D.N.Y. securities MTD oppositions filed 2020–2026, contribute to `securities_mtd_oppositions` corpus" by configuring a one-time scheduled search with the corpus binding set).
**Implementation flow:**
1. The PACER plugin emits an intake event per §5.1 step 8 carrying `source_kind`, `source_id`, registered `content_type`, and payload (case + entry + document path).
2. EC consults the binding table per DOC73 Corpus Source Bindings §3 (intake protocol).
3. For each matching active binding, EC tags the resulting Filing node with the binding's `corpus_id` scope tag before writing.
4. If any matching binding has `contribution_mode: "scope_and_extract"`, EC enqueues a corpus-scoped extraction task per DOC73 §14, bound to the corpus's `extraction_profile`.
5. Per-corpus trust posture (DOC73 §3.1, R5.3 A2) governs whether the new member is auto-confirmed or lands as a candidate awaiting user review.
**Critical separation of concerns:** the PACER plugin does NOT own corpus semantics, extraction profiles, member-node lifecycle, or trust-posture logic — those are DOC73-owned. The plugin is purely a binding-eligible source. If V1.2 finds it convenient to store binding metadata locally for performance, the authoritative store remains in DOC72 (per the bindings addendum §2.2) and the local cache is read-only.
**Filings without corpus membership** land in the ambient graph (default). Active-case monitoring works fine without any corpus assignment; corpus membership is opt-in, primarily for research / brief-bank workflows.
---
## 8. Error Handling and Monitoring
### 8.1 Error Types
| Error | Handling |
|-------|----------|
| PACER authentication failed | Toast + banner in PACER tab. Pause monitoring. Prompt re-auth in Settings. |
| PACER rate limited | Back off exponentially. Log. Resume after cooldown. |
| Document download failed | Retry 2x. If still failing, mark entry as "download failed" with error. Alert user. |
| Network error | Skip this cycle. Retry next scheduled check. |
| CourtListener API down | Silently fall back to direct PACER (paid). Log cost difference. |
| Case not found | May have been sealed or transferred. Alert user. Mark case as "needs attention." |
| Save folder inaccessible | OneDrive offline? Local disk full? Toast error. Queue document for retry. |
| Intake event rejected by EC | Log. Surface in Errors panel. User-resolvable through corpus admin (e.g., binding refers to deleted corpus). |
| Agent instruction task failed | LLM error on processing. Log. Document still saved. User can manually trigger later. |
### 8.2 Error Display
Each watched case shows its error state in the tab:
```
● Healthy — no errors, last 5 checks clean
⚠ Warning — non-critical issue (e.g., CourtListener fell back to PACER)
✖ Error — critical issue requiring attention (auth failed, case not found)
```
The Errors section in the case detail panel shows a scrollable log of recent errors with timestamps.
---
## 9. Cost Management
### 9.1 Cost Dashboard (Bottom of Tab)
```
PACER Cost Summary
├─ This quarter: $14.30 / $30.00 free threshold
│ ░░░░░░░░░░░░░░░░░░░░░░░░░░ 47%
├─ Projected quarter total: ~$28.00 (under free threshold)
├─ Breakdown by case:
│ Brooge: $8.40 (22 docs from PACER, 12 from RECAP free)
│ Narayanan: $4.20 (14 docs from PACER, 8 from RECAP free)
│ Research: $1.70 (5 searches + 3 docs)
├─ Savings from RECAP: $6.30 (20 docs that would have cost money)
└─ [View detailed cost log]
```
### 9.2 Cost Controls
```
Settings > Plugins > PACER > Cost Management
├─ Quarterly budget: [$100.00 ] (alert when reached)
├─ Hard daily cap: [$25.00 ] (kills run if exceeded)
├─ ☑ Warn before downloads estimated over $3.00
├─ ☑ Prefer CourtListener / RECAP before direct PACER
├─ ☑ Contribute downloads to RECAP archive (helps community)
├─ ☑ Show cost in PACER tab dashboard
├─ ☑ Require confirmation for autonomous PACER pulls when estimated cost > $X
└─ Per-case cost limit: [$25.00 ] per quarter (optional)
```
The hard daily cap is non-negotiable — a regex bug or runaway loop must not be able to produce a surprise bill. The cost gate at `assertCostGateAllows()` in §5.1 enforces this before every direct-PACER fetch.
---
## 10. Plugin Configuration Page
This page is the PACER plugin's instance of the standard plugin settings surface defined in **Q Plugin System Architecture R2 §8**. Credentials, connector status, and per-plugin configuration follow the universal pattern (Q Plugin System §3 manifest `requires_auth` schema, §6.5 connector ownership routing). Future plugins use the same pattern; nothing here is PACER-specific architecture.
Accessible from **Settings > Plugins & Extensions > PACER > Configure**:
```
PACER Plugin Configuration
ACCOUNT
├─ PACER
│ ├─ Username: [wbrody ]
│ ├─ Password: [•••••••• ] [Show]
│ ├─ Status: ● Connected — last auth 2h ago
│ └─ [Test Connection]
└─ CourtListener
├─ API Token: [****abcd ] [Update]
├─ Status: ● Connected
└─ [Test Connection]
GLOBAL DEFAULTS
├─ Default check frequency: [Every 6 hours ▾]
├─ Default auto-download: ☑ Substantive filings only
├─ Default save location: [📁 OneDrive - Schall Firm / Cases / {case_name} / PACER]
│ Available variables: {case_name}, {case_number}, {court}, {year}
├─ Default alert settings:
│ ├─ ☑ Toast notification
│ ├─ ☑ Morning briefing
│ ├─ ☑ Apple Reminders (for deadlines)
│ └─ ☐ Email alert
├─ Filing type filter (default):
│ ├─ ☑ Motions ☑ Orders ☑ Opinions ☑ Complaints
│ ├─ ☑ Expert reports ☑ Declarations ☑ Stipulations
│ └─ ☐ Certificates ☐ Notices of appearance ☐ Civil cover sheets
└─ CM/ECF email auto-capture:
├─ ☐ Enabled (requires DOC16 email processing)
└─ Email pattern: [ecf_notification@*uscourts.gov]
COST MANAGEMENT
├─ (see §9.2 above)
KNOWLEDGE GRAPH
├─ ☑ Store case entities in DOC72 (via EC intake events)
├─ ☑ Store judge profiles from observed cases
├─ ☑ Track expert witnesses across cases
├─ DOC72 nodes: 342 (87 cases, 12 judges, 45 parties, 198 filings)
└─ [View PACER knowledge in DOC72]
CORPUS BINDINGS (DOC73)
├─ This plugin contributes to N corpora via M bindings.
├─ [Manage bindings] — opens DOC73 corpus admin filtered to PACER source
└─ See §7.3 for the source-binding contract.
AGENT INSTRUCTIONS (GLOBAL)
├─ These instructions apply to ALL watched cases unless overridden per-case.
├─
│ Rule: When any new court order is downloaded
│ Then: "Extract all deadlines. Add to calendar with 14/7/1 day reminders.
│ Push critical deadlines to Apple Reminders."
│ [Edit] [Delete]
│
│ [+ Add Global Rule]
DATA
├─ Watched cases: 20
├─ Documents cached: 847 (2.3 GB)
├─ [Export all PACER data]
├─ [Clear document cache] (keeps watch list and settings)
└─ [Reset plugin] (removes all data and settings)
```
---
## 11. Interaction with Other Plugins
The PACER plugin can trigger and be triggered by other plugins:
| Source | Trigger | Target | Action |
|--------|---------|--------|--------|
| PACER | New deadline extracted | Apple Reminders | Push deadline to phone/watch |
| PACER | New filing in watched case | Spotify | (fun) "Breaking: new filing" jingle |
| PACER | New filing downloaded | EC → DOC72 / DOC73 | Emit intake event; EC writes entity, applies corpus bindings |
| OneDrive watcher | New case folder detected | PACER | Suggest adding case to monitor |
| Calendar | Court date approaching | PACER | Auto-check for last-minute filings |
| Email (DOC16) | CM/ECF notification | PACER | Auto-download free document |
| Chat | "Search PACER for..." | PACER | Run search, return results |
**(V1.2 obligation:** each row implies a registered trigger schema. Per Will's failure-mode list ("phantom wiring," "unregistered content types," "unregistered UI surfaces"), each trigger needs explicit content-type registration (DOC20 §6.18.2) and, where applicable, surface registration (DOC21/DOC22). V1.1 leaves the table as documentary; V1.2 wires it up.)
---
## 12. State Court Note
PACER covers federal courts only. State court cases (like Paramount v. City of LA in LASC) can be added to the watch list as "manual only" entries — they appear in the dashboard for organizational purposes but don't have automated checking. The plugin UI shows them clearly as "(state - manual)" and the check frequency defaults to "Manual only."
If Docket Alarm integration is added in the future (as a separate plugin), it could provide automated monitoring for state courts using the same plugin architecture and the same DOC73 corpus binding contract.
---
## 13. Implementation Phases
```
Phase 1: Tab + Manual Search
├─ PACER plugin tool surface registered with EC, exposed externally through
│ the single ELNOR MCP gateway (NOT a separate per-plugin MCP server)
├─ CourtListener / RECAP integration (smartRetrieveDocument)
├─ Tab component with case list + detail panel + search
├─ Add/remove watched cases
├─ Manual document download and viewing
├─ Cost tracking
└─ Register as Q plugin per Q Plugin System Architecture R2 §3
Phase 2: Automated Monitoring
├─ PacerMonitorService (programmatic, scheduled)
├─ Per-case schedule configuration
├─ Auto-download with filing type classification
├─ Notification pipeline (toast, notices, morning briefing)
├─ Error handling and display
├─ Intake-event emission to EC (per §5.1 step 8)
└─ CM/ECF email auto-capture (needs DOC16 + V1.2 DOC25 wiring)
Phase 3: Agent Instructions
├─ Per-case agent instruction rules
├─ Global default rules
├─ Conditional triggering (filing type matching)
├─ DOC23 task queuing for AI processing (via EC, not direct)
└─ Deadline extraction → calendar integration
Phase 4: Knowledge Graph + Corpus Bindings
├─ Case / judge / party / filing / expert entity schemas (V1.2 obligation)
├─ DOC3 extraction prompts for court documents
├─ DOC73 Corpus Source Bindings integration (per §7.3)
├─ Cross-case research capabilities
├─ Judge analytics
└─ Expert witness tracking
Phase 5: Auto-Detection
├─ OneDrive new case folder detection
├─ Case number extraction from complaints
├─ Auto-suggest PACER monitoring
└─ Folder path auto-configuration
```
### 13.1 Effort Estimate (Recalibrated for Claude-Code-driven build)
V1.0's "13–19 hours total" reflected human-developer estimates. With Claude Code performing the implementation, the math is different — pure coding throughput is no longer the bottleneck; iteration against real PACER / CourtListener behavior is.
| Phase | V1.0 estimate (human-equiv) | V1.1 estimate (Claude-Code clock time) |
|-------|---:|---:|
| Phase 1 | 4–6 h | **2–4 h** |
| Phase 2 | 3–4 h | **1.5–3 h** |
| Phase 3 | 2–3 h | **1–2 h** |
| Phase 4 | 3–4 h | **2–4 h** |
| Phase 5 | 1–2 h | **0.5–1 h** |
| **Total** | 13–19 h | **~7–14 h clock time** |
**What still consumes clock time even with Claude Code:**
- Each-court CM/ECF idiosyncrasies. Each federal district's docket HTML and CM/ECF flow varies. Claude Code can write the parser fast, but the variations only surface when running against real cases. Iteration time bounded by paste-back latency.
- PACER NextGen CSO authentication subtleties. Cookie/token behavior differs from public docs and is only knowable from live behavior.
- Cost-gate UX iteration. The confirmation flow has to feel right — too aggressive and it's annoying, too lax and surprise bills happen. Few rounds.
- User verification time. Will looking at outputs and confirming "yes this is the right brief, no this filing should have been classified routine, etc." Bounded by attention, not Claude Code throughput.
**Phase 1 can plausibly land in a single 3–4 hour focused session** assuming CourtListener/PACER credentials are in place and 5–10 sample cases are available for end-to-end verification.
V1.2 architectural rewires (EC-as-sole-writer plumbing, DOC25 ingestion contract for CM/ECF, content-type registration completeness, surface registration, entity schemas) add roughly 2–4 hours on top — these are spec-driven changes mostly, not new code.