Inspiration

The person this is for walks out of a consulting room holding nothing. In a study of 42 adults tested on twenty items after a 45-minute orthodontic consultation at a private dental practice, mean recall was 75%, and three of the forty-two got all twenty. It is one small single-site study, and we quote it as a floor. BRFSS 2022 puts 11.3% of US adults aged 45 and over reporting confusion or memory loss that is getting worse; 31.4% of them need help with daily activities, and only 44.3% have told a clinician about it. Among older-adult carers, 36.5% give twenty hours a week or more.

Plaud and Abridge both work this room and both point the output at the clinician. The patient is the unserved party, and none of Bee, Limitless, Plaud, Omi or Abridge publishes a bystander consent mechanism at all. That gap is what made this buildable rather than only useful.

What it does

Second Chair announces itself out loud, records the answer, and refuses to keep a transcript without both. Afterwards it gives you a recap in plain words, the medication changes as structured rows each nailed to a verbatim quote, the questions you meant to ask and did not, and a narrower summary for the relative who could not come. It will not tell you a dose, whether to skip one, or whether a symptom is serious.

How we built it

There is no start button anywhere in this app.

That sounds like a design flourish and it is actually the constraint everything else was built around. The person Second Chair is for is the person who forgets, which is why a wearable is defensible here at all, and a product for that person cannot depend on them remembering to open it before an appointment. So capture is already running when the consultation begins, and consent has to be found inside a stream rather than handed to a session on construction.

establish() reads the stream for the announcement the wearer says out loud, takes the utterance that follows as the reply, and rules on it. Four outcomes. Granted keeps the transcript. Refused, unanswered and never-announced keep nothing, and in every case the consent record survives, because it is the proof that nothing else did. An ambiguous answer falls to refusal on purpose: being wrong that way costs one recording, and being wrong the other way costs a bystander their consent and $5,000 a violation under California Penal Code 637.2, with no actual damages required. "No, that's fine" comes out REFUSED. Refusal patterns are matched before assent patterns for that reason, and a missing word boundary once made a plain "No," read as no answer at all, which shipped for about ten minutes and is now pinned by the test that caught it.

The clinic is also the room where the usual escape does not exist. A lecture hall falls outside Penal Code 632 on its own, exempted as a public gathering; a consulting room is the room 632 was actually written for. The only route out is 632(b), which excludes anyone known by all parties to be recording, with RCW 9.73.030(3) supplying the procedure. Announce, record the announcement, or there is nothing.

/replay is the demo, and it shows the refusal first. The band across the top is brass while the gate is shut, the waiting room goes past struck through, the announcement lands and pins itself, the answer lands and the band turns verdigris. Change one dropdown to "No, I'd rather you didn't record this" and the same code takes the other branch: oxblood, every line struck through, the consent record all that survives.

Past the gate, the feature that justifies the hardware is the week. collisions.py sets the appointment against GET /v1/facts from the days either side: the ibuprofen question you wrote down and did not ask, against the Sunday conversation where you were recorded saying you take it most days. A phone with a record button holds one room. Bee holds the week. A collision states two recorded things and the relationship between them, and never draws the conclusion, because "ask about the ibuprofen, it can interact with your blood thinner" is medicine and this app does not practise it.

Amazon Bedrock does three jobs here, none of them decoration, split across two different chains. The plain-language recap and the medication extraction into structured rows run on FAST_MODELS: us.anthropic.claude-sonnet-5 first so the build upgrades itself when access lands, falling through to claude-sonnet-4-6, claude-sonnet-4-5-20250929-v1:0, then claude-haiku-4-5-20251001-v1:0. Deciding "covered" from "partly covered" on the question list runs on a separate chain, JUDGEMENT_MODELS: claude-opus-5, falling through to claude-opus-4-5-20251101-v1:0 and, as a last resort, back to claude-sonnet-4-6. The harder call gets the stronger model on purpose. On the ask surface the model may choose which utterances to show and may never write the answer, so the text on screen is copied out of storage by index. Losing Bedrock is a stated outcome rather than a quiet downgrade: in a clinical setting a half-written summary is worse than none, so the recap says no recap was written and shows the record in the words that were used, quoted and cited line by line.

Python and FastAPI, server-rendered, ten templates. Bee is mocked at one place, the HTTP call. MockBeeTransport answers the full documented set of routes, but the product itself calls three: the stream, and read-and-write on facts and on todos, with week.json there because the cross-day feature needs a week and not a room. Every fixture utterance carries Unknown as the speaker, and a test scrambles every label and asserts the output is byte-identical. 405 tests pass, 11 skipped, no AWS credentials needed.

Challenges we ran into

The dangerous bug was in a field nobody thought of as text. The medication rows carried an optional short note, and beside a real drug name Sonnet 4.6 wrote "Stop immediately, no taper needed" and "Take half a five milligram tablet until current box runs out". Both were faithful to the transcript and both are generated dosing instructions on a screen a patient reads. Every other field in the row was verified against a verbatim quote; this one was prose, so nothing checked it. A study in which GPT-3.5 rewrote 100 real discharge summaries found potentially harmful safety issues attributable to the tool in 18% of cases, and this is exactly that failure. The field is no longer read from the model at all, and eight tests pin it. Looking at the rendered page rather than the passing suite is what found it.

The honest argument against this product is that a phone with a record button captures the same audio, and the entire case for a wearable rests on one unverified claim: that a person whose defining problem is forgetting will also forget to press record. Across 1,500 recent r/ADHD posts, "consent" and "privacy" appear zero times and "recording" seven. So there is no start button anywhere in the app. The announcement does the work a record button would have done, and it fails loudly, in front of a witness, which is the only kind of failure a forgetful person recovers from.

bedrock-runtime also has no per-request deadline, only socket timeouts, so a slow generation that keeps dribbling bytes can outlive any wall clock you had in mind. Every call runs on a worker thread against our own deadline.

Accomplishments that we're proud of

The product refuses to become the record of truth. The transcript expires on a clock shown on the front page, any medicine row can be overruled by the clinic's printed summary, the export opens and closes by saying the clinic's own summary is the one that counts, and "destroy everything" destroys the consent ledger too rather than quietly re-ingesting from Bee afterwards.

What we learned

An optional free-text field in a structured extraction schema is an unguarded output channel, and it will be the one that hurts somebody.

What's next

A live Bee account, the institution's own visitor policy wording in place of ours, and a stronger consent certificate co-signed by the clinic.

Built With

Share this project:

Updates

Submission history