Appearance
Claims triage
First-notice claims triage, decided by rules, an AI model and an adjuster together: the policyholder answers a claim form with evidence, four rules check the policy, the amount and how often they claim, a model reads the claimant's own account before a clean claim is fast-tracked, and anything unusual goes to an adjuster with the model's brief. Every rule result, model answer and decision is on the run's record. Pack: examples/policies/claims-triage/.
A pattern for expressing a claims policy, not insurance guidance: the thresholds, questions and fields are placeholders chosen to make the example run; a real policy comes from the business's own rules. Its model steps call one install, chatgpt (The chatgpt install).
The decision it automates
Whether to fast-track the claim, send it to an adjuster, or decline it, when the claim form is submitted. The rules decide; the model can only send a claim to an adjuster, never pay or decline one.
Data expected
- The policyholder as a subject with
policyStatusandpolicyAgeDays, which your claims system keeps current before it starts the run. - The claim form's answers under
submission:claimType,incidentDate,amount(USD),description(what happened, in the claimant's words; at most 2,000 characters), apoliceReportNumberfor thefts, and optional photos and an invoice. - A
claim.filedevent for every claim, posted throughPOST /events, so the frequency rule sees the history. - An install named
chatgptof the platform'schatgptapp, with your OpenAI API key.
Steps and rules
| Step | Type | Why |
|---|---|---|
collect | wait_for_collection | The claim-form flow; thefts add a police-report step. |
rules | evaluate_rules | The claims-triage rule set under max_severity. |
route | branch | rules.outcome == reject goes straight to the decision, without the model; any other claim to read. |
read | call_app | decide through chatgpt on the claim: two questions, answered under ai. |
gate | branch | rules.outcome == manual_review goes to brief; ai.answers.consistent.probability >= 0.8 fast-tracks a claim the rules approve; the rest go to brief. |
brief | call_app | generate through chatgpt: the adjuster's brief, under brief. |
review | create_case | claims_adjuster, 72-hour SLA, labeled (queueFrom) with the adjusters the model suggests. |
decide | emit_decision | From the rules, or the adjuster's decision. |
The rule set claims-triage (useCase: custom) uses max_severity: a failed block rule rejects, a failed warn rule sends the run to review, and the weights add up to the score.
| Rule | Type | Severity, weight | Fails when |
|---|---|---|---|
claim_policy_active | comparison | block, 100 | subject.policyStatus is not active |
claim_early | comparison | warn, 30 | subject.policyAgeDays is under 60 |
claim_amount | score threshold | warn, 30 | amount is above $5,000 |
claim_frequency | velocity | warn, 40 | more than two claim.filed events in 90 days |
The model steps
read writes the model an account of the claim from four of the form's answers, claimType, amount, incidentDate and description (its stateTemplate, filled through variables), and asks two questions:
| Question | Answer | Asks | Read by |
|---|---|---|---|
consistent | yes or no, threshold 0.8 | Does the claimant's account support the claim as filed: an incident of the type they chose, on or around the date they gave, with a loss that could account for the amount claimed? | gate: a claim the rules approve is fast-tracked only on a yes at 0.8 or more |
handling | desk, field or specialist | Which adjusters should handle the claim, from what the account says | review: the case's queue label |
A probability under 0.8, a model that cannot tell included, takes the branch's default to an adjuster: the model never declines a claim and never fast-tracks one the rules sent to an adjuster (Routing on an answer). The question's threshold is the branch's, so ai.answers.consistent.value says which way a clean claim went.
brief runs only on the way to the case, from the same four answers, and answers a ClaimBrief object: summary, claimedItems, cause (null when the claimant does not say), thirdParty, injury and questions, what the adjuster may want to ask the claimant. Its instructions keep it to the claimant's words and from saying whether the claim is covered, genuine or should be paid: thirdParty and injury are what the claimant says, not findings.
What the vendor sees
The four answers and the steps' own text, through the install's connection: not the policyholder's name or policy data, the police report number, the photos or the invoice; no document or image reaches a model (Data protection). With the one-click install's configuration, both steps reach OpenAI's Responses API, with storing off. The claimant writes the description and may write instructions into it: at worst, an answer the model was talked into fast-tracks a claim every rule passed, as the rules alone would (Prompt injection).
The chatgpt install
A pack never carries an install: its steps call one by name, so the pack declares it, "installs": { "chatgpt": "chatgpt" }, the platform's ChatGPT (OpenAI API). The import reports chatgpt missing (--publish publishes all the same), and the admin console's import result installs it in one click, with a preset configuration and a sample key in place of yours. Store your OpenAI API key on the install's page (Connect › Apps, the install chatgpt, Configuration › Keys, openaiApiKey) before the workflow runs.
Until you do, the run fails: OpenAI refuses the sample key, so every claim the rules do not decline fails at read, with no case and no decision. A model call that fails once the key is in does the same: an outage that outlasts the retries, an exhausted quota or a refusal fails the run at read or brief. The vendor's answer is on the call's invocation record, under the run's app calls; once the call can succeed, replay the run from read (Operate › Runs, Replay from step), and the claimant is not asked again. Without any install named chatgpt, the run fails at read with unknown_install. To ask Claude or Gemini instead, install that app under a name of your own and name it in the steps' app and in the pack's installs: every model app answers decide and generate in the same shape (Installing a model app).
What a reviewer sees
A claims_adjuster case labeled with the adjusters the model suggests (desk, field or specialist, which saved queues filter on), with the form, the photos and invoice when attached, each rule's result, the model's calls under Vendor checks, and its answers (ai) and brief (brief) in the run context. case.sla.breached reaches your systems if the SLA slips.
How to adapt it
Write the questions, the choices and the brief's schema for your book of business, and move the 0.8 in gate together with the question's threshold. Add a call_app step for your policy administration system, through an http-api install for its API (Adding a vendor step), to confirm coverage instead of trusting the subject's fields; a document check on the invoice (through an http-api install whose documents are on, with start when the vendor answers later: Documents); and payee screening against a sanctions list or a screening vendor (Seller and payout screening shows the pattern). Those are a vendor's or a list's to answer, never a model's.
Run it
bash
pnpm policy:import examples/policies/claims-triage --publishThe check runs two fixtures against the model stub (scripts/ai-stub.mjs), whose answers a cue word in the claimant's account picks. expect.json files a $1,800 damage claim 21 days into the policy, for a delivery van that backed into the policyholder's parked car: the early-claim rule fails, so the claim goes to an adjuster whatever the model says. Cued high, the stub answers consistent yes at 0.95 and handling specialist, and writes a brief; a claims_adjuster case opens, the check approves it and the run completes with a manual approve. expect-fast-track.json files a $650 bicycle theft, with a police report number, on a policy 412 days old: every rule passes, the stub answers consistent yes at 0.95, and the run completes with an automated approve, no case opened.