@gtmi/create-cr-demo
v1.15.8
Published
Scaffold a new Twilio demo app from the cr-demo baseline
Downloads
945
Keywords
Readme
@gtmi/create-cr-demo
One command scaffolds a working, cross-channel AI agent demo built on Twilio Agent Connect — then provisions the Twilio stack behind it for you.
npx @gtmi/create-cr-demo my-appTable of contents
- What you get
- Prerequisites
- Usage
- Next steps after scaffolding
- Development
- Folder layout
- Embedding
- Other scripts
- License
What you get
A starter demo showing one AI agent conversation that follows a person across channels. A Fastify backend runs on Twilio Agent Connect (TAC); a Next.js frontend opens a Twilio Memory profile and a matching Segment identity for each visitor. Visitors pick from four scenarios, then talk to the agent over voice (phone or in-browser WebRTC) or chat (webchat or SMS) — the same profile follows them the whole way — while the browser panel surfaces AI Operator results, Observations, and the traits gathered along the way.
The screenshots above are the generated app, unmodified.
How it fits together
Every webhook Twilio sends arrives through a single host — your ngrok tunnel locally,
LIVE_HOST_URL once deployed — and every channel resolves the same Memory profile. That is what
lets one browser panel render a phone call, a webchat and a text as a single transcript.
The profile is the join key, not the conversation: someone who both chats and calls produces two Twilio Conversations but one profile. A handset joins that profile once its number is merged in.
Around that spine the generated app wires up:
- Twilio Memory — profiles, traits and Observations, written as the conversation goes
- Twilio Sync — a per-profile stream the browser subscribes to, so the transcript is live
- Intelligence Configuration — Language Operators scoring each turn
- AWS Bedrock — the LLM generating replies
- Segment — optional browser + server sources emitting
Call Started,Call Ended,Tool Called
Your generated app's own README.md carries the full architecture diagram, the per-variable
environment reference, and the deploy runbooks. It ships in the scaffold, so read it there — this
page is deliberately the short version.
Integrations
| Integration | Requirement | Notes |
| ----------- | ----------- | ----------------------------------------------------------------------------- |
| Twilio | hard | Conversation Relay needs it; without it there is no voice channel |
| AWS | medium | pnpm init:aws deploys the agent to ECS Fargate; any Docker host works |
| Segment | soft | Skip it and the site mints its own anonymous ID; only the event stream is off |
| Vercel | soft | pnpm init:vercel is the default target for apps/site; deploy anywhere |
Only Twilio is load-bearing. Leave the others' credentials blank and the demo still runs, minus that piece.
Prerequisites
Node.js
>=24pnpm
11.25.0— the generated app pins it viapackageManager. You do not need it to run the scaffold (npxhandles that), but the scaffold runspnpm installfor you, so a local pnpm older than the pin will do that install on your version and print anUpdate available!notice. To match it first:corepack enable # once per machine, if you have not already corepack use [email protected]ngrok CLI — only if you need to expose the agent publicly
Accept the Conversation Memory terms of service — Twilio Console → Products & Services → Conversation Memory → Overview. One-time per account, and
initcannot do it for you. Skipping it failspnpm init:twiliopartway through withTerms of service have not been accepted.
Usage
npx @gtmi/create-cr-demo my-appWhat the scaffolder does
Creates my-app/ containing:
- A pnpm + Turborepo monorepo with two pre-wired apps:
apps/site— Next.js frontend (React, Tailwind)apps/agent— Fastify backend (TypeScript)
- Shared config packages (
config-eslint,config-prettier,config-typescript,jest-presets) - Shared business-logic packages both apps depend on (
analytics,language,memory,scenarios) — the Segment, language, Memory-read and scenario contracts the two apps agree on - Husky hooks: conventional-commit validation, plus a branch-name convention that warns rather than blocks
- A root
.env.examplewith documented variables, plus one per app
It then runs git init, pnpm install and an initial commit for you, and seeds a .env.local
next to every .env.example — at the root and in each app — so there is nothing to copy by hand.
Those files are gitignored, so the initial commit cannot capture what you put in them.
The install prints whatever pnpm normally prints, and on a first run that includes some noise
worth recognising as harmless: deprecation warnings for transitive subdependencies, and
Ignored build scripts: core-js, esbuild, sharp — pnpm declining to run install scripts it has
not been told to trust. Neither affects the demo. Nothing else should scroll past: the scaffolder's
own commit is quiet and skips the hooks it has just installed, since those exist to check your
commits rather than its one.
Next steps after scaffolding
Nothing needs filling in by hand first. pnpm run init prompts for your Twilio and Segment
credentials itself and writes everything else it needs back into the seeded .env.local files:
cd my-app
pnpm run init # provisions your Twilio stack, then your Segment sources
pnpm dev:std # both apps plus an ngrok tunnel to the agentThe only variables you would ever set by hand are the ones pnpm run init never touches — e.g.
NGROK_AUTHTOKEN, or anything needed for the standalone pnpm init:vercel / pnpm init:aws
errands. Your generated app's README has the full init-filled-versus-manual breakdown.
pnpm run init runs each provisioning step in order, passing flags like --prod, --patch,
--swap, --dry-run, --yes and --verbose through verbatim. Every step is also a command of
its own, for re-running just that piece:
| Command | Runs |
| ------------------- | ---------------------------------------------------------------------------------------------------- |
| pnpm run init | every step below, in order |
| pnpm init:twilio | the Twilio Conversations stack (Memory Store, phone number, Conversation/Intelligence Configuration) |
| pnpm init:segment | the two Segment analytics sources (browser + agent) |
| pnpm init:vercel | not part of pnpm run init — a one-time deploy errand for apps/site |
| pnpm init:aws | not part of pnpm run init — a standalone deploy errand for apps/agent |
Both provisioning steps are safe to re-run — resources are resolved by name and adopted rather than duplicated — and both are optional.
pnpm init:aws deploys apps/agent as an ECS Fargate service behind an ALB via CloudFormation. It
needs pnpm run init to have already run (it reads the Twilio credentials and LIVE_HOST_URL that
step wrote), plus Docker running locally and an ACM certificate already requested and DNS-validated
for the target region. AWS credentials resolve through the AWS SDK's own default provider chain — a
profile, env vars, or an instance role — never prompted for and never written to .env.local:
aws sso login --profile profile-used-here # if your account uses AWS SSO
export AWS_PROFILE=profile-used-here
pnpm init:aws # your personal namespace: stack + ECR repo named after the app
pnpm init:aws --prod # the same, on the shared stack (the bare app name)Development
pnpm dev # both apps: site on http://localhost:3000, agent on http://localhost:3001
pnpm dev:std # the same, plus an ngrok tunnel to the agent
pnpm ngrok # just the tunnelTwilio has to reach the agent for voice and inbound messaging to work, so pnpm dev:std is the
one you want for a full end-to-end run. Plain pnpm dev is fine for frontend work.
Folder layout
apps/
site/ Next.js frontend
agent/ Fastify backend
packages/
analytics/ the Segment contract shared by both apps: what "configured" means, the
event names, and the anonymous-ID storage key
config-eslint/
config-prettier/
config-typescript/
init/ pnpm run init, and the steps it runs: init:twilio, init:segment — plus the
standalone init:vercel and init:aws
jest-presets/
language/ the supported-language contract shared by both apps
memory/ Twilio Memory reads shared by both apps
scenarios/ the scenario config both apps share: system prompts, per-scenario Contact
traits, and intro card copy
scripts/
ngrok.sh
prepare-husky.cjsEmbedding
The site refuses to be framed by any origin except Twilio's, via a
Content-Security-Policy: frame-ancestors header. One array in
apps/site/src/network/csp/csp.constants.ts configures it:
export const FRAME_ANCESTORS = ['https://twilio.com', 'https://*.twilio.com'] as const;Add an origin to let your own page embed the site; empty the array to forbid framing outright. A
cross-origin iframe placing voice calls also needs allow="microphone" on the <iframe>, or the
browser blocks getUserMedia and every call fails at microphone access.
Other scripts
| Command | What it does |
| ------------------ | ------------------------------------------ |
| pnpm build | Build all apps via Turbo |
| pnpm lint | Lint all packages |
| pnpm check-types | TypeScript type-check across the workspace |
| pnpm test | Run the test suites |
| pnpm format | Prettier-format **/*.{ts,tsx,md} |
| pnpm clean | Clean build artifacts |
License
MIT — see LICENSE.
