Model the behavior before you build it.
Most software gets planned from what people say they want. brine plans it from how the work actually happens. You send a question tree to the people who do the work: the operations team a new internal tool has to fit, the customers or clients an app is for, the specialist who knows how a job is really done. They answer one question at a time, typed or spoken. A model reads each answer to choose the next question, so the interview follows what they actually do. Their answers come back as a behavior model you can build against:
- Gherkin scenarios for how the work flows, each one traced to the answers it came from.
- A fact ledger for everything else they said: numbers, timers, rules, their exact wording, real cases, red flags, terms, wishes, risks and what they measure. Each fact is typed and cited, and can be emitted as constants for code or rendered as a backlog, risk register or playbook.
One typed or spoken answer becomes a follow-up question, traced scenarios, typed facts, and an open question where the respondent was vague, instead of a guess.
Use it to:
- Plan an internal tool and its stack. Interview the team that runs a process, such as an agency moving a client request to a delivered video: where the request lands (a monday board, a Slack thread, a shared inbox), who approves it, what gets checked before it counts as done, and where it waits. The ledger separates fixed rules that belong in code, judgment calls that need a person (or a model, with evals drawn from real cases), and the systems and records each step reads or writes. That tells you what to build and what to integrate, not a vendor's demo.
- Plan an app around a customer, client or user. Model their process before you design screens. For a clinic's front desk: the states an appointment moves through, the reminder that goes out 48 hours before and who sends it, the no-show rule, and the insurance exceptions staff sort out by phone today.
- Write down how a specialist does the job. A senior estimator pricing a renovation, or a payroll lead closing the month: the inputs they trust, the checks they run and the thresholds they use, in their own words, so the team and its software work to the same spec.
- The tree (
src/spec.ts,src/walk.ts). Chapters of questions, walked in order.whenguards skip what does not apply,nextjumps go forward, anddecideasks Jev typed questions about an answer ("does this name an exception?", "who caused the delay?") so later guards branch on what was said.brine checkproves every address resolves, every jump goes forward and every guard looks back, and it samples walks to tell you how long a sitting is. - The page (
src/ui). One question at a time with a chapter list to jump around, and a waveform button in the answer box that records. The respondent never sees transcripts, reasons, branches or Gherkin. - The Worker (
src/worker.ts). A dependency-free Cloudflare Worker: invite links and passcodes, each respondent's walk in its own Durable Object, recordings and an append-only answer log in R2, transcription through OpenRouter's speech-to-text endpoint (openai/gpt-4o-mini-transcribeby default), decisions through OpenRouter's Decisions API, and an admin export. - The loop (
src/loop.ts). What happens after the first round:brine traceties every as-is scenario back to the answers it came from (@q:tags) and lists answers nothing cites;brine followupdrafts the second round from the features' Rules (read-backs) and# TODOs. - The ledger (
src/ledger.ts). Everything the respondent said that is not behavior (numbers, timers, rules, their wording, stories, signals, terms, ideas, risks, metrics) as typed facts cited to answers;brine ledger check|render|emit|recordsprojects it into code, documents and retrieval records. - The skill (
skills/brine). An agent skill: how to design the questions from a vocabulary or pipeline (references/method.md), how to write Gherkin from the answers (references/gherkin.md), and what else the answers become (references/derivations.md).
bun install
bun test # the walk, the checker, the Worker
bun bin/brine.ts check example/src/interview.ts
bun bin/brine.ts outline example/src/interview.tsInstall the skill for your agent (Claude Code, Cursor, Codex and others) from skills.sh:
npx skills add OpenRelationship/brineThen ask the agent to "design a brine interview for about ". The skill tells it to clone this repo for the code.
Write questions.ts exporting interview: Interview, then:
// worker.ts
import { brine } from "brine/worker"
import { interview } from "./questions"
const app = brine(interview)
export default app
export const BrineSession = app.BrineSession // one Durable Object per respondent// main.tsx
import { Brine } from "brine/ui"
import "brine/ui/brine.css"
createRoot(document.getElementById("root")!).render(<Brine interview={interview} brand={{ name: "Acme" }} />)example/ is a complete app. It needs a KV namespace (BRINE), an R2 bucket (BRINE_AUDIO), and
two secrets: OPENROUTER_API_KEY and BRINE_ADMIN_TOKEN. The Durable Object (BRINE_SESSIONS) and
the passcode rate limit (BRINE_ENTER_LIMIT) are declared in example/wrangler.jsonc; both are
optional.
wrangler kv namespace create BRINE # put the id in wrangler.jsonc
wrangler r2 bucket create brine-example-audio
wrangler secret put OPENROUTER_API_KEY
wrangler secret put BRINE_ADMIN_TOKEN
bun run example:build && wrangler deploy --config example/wrangler.jsoncbun bin/brine.ts card example/src/interview.ts --company "Sam's Bakery" --mark logo.svg --out publicwrites public/card.png, the link preview for the invite: who the interview is for, a heading,
how long a sitting takes (estimated from the kinds of questions a walk asks) and how many
questions. Serve it next to the page and point og:image at its absolute URL; the command prints
the tags. It needs the optional @resvg/resvg-js.
export BRINE_ADMIN_TOKEN=…
bun bin/brine.ts invite https://your.worker.dev "Sam Baker" # prints the link to send
bun bin/brine.ts status https://your.worker.dev
bun bin/brine.ts export https://your.worker.dev ./answers # answers.json + answers.mdanswers.md lists every asked question with its why and yields, the answer, verbatim
transcripts and Jev's reads. Hand it to Claude with the skill loaded and ask for the features.
{
id: "wholesale", kind: "long",
ask: "Walk me through the last wholesale order, from the call to the van leaving.",
when: { q: "sources", is: "wholesale" }, // only if they take wholesale
decide: { exception }, // Jev: does the answer name an exception?
why: "The wholesale path end to end, from a real instance.", // designer only
yields: "Scenario: a wholesale order — Given/When/Then", // designer only
},
{
id: "wholesale_exception", kind: "long",
ask: "You mentioned it sometimes goes differently. Tell me about the last time it did.",
when: { q: "wholesale", decision: "exception", is: "yes" },
why: "…", yields: "Scenario: wholesale exception",
}Kinds: long, text, choice, multi, number, scale. Guards: is, not, answered,
atLeast, decision, and all / any / none. A decision's fallback is used when there is no
model, so pick the result that asks more.
The first round is not the end. Write the as-is features from answers.md with @q: tags and
# TODO / # IDEA / # CONFLICT markers, rule on the conflicts (# RULED:), write the product
specs, fit them onto a shared step set, then send a short second round that reads the rules back:
bun bin/brine.ts trace questions.ts answers/answers.json features/**/*.feature # every @q: resolves, every answer cited
bun bin/brine.ts followup round-2 "Did we get it right?" features/**/*.feature > round2.ts # draft; rewrite in their wordsScenarios hold behavior. Everything else the respondent said (numbers, timers, rules, their wording, real cases, red flags, terms, wishes, risks, what they watch) goes into one fact ledger, each fact cited to its answers, and every other artifact is projected from it:
bun bin/brine.ts ledger check questions.ts ledger.json answers/answers.json # well formed, every citation a question
bun bin/brine.ts ledger emit ledger.json number timer rule template > src/facts.gen.ts # code reads constants by id
bun bin/brine.ts ledger render ledger.json idea # the backlog (risk, term, ... likewise)
bun bin/brine.ts ledger records answers/answers.json ledger.json features/**/*.feature > answers.jsonl # retrievalThe steps are in skills/brine/SKILL.md; the markers and the step pass in
skills/brine/references/gherkin.md; the ledger's kinds, projections and checks, ranked, in
skills/brine/references/derivations.md.
Apache License 2.0. See LICENSE.

