Reimagining Shopping
Shopping by standing instruction, paid only after your tap
You tell the box what you want and when: "the Chemex filters when they are under $16", "keep the house stocked". An always-on box checks real stores on a schedule, reads your receipts, and when a deal or a reorder is due your phone asks one question with the price against your limit. Tap Approve and it pays, with every checkout signed by Visa's Trusted Agent Protocol. The model never holds the card or a buy tool.
Proof In the live run on Oct 23, Apify read Chemex filters at Best Buy Canada for $15.36 CAD, the box asked, and after the tap it bought them at that price with a Stripe test-mode charge on a Visa test card. Undoing the household reorder refunded it in Stripe test mode. Every payment was test money.
What Visa asked for
Visa published weighted criteria for the track; the full brief was not published. Quoted from the project's track plan.
Innovation in reimagining shopping (25%).
MetShopping becomes standing instructions: "when it's under $16", "when it's back", "keep us stocked". The box carries them out around the clock, and you only answer yes or no. Agents can also buy their own supplies (a paid API) within a budget, over x402.
User experience (25%).
MetSay it in words, or fill four fields. The phone shows one card: what, how many, the price against your limit, TEST PAYMENT, Approve. Undo gives the money back: undoing a purchase task refunds its order.
Technical execution with AI (20%).
MetClaude, inside Factory's Droid, turns your words into a watch and reads receipts to decide what runs out. Code does the money: the price rule, the budget, the signature, and idempotent charges that survive a power cut. Apify supplies live prices. Every check, approval and payment is a line in the action log.
Commerce impact (15%).
MetMerchants get agent orders they can verify with TAP instead of blocking every bot, at the price the buyer named. Households stop running out of the things they buy every week.
Trust and responsibility (15%).
MetThe agent never sees the card or the mailbox login and cannot buy on its own. Every purchase needs your tap and stays within its budget. A signed order cannot be changed in transit or replayed. Test money only, enforced in code: the store refuses a live Stripe key and orders over $500.
Screenshots



