Skip to main content

oak-domain-legal-intake

An access-to-justice legal-intake, triage, and referral domain for the OakQuant platform — the first non-investments domain built on Timber's plugin system, and its altruistic B2B2C pillar.

License: Apache 2.0 Python 3.11+ Status: Live in production PyPI

Live in production across all three layers. A legal-aid or pro-bono organization gets a full intake-to-referral workflow — take a matter in, model the parties, triage and route it, track deadlines and activities, screen eligibility, match it to real legal-aid programs and crisis resources, assemble applicant-facing documents (including translations), and hand the applicant a printable referral packet or wallet card — plus a public, no-login "find help" screener anyone can use. It ships as a discoverable plugin that registers into timber/grove/acorn at startup with zero edits to any sibling repo, and is fully ring-fenced by a per-enterprise legal_intake capability: a tenant that isn't provisioned for it never sees a nav item, a home widget, or an endpoint.

What it is

oak-domain-legal-intake is a discoverable Timber domain plugin. Installing it adds a legal-intake capability to an OakQuant deployment; leaving it out is a no-op. Like every oak-domain-* package it is fully additive and opt-in — it ships its own models, services, HTTP surface, agent tools, and UI contributions and wires them into the platform's shared registries at startup, with no edits to the core Timber, Grove, or Acorn libraries.

It was the proving ground for OakQuant's domain-plugin pattern: the first domain built on Timber's plugin system that is not the investments domain, demonstrating that a brand-new, unrelated domain can plug in cleanly through a single entry point per layer.

Why legal intake — access to justice

Legal aid and pro-bono organizations triage far more people than they can serve, and the quality and consistency of that triage decides who gets help. This domain exists to make that triage fairer, faster, and more accountable — and to point every person, served or not, toward real help. Several commitments are encoded directly into the schema and services rather than left to policy:

  • Help, not gate. A disposition routes or refers a person; it never renders a "denial". Eligibility and cost outputs are estimates that point toward help — they never tell anyone they are out of options.
  • Data minimization. Operational fields only; no free-text PII columns. Protected attributes (used only by the fairness audit) and sensitive eligibility inputs (income, household) are isolated in their own stores and are never read by routing or the learning loop.
  • Meaningful human review. Assembled documents and translations always land in staff_review and are never delivered to an applicant until a human approves them.
  • Not legal advice. The guidance and conversation surfaces give legal information and navigation only — explicitly guarded, plain-language, never case strategy or outcome predictions.
  • Real data only. The directory seed and every ingested resource are real national authorities, hotlines, and their real contact info — nothing fabricated.
  • Append-only logs. Event and outcome logs support contestability and audit.

The plugin shape

This package plugs into all three OakQuant layers through one entry point per layer, plus a generic secrets entry point. Each layer discovers only its own entry-point group and imports only that entry point's module — so the Timber layer never pulls in Grove/FastAPI or Acorn.

Layer / concern Entry-point group Object Contributes
Timber timber.domains oak_domain_legal_intake:LegalIntakeDomain 14 ORM models + all domain services, registered under service_registry.domain("legal_intake")
Grove grove.domains oak_domain_legal_intake.grove_plugin:LegalIntakeGroveDomain FastAPI router mounted at /api/v3/legal-intake (grove-key + capability + tenant-isolation gated)
Acorn acorn.domains oak_domain_legal_intake.acorn_plugin:LegalIntakeAcornDomain Oracle intake-assistant profile + a legal-safe Rustle persona + ~28 gated agent tools
Secrets grove.secret_specs oak_domain_legal_intake:secret_specs optional runtime secrets (CourtListener / USCIS), injected from ranger at grove bootstrap — all required=False, so a missing key never blocks startup and grove core names no legal vendor

Beyond entry points, the timber plugin registers UI, calendar, and conversation contributions into the same shared registry — the Legal Intake nav item, the home-page widgets (triage queue / recent / quick actions / public link / upcoming), the legal calendar taxonomy, the domain's calendar-event generators, and per-case Rustle access — each gated to the legal_intake capability, so grove core holds no legal-specific nav, page, or calendar config.

How discovery works

The domain advertises itself via timber.domains. At startup (initialize_timber, Step 8.5), Timber discovers the package, instantiates LegalIntakeDomain, and calls register(ctx) once, before table creation — so the models get their tables created in the following step. register(ctx) takes every runtime dependency (db handle, registries) from the injected DomainContext rather than importing core singletons, keeping the dependency direction one-way. The Grove and Acorn plugins follow the same shape against their own entry-point groups and contexts, registered when those apps start.

