Inspiration

Most “AI in finance” products let a model decide whether someone is worthy of money. That is the opposite of fair. We wanted a small lending pool where the rules decide, the AI explains, and the people choose.

The problem we care about is everyday credit: a car repair, a gap before payday, a $50 to $300 loan that a credit score would block. Payday products hide cost. Mainstream scores lock people out before they can prove they repay. We wanted something neighbors could actually understand: a shared pool, a flat fee, a reserve that takes the first hit, and a tier ladder driven by repayment, not by a black box.

What it does

Potluck is a micro peer-to-peer lending pool.

Lenders deposit into a shared pool and see honest numbers: their balance, the reserve, outstanding loans, and a worst-case that is low-risk, not risk-free. Borrowers take short loans ($50 to $300) with a 2% flat fee, four weekly payments, no interest compounding, and no late fees. A tier ladder (0 to 3) sets the max loan. Repayment is the only thing that moves someone above Tier 1. Optional signals can raise the starting tier by one step and can never lower it.

Money is integer cents. Every deposit, loan, repayment, and cycle close is an append-only double-entry ledger entry that must balance before it writes. At cycle close, fees split between lenders, reserve, and operations. The reserve absorbs defaults first; lenders take a loss only after it is exhausted.

AI never sets terms. After Google sign-in, the server builds a scoped fact bundle (borrowers see their own facts; lenders see aggregates). Amazon Bedrock explains those facts in plain English. A filter blocks recommendations, approvals, predictions, and any dollar or percent that is not already in the bundle. Failures fall back to a template. Every call is audited.

How we built it

We split ownership so the money layer and the AI layer cannot mix.

  • Money core: loan math, pool and reserve accounting, ledger, scheduler, clock, seed data, mock payments.
  • Experience: Next.js App Router screens, Tailwind, design system, demo panel.
  • Trust and AI: tier engine, community impact, identity, Google OIDC (arctic, openid + profile only), signed HttpOnly sessions, Bedrock explainer, filter, adversarial evals.

The stack is TypeScript (strict), Next.js, Tailwind, Drizzle over SQLite / Turso, Vitest, Playwright, and Vercel. Rules are pure functions: no database, no network, no Date.now(). Time is a parameter. The LLM receives only a sanitized fact bundle and never writes the ledger. Tests lock the spec fixtures, including the $100 + $2 fee schedule that displays about 41% APR.

Challenges we ran into

The constraint we chose was the hardest one: the model must never do math, never approve, and never write money. That meant facts, ownership checks, and the filter had to be testable before Bedrock was wired.

Infra disagreed with the happy path. Bedrock API keys are denied by the student AWS organization’s service control policy (bedrock:CallWithBearerToken). IAM-signed Converse calls work. SigV4 path encoding had to match what Bedrock expects (: in a model id becomes %253A in the canonical URI). Vercel reserves AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY, so a key that works locally can still fail in production.

On Windows ARM64, libsql and the bundler needed x64 Node and x64 pnpm. Auth was late-night work: first-time Google users pick borrower or lender before any row is written, and the browser is never trusted to supply an id, name, or role.

An adversarial eval (pnpm ai:eval) then ran 37 prompts through the live pipeline and found a real gap: the filter caught recommend but not recommendations. We fixed the inflections.

Accomplishments that we're proud of

  • A working demo where every dollar is derived from a balanced, append-only ledger.
  • Fairness encoded as functions and fixtures, not as prompt copy.
  • An AI layer that can explain a loan or the pool and still refuse to advise, approve, or invent a number.
  • Google sign-in that stores only a derived user id and a display name: no email, tokens, or raw Google subject.
  • 300+ unit tests plus a live eval that caught a production filter bug before the demo. ## What we learned Fairness is easier to defend when it is a function, not a paragraph in a prompt. Once the numbers live in tests that match a written spec, the model can only talk about what the backend already computed.

“AI product” work is mostly access control: who is signed in, which loan they own, which intent their role may ask, and which keys never enter a prompt (Google name, email, KYC, employment, education).

“The model is reachable” is not the same as “the deploy can call it.” Host reserved env names, org-level SCPs, and signing details matter as much as the prompt.

What's next for Potluck

  • Scope every money route to the signed-in session instead of demo ids, and guard demo reset in production.
  • Finish the Google role-choice UI and hide the account picker on the live site.
  • Make Bedrock credentials work cleanly on Vercel (host-safe env names, least-privilege IAM).
  • If we take it past the hackathon: real payments, a shared rate limiter, and a reserve policy people can read in one page. The rule we will not relax is the one we started with: the ledger decides the numbers; the model only explains them.

Built With

Share this project:

Updates

Submission history