[feat-002] Legal database search with Files and Sources picker

↗ view on GitHub · Nick Whitehouse · 2026-05-03 · 6a4ea15e

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>
Repository nwhitehouse/mike
Author Nick Whitehouse <nick.whitehouse@mccarthyfinch.com>
Authored
Parents 6d2aac9e
Stats 11 files changed , +575 , -30
Part of Legal database search tool + Files-and-Sources picker

Capture this commit into my fork

Download a Markdown prompt that tells Claude how to port this exact commit into your working tree. Run it via claude -p < capture-commit-6a4ea15e.md from inside the repo you want the change in.

⬇ Download capture-commit-6a4ea15e.md