Governed voice agents

Every turn asks permission.

The governance engine sits between the agent and everything it can see, say and do. One policy primitive, synced from your systems, explains every turn — and it is the one boundary the learner cannot cross.

A trustworthy agent is not one that behaves well. It is one that could not misbehave if it tried — because it never held the field, the line or the permission.

Four questions, one engine

See. Say. Do. Why.

See

Fields and records, not databases.

The agent reads due_amount, never the card number; the DPD bucket, never the credit score. Only accounts in its assigned portfolio, only inside calling hours.

Say

Frozen lines, tone by bucket.

AI disclosure, consent and the grievance line are exact-match. Tone is set by DPD bucket, languages are enumerated, banned phrases are enforced before speech.

Do

Actions carry a tier.

Promise-to-pay, payment link and callback are automatic. A fee waiver waits for a human. Transfers go warm, to a named queue. A deny anywhere beats an allow anywhere.

Why

Every turn has a receipt.

Which policy permitted it, which client system it was synced from, when the grant expires. formant policy --explain answers it for any turn, any call.

One primitive

A policy is agents × customers × permissions.

There is no separate permissions screen, prompt rule and escalation sheet to keep in step. A policy names a group of agents, a set of customers or journeys, and what those agents may see, say and do for them. Policies nest — tenant, journey, pod — and the lower level only ever narrows the one above.

Deny rules win. A tenant-wide deny on PII cannot be undone by a campaign pod, by a prompt edit, or by a learned improvement.

Policy hierarchy · tenant → journey → pod
Tenantlender · all agents
denycard_number · credit_score · Aadhaar · PAN — for every agent, every journey
sayAI disclosure · recording consent · grievance line — frozen, exact match🔒
syncLMS · do-not-call list · RBI FPC calling-hour map
Journeycollections · bucket 1
seedue_amount · dpd_bucket · last_payment · promise history
saytone bucket-1 · Hindi / Hinglish / Tamil · no threat vocabulary
docapture PTP · send link · schedule callback auto · waive fee approval
Podsep-campaign-b1 · expires 21 Sep
seerecords in portfolio B1-west only · 08:00–19:00 IST
dotransfer → queue b1-west-humans (warm, with brief)
grant7-day campaign grant · auto-revokes · nothing inherits from a dead podexp
a pod inherits the journey, the journey inherits the tenant · a deny anywhere above beats an allow anywhere below
Why · access provenance

One turn, explained.

Every turn the engine writes a trace: the fields it read and the policy that allowed each; the fields it was refused and the deny that refused them; the actions it took, and the ones it parked for a human. The trace is what your audit reads.

formant policy --explain · call c_7f3a9 · turn 6
$ formant policy --explain --call c_7f3a9 --turn 6
agent collections-hi · 14:02:40 IST · customer ████1174 · portfolio B1-west
✓ see due_amount · dpd_bucket · last_payment_date ← pod.sep-b1 ⊂ journey.collections ⊂ tenant
✗ see card_number · credit_score ← tenant.deny.pii · deny wins over pod allow
✓ see record ████1174 in assigned portfolio · calling window 08:00–19:00 ← rbi_fpc map v3
✓ say tone=bucket-1 · lang=hi-IN|hinglish · frozen: ai_disclosure ✓ grievance_line ✓
✓ do capture_ptp auto · send_payment_link auto · schedule_callback auto
! do waive_late_fee → needs approval · floor supervisor
synced: LMS 14:01:58 · do-not-call 13:55:00 · grant pod.sep-b1 expires 21 Sep 23:59
verdict turn allowed · trace tr_… written · retained per policy

Illustrative trace. replace with a live --explain

Action log · allowed / denied · one call
14:02:11ai_disclosurefrozen line · exact match · tenant.say
14:02:15identity_verifiedmethod=dob · fields: name, dob
14:02:19read_fielddue_amount · dpd_bucket · journey.see
14:02:19read_fieldcredit_score · denied · tenant.deny.pii
14:02:40calling_window14:02 IST in 08:00–19:00 · rbi_fpc v3
14:03:12capture_ptpdate=2026-09-18 · tier=auto
14:03:20send_payment_linkchannel=whatsapp · consent=yes · tier=auto
14:03:41waive_late_feeheld · tier=approval · floor supervisor!
14:03:58disclose_to_third_partycaller not RPC · denied · deny wins
14:04:10trace_writtentr_… · synced LMS 14:01:58 · DNC 13:55

