Inspiration
Bucket started with Melissa Stone's cash envelopes. She could build a budget and assign every dollar, but between ADHD and a busy life, the plan was hard to keep while she was actually spending. Budgeting apps sorted her purchases afterward, when the money was already gone. The envelopes worked because she could feel each one get thinner, and borrowing from the one marked "rent" was a choice she had to make with her own hands. Researchers call that small sting the pain of paying (Prelec and Loewenstein, 1998), and cards and phones dull it. Jason knows it from the other side: collectibles, and the newest tech the week it ships.
Our first version, built for the Nebius x NVIDIA hackathon, put that pause back into ordinary purchases. Then we looked at where checkout is heading. A shopping agent removes the last moment that was left: no card in hand, no checkout screen, no pause at all. If the envelope matters when a person pays, it matters more when software pays for them.
So this version puts the envelope between the agent and PayPal. You decide once, calmly, which buckets are needs and which are wants. The agent can buy, but every want is held to that decision: a live PayPal authorization with a plain reason to wait, until you keep it or let it go.
What it does
You sort your money into buckets and decide once, calmly, which hold needs and which hold wants. Then you send an agent shopping: "trail running shoes, under $150."
The agent (Nemotron Super) searches real listings through Channel3, picks one, and files it into one of your buckets without knowing which buckets are needs. A second model (Nemotron Nano) checks that the pick is actually the thing you asked for. If the bucket is a need, a screen checks the purchase against your own history; only a confident doubt holds it, and a weak one is logged rather than raised.
If the bucket is a want, Bucket looks for a real reason to wait in your own records: it would overdraw the bucket, you bought or let go of something like it recently, one is already on hold, or the same search found something similar for meaningfully less. Each reason is a fact you can check, and every dollar figure is computed in code, never by a model. Then code applies the rule: needs go through; a want with a reason, or over its bucket's threshold, is held.
Held means a live PayPal authorization. The money is reserved, not taken, and the hold sits in a PayPal tab with its reasons, its authorization id and a countdown. Keep it and Bucket captures it. Let it go and Bucket voids it; the money stays in its bucket, or goes to Savings if you would rather see exactly what waiting kept. Do nothing and the clock voids it. Every hold and every refusal is listed with PayPal's own ids on a public ledger you can sort and filter.
How we built it
The money runs on PayPal's REST APIs in the sandbox. A buyer's PayPal wallet is saved once through the Vault API. After that the agent creates orders with intent: AUTHORIZE paid from the saved wallet, and PayPal completes the order and places the hold in one call, with no popup. Bucket captures or voids each authorization exactly once: a claim in the database means two taps, or a tap racing the clock, produce one PayPal call. Every call carries an idempotency key derived from the hold, and after a failed call Bucket asks PayPal what actually happened before recording anything. The bucket id rides on PayPal's order record as custom_id.
The agent is NVIDIA Nemotron Super on Nebius Token Factory, the second check is Nemotron Nano, and the screen is Nano escalating to Ultra when it disagrees. Product search is Channel3. It all runs on Cloudflare Workers with D1.
Models never touch money. Their outputs are a product number, a bucket, a yes or no, and a need-or-want word, and code turns those into PayPal calls. A test fails the build if anything from the AI engine appears in the payments module's import graph.
Challenges we ran into
The first morning went to a PayPal detail worth knowing: a client-credentials token keeps the permissions it was issued with, and PayPal hands back the same token for hours. Our app issued one before Vault was switched on, so every check looked like Vault was broken. A fresh app with the feature on before its first token fixed it.
The agent was harder. On real catalog data it bought an oat-milk-named bath gift set as groceries, then declined good running shoes, then bought an oat milk strainer bag "for making oat milk." The root cause of the first two was ours: the catalog's categories arrive as objects, and every model had been reading "[object Object]". The third taught the real lesson. A model asked to find something leans toward finding it. So a second model, asked only whether the pick is the thing requested, now has the power to overrule it.
Accomplishments that we're proud of
- A real agent that buys through PayPal with no popup, and real holds that a person releases with one tap.
- Every claim is checkable. The ledger lists PayPal's authorization ids, declines list what the agent looked at, and each thing the video claims about money is a test.
- The agent can be wrong without anyone losing money. That is the design, not an accident.
What we learned
Trust in an agent with a wallet comes from the boundary, not the model. The best model we tried still made confident mistakes on real data. What made those mistakes harmless was that no model's answer moves money on its own: a second opinion can stop a purchase, code decides, and PayPal's authorize and capture gives a person the last word.
What's next for Bucket
Whole lists: hand the agent a shopping list and it files every item, passing needs and holding wants, in one run. After that, comparing prices across stores and online deals for the needs, so the agent saves money on what you do buy, not only on what you let go.
Built With
- channel3
- cloudflare-d1
- cloudflare-workers
- nebius-token-factory
- nvidia-nemotron
- paypal
- paypal-orders-api
- paypal-vault
- react
- tailwindcss
- tanstack-start
- typescript
