Build Thrumble
KINDAreplaces $99/mosaves $1,188/yrback to the verdict
One inbound number answered by a speech to model to speech loop that discloses what it is, obtains consent before recording, keeps the response latency inside the budget a conversation tolerates, hands off to a person when it should, and deletes recordings on a schedule you configured.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- installfree
Why Runs the media pipeline and the agent loop.
Get it nodejs.org, or nvm install 22. open ↗
Verify
node --version prints v22 or higher - decidean hour of advice, and it is the cheapest part of getting this wrong
Why It determines the first sentence the agent says and whether you may record at all. Consent rules differ by jurisdiction and disclosure of automation is required in some places, so this decides the build rather than following it.
Get it Identify every jurisdiction a caller might be in, take the strictest applicable rule, and confirm your position with someone qualified if this is commercial. Record what you concluded and when.
Verify
A written note names the jurisdictions, the rule applied and the date confirmed - API keya number is typically a few US dollars a month plus per-minute charges
Why You need the raw audio both ways. Many products give you call control without the media, which cannot support this.
Get it Choose a provider that offers a bidirectional media stream over a socket, and take a number in the country you will answer in. Confirm media streaming is available on your plan before building.
Verify
Audio arrives from a real call and audio you send is heard - API keypriced per minute and per token; a three minute call is typically a few cents and adds up quickly under load
Why All three must stream. Any one of them batching adds a second the caller feels.
Get it Providers for each, chosen for streaming support rather than accuracy alone. Set spend limits when you create the keys.
Verify
Each streams partial output rather than returning at the end - have readyfree
Why Latency, interruption and transcription accuracy all behave differently on a real call than in a local test, and background noise is the normal case.
Get it Your own phone. Test from a car or a street as well as from a desk.
Verify
Ten real calls have been made and their timings recorded - decidefree
Why Recordings, transcripts, summaries and consent records may have different periods, and automatic deletion has to be built rather than remembered.
Get it Write it before launch: what is kept, for how long, and why. Consent records usually outlive recordings because they are the evidence you were entitled to record.
Verify
The policy is written and the deletion job implements it
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- calls(id, direction, from_hash, to_number, started_at, ended_at, outcome, disclosed_at, consent_state, jurisdiction) - turns(id, call_id, ordinal, speaker, text, started_ms, ended_ms, latency_ms) · speaker is caller or agent - recordings(call_id, storage_key, encrypted, expires_at, deleted_at) · nullable, because consent may be refused - tool_calls(id, call_id, turn_id, name, arguments_json, result_summary, duration_ms) - handoffs(call_id, at, reason, destination) - retention_runs(at, deleted_count) · proof that automatic deletion actually ran - A call with consent refused has no recording row. The absence is the record, and the transcript retention is a separate decision.
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
DATABASE_URLsecret | required | postgres://user:pass@localhost:5432/calls | Calls, turns and consent records. Personal data with retention obligations. |
RECORDINGS_BUCKET | required | call-recordings | Encrypted at rest, with lifecycle expiry set as a second line of defence. |
DISCLOSURE_CONFIG | required | ./config/disclosure.json | What the agent says first, per jurisdiction. Configuration so it can change without a deploy. |
RESPONSE_BUDGET_MS | required | 900 | Target gap from the caller finishing to the agent speaking. Breaches are logged. |
MAX_TOOL_CALLS_PER_CALL | required | 6 | Cap, so a looping agent cannot produce a long silence and a large bill. |
RECORDING_RETENTION_DAYS | required | 30 | Per your written policy. Deletion is automatic and logged. |
CONSENT_RETENTION_DAYS | required | 2555 | Usually longer than the recording, because it is the evidence you were entitled to make it. |
The build, in order
Answer, disclose, and ask before recording
The number answers, says what it is, and does not record until it has permission.
A provider that gives you the audio stream. Confirm you can receive and send audio before anything else.
Files
src/telephony.tsAutomated system, who for, recording, why, how to object. Configuration, not a string in code.
Files
config/disclosure.jsonNothing to disk before consent. Refusal is a supported path with the call continuing.
Files
src/consent.ts
done when · tick each as it passeswatch out- Starting the recording at pickup and disclosing afterwards means you recorded before consent, which is the thing the rules exist to prevent. Buffer nothing to disk until consent is given, and make refusal a supported path rather than a failure, because a caller who says no still deserves service.
The latency budget, measured
The agent replies fast enough that the caller does not think the line dropped.
Use them to detect end of speech rather than waiting for a final result.
Files
src/stt.tsSynthesis begins before generation finishes. This is where most of the perceived latency goes.
Files
src/tts.tsTranscription, generation, synthesis and total, per turn. You cannot tune what you have not measured.
Files
src/metrics.ts
done when · tick each as it passeswatch out- Waiting for a final transcript, then a full model response, then a full synthesis before speaking produces several seconds of silence, and callers hang up or start talking again. Overlap the stages: interim transcription while they speak, generation as soon as they stop, speech as soon as the first sentence exists.
Interruption, which is how people talk
A caller can interrupt the agent and the agent stops.
Voice activity on the inbound stream while outbound audio is playing.
Files
src/barge.tsCancel synthesis and drop the queued audio. A half second of continued speech feels rude.
Files
src/tts.tsTruncated at the interruption and marked. The transcript must match the conversation.
Files
src/turns.ts
done when · tick each as it passeswatch out- Recording the full generated reply in the transcript when the caller interrupted halfway makes the transcript disagree with the conversation, and any summary built from it describes things that were never said. Log what was actually spoken, and mark it as interrupted.
One tool, and knowing when to stop
The agent can look one thing up, and it does not invent an answer when it cannot.
Something genuinely useful to a caller. One is enough to prove the pattern.
Files
src/tools.tsIn the prompt and in a check. Test with a question outside the data.
Files
config/prompt.mdPer turn and per call. An agent looping on tools produces a long silence and a large bill.
Files
src/agent.ts
done when · tick each as it passeswatch out- An agent that answers a factual question without the tool because it sounds plausible will tell a caller something wrong in your organisation's voice, and they will act on it. Constrain the prompt to answer only from tool results for anything factual, and test with a question whose answer is not in the data.
Handing off to a person
The agent transfers when it should, and the caller does not have to repeat themselves.
No negotiation, no retention attempt. This is the behaviour that earns trust.
Files
src/handoff.tsTwo consecutive low-confidence turns is a transfer condition rather than a third try.
Files
src/handoff.tsSo the caller does not start again. This is most of the value of the handoff.
Files
src/summary.ts
done when · tick each as it passeswatch out- An agent that will not transfer traps the caller in a loop, which is the experience that makes people hate these systems. Transfer on the first explicit request without argument, and treat two consecutive failures to understand as a transfer condition rather than a third attempt.
Retention, deletion and the record you must keepproduct builder
Recordings expire automatically and you can prove they did.
The period comes from your written policy, which comes from the position you settled in rule zero.
Files
src/retention.tsdocs/retention.mdA policy that relies on someone remembering is not automatic deletion.
Files
src/retention.tsCovering every artefact. Keep the consent record, which is your evidence.
Files
src/requests.ts
done when · tick each as it passeswatch out- Deleting the recording but keeping the transcript, or the reverse, satisfies neither the retention policy nor the caller's expectation. Decide what each retention period covers, apply it to every artefact, and keep the consent record longer than the recording because it is the evidence that you were entitled to make it.
That is the whole plan for Thrumble. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- Outbound campaigns and their separate legal surface.
- Production telephony operations at volume.
- Legal advice about your consent position.
- The agent quality of a platform tuned on many thousands of calls.
- hosted agent builder, knowledge bases, tools, and transfer destinations
- outbound campaign dialer and contact workflows
- managed phone numbers, concurrency, and telephony debugging
- call logs, recordings, post-call extraction, and analytics
- uptime, support, and multi-tenant workspace polish
- A second language, which mostly means a second disclosure and a different speech pipeline
- Post-call summaries written into whatever system your team already uses
- Sentiment or outcome tagging, once you have enough calls for it to mean anything
Need the files? The project pack on the verdict page hands your agent the whole brief · more voice ai.