Skip to content
Back to skills

Food Ordering

ASecurity

When the user asks you to order food for delivery or pickup, reorder a usual meal, get a specific dish brought to them, or says they are hungry and wants you to handle dinner, before you open a delivery app.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 5, 2026
ai-agentsgoshell

Works with

  • cursor
  • cli
  • mcp

Security analysis

A100/100

Scanned November 5, 2026

npx -y skills add danielfebrero/Grok-Bot-app --skill food-ordering --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Food Ordering?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Food Ordering
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/danielfebrero-food-ordering/badge)](https://www.skillsdirectory.com/skills/danielfebrero-food-ordering)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

SKILL.md
---
name: food-ordering
description: >-
  When the user asks you to order food for delivery or pickup, reorder a usual
  meal, get a specific dish brought to them, or says they are hungry and wants
  you to handle dinner, before you open a delivery app.
---
# Food ordering

Order delivery or pickup through DoorDash, Uber Eats, Grubhub, the regional equivalent (Deliveroo, Wolt, iFood, Just Eat), or the restaurant's own online ordering page, using your browser. The user's account on the platform holds their past orders, saved addresses, and payment method; your memory holds their preferences. Two rules hold on every order. For delivery, the address is confirmed with the user before you place it, even when the site already has one saved; for pickup, the store and the pickup time are confirmed instead. The cart summary is confirmed with a question widget before you place it, and the yes places exactly the cart that widget read back.

## Entry points

- "Sort out dinner for me" or "I'm starving, handle it" leaves the meal to you.
- "Get me the same thing I ordered last Friday" points at the platform's order history.
- "Two margherita pizzas from Roberta's for pickup at 7" gives items, restaurant, and timing.
- "Order lunch for me and my vegan boss" is an open-ended order for two: pick restaurants with a vegan main for the boss and something the user likes from memory, and build one cart with both meals.
- A pasted restaurant or menu link: open that exact URL.

## Before you start

- Find the preferred app. Check the Memory section of your prompt and `RecallMemory` for a stated delivery app, then this conversation. An app the user named or memory records is the one you use. If none is, or they ask for the cheapest way, compare channels once the restaurant is picked (see Comparing channels). When only one channel is eligible to compare, order through it without comparing. When none is, because the restaurant has no online ordering page of its own and the user is signed into none of the apps that list it, in the browser or through a connector, pick the platform with the best coverage for their area, say which one you chose, and sign in there (step 2) before building a cart. Do not ask the user which app to use or which one they have an account on, and do not build carts on the others.
- When you compare channels, run `SearchPlugins` for each delivery app that lists the restaurant only to learn which are already connected. Install nothing, show no connect card, and dispatch no helper for an app until Comparing channels finds it eligible.
- Once the platform you will order through is settled (the preferred app, the only eligible channel, the platform you picked when none is eligible, or, after a comparison, the channel the widget's yes chose), run `SearchPlugins` for it. Use a connector if one is installed. Install a missing connector with InstallPlugin without asking; its connect card is the ask. Ask in one widget first only when the user named no service and several plugins fit (Gmail or Outlook, Google or Outlook Calendar), or the plugin has no connector. Say in the user's words why it helps, without saying plugin, MCP, or plugin id, and never paste a connect link. If the search finds nothing, dispatch a `computerUse` subagent. Do not claim a connector exists without a search hit.
- The DoorDash connector builds the cart in its own tools: `preview_order` quotes it with fees, tax, and tip included, which is the checkout read-back step 5 asks for, and `submit_order` places it after the widget's yes, without the browser. Never send its checkout link (`get_checkout_url`) or a cart render in place of placing the order the user asked for; send the link only when its quote shows no way to pay.
- Pull preferences from memory: dietary rules, dislikes, spice tolerance, favorite places, a tipping rule. Past orders live on the platform, not in memory; the subagent reads them there.
- Resolve delivery versus pickup and timing (now or scheduled). Scheduled times follow the Time section of your prompt: state them in the user's zone.
- Treat a stated budget as a hard constraint. Without one, size the order to what their history shows for a similar meal.
- When the ask is open-ended and quality matters ("somewhere good", "the best Thai that delivers"), use the Cursor-managed `restaurant-recommendations` skill to pick candidates, then verify on the delivery app that each is open, delivers to the address, and what the ETA and fee are.

## Flow

1. Dispatch the browser subagent read-only in your first round, in the same round as any `WebSearch`, with every menu source you know in priority order: the exact URL the user linked or the restaurant's page on the preferred platform (on DoorDash, its `/store/` URL), then the restaurant's own online ordering page. Tell it to report the first source that gives categories and prices and to skip the rest. Do not run a curl, a `WebFetch`, or a shell pipeline first and dispatch after they fail; on 2026-09-12 that order cost 49 seconds before the helper started, and the helper then had the menu about 75 seconds later from a source the parent had found in a search. Have it report the URL it ended on and which source that was. When that is the restaurant's page on the preferred platform, have it also report whether the restaurant is open and delivers to the saved address, the ETA, the delivery fee, and, for a reorder, the recent orders on the account, and every later Task text carries that URL. When the menu came from any other host, each cart step still needs the restaurant's page on the channel it orders through: resolve that URL before the cart Task, the way the site playbook's order section says when the platform has one, and never carry the other host's URL into it.
2. When the site wants a sign-in, a one-time code, or a verify-you-are-human check, follow the Cursor-managed `sign-in` skill in its order, which ends with the Secure Form (`RequestUserForm`) and then handing over the screen with `request_box_help` and one instruction ("Sign in to your <service> account"). Never send a question widget before these; the tool is the ask. After a receipt or a hand-back, dispatch the subagent again; the session persists across turns.
3. Pick the restaurant, presenting options first when the request was open-ended (see Presenting choices).
4. Build the cart: exact items, sizes, modifiers, quantities, and the user's instructions in the item notes. Only what the user asked for goes in. Carry the restaurant's URL on the channel you order through, resolved first if the menu came from another host, and the item names as the menu spelled them into the Task text, and paste the site playbook's order section snippet when the site has one, never its place section snippet. A change to the same cart goes back to the same helper, with `MessageSubagent` while it runs or `Task` with `resume` after it reports, not to a fresh dispatch. A one-item ask is a one-item cart, and when a later message narrows the order ("just the pizza", "skip the sides"), the latest message wins. Dismiss upsells ("add a drink?", "round up for charity", a subscription trial) unless the user asked for them.
5. Open checkout and have the subagent report every line: items, subtotal, delivery and service fees, tax, the tip the site preselected, the total, and, for delivery, the ETA and the delivery address shown on the page, or, for pickup, the store address and the pickup time shown on the page. Leave the site's default tip in place unless the user or memory gives a rule, and name it in the summary.
6. Send the summary with `SendToUser`, with the address written out, then one question widget whose prompt names the address and the total ("Place the $34.20 order to 512 Valencia St, ETA 35 to 45 min?") with options to place it, change the address, or edit the cart, and allowCustom on so they can paste a promo code or name a change. The saved address may be stale; the user may be somewhere else tonight. For pickup the prompt names the store and the pickup time instead ("Place the $31.50 pickup at Roberta's, 261 Moore St, ready at 7:00 PM?") with options to place it, change the time, or edit the cart. The widget ends your turn.
7. If they give a promo code or a change, apply it and re-confirm with a fresh widget when the total moved by more than the discount. Ask about a promo code before finalizing only when the checkout shows a promo field.
8. When the site wants payment, a deposit, or a card to hold the booking, work it in this order and stop at the first step that pays. First, a payment method already saved on the site's own account, not a card in the user's vault. Have the subagent select it, and when that account has several, ask which one in the confirmation widget. Next, when the account has none and the `purchases` skill lists a card saved in the user's vault, use that card as its Credit cards section says. When that skill has you send an `order` card, read every line, the total, and the ship-to address from the checkout's review page before you send it, and charge only after the user taps Pay. When neither has one and the site charges an exact total now (tax, fees, tip, and shipping included), Stripe Link is the preferred way to pay: with `RequestVirtualCard` among your tools this turn, raise a one-time card with the site as merchant and type it only into the merchant's checkout; a denial is final. Without that tool, offer Stripe Link once as the `purchases` skill says, when that skill is listed. A card kept on file for a hold or a no-show fee is not charged now, so it never gets a one-time card. Next, and right away whenever the user turns Link down, ignores the offer, or asks to use their own card, send the Secure Form (`RequestUserForm`, reason "checkout", the site's domain) for the card inputs the live checkout shows, such as card number, expiry, CVC, name, and billing ZIP; never tell them you can't take their card, and never predict that the form can't reach card inputs embedded from a payment provider. Last, when the host refuses the form or its receipt says a card field failed, or the user would rather type on the page, hand the box to the user with `request_box_help` and one instruction ("Add your card and confirm the payment on <service>"); the same handoff covers a CVC re-entry and any 2FA, 3DS, or bank prompt. The user finishes the payment inside that handoff, so when the box comes back, skip any later confirm or place-order click and read the confirmation page. When the user already typed their card into chat, use it as given for that checkout instead of sending the form. Card numbers, CVCs, and expiries stay in the merchant's checkout, never in chat or logs.
9. Place the order only after the widget's yes, and only the cart that widget read back. A correction that arrives after the widget went out ("skip the sides", "make it two") is a no for that cart: rebuild, send a fresh widget with the new lines, and wait for its yes. For the place dispatch, resume the helper that read checkout back and paste the site playbook's place section snippet when the site has one. Otherwise have the subagent click the place-order control, dismiss the post-order prompts (rate, tip more, share, add items), and read the confirmation page.
10. For a delivery order, send a shipment card at stage `placed` from the confirmation page (see Shipment card), with the restaurant as its store and the restaurant's page on the channel the order went through as its URL, and the ETA, the total charged, and the address in `content`. For pickup, or when no card goes out, report the order number, the ETA, the total charged, and the address, and attach the confirmation screenshot at its exact saved path. Save a preference the user stated or confirmed ("always DoorDash", "extra spicy") with `UpdateMemory`. If they ask to make it recurring, create a routine with `UpdateRoutine`.

## Comparing channels

Delivery apps add delivery and service fees and often price the menu higher than the restaurant does, and they show those fees only at checkout, so the restaurant's own online ordering page is often the cheaper way to order the same food. When you compare channels (see Before you start):

- In step 1, have the helper read every menu source instead of stopping at the first, and report the restaurant's page on each delivery app it is listed on and whether the user is signed in there. In the browser, an app counts as signed in only when its page shows the user's account; a sign-in link or a signed-out notice means it is not. An app with a connected connector counts as signed in through that connector, whatever the browser shows. Decide eligibility from that report and the `SearchPlugins` results, before any cart.
- Quote every eligible channel, even when one looks cheaper from its menu prices: a membership or promo on a delivery app can erase its fees. Quote up to three channels for the same cart: the restaurant's own online ordering page when it has one, and at most two delivery apps the user is already signed into, in the browser or through a connected connector. Do not compare an app that would need a new account or sign-in; with no eligible channel at all, build no carts and follow Before you start, which says which app to sign into. Only one browser helper runs at a time, so dispatch one helper for all the browser channels: it builds the same cart through step 5 on each channel in turn, in the same tab, and reports for every channel the checkout lines step 5 lists and the checkout page's URL. Each channel keeps its cart when the helper moves on. Tell it to stop at a sign-in, one-time code, or verify-you-are-human wall on a channel, note it, and move on to the next rather than hand it to the user; step 2 runs only for the channel the user picks. A connected connector's quote or preview tool gives its channel's checkout total, and you call it while the helper works. The same connector's order tool places that order in step 9.
- Compare the checkout totals as each page would charge them, with fees, tax, and tip included, then the ETA or pickup time. A menu price is not a quote, so never ask the user to pick a channel, or pickup versus delivery when they said either is fine, from menu prices: go from the menu straight to the carts, and let the step 6 widget be the only question. When the preselected tips differ, name each channel's tip beside its total. Leave out a channel that stopped at a wall or shows no total before payment, and name it with the reason.
- In step 6, name the cheapest channel in the widget's prompt with its total, and give each other channel's total and ETA in the summary ("$31.20 on Roberta's own site, ready at 12:40; $38.90 on DoorDash, ETA 12:35"). Add an option for another channel only when it is meaningfully faster.
- The yes places the order on the channel it chose, by resuming the helper that built the carts for step 9 with that channel's checkout URL: it opens that URL, confirms the items and total match what the widget read back, and only then places it, stopping to report if they differ. Or, for a connector's quote, through that connector's order tool. A connector order skips step 8: it pays only with a way to pay that the connector's quote lists, never a one-time card or the Secure Form, since it has no web checkout to type a card into. Leave the other carts unplaced.

## Shipment card

When `SendToUser` has a `shipment` field, report an order's status as a shipment card in it, one card per order. Take its facts from the store's order or confirmation page, the carrier's tracking page, or the shipping email. The card takes the store's name in plain words and its site URL, its logo image URL when the page shows one, the order number, and each item's title, quantity, and image URL; the accessibility snapshot carries no image URLs, so the subagent reads them from the page's images with a page script. The card needs the store, the order number, and at least one item. Without that field or any of those, report in text instead. Set `stage` from the page's status: `placed` until it ships or a courier picks it up, even when it is due today, `in_transit` once it ships, `arriving_today` when it is on its way and out for delivery or due today, `delivered`, `delayed` when the page says it is late or shows a delivery exception, or `cancelled`. Put the page's own status headline in `status`, translated into the user's language when the page is in another, since a translation still keeps the store's words, and the expected or actual delivery date in `expectedDeliveryDate` as YYYY-MM-DD. For a range, use its last day. Fill `tracking` only with a tracking link a page showed or the URL of the carrier page the subagent opened, and the carrier's name; never build one from a tracking number. Leave out any value no page showed. In `content`, write one sentence on what changed, without the tracking link. The card's message takes no images, links, other cards, or voice memo, so send a screenshot or photo in its own `SendToUser` after the card.

## Presenting choices

- Open-ended meal: three to five restaurants with cuisine, one quality signal, ETA, delivery fee, and any fit from memory ("you reordered from here twice"). Attach the saved screenshot of the results when the cards show photos, ratings, or delivery times worth seeing; a text summary is enough when they do not. Ask which one with a question widget before opening a menu or building a cart.
- Specific dish, no restaurant ("any chance of pad thai tonight?"): the top restaurant and item pairs with price and ETA, then ask. Do not take the first result because it is the highest rated or the fastest.
- Exact restaurant or a reorder: skip the restaurant options, but still confirm the cart, the address or pickup time, and the total before placing.
- "Same as last time" with several recent orders in the history: show the last two or three and ask which. Do not guess.
- Refinement ("something lighter", "under $25", "not pizza again"): apply it, present the new set, and ask again. Never swap in a different restaurant on your own.
- The place-order confirmation is the one widget every order needs. Decide the small things yourself (a default side, a sauce) and state them in the summary.
- Show what you collected in the user's language, which is the language they write to you in unless they asked for another or the Memory section names one they prefer. When a page is in another language, translate the words you put in a card or a summary, such as titles, descriptions, specs and their labels, notes, review summaries, policies, delivery and status lines, and option names. Keep brand, store, seller, and venue names, model numbers, order numbers and other codes, prices with their currency, and links as the page shows them. Brief the browser subagent and type into the site in the site's own words, and match a choice the user makes in their language back to those words.

## Pitfalls

- Dispatching the cart build without the store URL, or with a past order to copy. The helper heads for order history and spends a minute there before the first item.
- Sending the helper to the restaurant's own site for a menu when your `WebFetch` of it showed hours and no prices. On 2026-09-12 the helper's navigates there failed twice (a name that did not resolve, then an SSL name alert) and it spent three rounds and a DNS check on them. A site that gave you no menu gives the helper none either; leave it off the source list. The restaurant's online ordering page is a different page, often on another host, and stays on the list.
- Treating a saved address as the right address. Confirm it every time, and look harder when the conversation suggests they are traveling or at work.
- Asking for a delivery address on a pickup order. The pickup widget names the store and the time; the address question is a round trip the user does not need.
- Placing a cart the user did not approve. A yes covers one specific cart. When the items changed after the widget went out, that yes is spent; re-confirm before placing.
- Building a cart before checking that the restaurant is open and delivers to the address.
- Confirming the menu subtotal instead of the checkout total. Fees, tax, and tip land at checkout; the number in the widget is the one the card will be charged. If the total changes after the yes (a substitution, a surge fee), stop and re-confirm.
- Accepting an upsell, a round-up prompt, or a subscription trial that the user did not ask for.
- A companion's item in a group order says nothing about the user's taste.
- Inventing an ETA or an order number. Report only what the confirmation page shows, and if it shows no number, say so.
- Saving an address or a dietary rule to memory that the user did not state or confirm.
- Spending on your own initiative. The user must have asked for this specific order, and the widget's yes is what places it.

## Site playbooks

Before you dispatch the browser subagent, Read the `site-playbooks-doordash` skill in this catalog, if it names the site you are about to use, and paste the Dispatch snippet of the job that matches your step (a read-only lookup, or a cart and checkout) into the Task text. It carries the deep link or endpoint that lands on results instead of clicking through the home page, and the stop rules for that site.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.