The Grove router mounts outside grove's auth middleware and re-asserts three boundaries on every request: the X-Grove-API-Key service-key check, the per-enterprise legal_intake capability gate (absent capability → 404), and strict enterprise isolation (reads scoped to the caller's visible tenants, writes stamped with the caller's tenant, cross-tenant → 404).

Capabilities

Everything below ships in the package and is live in production. Each capability is reachable three ways — a Grove endpoint under /api/v3/legal-intake, an Acorn agent tool, and (where it has a UI) a home widget or page — all behind the same capability gate.

Intake & cases

The instrumentation core: an IntakeCase (operational, PII-minimized fields only) with an append-only IntakeEvent log, StaffDecision records that capture the human's call and any override reason, and a terminal Disposition that routes or refers (never denies). The IntakeParty spine models everyone on a matter — applicant, opposing party, dependents, advocate, interpreter — linking internal parties to real platform users so routing knows who to contact. Staff work the queue (/queue, /queues/mine, admin /admin/queues); a served recipient sees only their own cases through a server-enforced self-help view (/my-cases).

Routing & decisions

A RoutingSuggestionService proposes where a matter should go, reaching grove's shared routing spine through the grove_core bridge (no grove import). Staff record the decision, route to a real queue or person, and close with a disposition — each step captured for audit and folded into the case timeline.

Activities, deadlines & calendar

CaseActivity is the "what happens and when" spine — intake interviews, advocate consults, hearing prep, hearings, filings, follow-ups, and hard deadlines. ActivityService can seed a sensible default workplan for a matter, and a deadline activity is auto-seeded whenever a case's key_deadline_at is known. Scheduled activities for an assigned user are emitted onto the shared calendar and the home "Upcoming" widget by the domain's own calendar-event generators, with no grove change.

A separate deterministic deadline calculator (DeadlineService, verified rules only) computes statute-of-limitations / hearing / appeal windows conservatively — engineered to never be wrong-late. Reachable at /deadlines/calculate and per case.

Directory & eligibility

An HSDS-aligned referral directory (Open Referral Human Services Data Specification): LegalAidProgram and SupportResource rows carry organization / service / location / eligibility / taxonomy so 211, findhelp, LSC-grantee, and any Open Referral feed are interchangeable. The directory is deep-link-first — an entry can resolve the caller's ZIP/state to a real referral URL at match time — so even a thin table yields real referrals via the seeded national gateways. EligibilityService.match ranks programs for a case and returns a whole-person bundle, surfacing crisis resources first whenever a safety indicator or matching need is present. Sensitive eligibility inputs live in an isolated EligibilitySnapshot; estimated_pct_fpl is computed from a dated, sourced Federal Poverty Guidelines table (services/fpl.py) for auditability. CostEstimateService gives a transparent read on fee-waiver rights and likely out-of-pocket cost after free help. All of it is help-not-gate: an estimate, never a verdict.

Guidance & research

GuidanceService answers plain-language legal-information questions with a cost-tiered strategy — a curated knowledge base first, a generative fallback (cambium, with cost-ledger discipline) only when needed — and is guarded as not legal advice. research.py adds CourtListener case-law lookup (anonymous + rate-limited when no key is set, richer with the optional ranger-injected token). Curated document assembly (DocumentService) turns templates — hardship letter, fee-waiver request, evidence checklist, demand letter — filled with case fields into a draft that always enters staff_review and is delivered only after a human approves.

Advocate tools

PacketService composes the directory match, the verified deadline, and a curated "what to bring" checklist into a printable referral packet; WalletCardService produces a compact pocket hand-out. Both render to PDF through Timber's shared common.render (the [pdf] extra), keeping the PDF engine out of the plugin. Endpoints serve either JSON or PDF (/cases/{id}/packet, /cases/{id}/wallet-card).

Multilingual

TranslationService translates an assembled document into the applicant's language via the shared cambium generator (translation is a prompt + a review discipline, not a new capability). Supported today: Spanish, Chinese, Vietnamese, Haitian Creole, and Arabic. A machine translation lands as a new staff_review document behind the same human-verification gate — it is never delivered until a person approves it.

Equity & fairness

