Inspiration
At a small online business, one person usually ends up owning the "weird cases". A card got declined. An invoice says $1,240 but the payment says $1,180. Somebody wants a refund for an order whose payment never went through. A chargeback notice shows up with a deadline. Each one is a little investigation, and most of the time goes into reading, sorting and writing the first reply, not into the actual decision.
I wanted a tool that does the boring part for a whole batch at once and leaves the decision with a person.
What it does
You paste or upload a batch of exceptions (CSV, JSON, or plain text with one item per block). Click Triage, and every item lands in a review queue with:
- a category (failed payment, invoice mismatch, refund request, dispute or chargeback, duplicate charge, or needs a human)
- a priority (P1 to P3)
- a suggested next action and a drafted reply that uses the real names, order numbers and amounts
- a short "why", plus the exact lines from the source text it relied on, highlighted
It also looks across the batch. If the same customer was charged the same amount twice, the two reports get linked and only one refund is suggested. If someone asks for a refund on a payment that failed earlier in the same batch, it tells you no refund is needed because the money was never captured. If an invoice and payment don't match, it shows the difference and the missing reference.
When a new message lands after the batch, such as an angry email in Spanish or a forwarded bank letter, Paste a new one pulls out the customer, amount, order and what they want, and finds the case it belongs to. Every quote is checked against the pasted text; anything the engine made up is shown as dropped instead of being hidden.
The reviewer goes down the queue with the keyboard (j/k to move, a to approve, x to escalate, r to reject, e to edit), edits the draft if needed, adds an internal note, and exports every decision to CSV with the final reply text. The desk survives a page refresh, and Clear desk starts over. Nothing is sent and no money moves. An approval is just a recorded decision.
It runs with no API key at all in demo mode, using a deterministic rules engine, so anyone can try it. If you set an OpenAI or Gemini key, it uses the model for triage, and the same batch checks still run on top so the AI can't miss a duplicate or suggest a refund for a failed payment. Each item shows whether the AI, the rules, or a rules fallback handled it.
How we built it
I started in an empty folder with the Devpost Learn skill pack (npx skills add challengepost/learn-ai-basics --all -y) and followed its steps in order: start, scope, PRD, spec, build. The planning docs it produced are in the repo under devpost/ (scope.md, prd.md, spec.md, plus the build checklist and an app map).
The coding agent was Cursor's agent (Cursor CLI). The build checklist split the work into small slices, and each one was tested and committed before the next, which you can see in the git history.
Stack: Node 20 with the built-in http module, plain HTML, CSS and JavaScript with no build step, and node:test for tests. No database: decisions are kept in the browser's localStorage. One command to run: npm install && npm start.
Challenges we ran into
- Pulling names, order numbers and amounts out of messy text without getting them wrong. Early versions grabbed words like "there" as a customer name, so this needed real test cases.
- Keeping AI mode honest. In one test run the model labeled a refund request as a failed payment and lost the point that no refund was needed. The fix was to run the deterministic batch checks after the model and let them override it, with a note in the "why".
- Calling the model one item at a time was slow, so calls now run in parallel with a limit.
Accomplishments that we're proud of
- It works end to end with zero setup and no key.
- Every suggestion shows its evidence, so the reviewer can check it in a few seconds instead of trusting it blindly.
- The cross-batch checks catch the cases that are easy to get wrong when you look at one ticket at a time.
What we learned
Planning first made the build faster, not slower. Once scope, PRD and spec were settled, the agent had a clear finish line for every slice, and fixes went back into the plan instead of drifting.
What's next for Exception Desk
- Read exceptions straight from payment and accounting tools instead of copy and paste
- Send approved replies from the desk
- Shared queues for small teams, with a history of who approved what
- More batch checks, like partial refunds and repeated declines on the same card
Links
- Code: https://github.com/spalaai/exception-desk
- Demo video: https://youtu.be/Z_0T3GrV4J4
Built With
- css3
- cursor
- gemini
- html5
- javascript
- node.js
- openai
Log in or sign up for Devpost to join the conversation.