AI Decision System
Replayable, offline-verifiable records for AI-assisted go/no-go decisions: experiment promotions, typed model answers and human-approved actions.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
A case-management app for people representing themselves in North Carolina
civil court — small claims matters heard by a magistrate, and other civil
matters filed with the clerk.
The user has no lawyer, has never done this before, and is afraid of getting it
wrong. Everything here is built for that person.
The rule this codebase is organized around
CaseForge organizes information. It does not decide anything.README 전문 보기 ↗A case-management app for people representing themselves in North Carolina civil court — small claims matters heard by a magistrate, and other civil matters filed with the clerk.
The user has no lawyer, has never done this before, and is afraid of getting it wrong. Everything here is built for that person.
CaseForge organizes information. It does not decide anything.
The user enters and confirms every fact. The software stores, formats, reminds, and displays. The moment the software applies a legal rule to the user's facts, it is practicing law without a license.
| We do | We never do |
|---|---|
| Store the date the user entered | Calculate a deadline from a legal rule |
| Show the AOC form they picked | Tell them which form they need |
| Save what they typed in a field | Decide what belongs in the field |
| Read a date off an uploaded document | Interpret what it means for their case |
| Organize their exhibits | Tell them which exhibits help |
CaseForge also never files anything with the court.
Confirm-before-save is architecture, not a UI convention. Three things hold it up:
Confirmed<T> (lib/domain/confirmation.ts) —
every time-sensitive value in the model is wrapped in a type that cannot be
constructed without a user id and a stated source (user-entered, or
read-from-document with the document id it was read off).
assertWritable (lib/db/guard.ts) — the data layer
re-checks at runtime, on every write, that each registered time-sensitive
field holds a real confirmation. Types disappear at compile time; this does
not. A bug in a form, a route, or a future AI extractor cannot quietly write
a date.
Proposals are a separate table — anything CaseForge thinks it read
lives in proposals, is never rendered as part of the case record, and can
only leave that table through a user confirming or dismissing it.
Adding a dated or legally-consequential field to the model means registering it
in TIME_SENSITIVE_FIELDS. npm test covers the guard, including forged
confirmations.
Case types live in a registry (lib/domain/case-types.ts), and each entry declares whether the Administrative Office of the Courts actually publishes a fill-in complaint form for it:
Where complaintForm is null, the app says so plainly and stops. It does not
help the user assemble a complaint from their answers, because turning a
person's situation into a legal document is authoring a legal document. The
organizing half of the product — vault, timeline, evidence, hearing prep — works
for every case type regardless.
Form numbers were read from the AOC statewide forms search on the date in
FORMS_VERIFIED_ON. Re-check before relying on them; forms get revised.
All dates live on TimelineEvent, whose date is a Confirmed<string>. There
is no second path. Reminders are only ever attached to a confirmed date.
Reminders are in-app only. A user can flag a date and see it on their timeline, but nothing is delivered by email or text — there is no provider wired up. The timeline says so out loud rather than implying a court date will be chased down for the user.
AI features switch themselves off without a key. With no
ANTHROPIC_API_KEY, the story organizer is hidden and uploads go straight to the
manual form. Nothing else changes. Model calls use claude-opus-5 with
server-side refusal fallbacks enabled.
The app runs with no database at all. Set these four variables and it switches over to Supabase for sign-in, data and uploaded files — no code changes.
NEXT_PUBLIC_SUPABASE_URL= # Project Settings -> API
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY= # the publishable (or anon) key
SUPABASE_SECRET_KEY= # the secret (or service role) key
CASEFORGE_PREVIEW=0
On Vercel these go in Project Settings -> Environment Variables. The secret key
is server-only: never prefix it with NEXT_PUBLIC_.
In the Supabase project, once:
case-documents bucket, and the trigger that makes a profile when someone
signs up.https://<the live domain>/auth/callbackhttp://localhost:3100/auth/callback (for local development)Sign-in is by emailed link — no passwords are stored anywhere. Supabase sends the email; its default template is fine to start with.
What switching on changes: CASEFORGE_PREVIEW stops closing sign-up as soon
as Supabase is configured, so accounts open the moment the keys are set. Expect
to migrate nothing — the local .data file is development data only.
npm install
npm run dev
npm test # the confirm-before-save guard, and the county table
npm run typecheck
A fresh clone builds with no configuration:
git clone <this repo>
cd caseforge
npm ci
npm run build
To put it online, import the repository at vercel.com/new
and press Deploy. vercel.json already sets CASEFORGE_PREVIEW=1, which closes
sign-up with a plain explanation — the file-backed store does not persist on
serverless, so accounts cannot work until a real database is wired in. Nothing
else needs configuring.
Everything is in this repository; there is no state held anywhere else yet. To run it under your own accounts:
Do this before anyone real signs up. Once the app holds users' court documents and takes payments, moving it stops being an administrative task: a Stripe account cannot be transferred between people, and a database of other people's legal documents is not a file you can simply hand over.
See .env.example. There are only two today, both optional locally. Anything added later — a database URL, an API key, a Stripe secret — belongs there as a documented placeholder, never committed with a real value.
This is a development build. These are blocking, not nice-to-have:
getSession / requireSession / signIn /
signOut interface is the seam, and no page or action should need to change.limitCents: null on
purpose. Each county's chief district court judge sets a local limit under the
$10,000 statewide ceiling. Populate these only from nccourts.gov, and set
verifiedOn when you do. Until then the app says plainly that it does not know
the limit, which is true, rather than showing a number we invented.CaseForge shows a county's dollar limit as information. It does not compare the user's claim against it, and does not tell them whether their case belongs in small claims court. That comparison is applying a legal rule to their facts. The same reasoning keeps the app from picking a case type, picking a form, or computing a deadline.