Illustrative call. replace with a live action log

Do · approval tiers

Automatic, approved, or never.

Every action the agent can take carries a tier and a source. The tier decides who acts; the source is the client system or policy the rule was synced from — so your risk team can trace a waiver back to the sheet it came from.

Action register · collections · bucket 1
ActionTierWho decidesWhere the rule comes from
capture_promise_to_payautothe agent, inside calling hoursjourney.collections · LMS field map
send_payment_linkautothe agent, on an opted-in channel onlyjourney.collections · DPDP consent flag
schedule_callbackautothe agent, within the RBI FPC windowtenant.sync.rbi_fpc_map
waive_late_feeapprovalfloor supervisor, in the dashboard, mid-calljourney.collections.approvals
offer_settlementapprovalcredit operations, before the line is spokentenant.approvals.credit
transfer_to_humanauto · warmthe agent, to the named queue onlypod.sep-campaign-b1.queues
disclose_to_third_partydeniedno one — not the agent, not a supervisortenant.deny · RBI FPC · deny wins

Illustrative register for one journey. replace with the client's approval matrix

Policy sync · continuous
LMSfield_mapdue_amount · dpd_bucket · portfolio — pulled every minute; a field removed upstream disappears from the agent's view on the next turn
DNCdo_not_callthe do-not-call list is a record-level deny; a number added at 13:55 is unreachable at 13:56
FPCrbi_fpc_mapcalling hours, tone vocabulary and grievance line mapped to policy rules, version-hashed
PODgrant_expirysep-campaign-b1 · 7-day grant · revokes itself on 21 Sep 23:59; nothing needs to remember to switch it offexp
Synced, not copied

Your systems stay the source of truth.

Policies are not a document we write once. They are synced continuously from the client's loan management system, do-not-call list and the RBI Fair Practices Code mapping your compliance team owns. When a rule changes upstream, the agent's permission changes with it — no release required.

Grants expire. A campaign pod gets seven days and takes its access with it when it ends.

What the agent may remember
The boundary of learning

The learner improves the agent. It cannot touch the policy.

The weekly learning cycle fine-tunes phrasing, objection handling and intent recognition from graded calls. Governance is the one thing it never trains on: a governed line is checked by exact match, not by a model, and a candidate that moves one is blocked by the evaluation gate before a human even sees it.

Release gate · candidate v43 · governed diff
learned"already paid via UPI" handled in Hinglish — 212 corrected callsallowed
learnedshorter greeting; reads "19 tareekh" in Hindiallowed
governedAI disclosure line · hash unchangedexact ✓
governedgrievance line · hash unchangedexact ✓
blockedcandidate paraphrased the consent statement in Tamildiff ≠ 0 · release stopped
governed lines: 0 learnable tokens · a policy edit is a policy release, signed by its owner — never a model release

Illustrative gate. replace with a real candidate diff

FAQ

What your risk team will ask.

Who can change a policy, and how do we know it changed?
A named owner on your side — typically compliance or the collections head — through the policy console or your own system of record. Every policy version is hashed and signed; every turn's trace names the version that permitted it, so a change is visible in the audit the minute it takes effect.
Can a prompt edit, a fine-tune or a clever customer widen what the agent can see?
No. Field- and record-level access is enforced by the engine before the model is called: a field the policy denies is never in the context, so there is nothing to talk the agent into revealing. The learner trains on graded calls, never on policy, and governed lines are exact-match on every release.
How do calling hours, do-not-call and the Fair Practices Code get in?
They are synced from your systems, not retyped. The RBI FPC mapping your team owns becomes policy rules (calling window, tone vocabulary, grievance line); the do-not-call list is a record-level deny refreshed continuously; a number added to it is unreachable on the next dial.
What does the auditor actually get?
Per call: the action log (allowed, denied, held for approval) and, for any turn, the provenance trace — the policy path, the source system, the sync time and the grant expiry. It is exportable, retained per your policy, and lives inside your deployment, whether VPC or on-prem.
Under NDA

Read one call's trace.

See a policy trace
Readiness

Map your policies before the pilot

Get a Call Readiness report