nwhitehouse wires Mike into the public US legal corpus

A new search tool lets the assistant pull live citations from four open federal sources - but only when the user explicitly turns them on.

searchchat-ui

nwhitehouse has added a legal research tool that fans out across CourtListener (federal and state case law), GovInfo (official US government documents), the Federal Register (daily rulemakings), and the eCFR (the live Code of Federal Regulations). Queries hit all four in parallel with a strict per-source timeout, so a slow API doesn't stall the whole answer, and missing API keys degrade gracefully rather than breaking the chat.

The interesting design choice is the hard gate: the tool literally isn't offered to the model unless the user has ticked a source in the chat input. Even if the model tries to widen the net mid-call, the backend clamps it back to what the user selected. The UI lives in a new Files and Sources picker built to absorb future sections like a knowledge base, integrations, or EU and UK law without a rewrite.

So what Worth a look for any legal-AI team that wants grounded US federal citations without paying for Westlaw or Lexis - and a clean template for keeping model-callable tools on a user-controlled leash.

View this fork on GitHub →

Spotted something wrong? Or know the PR text has fresher detail than the writeup above?

Commits in this thread

1 commit from nwhitehouse/mike, oldest first. Source extracted verbatim from the harvested git log.

SHA Subject Author Date
6a4ea15e [feat-002] Legal database search with Files and Sources picker Nick Whitehouse 2026-05-03 ↗ GitHub
commit body
Adds a `legal_search` tool that fans out across four open US legal databases
(CourtListener, GovInfo, Federal Register, eCFR), gated by a new "Files and
Sources" picker on the chat input. Hard gate: when no sources are selected,
the tool isn't in the schema at all.

Backend
- backend/src/lib/legalSearch.ts (new): TS port of work___'s
  legal_search_service.py. Promise.allSettled fan-out, 12s per-source
  timeouts, graceful degradation when an API key is missing or a source
  errors. Includes formatLegalResultsForModel() that produces markdown
  links so the model can cite inline.
- chatTools.ts: new LEGAL_TOOLS array (kept separate from always-on TOOLS
  so it can be conditionally appended). Dispatch case in runToolCalls
  defensively clamps the model's `sources` arg to the user's selection.
  runLLMStream takes new `sources?: { legal?: string[] }` param;
  conditionally appends LEGAL_TOOLS and a system-prompt line restricting
  the model's `sources` arg to the user's selection.
- routes/chat.ts: reads `sources` from request body, passes through.
- .env.example: documents COURTLISTENER_API_TOKEN, GOVINFO_API_KEY (FR +
  eCFR are open APIs, no auth).

Frontend
- AddDocButton.tsx → FilesAndSourcesButton.tsx (rename + extend). Trigger
  label "Files and sources"; count = attached files + selected sources.
  Sectioned popover: existing Upload / Browse + new "US Legal Sources"
  section with 4 checkboxes (Court Opinions, Federal Legislation, Federal
  Register, Regulations CFR). Default off. Architected so future sections
  (Knowledge Base, Integrations, EU/UK Law) drop in without rework.
- ChatInput.tsx: tracks selectedLegalSources, passes to button, includes
  in submitted MikeMessage's `sources` field, resets to [] after submit
  (per-message-only - no chat-level persistence in v1).
- MikeMessage.sources (transient field, not persisted in history).
- useAssistantChat.ts + mikeApi.streamChat: thread `sources` through to
  POST /chat body.
- Renamed prop `hideAddDocButton` → `hideFilesAndSourcesButton`; one
  caller updated (project chat page).

Smoke-tested both open APIs (Federal Register + eCFR) end-to-end against
real endpoints - both return real results in <1.5s.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Capture this thread into my fork

Download a single Markdown prompt that tells Claude how to port every commit above into your working tree — adapting paths and structure to match your repo. Run it via claude -p < capture-thread-115.md from inside the repo you want the changes in.

⬇ Download capture-thread-115.md