Legal
"Stop putting this stuff in email." "Stop documenting non-compliance."
>
Two rules. Eighty percent of preventable litigation loss. Now encoded.
The Legal module does two things — reactive eDiscovery and proactive Legal Hygiene. Most legal software does the first thing. The hygiene scanner is what's different.
Layer 1 — Reactive eDiscovery
The standard workflow when litigation happens: matter → hold → custodian notification → preservation tracking → release.
Four entities for the reactive side:
- LegalMatter — lawsuit / regulatory / investigation / contract / employment / ip.
litigation_holdflag +hold_triggered_atstamp drive the preservation clock. - LegalHold — issued against a matter. Counters for custodian count + notifications sent + notifications acked.
- HoldCustodian — person/system included in a hold. Per-row
notification_sent_at/acknowledged_at/data_preservedtracking. README's 24-hour notification clock starts when this record is created. - LegalHygieneFlag — covered below.
Tools: create_legal_matter, trigger_legal_hold (auto-flips matter.litigation_hold), add_hold_custodian (rolls counters back to the hold), ack_hold_custodian, release_legal_hold (clears matter.litigation_hold when no other active hold exists).
The matter drawer is the operator surface — full hold list, custodian acked/preserved tracking, hygiene flags tied to this matter, primary "⚖ Trigger litigation hold" button when no hold is active.
Layer 2 — Proactive Legal Hygiene
The differentiator. Most legal software helps you respond to litigation after it happens. This stops the documents from being created in the first place.
The mechanism: deterministic regex pattern matching on communications. AI runs *once at build time* to generate the PATTERN declarations from the industry's liability landscape. At scan time it's pure regex — patterns either match or they don't. No hallucination.
src/legal.ts ships six patterns straight from the README:
| Pattern | What it catches | Severity | Risk impact | |---|---|---|---| | known_noncompliance_language | "we are aware that / despite our policy / contrary to our policy" | critical | −20 | | litigation_anticipation_language | "if this goes to court / legal exposure / when we get sued" | high | −15 | | cover_up_language | "don't put this in writing / no paper trail / delete this email" | critical | −25 | | privilege_waiver_language | "forwarding from our attorney / our lawyer said / sharing legal's view" | high | −20 | | hr_liability_language | "just between us / don't tell HR / keep this informal" | high | −15 | | sales_warranty_contradiction | "I told the client we would / verbally agreed / committed outside the contract" | high | −10 |
The cover-up family penalizes hardest because attempting to suppress evidence is worse than the underlying issue. Courts take a very dim view. So does the jury.
The math
// scoreText(text) returns {score, matches}
// score starts at 100
// each match contributes its (negative) risk_impact
// score floors at 0
A clean message scores 100. A single noncompliance line lands at 80. A cover-up + litigation anticipation in the same message lands in the 40s. The scoring matches the README's legal_risk_score formula.
scanText returns char offsets so the UI can highlight the matched phrase inline. Multi-match-per-pattern is supported; overlapping matches collapse to the first.
The Hygiene Scanner UI
Legal → Hygiene Scanner is the demo headline:
- Textarea on the left; right panel on the right
- 250ms-debounced live scan as you type
- Big legal-risk score number erodes from 100 with each match. Color: green ≥90, amber ≥60, red below.
- Match cards per fire: pattern name + severity badge + risk-impact pts + excerpt with the matched phrase highlighted in red
<mark>+ the operator-facing alert message - Six sample buttons across the top: Cover-up / Noncompliance / Litigation anticipation / Privilege waiver / HR liability / Benign. The attorney demo flow.
- Log this scan button persists a LegalHygieneFlag per match to the review queue
The review queue
Legal → Hygiene flags. Per-row review actions:
- ✓ Reviewed — acknowledged, no further action
- ↑ Escalate — sent up the chain
- ✗ Dismiss — false positive
Filter by status. Critical-severity flags carry a bold-red pill (the cover-up family).
The cross-link
Hygiene flags can be tied to a specific matter via matter_id. When a matter is open and the scanner catches a phrase about that matter, the flag shows up in the matter drawer too — the proactive scanner finding becomes load-bearing for the reactive case file.
The sales angle for AI-focused attorneys
Most "AI for legal" products use LLMs *at scan time*. That means hallucinations, drift, and a defensibility problem ("why did your AI flag this and not that?"). Accelerando's hygiene scanner inverts that: the AI runs once when the patterns are generated for the industry, and the patterns are *human-reviewable, deterministic regex*. At runtime, the scanner can be reasoned about in a deposition.
The patterns are visible, auditable, and version-controlled in the .agi tree. You can git-diff the pattern library between two dates. You can show opposing counsel exactly which phrases your system flagged and why. That's a defensibility posture no LLM-driven scanner has.
What's deferred
The agicore-examples reference (agicore-examples/accelerando/legal) ships 10 entities; this module ships 4. The deferred entities — DocumentCollection, ReviewDocument, PrivilegeLogEntry, ProductionSet, ExternalConnector, RetentionPolicy — are the Layer 1 production-grade collection + review machinery. The matter / hold / custodian backbone they extend is in place.
Plus: tenant-configurable hygiene patterns (a HygienePattern entity for runtime-authored patterns) and AI-generated industry-specific patterns at onboarding (GenerateLegalHygienePatterns from the reference) are the natural next moves on Layer 2.