The running example
Northpine is an outdoor-gear shop. Its standard policy refunds unused items returned within 30 days, and its support bot handles those. Everything else, such as a late request or a used item, is an exception that needs judgment: grant the refund, send it to a person, or deny it. Northpine’s support app asks Moonbounce to make that call. The decision is calledrefund-exception, and a ticket like this one goes in:
Order $129, delivered 42 days ago, no refunds in the last year. The zipper on my sleeping bag ripped out the first night.and an outcome comes out:
grant. The app then does whatever grant means in Northpine’s code.
From content to an outcome
A decision doesn’t ask a model “should we grant this?” in one go. It breaks the judgment into small yes/no features, and combines the answers with a recipe you can read:- Features are indicators in the content, detected with a prompt such as “Does the customer describe a defect, damage on arrival, or the item failing under normal use?”. An engine, a language model Moonbounce runs, answers each one with the probability that the answer is yes. For the sleeping bag,
defectivecomes back as 0.96. - Aggregators combine answers. A
combinenode turns the five answers into one score between 0 and 1. Your spec says which way each answer pushes: a defect raises the chance of a grant, a late request lowers it. Acalibratenode then maps that score onto the probability that the decision’s target is true, here “The refund exception should be granted.” - Cut points turn the score into an outcome. Northpine’s are: below 0.38 is
deny, from 0.38 isescalate, from 0.60 isgrant. The sleeping bag scores 0.766, so it lands ongrant.
Who owns what
Your code is the source of truth for what the decision is. Moonbounce runs it and learns from it, but never changes your production behavior on its own.
Nothing reaches your production traffic except through a merge in your repository. A suggestion from Moonbounce is a code diff your coding agent applies and you review, like any other pull request.
The loop
The decision gets better through a loop of five steps:1
Describe the decision
You, or your coding agent, write the spec: the features, how they combine, and the target. You seed it with about a dozen labeled examples so Moonbounce has cases to test changes against. Describe a decision.
2
Evaluate items
Your app calls
POST /v1/evaluate with the content, the spec and its cut points, and acts on the outcome. Every evaluation is stored with all of its answers. Evaluate content.3
4
Improve
From your feedback, Moonbounce proposes one change, such as rewording a feature’s prompt or adding a missing feature, and previews it: it replays the new version on your past cases and shows what it fixes, what it breaks, and how strong that evidence is. Suggestions and previews.
5
Accept through your merge
Your agent applies the change to the spec in your repository and opens a pull request. You merge it, your app deploys it, and the new version starts serving. Moonbounce counts the suggestion as accepted when the new version first serves production traffic.
The loop, once, for Northpine
Northpine’s spec has no feature about shipping. That’s a gap: the shop’s guidance says a late or lost delivery is the shop’s own failure and a reason to grant. Here is how the loop closes it.- A ticket comes in: “The tent showed up two weeks late (stuck at the regional hub), I used it once on the trip it was for.” It’s 39 days after delivery. No feature captures the late delivery, so the score is 0.540, just under the grant cut, and the outcome is
escalate. A person has to look at it. - The person who handles the escalation grants the refund, and the owner tells Moonbounce it should have been
grant, with the reason “The carrier delay ate their return window; that’s our failure.” They also confirm that two answers were right: the request is past the window, and nothing is broken. So the problem isn’t a wrong answer but a missing feature. - After a few cases like it, some sent as feedback and some answered in the owner’s review queue, the developer’s coding agent asks for a suggestion. Moonbounce finds that no existing feature explains these misses, and proposes a new one: did the carrier deliver the order late, or lose it? It previews the change on Northpine’s past reviewed cases: the carrier-delay tickets now land on
grant, and no other case changes outcome. - The developer’s coding agent applies the suggestion to
moonbounce/refund-exception.jsonand opens a pull request. The developer reads the diff and the preview, and merges. - Northpine’s app deploys, and its next refund request runs on the new version. Moonbounce records the suggestion as accepted.
Three ideas to hold on to
- Your code is the source of truth. The spec, the weights pin and the cut points live in your repository and change together in one pull request. What merges is exactly what was previewed.
- A version is a pair of hashes. The structure hash identifies the features and how they combine; the weights hash identifies the numbers inside the aggregators. There are no drafts and no version numbers: any spec you send is a version the moment it arrives, and two specs that differ only in formatting or key order get the same hash. Versions and hashes.
- The score means something. A score is meant as the probability that the target is true, so a cut point at 0.60 says “grant when we’re at least 60% sure the refund should be granted.” Before weights are fitted to your feedback, the score is the plain average described in From answers to an outcome, and the response says so.
What Moonbounce doesn’t do
- You write features in plain words; Moonbounce compiles their prompts for the engine.
- It doesn’t take actions. It returns an outcome name, and your code decides what that means.
- It runs one decision per call. If your app chains decisions, chain them in your code.
- It reads text and JSON today. Images, audio, video and documents are refused with a clear error until an engine supports them.