Skip to content
Arslan Vuzmal Lone
PROJECT · SUPPORT · VOICE AI & SUPERVISED AUTOMATION

VoxCircuit: voice and chat that can book and update records, with a person approving the risky parts

Phone, web voice and web chat land in one conversation record. The AI agent can only propose an action; a plain-code policy decides whether it runs, waits for a person, or is refused. The product is called VoxDesk; the repository is VoxCircuit.

By Arslan Vuzmal Lone·Built August 2026·Updated August 2026·Open source
VoxCircuit → proposed actions in one conversationPolicy 2026-08-12.1
ALLOWcheck_availability
risk 5 · LOWruns
ALLOWbook_appointment
risk 35 · MEDIUMruns
HOLDreschedule_appointment
identity not verified · risk 75ESCALATE
DENYschedule_callback
contact opted outrefused
Figure 1:What the policy returns for typical requests. Sample data.

At a glance

FOR
Service businesses that take bookings and requests by phone and chat
DOES
Answer · propose actions · policy check · human approval · audit
INPUT
Phone (Telnyx), web voice (ElevenLabs), authenticated web chat
OUTPUT
Contacts, appointments, tasks, follow-ups and handoffs, with an audit trail
BUILT WITH
Next.js 16, TypeScript, Prisma, PostgreSQL 16, Zod
HUMAN IN LOOP
Risky actions wait for a person with approval permission

Letting an AI answer the phone is easy. Letting it change your records is the hard part.

A chatbot that only talks can be wrong and nobody is hurt. Once it can book, cancel, update a contact or call someone back, every action needs to be the right customer, the right business, not a duplicate, and allowed.

VoxCircuit treats whatever the model asks for as a request, not a permission. The request is checked, scored and either run, held for a person, or refused, and every step is written down.

One requested action, from proposal to recordStep 1 of 4
Step 01

Proposal

During a call or chat the agent proposes a tool call, for example reschedule_appointment.


How it works

Each stage as it exists in the repository. Select a stage to see what it uses and what happens when it fails.

How it runsSelect a step · arrow keys move
Channel
Conversation
Authority
Record
Step 01 · Channel

Phone, web voice, web chat

What happens

Each channel is normalised into one Conversation (a phone call also gets a Call record)

Uses

Telnyx adapter, ElevenLabs adapter, authenticated POST route

If it fails

Simulation mode is the default; live mode refuses to start without full configuration


Execution sequence

One item, traced through the system boundaries.

A caller asks to move an appointment
  1. Caller to Voice agent: “Can I move Thursday to Friday?”
  2. Voice agent to VoxCircuit: propose reschedule_appointment
  3. VoxCircuit to VoxCircuit: schema + token + policy (identity not verified → ESCALATE)
  4. VoxCircuit to Staff approver: approval request (15 min)
  5. Staff approver replies to VoxCircuit: approve exact payload
  6. VoxCircuit replies to Voice agent: rescheduled; result stored once
  7. Voice agent to Caller: “You’re booked for Friday.”

One item, start to finish

1. Conversation opens

A web voice session starts against a verified agent version; a Conversation and its state are created.

2. Action proposed

The caller asks to reschedule. The agent proposes the tool call with the new time.

3. Held for a person

Rescheduling needs a verified identity. It was not verified, so the policy escalates.

4. Approved and recorded

A staff member approves the exact payload. The change runs once and the decision is in the audit log.


The policy that decides what the agent may do

Pick the tool the agent wants to call and set the session facts. The scoring is the repository’s deterministic policy, copied rule for rule.

The voice or chat agent can only propose a tool call. This policy, in plain code, decides whether it runs, waits for a person, or is refused.

ESCALATErisk 75 · HIGH
IDENTITY_NOT_VERIFIED +25
Risk 60 or more escalates to a person with tools:approve permission. Opt-out and handoff requests are always allowed. Outbound contact with a suppressed contact is denied.

Logic copied from VoxCircuit lib/security/tool-governance.ts (policy version 2026-08-12.1). Inputs are yours to change; nothing here calls a model or a server.


Architecture

The layers and the decision path, taken from the repository code.

