At the end of a shift a construction foreman reports hours out loud, and weeks later a worker disputes the number on his paycheck. The only record is the foreman's memory. CrewVoice keeps the habit - talking - and adds a record that can be checked. The foreman presses Start and says 'Jose worked nine hours today'. The agent runs on the AssemblyAI Voice Agent API (speech in, speech out, tool calls in the middle) and calls record_hours, which only ever creates a PENDING row. The agent reads the name and hours back; the row is confirmed only after the foreman says yes. Pending rows never reach payroll. The rules live in the tools, not in the prompt, so the model cannot talk its way past them: hours outside 0-16 for one day are refused and re-asked; a name that is not on the crew list comes back as a question with candidates, never a guess; a second entry that pushes someone past a full day asks whether it replaces the first. Names are folded before matching (accents, first names, surnames, short forms), so 'Jose' from speech recognition and 'Jose Ramirez' on the crew list are the same person, and English and Spanish reports land on the same sheet. At the end of the day the agent lists who was never mentioned. /export.csv contains confirmed rows only, each with heard_as (what recognition produced) and source_utterance (the sentence it came from), so a disputed hour is settled by the record. Stack: FastAPI bridge that keeps the API key on the server, WebSocket to AssemblyAI with PCM16 24 kHz audio, AudioWorklets in the browser. Deployed on Render, MIT licensed.
Category tags: