Voice and chat agents that understand people and act safely.
Callers talk naturally, and the system maps what they mean to the right action. A fast decision
model reads what was said and answers typed questions; it never writes the reply. What the agent
says and does is predictable: the lines are fixed, code decides what happens next, and a policy
gate checks every action. Replies are fast, because a decision is a short typed question, not a
composed answer.
An open-source TypeScript framework. Apache-2.0. Pre-release. Runs on a laptop with no keys.
How it works
Three parts, each with one job. The model never decides, and the code never guesses.
1 The model understands
A fast decision model reads what the caller said and answers typed questions: is this a request
to reschedule, which of these three appointments, what date was given. It returns judgments with
probabilities, never generated text. Callers can say it in their own words, give three answers
at once or change their mind.
2 Code decides
Deterministic code owns the dialog: which form is active, which slot to ask next, when to read
back, when to hand off to a person. The same judgments and state always lead to the same step,
and every line the caller hears is a fixed, approved line filled with checked values.
3 The gate checks every action
Before any tool runs, a policy gate checks the caller's identity level, whose record it is,
exact confirmation, role and attempt limits. The gate does not read the conversation, so no one
can talk past it. Every decision, allowed or refused, goes to a hash-chained audit log.
Reproducible. Replay a call against its recorded model answers and get the same outcome.
Explainable. The audit names the rule that passed or failed, and what it compared.
Not steerable by the caller. What a caller says is data the model classifies, never instructions the code follows.
Tunable. Thresholds are numbers, adjusted by measurement rather than by rewording a prompt.
An app is a folder
YAML for what is data: intents, forms, slots, prompts, policy, identity, locales. TypeScript for what
runs: tools, form hooks, rules of your own. defineApp joins the two. Most slots are
configuration: name a type from the slot library (digits, choice,
date, birthdate, name, record, text)
and give it a few options.
It reads every YAML file against its schema and cross-checks the folder against the code: a slot a
form names that does not exist, a line the engine needs that no prompt provides, a tool with no
policy. Each problem is one line, file:line:column path message -> fix,
written for a person or an assistant to act on. Here is the first line it printed for a misspelt slot
name in the utility's forms.yaml, and the run after the fix:
$ pnpm check
forms.yaml:11:20 forms.report_outage.slots[1] slot "symptm" is not defined -> rename it to "symptom", or add "symptm:" to slots.yaml (a library type, or { type: code } with the slot in src/app.ts (code.slots.symptm))
$ pnpm check
apps/clinic: ok
apps/utility: ok
Built for AI coding assistants
The repository is written to be read by an AI coding assistant as well as by you. A root
CLAUDE.md
gives the roles, the commands and the rules,
llms.txt
indexes the docs, and every app has a CLAUDE.md of its own.
The create-app skill
The procedure an assistant follows to turn a paragraph into an app: a worksheet, the mapping onto
slot types, policy and identity, the scaffold, the corpus and scripted calls, then the checks until
they pass. It comes with a page of verified patterns and a corpus guide.
The scaffold the skill calls. It writes a small app under apps/<name> that passes
pnpm check, its own tests and its regression as created. Add --identity for
an app that verifies its callers.
Two fresh assistants, with no context from the people who built the framework, were each given one
paragraph (a fictional electric utility, a fictional transit agency) and told to use the skill. Each
built a working app, in about 15 and 11 minutes by their own count, with pnpm check and
the scripted calls green. Both caught the same real hole in their own policy by reading the policy
matrix: a delegate could have had a one-time code texted to someone else's phone. The engine now
refuses that for every app. Every stumble they logged was fixed or recorded with its reason.
Policy is a file, not code. policy.yaml names the rules each action runs, and
identity.yaml says who the app serves and how a caller proves who they are. Both compile
to what the gate runs. Three generated pages make a change readable by someone who does not write code:
POLICY.md, the policy card: each action and each rule in plain English, with diagrams, written from the same compiled policy the gate runs.
policy.matrix: for every action and every kind of caller, the verdict and its reason, so a policy change shows up as a diff of what the gate decides.
APP-MAP.md: the app's intents, forms, slots, actions and rules as diagrams.
Each is written by a command and compared by a test, never written by CI.
CODEOWNERS
makes a change to the policy files and these pages need compliance's review.
From apps/utility/policy.matrix:
who may set up a payment arrangement. A customer needs the one-time code (level 2), their own account
and an exact read-back; a property manager goes to a person.
Two fictional organizations. Every name, date and number in them is made up, and neither needs a key to run.
Example Family Practice
A clinic's appointment line: a caller can schedule, reschedule, cancel or confirm an appointment
with one of eight providers. The first app to read. It has every slot configured from the slot
library, writes that go through the gate after a read-back, 241 labelled utterances and 89
scripted calls.
An electric utility's phone and chat line, built by an AI coding assistant from one paragraph.
Report an outage, hear a balance after verifying, or set up a payment arrangement behind a
one-time code. A property manager acts for their buildings. The app to read for identity and policy.
Start an app of your own. It passes the checks as created; add --identity for one that verifies callers.
pnpm create-app <name>
Then read Authoring an app,
or give an AI coding assistant a paragraph describing your app and point it at the
create-app skill.
Pre-release: APIs will change, and the package is not on npm yet. Next on the
roadmap,
coming soon: a knowledge base of approved answers, chosen by the model and spoken as approved, never generated.