System Architecture StackTop-down request path
System Architecture Stack
LayerComponentTech StackResponsibility
Layer 1: ChannelsTelephony and voice adaptersTelnyx (PSTN/SIP), ElevenLabs (realtime voice), simulation providerTransport only; no business decisions
Layer 2: ConversationCanonical conversationKEYNext.js 16 API routes, Prisma, PostgreSQL 16One record per interaction, persisted state
Layer 3: AuthorityTool governanceKEYZod, signed context, deterministic policy, approvalsDecides ALLOW, DENY or ESCALATE
Layer 4: OperationsDomain services and auditSerialisable transactions, event inbox, background jobsContacts, appointments, tasks, handoffs, reconciliation
VoxCircuit decision pathRed dashed line = fallback route
  • Call / chat goes to Agent proposes: turn
  • Agent proposes goes to Policy: tool call
  • Policy goes to Execute once: ALLOW
  • Policy falls back to Human approval: ESCALATE
  • Policy falls back to Refused: DENY
  • Human approval goes to Execute once: approved

Decisions and trade-offs

DecisionInstead ofWhyWhere in the code
The model proposes; code decidesLetting the agent call business APIs directlyA plausible payload is not permission. Policy, identity and approval sit between the model and the database.lib/voice-agent/tool-executor.ts, lib/security/tool-governance.ts
Execute-once fingerprintsTrusting retries not to repeatNetwork and agent retries are normal. The same action returns the stored result instead of booking twice.lib/voice-agent/tool-executor.ts (operationFingerprint)
Simulation by defaultLive telephony in developmentSimulation creates sim_ records and never touches a carrier, so the whole flow can be exercised without paid calls.lib/telephony/mode.ts, lib/telephony/providers/simulation.ts
Verify provider events on the raw bodyAccepting webhooks after JSON parsingSignatures are checked on the exact bytes received, with a five-minute window and event-ID de-duplication.lib/telephony/providers/telnyx.ts
Source: Read from github.com/arslanvuzmal/VoxCircuit

What went wrong first

Web voice said “ready” too early

The first version decided the voice demo was ready before the provider had actually authorised a conversation. The fix made the signed conversation URL the readiness boundary and moved provider authorisation behind the authenticated bootstrap step.

Pull request #31, 14 August 2026 ↗

An unchecked agent identifier

The voice bootstrap accepted the configured agent identifier without validating it. A follow-up change added the check.

Pull request #34, 15 August 2026 ↗

Results

Only numbers produced by a committed, repeatable script appear here as measured. Until then, each result says how it will be measured.

To be measured
Voice round-trip latency

Only stages that can be run locally will be timed; anything that needs live Telnyx calls is labelled not measured.

To be measured
Policy decisions on a fixed scenario set

ALLOW / ESCALATE / DENY counts for a committed list of scenarios, run through the repository’s test suite.

To be measured
Calls answered for a business

Only measurable with a client running live telephony.


Run it yourself

Local development from the README. Telephony stays in simulation mode. Full instructions ↗

bash
git clone https://github.com/arslanvuzmal/VoxCircuit.git
cd VoxCircuit
npm ci
cp .env.example .env.local
docker compose up -d
npx prisma migrate dev
npm run dev
Versions: Node.js 20+ · PostgreSQL 16 · Next.js 16

Questions people ask first

Can the AI change records on its own?

Only low-risk actions that pass the policy. Anything scored 60 or above, or needing a verified identity it does not have, waits for a person with approval permission.

What happens if the same request arrives twice?

Each action carries a fingerprint of its exact payload. A repeat returns the first result instead of running again.

Does it make real phone calls?

It can, through Telnyx and ElevenLabs, once those accounts and secrets are configured. Out of the box it runs in simulation mode and never contacts a carrier.

Is there a demo I can try?

Yes, the public demo at vox-desk.vercel.app/demo.

Related reading & systems

Want VoxCircuit working in your business?

Book a 20-minute scoping call. I will review your current systems, map where manual friction is costing you time, and give you an honest quote.

AI Workflow Audit · €390 · Credited toward build · or email arslanvuzmallone@gmail.com