FairnessService runs a deterministic four-fifths-rule disparate-impact audit over routing and disposition outcomes. It is the only service permitted to read the isolated protected attributes, and it does so for human review only, never for routing. A feature_guard enforces that boundary the other direction: it strips protected attributes before any operational feature reaches routing, eligibility ranking, or the learning loop. Reachable at the admin-gated /audit/fairness.

Data ingestion & upkeep

A keyless HSDS ingestion pipeline (fetch → map → dedupe → Census-geocode → upsert) normalizes public Open Referral / HSDS and LSC-grantee feeds into the directory, idempotent by (enterprise_id, source_ref), real/verifiable feeds only (a no-op when none is configured). Resource-upkeep sweeps keep the directory trustworthy: a link-health probe stamps every directory URL's health_status/verified_at (a dead link is flagged, never deleted), and a program-scan surfaces public-feed candidates missing from the directory for human review — it never auto-inserts. Both run behind admin endpoints (/admin/ingest/*, /admin/upkeep/*) and weekly schedulers.

Adaptive learning loop

An outcome-driven learning substrate (cambium.adapt) records P(favorable) at routing time from operational features only (through the feature_guard), observes each case's terminal outcome, and matures to per-feature weights that gently nudge routing and eligibility ranking. It is small-sample-tempered — deliberately inert until real case/outcome volume accrues — so it never over-fits early data. Admin: /admin/learning/{status,mature}.

Public, no-login self-serve

A /public/find-help directory search and a /public/eligibility-screener let anyone check for help with no account, and /public/{slug}/apply accepts a public intake. This is the front door for people who will never log in.

Install

pip install oak-domain-legal-intake

This pulls in timber-common>=1.1.2 (the plugin scaffolding — ServiceRegistry, DomainPlugin / DomainContext, timber.domains discovery, the Step-8.5 init hook, and common.render for HTML→PDF), cambium-ai>=0.2.7 (cost-disciplined generation for guidance and translation, import-guarded so a cambium-less process still serves the curated tier), and httpx (CourtListener). Once installed, discovery is automatic via the entry points — no configuration needed.

The optional dev extra adds pytest, fastapi (to exercise the Grove router standalone), httpx, and xhtml2pdf (so the packet-render test actually produces a PDF and catches CSS regressions):

pip install "oak-domain-legal-intake[dev]"

Optional runtime secrets (COURT_LISTENER_API_TOKEN, USCIS_CLIENT_ID, USCIS_CLIENT_SECRET) are advertised via grove.secret_specs and injected from ranger at grove bootstrap; all are optional and degrade gracefully when unset.

Entry points reference

[project.entry-points."timber.domains"]
legal_intake = "oak_domain_legal_intake:LegalIntakeDomain"

[project.entry-points."grove.domains"]
legal_intake = "oak_domain_legal_intake.grove_plugin:LegalIntakeGroveDomain"

[project.entry-points."acorn.domains"]
legal_intake = "oak_domain_legal_intake.acorn_plugin:LegalIntakeAcornDomain"

[project.entry-points."grove.secret_specs"]
legal_intake = "oak_domain_legal_intake:secret_specs"

Services are reached at runtime through service_registry.domain("legal_intake") — e.g. .intake, .outcome, .audit, .party, .routing, .activity, .guidance, .document, .eligibility, .cost, .deadline, .fairness, .link_health, .program_scan, .ingest, .packet, .wallet_card, .translation, .learning.

License

Apache-2.0. See LICENSE.

Metadata

Release files for oak-domain-legal-intake 0.25.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for oak-domain-legal-intake 0.25.1
File Size Uploaded
oak_domain_legal_intake-0.25.1.tar.gz 202.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for oak-domain-legal-intake 0.25.1
File Interpreter ABI Platform
oak_domain_legal_intake-0.25.1-py3-none-any.whl Python 3 none any Details

Total release size: 404.8 kB

Release history Release notifications | RSS feed

This release

0.25.1 This release

2 release files

0.25.0

2 release files

0.23.0

2 release files

0.22.0

2 release files

0.21.0

2 release files

0.20.2

2 release files

0.20.1

2 release files

0.19.0

2 release files

0.18.0

2 release files

0.17.0

2 release files

0.16.0

2 release files

0.15.0

2 release files

0.14.0

2 release files

0.13.0

2 release files

0.12.0

2 release files

0.11.0

2 release files

0.10.0

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.5

2 release files

0.5.4

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page