Guided-flow activation — operator playbook
How to turn on a guided flow for a real tenant. The engine, the config UI, the billing tile, and the Stripe reporter all ship inert — this is the checklist that activates them. Design: ADR-0169 (engine), ADR-0170 (billing).
Two independent switches
Section titled “Two independent switches”Activation has two orthogonal switches — you can flip one without the other:
| Switch | What it does | Needed for |
|---|---|---|
A. Entitlement — the guidedFlows feature flag |
Lets a persona’s flow spec actually run |
Any live flow (free pilot or paid) |
| B. Billing — the Stripe meter + env var | Turns completed flows into invoice line items | Charging for it |
A free pilot = switch A only. A paid tenant = A + B. The flow runs on A; completions are recorded to the audit trail regardless (so you can backfill billing later — the reporter reads history).
Step 1 — Enable the entitlement (switch A)
Section titled “Step 1 — Enable the entitlement (switch A)”guidedFlows is off on every plan by default. Enable it per-tenant with a feature_flags
override, then purge the KV cache (flags cache for 300s under ff:{tenantId}).
# Set CLOUDFLARE_ACCOUNT_ID=25b5fba80388bf85bd9adb9001458c5e for prod.# 1. Override the flag for the tenant (updated_at is NOT NULL — include it):wrangler d1 execute puccha-db-<env> --remote --command \ "INSERT INTO feature_flags (tenant_id, key, value, updated_at) VALUES ('<tenantId>', 'guidedFlows', 'true', unixepoch()) ON CONFLICT(tenant_id, key) DO UPDATE SET value='true', updated_at=unixepoch()"
# 2. Purge the cached flags. They cache for 300s in the KV_SESSIONS namespace# (binding KV_SESSIONS; the id is in apps/app/wrangler.<env>.toml):wrangler kv key delete "ff:<tenantId>" --namespace-id <KV_SESSIONS-id> --remote(Or just wait 300s for the cache to expire.)
Recommended for Business+ tenants only (the packaging tier, ADR-0168). Nothing stops you enabling it on a lower plan for a pilot; the entitlement is orthogonal to the plan.
To disable later: set the override value='false' (or delete the row) and purge the cache.
Step 2 — Configure the flow on a persona (no SQL)
Section titled “Step 2 — Configure the flow on a persona (no SQL)”Self-serve in the console — no database work:
- Open
/c/{slug}/personas→ Add persona (or Edit an existing one). - Under Custom instructions, toggle Enable guided flow.
- Set What it builds (draft kind), add the details to collect (slot keys + whether each is required), and a max turns cap.
- Save. The card shows an amber Guided flow badge.
Slot keys matter: the model is constrained to the exact keys you declare (that constraint
is what makes flows reliably reach completion — see ADR-0169 / the slot-key fix). Name them
plainly (use_case, team_size, dates, budget).
Make it the tenant’s default persona (or the one bound to the channel visitors hit) so the flow actually runs for them.
Step 3 — (Paid only) wire billing (switch B)
Section titled “Step 3 — (Paid only) wire billing (switch B)”Skip this for a free pilot. To charge per completed flow:
- Stripe meter + price — follow
stripe-setup.mdMeter 4 — Guided-flow add-on (event_name = puccha_guided_flow, Sum aggregation). Create a metered Price on that meter at the agreed per-flow ฿ rate (a founder decision — there is no default in code). - Attach the price to the tenant’s subscription as an added subscription item (the guided-flow price is not auto-attached at checkout like the base plan; add it to the sub of each add-on tenant).
- Set the env var (per env):
wrangler secret put STRIPE_METER_EVENT_GUIDED_FLOW→puccha_guided_flow. Until this is set the reporter logsno_meter_event_nameand skips — no charge. - (Optional) add the ฿ figure to
PLAN_METAso the billing tile shows the rate.
Billing runs end-of-period: the monthly usage-reporter cron (1st @ 01:00 UTC) counts
the previous month’s flow.completed events and reports one meter event per tenant.
Step 4 — Verify end-to-end
Section titled “Step 4 — Verify end-to-end”- It runs: as a visitor, open the tenant’s widget (or
/c/{slug}/flow-teston non-prod), start the flow, answer the elicited slots. On completion a Draft card renders (title + your-details + tap options). - It recorded: the conversation’s
metadata.flow.statusisdeliveredand aflow.completedaudit row exists:SELECT count(*) FROM audit_logWHERE action='flow.completed' AND tenant_id='<tenantId>'AND ts >= strftime('%s','now','start of month'); - It shows: the count appears on
/c/{slug}/billing→ Current period usage → Guided flows completed. - It bills (paid only): spot-check via the admin-authenticated
GET /api/cron/usage-reporter(scopes to your tenant). ⚠️ This also reports real resolution/API overage for your tenant — it is idempotent, but don’t run it casually on prod. The returned summary carries aflowAddoncount.
Reconciliation
Section titled “Reconciliation”The invoiced quantity for any period must equal the audit count — the audit trail is the source of truth (no separate counter):
SELECT count(*) FROM audit_logWHERE action='flow.completed' AND tenant_id='<tenantId>' AND ts >= <periodStartUnix> AND ts < <nextPeriodStartUnix>;Compare against the Stripe meter events (Stripe → Billing → Meters → Guided-flow add-on → Events) for the same window.
Turn it off
Section titled “Turn it off”- Stop a flow without losing the persona: edit the persona → toggle Enable guided
flow off (sends
flow: null). - Revoke the entitlement: set the
guidedFlowsoverride tofalseand purge the KV cache. Any personaflowspec goes inert immediately. - Stop billing but keep flows running (free): unset
STRIPE_METER_EVENT_GUIDED_FLOW.
Related
Section titled “Related”- ADR-0169 — the engine + the reliability model.
- ADR-0170 — the billing decision + rationale.
stripe-setup.md— the Stripe meter/price mechanics.../design/guided-flow-onboarding-playbook.md— how to design a good flow (slots, sources, completion) for a vertical.