Open it yourself
- The Shopper track's code and READMEThe TAP signer is
tap.ts, the GurtOS Test Store isstore.ts, the demo mailbox isinbox.ts. - The x402 supply payment from the live run, on Solana ExplorerPublic, no sign-in. An agent paid $0.03 of devnet USDC (test money) for a report it needed.
- Visa's Trusted Agent ProtocolThe open spec and sample agent the box follows for signing checkouts.
- Docs: run a shopping agent
Evidence
The live run, Oct 23, on the x86 test VM (DEMO_LIVE=shopper ./demo):
- Stripe test mode charged the Hario filters bought from the watch, and refunded the household reorder when its task was undone.
- An agent paid $0.03 of devnet USDC for a report over x402 (the transaction).
- Droid read the receipts and proposed exactly the filters and paper towels.
- Apify read the Chemex filters (Best Buy SKU 20220310) at $15.36 CAD, and the box bought them at that price after the OK, as a Stripe test-mode charge.
- Droid turned "Get me the Chemex coffee filters at Best Buy when they're under $14" into a watch with a $13.99 limit.
The merge gate, every run. ./demo runs this track offline on every merge, with simulated payments. The latest
run, Oct 24 on the x86 test VM, passed all 22 sections (175 checks, 0 failed). This track's part:
track shopper
ok the box loaded the shopper tools
ok the agent registry serves the box's TAP public key, never the private one
ok the store refuses an unsigned order (an agent without the box's key)
ok a signed order changed in transit is refused: the signature covers the body
ok a captured signature cannot be used twice (the dripper is sold out, so nothing was charged)
ok a check task (no network, no secrets) saw Hario V60 02 paper filters, 100 count at $8.99: above the $7.00 limit, so it keeps watching
ok it dropped to $6.50, and the buy waits for the owner: "Buy 2 × Hario V60 02 paper filters, 100 count for $13.00? $6.50 each, ..."
ok approved from the phone, it paid $13.00 within the $14.00 budget
ok the store verified the TAP signature, then charged a TEST payment: Visa test card ending 4242, simulated pi_sim_…
ok no Stripe call in this run: the payment is simulated and says so (offline demo run: no Stripe call)
ok the watch closed: one purchase, no repeats
ok the agent got 10 receipts from the demo inbox; 2 other emails stayed in the mailbox
ok the receipts show filters and paper towels run out this week
ok it never saw the mailbox login or the sign-in code email
ok the proposal used the store's prices and waits for the owner: Reorder for the household: 1 × Hario V60 02 paper filters, 1...
ok approved, the reorder was paid: $17.99 TEST payment
ok undo on the purchase task refunded the order (re_sim_…)
ok supplies over x402: the task holds only the wallet tools, reaches only the seller, and may spend 3 cents
ok no card, signing key, mailbox password or Stripe key anywhere in the action log
How it works
- YouSay what you want"Get me the Chemex filters when they're under $14." Droid turns it into a watch with
shopper.watch. It holds no buy tool. - TaskA check task, on a scheduleNo network, no secrets. It calls
apify.checkPriceorshopper.checkPrice; the result goes in the log. - GurtOS coreThe rule, in codeIn stock and at or under your limit? Then the box starts a purchase task with a budget of your limit times the quantity.
- YouApprove on your phone"Buy 2 × Hario V60 02 filters for $13.00? ... TEST PAYMENT." Other tasks keep running.
- GurtOS coreshopper.buy signs and paysReads the card and the signing key from the vault, signs the order with TAP (RFC 9421, Ed25519, with a content digest), checks out with an idempotency key.
- OutsideThe store verifies, then chargesThe GurtOS Test Store checks the signature, the price and the stock, then charges Stripe test mode with a Visa test card.
- Task
- its own Linux user, its own copy of the files, no keys
- GurtOS core
- the GurtOS service on the box, root, the only part that reads the vault
- Outside
- a service outside the box
- You
- a person, on the portal, a phone, Jira or a chat
Three things it does.
- Restock and price watcher. The box checks a store on a schedule. When the item is in stock at or under your price, your phone asks: Buy 2 × Hario V60 02 paper filters, 100 count for $13.00? $6.50 each, down from $8.99, under your $7.00 limit. TEST PAYMENT.
- Household reorder. Claude reads the receipts in the household's mailbox, works out what runs out this week, and proposes one reorder for your OK. It sees the receipts only: never the mailbox login, never your other email. The date arithmetic (how often an item is bought, when it runs out) is code; Claude does the judgment.
- Agents buying their own supplies. A task pays for an API it needs with the wallet track's x402 payments, within its budget. See the Coinbase page.
Why a hijacked model cannot spend your money.
- The model never holds a buy tool or the card. Droid gets
shopper.watch(set a rule) andshopper.propose(suggest a reorder). Only purchase tasks the box itself starts holdshopper.buy, and each one asks you first. - Prices come from the store, not the model.
shopper.proposetakes SKUs and quantities and looks up the prices itself. - Two gates on money: the tap, then the task's budget. A purchase above the budget stops and asks again.
- Power cuts do not pay twice. Each checkout carries the broker's stable call key as its Idempotency-Key, at the store and at Stripe.
- One proposal and one watch per agent task, so a looping agent cannot flood your phone.
Visa Trusted Agent Protocol. The box signs every checkout the way Visa's sample agent does: an RFC 9421 HTTP
message signature with the sig2 label, Ed25519, keyId, nonce, created, expires (8 minutes) and the
agent-payer-auth tag. One addition: it also signs content-digest (RFC 9530), so a different item, quantity or
price fails the check. The store refuses an unsigned order, a changed body, a replayed signature, an expired one, an
unknown key, and a signature made for another store. The box publishes its public key at
GET /t/shopper/keys/box-shopper in the shape of TAP's registry.
Signature-Input: sig2=("@authority" "@path" "content-digest"); created=1761271440; expires=1761271920;
keyId="box-shopper"; alg="ed25519"; nonce="…"; tag="agent-payer-auth"
Signature: sig2=:…:
Content-Digest: sha-256=:…:
Try it
- On a box, as root:
tracks/shopper/setup.sh. It adds the Visa test card (pm_card_visa), a new Ed25519 signing key and a demo mailbox password to/etc/box/vault.env. - Optional: add
STRIPE_SECRET_KEY=sk_test_...for real Stripe test-mode charges (the store refuses a live key), andAPIFY_TOKENfor live Best Buy prices. - Open the Shopper app at
/t/shopper/from the portal's app grid. Say "Get me the Hario V60 filters when they're under $7", or fill the four fields. - Open the GurtOS Test Store at
/t/shopper/storeand drop the price. The next check asks on your phone; approve it. - Undo the purchase task from the portal and watch the store refund the order.
Or run the whole flow: ./demo (offline, simulated payments) or DEMO_LIVE=shopper ./demo (Stripe test mode,
Apify, Droid and devnet USDC).
Live, test and simulated
| Part | State | Details |
|---|---|---|
| Best Buy Canada prices and stock | Live | Through Apify's Playwright Scraper, the Apify track's apify.checkPrice. Best Buy Canada doesn't sell Hario filters, so the live watch is on Chemex filters. |
| Matching your words, reading receipts | Live | Droid with Claude. |
| Visa Trusted Agent Protocol | Live | Real signatures and real checks, following Visa's open sample. The key registry is the box's own route, not Visa's. |
| Payments | Test money | Stripe test mode with the Visa test card 4242 once a Stripe test key is in the vault; simulated, and labelled so, before that and in offline merge-gate runs. Never real money. |
| The GurtOS Test Store | Simulated | Ours. It stands in for the merchant, because no real store takes a test card. A Best Buy deal is bought here at Best Buy's live price. |
| The household mailbox | Simulated | A demo POP3 mailbox on the box with sample receipts we wrote, standing in for Gmail. We could not make a Gmail account for the demo. |
| Agents buying supplies over x402 | Test money | Real x402 payments by the wallet track, in USDC on Solana devnet, which has no value. |
| CAD prices against US-cent budgets | Simulated | A fixed rate of 0.73. |
| Visa Intelligent Commerce | Not built | Access needs a Visa representative, so nothing here depends on it. |
Limits
- A watch closes after one purchase, or when you deny it. Watch again for another.
- The running-low estimate assumes each purchase lasts until the next, whatever the quantity.
- The test store keeps price and stock changes in memory; they reset when the box restarts. Orders are on disk.
- The store remembers used nonces in memory. After a restart a captured signature could be sent again within its 8 minutes, but its Idempotency-Key still returns the first order instead of charging twice.
- Visa's sample verifier only knows
@authorityand@path, so it would not accept our signatures, which also cover the body.