← back to Delivery Address Fix
SKILL.md
132 lines
---
name: delivery-address-fix
description: Pluggable, provider-adapter skill that fixes/saves a delivery address on a food-delivery account (UberEats, DoorDash, Instacart) by driving a REAL headed Chrome through the provider's own site UI, with human-in-the-loop 2FA relayed over email. Use when Steve (or any authorized user) says "change my delivery address on <provider>", "my order is going to the wrong address", "save this address on ubereats/doordash/instacart", "/delivery-address-fix", or replies to an in-flight address-fix thread with a 2FA code, card digits, or an address. Born from the 2026-08-02 UberEats session (TK-10140); generalized per Steve's directive ("The system must work for all users. Allow user to plugin this skill for ubereats or Instacart and door dash", 2026-08-02, TK-10145).
---
# delivery-address-fix — pluggable delivery-address fixer
One engine, N provider adapters. The engine owns the browser session, the
human-in-the-loop (HITL) email relay, and the hard rails. Each adapter
(`references/<provider>.md`) owns the provider-specific selectors and flow.
## Architecture
```
user email/request
│
▼
ENGINE (this file) ADAPTERS (references/)
- session lifecycle ──► ubereats.md (PROVEN 2026-08-02)
- HITL email relay doordash.md (scaffold — verify on first run)
- hard rails instacart.md (scaffold — verify on first run)
- screenshots/audit
```
## Engine: session lifecycle
1. **Workdir per run**: `~/delivery-address-fix/<provider>-<yyyymmdd>/`
(screenshots, step scripts, HANDOFF.md). Keep a HANDOFF.md updated after
EVERY state change so any later session can resume cold.
2. **Browser**: long-lived headed REAL Chrome via Playwright persistent
context — launcher template in `scripts/browser-server.js` (edit profile
dir, CDP port, start URL per provider; one port per provider, 9223+).
Headless gets bot-walled; headed real Chrome is the proven path.
3. **Connect for each step over CDP** (`http://127.0.0.1:<port>`) with short
scripts — never restart the browser between steps; the parked session IS
the state.
4. **⚠️ Select the target tab by URL substring** (e.g. `uber.com`), NEVER
`pages()[0]` — other tasks open tabs in the same browser (proven failure
2026-08-02: a Tesla auth tab became index 0).
## Engine: HITL email relay (2FA, card gates, address)
The user is remote; codes and card digits arrive by email reply, gated by the
sender allowlist + secret phrase (per the mailbox's standing rules).
- **Code gates (SMS/call/email) EXPIRE FAST** — Uber sessions died in well
under 30 min. Enter codes the moment they land. If expired: restart the
auth flow (adapter has the script pattern), tell the user the NEWEST code
wins, and that any resend INVALIDATES prior codes. Never resend
speculatively — only when the user says the code didn't arrive.
- **Static gates (card-digit verification) do NOT expire** — park and wait.
NEVER guess digits, NEVER submit blank (risks killing the session). If the
reply contains no digits, re-ask specifying exactly which digits.
- **Email-code self-read**: if the provider offers an email code and the
user's inbox is George-readable, read it yourself (strip `<style>` blocks;
beware numbers in the provider's footer address masquerading as codes).
- Every ask to the user states: what's needed, the exact reply format
("1234 <secret-phrase>"), and that sooner is safer.
## HARD RAILS (engine-level, all providers)
1. **VERBATIM ADDRESS ONLY.** Save exactly the address the user typed —
street, city, zip, verbatim. NEVER infer an address from location data,
map readings, charger positions, or context. (2026-08-02 lesson: an
inferred "668 S Alameda St" from a Supercharger reading was WRONG —
"I have never been at alameda!!". If the user hasn't stated the address,
ask for it.)
2. **Never place, cancel, or modify orders** without an explicit per-action
go. Address save ≠ order authority.
3. **Surface before deleting**: list any existing saved addresses that look
wrong to the user before removing anything.
4. **Live-order first**: after login, check for an active order; if it shows
a wrong address, use the provider's order-Help change-address path (if
offered) before touching the address book.
5. **Screenshot every step** into the workdir; update HANDOFF.md.
6. **Credentials**: only from the secrets master (`~/Projects/secrets-manager/.env`)
or the user's explicit reply. Never echo full card numbers/codes back —
last-4 only.
7. **Ticket everything** (`tk`); cost line on every report ($0 local browser).
## Multi-user plugin model (Kickback.ai direction)
Per-user config object — everything user-specific is parameterized, nothing
hardcoded:
```json
{
"user_id": "steve",
"provider": "ubereats | doordash | instacart",
"login_email": "…",
"email_reader": "george:steve-personal | none",
"reply_gate": { "allowlist": ["…"], "secret": "…" },
"address": { "street": "…", "city": "…", "zip": "…", "nickname": "…" },
"cdp_port": 9223
}
```
The engine + adapters read ONLY from this config. A hosted/product version
(Kickback.ai) swaps the email relay for an in-app prompt but keeps the same
adapter contract: `login() → passGates() → liveOrderCheck() → saveAddress()`.
## Adding a provider
Copy `references/_adapter-template.md`, fill in: auth URL, login selectors,
2FA gate types observed, address-book path, order-help path, quirks. Mark
UNVERIFIED until a real run proves each step; promote to PROVEN with dates.
## Runnable scripts (merged from TK-10144, 2026-08-02)
Generic, parameterized — nothing user-specific hardcoded. All take
`--platform <ubereats|doordash|instacart> --user <email> --port <cdp> --match <url-substring>`;
per-user persistent Chrome profiles live under `profiles/<user>-<platform>/`
(gitignored) so a completed login survives restarts.
- `scripts/launch.js` — headed real Chrome (Playwright persistent context,
`channel: 'chrome'`), CDP exposed, navigates to the provider's auth URL.
Supersedes the per-run `browser-server.js` template (kept for reference).
- `scripts/state.js` — screenshot + page text of the target tab (selected by
`--match`, never `pages()[0]`).
- `scripts/enter-code.js` — types a 2FA code / card digits into the parked gate.
- `scripts/restart-login.js` — restarts an expired auth flow (auto-fires a
fresh code; remind the user the NEWEST code wins).
- `scripts/lib.js` — shared CDP attach + tab-select helpers.
Per-user setup: `config.example.json` → `config.json` (gitignored).
Extra flow notes and failure modes: `references/platform-notes.md`.
> Consolidation note: this skill absorbed `~/Projects/delivery-address-skill`
> (TK-10144) on 2026-08-02 per Steve's "work with the other terminal" email —
> two parallel sessions had built the same generalization. This repo is
> CANONICAL; the other is deprecated with a pointer.