Tickets arrive from customer monitoring, the branded portal, or embedded widgets in Airiam-built applications. Each source carries different trust levels and different priors into AI triage. The pipeline is identical; the defaults are not.
PHASE 1
The asynchronous ticket intake pipeline: three intake surfaces, eight triage stages, one Linear issue. Built on FastAPI + Pydantic AI + Neon Postgres + Linear API.
Next.js 15 at intake.airiam.com. JWT via Entra External ID.
TRUST: MEDIUM
EMBEDDED IN-APP
BDT · AIP · OSCAR · FinOps. HMAC + asserted user.
TRUST: HIGH
01INTAKE & AUTH
Resolve principal across four auth strategies; validate; persist; emit.
02EVENT BUS
Emit ticket.submitted to Service Bus; 202 returned to caller.
03PII SCRUB
Microsoft Presidio scans for PII / PHI markers; redacts before LLM call.
04CONTEXT ENRICHMENT
AIP customer table: tier, SLA, recent deploys, open P1s. Fast-filter by source.
05AI TRIAGE
Economical model tier. Quality gate, then structured triage (type, team, impact, urgency). Cost-optimized because it runs on every inbound event.
06PRIORITY CALC
Deterministic impact × urgency matrix lookup; not an LLM output.
07CORRELATION & DEDUP
Embedding + rule match against open Linear issues; suppress exact duplicates, link related incidents before any write.
08LINEAR PUSH
issueCreate mutation; lands in Triage with labels, team, and priority set.
LINEAR ISSUE
Awaiting triage.\nSelect a source and press RUN to watch a ticket move through all eight stages and land in Linear.
STAGE ·Stage detailLive input and output for the active stage
INPUT
// select a source and press RUN
OUTPUT
// output appears as each stage completes
POST-TRIAGE · LINEAR-TRIGGERED · AI RESOLUTION ASSIST
After the issue lands, a second model proposes the fix.
Triage is a high-volume classification job, so it runs on an economical model inside the intake pipeline. Recommending how to actually fix a bug or build a feature is a reasoning job, so it runs on a higher-end model. That model is not part of intake. It is kicked off only once the issue has been created in Linear, and it is the only tier granted access to the codebase and our internal procedures.
TIER 1 · TRIAGE
Economical model
RUNS INSIDE INTAKE · STAGE 05 · ONCE PER INBOUND EVENT
JOBClassify type, route to a team, score impact and urgency. Structured output only.
READSRedacted ticket text plus enrichment (tier, SLA, recent deploys). No code access.
OPTIMIZEDCost and latency at volume. Every inbound event pays for this call.
PRODUCESA triaged Linear issue in the Triage state.
TIER 2 · RESOLUTION ASSIST
Higher-end model
RUNS AFTER LINEAR · EVENT-TRIGGERED · ONCE PER ACCEPTED ISSUE
JOBRecommend the bug fix, or recommend how to address the feature. Reasoning over real code.
READSThe triaged issue, the relevant codebase, and our internal procedures and runbooks.
OPTIMIZEDReasoning quality. The higher cost is acceptable because it fires only on issues that survive triage.
PRODUCESA drafted recommendation posted back to Linear for an engineer to review.
01 · TRIGGER
Issue created in Linear
A bug or feature_request lands in the Triage state. Linear fires a webhook. Nothing here runs until this point.
02 · GATHER
Pull code and procedures
The worker retrieves the relevant repository context plus the matching internal runbooks and procedures.
03 · REASON
Higher-end model drafts
The capable model reasons over the issue, the code, and our procedures to produce a concrete recommendation.
04 · RETURN
Comment back on the issue
The draft is posted to the Linear issue. A human engineer reviews and decides. No auto-merge, no silent changes.
IF TYPE = BUG
Recommended fix
Grounded in the code and the on-call runbook, not guessed from the ticket text.
Root-cause hypothesis
Suspected files and functions
Patch sketch plus a suggested test
The runbook section it relied on
IF TYPE = FEATURE
Recommended approach
Where it fits in the actual codebase, measured against our engineering procedures.
Where it fits in the codebase
Affected modules and seams
Design sketch and rough sequencing
Relevant procedure or ADR references
WHY TWO TIERS
The economical model runs on every inbound event, so it has to be cheap and fast, and it never needs the code. The higher-end model runs only after an issue is created, so its cost is bounded to real work, and it is the only tier granted access to the codebase and our procedures. Triage stays out of the repo by design. The recommendation is always a draft for human review, never an automatic change.
PHASE 2 · IN DESIGN
PHASE 2 · IN DESIGN · CONVERSATIONAL CHANNELS · v2.0
From any conversation to a resolved, routed, or escalated outcome.
Phase 2 adds six synchronous channels in front of the Phase 1 pipeline. Customers call, text, WhatsApp, chat, or message us on Teams or Slack. A multi-turn AI agent applies the per-customer script, identifies emergencies, opens tickets when work belongs in Linear, and warm-transfers to a human with explicit validation when judgment is needed. Behavior varies by business hours per customer. The on-call rotation is paged only for what genuinely warrants it.
PHASE 2
Six conversational channels: voice, SMS, WhatsApp, in-app chat, Teams, Slack. Conversation Orchestrator maintains state across channel switches. Per-customer YAML script defines persona, hours, emergency definition, on-call rotation, and routing.
SIX CONVERSATIONAL CHANNELS
Channel catalog
Each channel has different affordances and constraints; the architecture accommodates them with channel adapters that normalize to a common conversation model. The same AI brain serves all six.
VOICE
Inbound phone calls answered by an AI agent that greets, identifies, classifies, and warm-transfers when needed.
STACKLiveKit Agents + Twilio SIP
STT/TTSDeepgram + ElevenLabs
LATENCY<800ms response
COMPLYTCPA AI disclosure
SMS
Multi-turn text conversation. Customer texts; AI responds; resolution may span minutes or hours.
STACKTwilio Messaging
REGA2P 10DLC required
LIMITS160-char segments
FITSstatus, FAQ, escalate
WHATSAPP
Same multi-turn pattern with rich media, read receipts, and seamless escalation to voice in the same thread.
STACKTwilio + WA Business
PRICINGPer-conversation (Meta)
WINDOW24hr CS window
TEMPLATESMeta-approved library
IN-APP CHAT
Embedded widget in BDT, AIP, OSCAR, FinOps. User already authenticated; app context pre-collected; highest-context channel.
STACKPreact + Web PubSub
AUTHHMAC + asserted user
CONTEXTroute, version, actions
FITSapp-specific help
MS TEAMS
Bot installed in customer's Teams tenant. DM the bot for support; Adaptive Cards for rich status; warm handoff via DM.
STACKBot Framework v4 + Graph
INSTALLPer-tenant by admin
RICH UIAdaptive Cards
FITSIT/ops staff
SLACK
Bot installed in customer's Slack workspace. Channel-native intake, slash commands, warm handoff via DM. Engineering-friendly.
STACKSlack Bolt SDK
INSTALLPer-workspace OAuth
RICH UIBlock Kit
FITSengineering teams
PER-CONVERSATION DECISION FLOW
Channel · Script · Decision
Every conversation runs through the Conversation Orchestrator and the customer's YAML script before terminating in one of three outcomes.
01
Channel arrives
Customer contacts via voice, SMS, WhatsApp, in-app chat, Teams, or Slack. Channel adapter normalizes the inbound to a common conversation event. Compliance disclosure played for voice. Customer identity resolved by phone, email, or channel-native ID.
02
Script applied
Conversation Orchestrator loads the customer's YAML script (persona, business hours, emergency definition, knowledge sources). Multi-turn Pydantic AI agent runs the conversation. Sentiment and intent tracked across turns.
03
Outcome decided
Agent reaches a confident decision: open a ticket, warm-transfer to a human, or declare an emergency. Outcome routes to the corresponding dispatcher. Every state change is hash-chained for audit.
BUSINESS HOURS × SEVERITY MATRIX (PER-CUSTOMER CONFIGURABLE)
SEVERITY
BUSINESS HOURS
AFTER HOURS
P1 EMERGENCY
Warm transfer to on-call senior; ticket in parallel; customer guided immediately
Same: page on-call; ticket; customer guided. Multi-channel escalation until acknowledged.
P2 HIGH
Warm transfer to on-call standard; ticket created
Open P2 ticket; on-call alerted via push (not call); SMS confirmation to customer
P3 MEDIUM
Try warm transfer; if no human within 90s, open ticket with response-time expectation
Open ticket; customer told response time per SLA
P4 LOW
Open ticket; customer told response time per SLA
Same: ticket only; response per SLA
THREE TERMINAL OUTCOMES
Resolved one of three ways
Every conversation reaches exactly one of these states. The Phase 1 pipeline runs whenever a conversation opens a ticket.
OUTCOME A
Open a ticket
Work belongs in Linear for asynchronous handling. Conversation transcript becomes ticket body. Customer told the ID and the SLA. Phase 1 pipeline executes downstream.
Triage transcript through Phase 1 stages
Linear issue created in Triage state
Customer informed of ID + SLA
Conversation closed cleanly
OUTCOME B
Warm transfer
A human needs to take over. Page the on-call per the rotation, brief privately, validate they have context, bridge them in, confirm customer is connected, exit. No blind forwards.
Brief on-call privately (15-30s)
Wait for explicit acknowledgement
Bridge customer with intro
Verify continuity, then exit
OUTCOME C
Emergency declared
Real emergency detected by keyword, sentiment, tier-topic matrix, or customer-defined trigger. Four things happen in parallel, not sequentially.
Page on-call (multi-channel escalation)
Give customer immediate guidance
Open P1 ticket in Linear now
Warm transfer in parallel
THE MARQUEE REQUIREMENT
Warm handoff with explicit validation.
The transfer is not complete until the human acknowledges they have context, the bridge succeeds, and the customer confirms continuity. No blind forwards. Every step recorded in the WORM audit chain. Industry research is unambiguous on this: the warm transfer is the moment customers either trust the AI or never come back, and full conversation context delivered to the live agent, not a five-line summary, is the differentiator.
CHANNEL
TRIGGER
VOICE · SENTIMENT THRESHOLD
1
TRIGGER
AI decides handoff is needed: complexity, sentiment threshold, explicit request, or policy.
Sentiment dropped to -0.62 at turn 4. Trigger: sentiment threshold exceeded. Selecting on-call: Daniel C (primary).
2
BRIEFING
AI privately briefs the human. Full conversation context, classification, sentiment trajectory, open tickets.
Brief sent to Daniel via Teams DM. Customer: Sarah Chen (ACME, Enterprise, Gold SLA). Issue: P2 incident with /api/orders. Sentiment trajectory: 0.4 → -0.62. Briefing length: 22 seconds read time.
3
VALIDATION
Critical step. Human must explicitly acknowledge. AI does not exit on silence.
Daniel clicked "I've got it" at 00:00:17. Acknowledgement logged. Context confirmed received. Proceeding to bridge.
4
BRIDGE & EXIT
AI bridges customer with introduction, verifies continuity, then exits the conversation.
AI: "I'm connecting you with Daniel from our team. He has the context." Customer: "OK, hi Daniel." Daniel: "Hi Sarah, I've got your case open." Continuity confirmed. AI exited at 00:00:34.
CRITICAL
The VALIDATION step is what separates this from a blind forward. If the human does not acknowledge within 60 seconds, the system retries with the next on-call. After two unacknowledged attempts, falls back to a P1 ticket with apology. Every acknowledgement, every bridge, every customer confirmation is hash-chained in the audit log. This is a defensible, contract-grade handoff.