What you can build with Snowflake CoCo CLI (+ Cortex)
I wanted to see how far you can get when the whole thing lives inside Snowflake: the data, the rules, the app, the audit trail and the alerting. So I designed and built a fraud policy copilot. You give it a flagged transaction id, and it gives back a risk score, the policy rules that fired (with citations), recommended next actions, a fraud-ring map, a case, and a native Snowflake alert trail. No external services.
The problem
Fraud analysts burn time hunting AML / KYC policy text for every alert. The decision itself is often quick; finding and citing the right rule, pulling customer context, and leaving an audit trail is what eats the day. I wanted a flow that goes from flagged transaction to policy-cited decision in one step, and keeps every review on record.
Demo (optional)
The design
I split the logic into small, modular skills and chained them, so each step is testable on its own and the same decision logic can run from the CLI or the app:
| Skill | Role |
|---|---|
get_case_context | Customer + recent transactions |
match_policy | Score against AML-style rules |
explain_decision | Citations + recommendation |
suggest_next_actions | Analyst next steps |
map_fraud_ring | Shared device / IBAN / phone / merchant links |
The rules are plain SQL. match_policy checks rules like large cross-border wires, wires from young accounts, large ATM cash, structuring (two or more small transactions in the 24 hours before a large wire), demo high-risk geographies and personal accounts sending large wires. Each fired rule adds points, the score is capped at 100, and the output is a JSON object with the rule code, title, severity and the rule text itself, so the citation travels with the decision.
How CoCo CLI and Cortex fit in
- CoCo CLI skills: each step lives under
skills/as its ownSKILL.md, and thefraud_case_reviewworkflow chainsget_case_context → match_policy → explain_decisionend to end from the CLI. - Cortex:
explain_decisioncan callSNOWFLAKE.CORTEX.COMPLETEto write the analyst-facing narrative from the matched rules. If Cortex isn't enabled on your account, it falls back to a static narrative, so the decision never depends on the LLM. - Streamlit in Snowflake: the app (
app/streamlit_app.py) mirrors the same decision logic with four tabs: Review, Fraud ring, Cases and Alerts. It usesget_active_session(), so there are no secrets to manage. - Native Snowflake Alert:
FRAUD_HIGH_RISK_ALERTwatches theHIGH_RISK_REVIEWS_24Hview (score ≥ 70) and writesALERT_HIGH_RISKevents intoCASE_EVENTS. Monitoring is a real platform object, not just a red banner in the UI.
Why it matters
- Everything stays in Snowflake. Data, rules, app, audit and alerting run in one governed place, so there's no data leaving the platform.
- Decisions are explainable. Scores come from deterministic SQL rules, and every fired rule is cited with its text. The LLM writes the explanation; it doesn't make the call.
- Modular by design. Skills are small and composable, so you can swap a rule set, add a skill, or run the same chain from the CLI or the app.
- Auditable by default. Every review lands in
REVIEW_AUDIT, and cases carry status transitions and comments. - Beyond single transactions. The fraud-ring view links customers through shared devices and IBANs, which is where a lot of real fraud hides.
Run it yourself
- In a Snowflake worksheet (
ACCOUNTADMIN, warehouseCOMPUTE_WH):USE DATABASE FRAUD_COPILOT; USE SCHEMA DEMO;
Then runsql/01→02→03→04→05in order. - Check the alert:
SHOW ALERTS LIKE 'FRAUD_HIGH_RISK_ALERT'; ALTER ALERT FRAUD_HIGH_RISK_ALERT RESUME; -- if suspended EXECUTE ALERT FRAUD_HIGH_RISK_ALERT; -- fire once without waiting
IfCREATE ALERTisn't available on your trial, there's a Task fallback at the bottom ofsql/03_audit_and_alert.sql. - Create a Streamlit app on
FRAUD_COPILOT.DEMOwith entry fileapp/streamlit_app.py(Git sync or paste). - Try it: review
T2005(structuring, high score) and open a case, compare withT2001(wire + geo) andT1001(clean control), map the ring forC005, then check the Cases and Alerts tabs.
What I learned
- Keep the decision deterministic and let the LLM explain. Rules in SQL plus a Cortex narrative with a fallback gave me something I could trust and still read like a human wrote it.
- Use the platform's own primitives. A native Alert and an audit table turned a demo into something that behaves like an operational system.
- Small skills beat one big prompt. Splitting context, matching, explaining and next actions made each piece easy to test and reuse.
- Be honest about scope. Sanctions screening uses a demo country list (
CY,IR,KP,RU) instead of a fake live feed. It's a prototype on small sample data, not a production sanctions product, and saying so up front keeps the design conversation real.