Raindrop

CI-native agent simulation

Simulate your agent.

Test your agent in realistic worlds before merging.

Get early access

Works with your stack

Bring your own traces.

The instrumentation you already use. No SDK rewrite.

run your agent. simulate the world.

Your real code runs unchanged against stateful service copies. Watch every tool call and state change without touching production.

refund dispute

support agent · run 01

Third time asking. I want a full refund.
A
I'll check the conversation, charge, and order history.
conversation history
A
Refund issued. Nothing in production was touched.
get_messages(channel: "support-escalations", latest: request.threadId)refunds.ts
1import { tools } from "@raindrop/simulate";
2
3export async function handleRefund(request: RefundRequest) {
4 // Read the full support thread before acting
5 const conversation = await tools.slack.history({
6 channel: "support-escalations",
7 latest: request.threadId,
8 includeReplies: true,
9 });
10
11 // Verify the disputed payment
12 const charge = await tools.stripe.getCharge({
13 chargeId: "ch_3Pk9",
14 expand: ["customer", "dispute"],
15 });
16
17 // Query the copied Postgres orders table
18 const order = await tools.supabase.from("orders")
19 .select("id, fulfilled_at, total")
20 .eq("payment_intent", charge.payment_intent)
21 .single();
22
23 // Query recent refund history
24 const history = await tools.clickhouse.query({
25 query: "SELECT count() FROM refunds WHERE customer_id = {id:String}",
26 params: { id: charge.customer.id },
27 });
28
29 // Call any external API against a generated response
30 const delivery = await tools.api.get({
31 url: `/shipping/${order.id}/eta`,
32 headers: { "x-region": "us-west" },
33 });
34
35 if (charge.disputed && history.refunds < 2) {
36 // Issue the refund inside the simulation
37 const refund = await tools.stripe.refund({
38 chargeId: charge.id,
39 amount: charge.amount,
40 reason: "requested_by_customer",
41 });
42
43 return buildResponse({ refund, delivery });
44 }
45}

Synthetic services

a synthetic copy of every service your agent touches.

We stand up faithful synthetic copies of the APIs your agent calls, then fill them with generated data — customers, threads, charges, tables — shaped like yours. Any situation, reproducible on demand.

slackstripeclickhousegithubsupabasesalesforcenotiongmailtwilioshopifylinearzendesk

CI verdict

eval what matters.

On every PR, raindrop finds the most relevant traces to replay against the change you’re making. See what improves, catch what breaks, and merge with confidence.

simulate · pr #482 · 20/20 traces replayed2m 14s

new issues

+2

hallucinated refund policy ×2

cost / run

−12%

$0.041 → $0.036

output length

+31%

watch: verbosity drift

tool errors

0

all synthetic calls clean

2 evals failed → merge blocked