Inspiration
A tenant served with a California eviction summons has a matter of days to respond, usually no lawyer, and a stack of paper written in a language nobody speaks. If they miss the deadline the landlord can request a default judgment and the case is decided without them ever being heard.
The information they need is public. It is just unreadable when you are frightened and working against a court clock.
What does not help is another AI that sounds authoritative. In this domain a confident wrong answer is worse than no answer, because a citation attached to it is exactly what makes someone believe it and stop looking. A tool a frightened person will act on has to be able to say I do not know, and it has to be able to show where every sentence came from when it does know.
So the design rule for the whole project was: the model reads and explains, and never decides anything with a legal consequence. The deadline is arithmetic. Which defenses apply is a fixed rule. Both are pure functions with tests, and neither has a model anywhere near it.
What it does
Photograph the summons. Gemini reads the case number, the court branch, who is suing, the date you were served and how you were served. If the photo is unusable it asks for a retake rather than guessing at a date somebody is going to plan around.
Then it works out the actual deadline. Ten court days from service, weekends and California judicial holidays excluded, plus five more court days if you were served by mail. If the deadline has already passed, it stops and refers you to a legal aid advocate instead of walking you through paperwork that will not help.
Ask it anything in your own words, by typing or by speaking. Every answer is grounded in a retrieved passage and carries the citation. If nothing in the corpus answers your question, it says so and offers a legal aid intake instead of improvising.
Then it prepares your Answer, form UD-105. Which defenses get included is decided by fixed rules from what you tick, never by the model. You get a real PDF.
And then step four, which is the part most tools skip: what to do with it. The court from your own summons, the deadline restated as a written date, the three ways to file, and form FW-001 if you cannot afford the fee. It never files anything. A person reviews it and files it.
How we built it
FastAPI on Cloud Run. Firestore holds the case and a step-by-step audit trail. Gemini 3.5 Flash on Vertex AI through the Google GenAI SDK does the reading and the answering. Retrieval uses Vertex text-embedding-005 over a small corpus of four documents. Cloud Trace collects spans.
Underneath is a substrate I wrote first and vendored into each of my three projects — config, guards, the Firestore wrapper, the Gemini client, telemetry, test fakes.
The console is plain HTML, CSS and JavaScript. No framework. It works on a phone, because that is what a tenant has, and it works on a desktop, because that is what an advocate helping them has.
The deadline arithmetic is pure functions with no model anywhere near it. Same for defense selection. The model reads and explains; it never decides a date or a legal position.
Challenges we ran into
The statute changed and nothing told me. Code of Civil Procedure § 1167 set the response period at five court days for decades. AB 2347 extended it to ten, operative 1 January 2025. I caught it by reading the Judicial Council's current guidance against my own corpus rather than trusting either.
This is precisely the failure mode the project is designed to prevent, so it had to hold against my own corpus first: unchecked, retrieval would return the superseded passage and attach a citation to the very section it was misquoting. Fifteen deadline tests asserted the old rule with worked arithmetic in the comments, so the suite was green over it and would have stayed green indefinitely. Every one was reworked against the amended text.
Court holidays were accepted and never supplied. compute_response_deadline takes a set of holidays. The tests exercised it. Nothing in production ever passed one, so every real deadline was counted as though courts never close. A tenant served in mid-November was told 30 November when the real date is 2 December, because Thanksgiving and the day after are judicial holidays. Served before Christmas, it was out by four days.
I fixed that by computing the list from statute rather than calling an API. CCP § 135 makes every Gov. Code § 6700 holiday judicial except Lunar New Year, Diwali, Genocide Remembrance Day, Admission Day and Columbus Day, and adds the day after Thanksgiving. That is fixed law, not live data, and a page that can 404 or change shape is not something a court deadline should depend on. The courts' own pages 404'd twice while I was researching this, which rather made the point.
The refusal guard refused the most basic question there is. I had a rule that when the top two retrieved passages score within a hair of each other, the ranking cannot separate them, so refuse. Then "How many days do I have to respond?" got refused, because § 1167 and the service-methods passage are both about the deadline. They were not rival answers, they were two halves of one. Refusing there was not caution, it was a bug wearing caution's clothes.
Gemini copied citations back with brackets around them. The prompt formatted passages as [{citation}] {text}, and the model returned [Cal. Code Civ. Proc. § 1167] including the brackets. That then failed the exact-membership check and a correct answer was thrown away as fabricated. I fixed the prompt rather than loosening the check, because exact matching on citations is the one invariant that cannot bend.
Data sources
Four documents: CCP § 1167 as amended, CCP § 1170, a note on service methods and when the clock starts, and the UD-105 field map. All public law.
Judicial holidays are computed from CCP § 135 and Gov. Code § 6700 rather than fetched.
The filing guidance comes from the Judicial Council's own self-help pages, including the fee waiver page that lists "fees to respond to a case" among what form FW-001 covers, which is exactly this filing.
No user data leaves the request beyond the case record needed to answer follow-up questions. There is no tenant database being built here.
Accomplishments that we're proud of
It says I don't know. When retrieval finds nothing above the similarity floor, the answer is a refusal and an offer to prepare a legal aid intake. For a tool that a frightened person will believe, the refusal is the feature.
Every citation is checked for exact membership in the passages the model was actually shown. A citation that was not in front of it does not survive, however plausible it looks.
The model never decides anything that matters. Not the deadline, not which defenses apply. It reads a photo and it explains retrieved text. Everything with a legal consequence is a pure function with a test.
Verification against primary sources, not against my own tests. Two defects in the most important number this product computes — a superseded statute and an unused holiday parameter — were both invisible to 143 passing tests and both found by checking the law itself. In a domain where being confidently wrong costs somebody their housing, that is the discipline that matters more than any feature.
What we learned
A green test suite tells you the code does what the tests say. It says nothing about whether the tests are right. Fifteen deadline tests asserted five court days with worked arithmetic in the comments. Every one of them was carefully, thoroughly wrong.
Check the primary source, not your memory of it. § 1167 said five days for decades and I would have sworn to it. Legal software has a maintenance property ordinary software does not: correct code becomes incorrect without anybody touching it.
An unused parameter is a silent bug. holidays was tested and never passed. The type checker was happy, the tests were happy, and production quietly counted Christmas as a working day.
Caution has failure modes too. A refusal guard that fires on the question the product exists to answer is not safe, it is broken. Safety that stops the tool working is not safety.
What's next for Eviction Response Helper
Four documents is not a corpus. Local rules vary by county, and a lot of what actually decides a case is not in the two sections I have.
Spanish, then Chinese and Tagalog. California courts serve those populations and a tool that only works in English is not serving the people who most need it.
An advocate-facing view. Legal aid offices triage dozens of these a week, and the case record and audit trail are already there.
A monitor on the statutes it cites. § 1167 changed in January 2025 and nothing in the system knew, which is a structural gap rather than a one-off: any tool that quotes law needs to watch the law it quotes. Diffing the corpus against the current text on a schedule is the obvious next build.
Log in or sign up for Devpost to join the conversation.