{
  "markdown": "# Peckish 🍜\n\n**Feeling peckish? Just ask.** An AI ordering agent for DoorDash — it searches,\ncompares real totals (fees included), builds the cart, and *you* approve every\norder. Built on [Claude](https://platform.claude.com) and DoorDash's official\n[`dd-cli`](https://github.com/doordash-oss/doordash-cli).\n\nOne tool layer, three surfaces:\n\n| Surface | Start | Best for |\n|---|---|---|\n| **Terminal chat** | `peckish` | Living in the terminal |\n| **Local web app** | `peckish-web` → http://localhost:4747 | Consumer-friendly UI: store cards, live quote, Stop button, order modal |\n| **MCP server** | `claude mcp add peckish -- npx -y peckish-mcp`, or the double-click [`.mcpb`](https://github.com/CydVilla/peckish/releases/latest) | Claude Desktop / Claude Code users — **no API key needed**; your Claude subscription powers the model |\n\n**Which one is for me?**\n\n- **Comfortable with a terminal?** → Terminal chat. Fastest, most informative.\n- **Want something that feels like an app?** → Local web app. Cards, live\n  quote, a proper Place-order button.\n- **Already use Claude Desktop or Claude Code?** → MCP server. No API key,\n  no separate chat window — Claude itself becomes your ordering agent, and\n  order confirmation appears as a native dialog.\n\n<p align=\"center\">\n  <img src=\"docs/demo.gif\" alt=\"Peckish finding a dinner under $25: tool calls run, a recommendation streams in with the fee-included total, and an order-confirmation dialog asks for approval before anything is placed.\" width=\"820\">\n  <br>\n  <em><sub>Scripted demo of the web app — store, prices and card are fictional;\n  the interface and the approval gate are the real ones.</sub></em>\n</p>\n\n**[peckish on the web →](https://cydvilla.github.io/peckish/)**\n\n**Updates:** every release ships with full notes, all artifacts, and a\n`SHA256SUMS.txt` on [Releases](https://github.com/CydVilla/peckish/releases) —\nsee [CHANGELOG.md](CHANGELOG.md) for the history. Watch the repo (Releases\nonly) to get notified.\n\nInstall in one line — no git clone:\n\n```sh\nnpm install -g peckish\n```\n\n**Prefer an app?** Download the\n[Mac app (.dmg)](https://github.com/CydVilla/peckish/releases/latest) —\nguided setup, no terminal at any step. See [Mac app](#mac-app) below.\nEverything runs on your own machine either way, because dd-cli holds your\nDoorDash session there — a Mac (Apple Silicon) or Linux x86_64, including\ncontainers and cloud sandboxes: see\n[Linux, containers and headless hosts](#linux-containers-and-headless-hosts).\n\n```\nyou › Find me a high-protein dinner under $25 that can arrive within 45\n      minutes. Avoid mushrooms and excessive fees.\n\n⚙ search_restaurants {\"query\":\"grilled chicken bowls\",\"limit\":8}  ✓ 2.1s\n⚙ get_menu {\"store_id\":\"35406455\",\"filter\":\"chicken\"}             ✓ 1.8s\n⚙ list_carts {\"store_id\":\"35406455\"}                              ✓ 1.2s\n⚙ add_items_to_cart {…}                                           ✓ 2.4s\n⚙ preview_order {\"cart_uuid\":\"…\"}                                 ✓ 3.9s\n\nBest fit: Sharon Korean Kitchen (4.8★, ~24 min) — Grilled Chicken Bulgogi\nBowl, $16.95. No mushrooms listed. Total with fees: $21.40 on your Visa\nending 1234. Suggested Dasher tip is $3.50 — that, another amount, or none?\n~$0.04 turn · $0.04 session\n```\n\n---\n\n## Get started (user guide)\n\n### 1. Prerequisites\n\n- **A Mac with Apple Silicon** (M1–M4) **or Linux x86_64** — the two platforms\n  dd-cli publishes builds for. Peckish is local-first: whichever machine you\n  run it on is the backend on every surface, because that's where dd-cli holds\n  your DoorDash session.\n- **Node.js 20+** — `node --version` to check; install from nodejs.org or brew.\n- **DoorDash CLI access** (currently waitlist-gated by DoorDash). Peckish\n  0.4.0 requires **dd-cli ≥ 0.2.1** — on Linux, **≥ 0.2.2**, the first release\n  with Linux builds. Download the release from\n  [doordash-oss/doordash-cli](https://github.com/doordash-oss/doordash-cli/releases),\n  **verify the SHA256 checksum against the published value**, then:\n  ```sh\n  # macOS (Apple Silicon)\n  tar -xzf dd-cli-v*-darwin-arm64.tar.gz && cd dd-cli-v*-darwin-arm64\n  # Linux (x86_64)\n  tar -xzf dd-cli-v*-linux-amd64.tar.gz && cd dd-cli-v*-linux-amd64\n\n  bash install.sh          # both platforms — installs to ~/.local/bin/dd-cli\n  dd-cli login             # sign in to DoorDash in your browser\n  ```\n  No browser on that machine (container, VM, cloud sandbox)? See\n  [Linux, containers and headless hosts](#linux-containers-and-headless-hosts).\n- **An Anthropic API key** for the terminal/web surfaces\n  ([console.anthropic.com](https://console.anthropic.com)) — *or skip the key\n  entirely and use the MCP surface with your Claude subscription (step 4).*\n\n### 2. Install Peckish\n\n```sh\nnpm install -g peckish\n```\n\nThat's it — you now have three commands: `peckish` (terminal chat),\n`peckish-web` (web app), and `peckish-mcp` (MCP server).\n\n<details>\n<summary>Or install from source (contributors)</summary>\n\n```sh\ngit clone https://github.com/CydVilla/peckish.git\ncd peckish\nnpm install\nnpm test          # optional: 25 unit tests, no network needed\nnpm run dev       # terminal chat (or: npm run web / npm run mcp)\n```\n\n</details>\n\n### 3. Run it — terminal or web\n\n```sh\nexport ANTHROPIC_API_KEY=sk-ant-…   # from console.anthropic.com\n\npeckish         # terminal chat\npeckish-web     # web app → open http://localhost:4747\n```\n\nOn boot Peckish verifies your DoorDash sign-in, shows your default delivery\naddress, and flags any open carts you forgot about. If sign-in is missing or\nexpired, Peckish offers to fix it for you: the terminal asks before launching\n`dd-cli login` (which opens your browser), the web app shows a sign-in card,\nand mid-conversation the agent can offer the same assist on any surface — you\napprove, sign in in the browser, and it picks up where it left off. On a\nmachine with no browser, Peckish skips that offer and tells you how to inject\na token instead — see below.\n\n### 4. Or run it inside Claude — no API key\n\nClaude itself becomes the ordering agent, and your Claude subscription pays for\nthe model. Pick whichever fits your client:\n\n**Claude Code** — one line:\n\n```sh\nclaude mcp add peckish -- npx -y peckish-mcp\n```\n\n**Claude Desktop** — download `peckish-0.2.2.mcpb` from\n[Releases](https://github.com/CydVilla/peckish/releases/latest) and\ndouble-click it. Claude Desktop installs it like a browser extension: no\nterminal, no Node install, no JSON editing.\n\n<details>\n<summary>Or configure Claude Desktop by hand</summary>\n\nAdd to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"peckish\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"peckish-mcp\"]\n    }\n  }\n}\n```\n\nIf dd-cli isn't at `~/.local/bin/dd-cli`, add\n`\"env\": { \"DD_CLI_PATH\": \"/your/path/to/dd-cli\" }` — desktop apps don't\ninherit your shell `PATH`.\n\n</details>\n\nPeckish is also listed in the [MCP Registry](https://registry.modelcontextprotocol.io)\nas `io.github.CydVilla/peckish`, so clients that browse the registry can find\nit directly.\n\nRestart Claude Desktop and ask it to find you dinner. Order confirmation\nappears as a native dialog; clients that can't render dialogs can browse and\nbuild carts but **cannot place orders** (fail closed).\n\n### 5. Everyday use\n\nThings to say:\n\n- *\"Find me a high-protein dinner under $25 that can arrive within 45 minutes. Avoid mushrooms and excessive fees.\"*\n- *\"Compare the real totals at the top two — fees included.\"*\n- *\"Reorder my usual from Sharon Korean.\"*\n- *\"What did I spend on delivery last month?\"*\n- *\"Is this place actually good?\"* (checks web reviews)\n- *\"Never mushrooms, ever.\"* → saved permanently; applied automatically next time\n- *\"Get me milk, eggs, and a pound of ground beef from Whole Foods.\"*\n\n**Placing an order** always ends with an explicit confirmation *you* perform —\ntyping `yes` in the terminal, clicking **Place order** in the web modal, or\napproving the dialog in Claude Desktop. Before that, Peckish must show you the\nitemized quote, confirm the tip, and name the card being charged. Decline\nanything and it backs off.\n\n**Controls & housekeeping**\n\n| Where | What |\n|---|---|\n| Terminal | `/prefs` saved preferences · `/cost` session spend · `/reset` new conversation · `/quit` · **Ctrl+C stops a running turn** |\n| Web | **Stop** button cancels a turn · **New chat** resets · header chip shows session cost · click the **address chip** to switch your delivery address (editing an address's text happens on doordash.com — Peckish picks it up automatically) |\n| Both | Preferences live in `~/.peckish/preferences.json`; a full audit log of every tool call and confirmation is written to `~/.peckish/logs/*.jsonl` |\n\n**Cost:** defaults are tuned for low spend at decent quality — `claude-sonnet-5`\nat medium effort, prompt caching on the system prefix and conversation tail,\nand server-side context editing that prunes stale menu payloads in long\nsessions. The cost meter shows the approximate spend per turn and per session.\nMax quality: `DD_AGENT_MODEL=claude-opus-4-8 DD_AGENT_EFFORT=high`. (On MCP,\nthe client chooses and pays for the model.)\n\n**Troubleshooting**\n\n| Symptom | Fix |\n|---|---|\n| `DoorDash sign-in is missing or expired` | Accept the built-in sign-in assist (it runs `dd-cli login` for you), or run it in a terminal yourself |\n| The same, on a headless Linux box | There's no browser to sign in with: `dd-cli export-token` on a machine that has one, then `DD_CLI_ACCESS_TOKEN=…` here ([details](#linux-containers-and-headless-hosts)) |\n| Auth errors right after upgrading dd-cli | New CLI versions can need fresh scopes — sign in again (assist, `dd-cli login`, or a fresh `export-token`) |\n| `Anthropic authentication failed` | `export ANTHROPIC_API_KEY=…` in the same shell, restart |\n| `dd-cli binary not found` | Install dd-cli (step 1) or set `DD_CLI_PATH=/path/to/dd-cli` |\n| `no dd-cli build` for your machine | dd-cli ships macOS arm64 and Linux x86_64 only — Intel Macs and Linux arm64 can't run Peckish |\n| Web app port in use | `PECKISH_PORT=5757 peckish-web` |\n| A turn ran away | Ctrl+C (terminal) / Stop (web) — history rolls back cleanly |\n\nEnv vars: `DD_AGENT_MODEL` (default `claude-sonnet-5`), `DD_AGENT_EFFORT`\n(`low`–`max`, default `medium`), `DD_CLI_PATH`, `PECKISH_PORT` (default `4747`),\n`DD_CLI_ACCESS_TOKEN` (read by dd-cli itself — browserless sign-in).\n\n---\n\n## Mac app\n\nA double-clickable app for people who never want to see a terminal:\ndownload `Peckish-x.y.z-arm64.dmg` from\n[Releases](https://github.com/CydVilla/peckish/releases/latest), drag\n**Peckish** to Applications, and open it.\n\n**First launch (Gatekeeper):** the app is ad-hoc signed but not notarized (no\npaid Apple Developer ID), so macOS won't open it on a plain double-click the\nfirst time. **Right-click the app → \"Open\" → \"Open\"** (or approve it under\nSystem Settings → Privacy & Security). Only needed once.\n\n> If macOS instead says **\"Peckish is damaged and can't be opened\"**, you have\n> a build from before this was fixed, or the download quarantine got confused.\n> Clear it once and it opens normally:\n> ```sh\n> xattr -cr /Applications/Peckish.app\n> ```\n\nFirst-run setup happens in the app — three buttons, no terminal:\n\n1. **DoorDash CLI** — one-click guided install (downloads the official\n   release, verifies its SHA256 checksum before running anything). If you\n   don't have dd-cli access yet, there's a waitlist link.\n2. **Sign in to DoorDash** — opens your browser; the app detects when\n   you're done. Your sign-in lives in the macOS keychain.\n3. **Anthropic API key** — paste it once; it's stored encrypted with\n   Electron `safeStorage` (keychain-backed), never in plain text.\n\nThen **Open Peckish** — same web app, same order-confirmation modal, same\nsafety gates; the app is just a shell that runs the local server for you on\na random localhost-only port. Requires Apple Silicon; Node.js is **not**\nrequired (the app bundles its own runtime).\n\nBuilding it yourself: `cd desktop && npm install && npm run dist` →\n`desktop/dist/Peckish-*.dmg`.\n\nThe `.dmg` is the one Mac-only surface. The terminal, web and MCP surfaces all\nrun on Linux too:\n\n---\n\n## Linux, containers and headless hosts\n\ndd-cli **v0.2.2** added Linux (amd64) builds, so all three Peckish surfaces run\non Linux x86_64 unchanged — same tools, same order gate, same audit log.\nInstall dd-cli from the same release page (asset\n`dd-cli-v<version>-linux-amd64.tar.gz`, verify its SHA256, `bash install.sh`),\nthen `npm install -g peckish`. If you put the binary somewhere other than\n`~/.local/bin/dd-cli`, set `DD_CLI_PATH` — Peckish also checks\n`/usr/local/bin/dd-cli` and your `PATH`.\n\n**With a desktop session** (`DISPLAY` or `WAYLAND_DISPLAY` set), nothing\nchanges: `dd-cli login` opens your browser and the built-in sign-in assist\nworks exactly as it does on a Mac.\n\n**Without one** — a container, a VM, a cloud sandbox, SSH with no forwarding —\nthe browser flow cannot complete, so Peckish stops offering it (no spawned\nlogin that hangs forever, no \"run `dd-cli login`\" advice that can't work) and\npoints at the token path instead:\n\n```sh\n# 1. on a machine that HAS a browser (dd-cli ≥ 0.2.2)\ndd-cli export-token\n\n# 2. in the environment that runs Peckish\nexport DD_CLI_ACCESS_TOKEN='<the token>'\npeckish            # or peckish-web / peckish-mcp\n```\n\ndd-cli picks the token up from the environment Peckish passes down, so every\nsurface authenticates without a keychain or a browser.\n\n- **That token is live access to your DoorDash account** — it can place real\n  orders. Treat it like a password: keep it in your runtime's secret store, not\n  in an image layer, a `docker run -e` in your shell history, or a committed\n  `.env`. Mint a fresh one with `dd-cli export-token` when it expires.\n- **The order gate does not change.** Placing an order still needs your\n  explicit approval on the surface you're using (typed `yes`, the web modal, or\n  the MCP dialog) — headless means no browser, not unattended ordering.\n- **`peckish-web` in a container** binds `127.0.0.1` *inside the container* by\n  design, so a published port (`-p 4747:4747`) can't reach it. Run the\n  container with `--network host` (Linux), or use the terminal or MCP surface,\n  which need no port at all.\n- **Not supported:** Linux arm64 and Intel Macs — dd-cli publishes no build for\n  either, and Peckish says so explicitly instead of failing obscurely.\n\n---\n\n## What it does\n\n- **Search → menus → cart → preview → confirm → submit**, with the real\n  fee/ETA quote (`order preview`) driving every recommendation.\n- **Comparison shopping**: builds carts at up to 3 finalists, compares true\n  totals + fee share + ETA, recommends one, deletes the losers.\n- **Fee tactics**: promo scanning with consent, pickup-vs-delivery comparison,\n  DoorDash credits surfaced, DashPass status shown.\n- **Memory**: dietary rules and habits persist across sessions and surfaces.\n- **History**: \"my usual\" from order frequency, honest spend breakdowns from\n  receipts, reorders with silent-drop detection.\n- **Web reviews** via Claude's server-side web search (never used for prices —\n  dd-cli is the only source of truth for ordering data).\n- **Group carts** (new in 0.4.0): \"start a group order for the team, $25 each\" —\n  creates a shareable cart link, optional per-person spend limit, host reviews\n  and submits when everyone's in.\n- **Express delivery** (new): asks for Priority when you want it fastest —\n  offered per-cart, priced into the quote before you approve.\n- **Credits control** (new): DoorDash credits apply by default; say \"don't use\n  my credits\" to opt out for an order.\n- **Enterprise chains** (new): Domino's, Sweetgreen, Dave's Hot Chicken and\n  other big chains are now orderable (dd-cli ≥ 0.2.1).\n- Work benefits (company budgets + expense codes), scheduled delivery,\n  pickup, groceries/retail/pets/alcohol.\n\n## Architecture\n\n```\nterminal REPL          local web app           MCP client (Claude Desktop…)\n src/index.ts           src/web.ts + public/    src/mcp.ts\n      └────────────┬─────────┘                       │  (client's model reasons;\n                   ↓                                 │   server instructions guide it)\n     Claude agent loop, streaming                    │\n     src/agent.ts · claude-sonnet-5 · strict tools   │\n     · adaptive thinking · context editing           │\n     · prompt caching · web_search · cost meter      │\n                   └───────────────┬─────────────────┘\n                                   ↓\n                 28 typed tools — src/tools.ts (strict: true)\n                                   ↓\n                 sanitizing wrapper — src/ddcli.ts\n                                   ↓\n                 dd-cli --json-output  →  DoorDash\n```\n\n## Safety model\n\nPlacing an order **always requires an explicit human approval rendered by the\nsurface, not by the model**:\n\n| Surface | The gate |\n|---|---|\n| Terminal | Type `yes` at a prompt |\n| Web | \"Place order\" modal (declines automatically after 5 min) |\n| MCP | Client elicitation dialog; clients without elicitation **cannot place orders** (fail closed) |\n\nAlso on every surface:\n\n- **Strict tool schemas** — the API guarantees tool arguments validate before\n  any handler runs (no malformed-argument class).\n- **Abortable turns** — Ctrl+C / Stop rolls history back to the turn start.\n- **Audit log** — every tool call, argument set, duration, confirmation\n  outcome, and submit result in `~/.peckish/logs/*.jsonl`.\n- Tip confirmed + card named before any submit ask; submit never auto-retries\n  (not idempotent); success reported only after `order status` confirms.\n- Merchant text treated as data (widget/assistant-instruction fields stripped);\n  read-only CLI calls retry once on transient errors, mutations never do.\n- Web server is localhost-only (Host + Origin checks).\n\n## What Peckish shares with DoorDash\n\ndd-cli ≥ 0.2.1 requires an `--intent` note on every command, which DoorDash\nsays it may review for research and product improvement. DoorDash's documented\nformat asks for your **verbatim prompt** — but food prompts routinely contain\ndietary, health, and religious signals, which DoorDash's own guidance says to\navoid. So Peckish defaults to privacy:\n\n- **What is sent:** a one-line goal summary authored by the model at generic\n  altitude (e.g. `Summary: Help the user order dinner`), plus an explicit\n  `user prompt/purpose: \"(not shared — Peckish privacy default)\"` marker.\n- **What is never sent by default:** your verbatim words, dietary rules,\n  budgets, names, saved preferences, or conversation content.\n- **Opt in to the full format:** set `PECKISH_INTENT_VERBATIM=1` and the\n  intent will include your opening request verbatim, as DoorDash's docs ask.\n\nIndependent of intent, DoorDash necessarily sees the API traffic itself\n(searches, carts, orders) — that's inherent to ordering.\n\n## Repo map\n\n| File | What it is |\n|---|---|\n| `src/index.ts` | Terminal REPL surface (abort, cost lines, /cost) |\n| `src/web.ts` + `public/index.html` | Web surface: SSE streaming, cards, Stop, confirm modal, Origin guard |\n| `src/mcp.ts` | MCP stdio server: 28 tools + session context, instructions, elicitation gates |\n| `src/agent.ts` | System prompt + streaming tool loop (beta: context editing; web_search; usage) |\n| `src/tools.ts` | Tool schemas (strictified) + handlers; menu trimming/filtering |\n| `src/ddcli.ts` | `execFile` wrapper: envelope parsing, UI-field stripping, error mapping, bounded read-only retry |\n| `src/platform.ts` | Supported dd-cli targets + whether sign-in can use a browser here or needs an injected token |\n| `src/confirm.ts` | Pluggable confirmation gates (fail closed) |\n| `src/costs.ts` / `src/logger.ts` | Cost accounting · JSONL audit log |\n| `src/prefs.ts` | Preference persistence (`~/.peckish/`) |\n| `tests/unit.test.ts` | 25 unit tests (`npm test`), no network needed |\n| `desktop/` | Electron shell for the Mac app (.dmg): onboarding + server launcher, no agent logic |\n| `packages/mcp/` | The `peckish-mcp` npm package — a launcher so `npx -y peckish-mcp` starts the MCP server |\n| `extension/` | Claude Desktop extension (`.mcpb`): manifest + vendored server. `node build-manifest.mjs && mcpb pack . peckish.mcpb` |\n| `server.json` | MCP Registry metadata (`io.github.cydvilla/peckish`) |\n\n## Releasing\n\nEverything ships from one tag. `.github/workflows/release.yml` publishes both\nnpm packages, registers the MCP Registry entry, builds the `.mcpb` and the\n`.dmg`, and attaches both to the GitHub release:\n\n```sh\nnpm version patch          # or edit the versions by hand\ngit push && git push --tags\n```\n\nEvery publish step is **skip-if-already-published**, so re-running a tag after a\nfailure is safe. `.github/workflows/ci.yml` runs typecheck, tests, a metadata\nconsistency check, and a real MCP handshake on every push.\n\n`scripts/check-consistency.mjs` guards the metadata that spans files and drifts\nsilently — the registry namespace casing, matching `server.json` name and\n`mcpName`, the 100-character registry description cap, and the extension's\nadvertised tool list. Run it locally before tagging.\n\n<details>\n<summary>One-time setup for the automation</summary>\n\n**npm** — either configure\n[trusted publishing](https://docs.npmjs.com/trusted-publishers) on npmjs.com for\nboth `peckish` and `peckish-mcp` (provider: GitHub Actions, repo\n`CydVilla/peckish`, workflow `release.yml`) so no secret is needed, **or** add an\n`NPM_TOKEN` repository secret using a granular access token with \"bypass 2FA\"\nenabled.\n\n**MCP Registry** — nothing to configure. The workflow authenticates with\n`mcp-publisher login github-oidc`, and GitHub's OIDC token proves the repo owner\nis `CydVilla`, which grants the `io.github.CydVilla/*` namespace.\n\n**Mac app signing** — the `.dmg` is built unsigned. Notarized builds would need\nan Apple Developer ID plus `CSC_LINK`/`CSC_KEY_PASSWORD` and notarization\nsecrets.\n\n</details>\n\n## Notes & limitations\n\n- Local-first by design: hosted delivery (SMS bots, voice) would require\n  DoorDash's partner API — your own machine is the backend here.\n- One open cart per store (DoorDash rule) — Peckish collision-checks and asks.\n- `payment-method list` sees cards only; wallet defaults (Apple Pay etc.) are\n  confirmed generically or via the browser checkout URL.\n- Age-restricted items can't be submitted by an agent — checkout URL fallback.\n- Popularity data is deliberately unused (per dd-cli guidance); web reviews\n  fill that gap with attribution.\n- Cost figures are close estimates from token usage at list prices.\n",
  "bytes": 22529,
  "sha": "93cccb31181ff8da97488226d657ebe29cc7ed64f7990bf70fc1ee31ee05e0e5",
  "repo_slug": "cydvilla/peckish",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_cydvilla_peckish_aac014ae/readme"
}