tandem
How to operate the Chrome browser shared with the human (the tandem MCP's browser_* tools). Use it whenever you need to navigate, read/analyze pages, get past…
Per-site navigation memory for tandem's shared browser. Profiles that describe a site's skeleton (routes), its durable locators, navigation recipes, and gotchas, so you navigate KNOWING instead of re-deriving the DOM each time. Use it when you start operating a site (check
$ npx -y skills add bgmacris/quimera-ai --skill map --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/mapContext preview
The summary Claude sees to decide when to auto-load this skill.
Per-site navigation memory for tandem's shared browser. Profiles that describe a site's skeleton (routes), its durable locators, navigation recipes, and gotchas, so you navigate KNOWING instead of re-deriving the DOM each time. Use it when you start operating a site (check
name: map description: "Per-site navigation memory for tandem's shared browser. Profiles that describe a site's skeleton (routes), its durable locators, navigation recipes, and gotchas, so you navigate KNOWING instead of re-deriving the DOM each time. Use it when you start operating a site (check whether a profile already exists), when you finish a recon worth saving, or when a saved locator fails (re-record). ASSISTED recon: you draft, the human confirms, it's saved."
Persists *how a specific site is navigated* in a per-host profile. Avoids re-deriving the structure (huge snapshots, ephemeral refs) every session. Complements the "Real navigation — patterns" section of the `tandem` skill: that is CROSS-site technique (infinite scroll, cookie banners…); this is knowledge OF-a-site (the routes of THAT site).
Full design and rationale: `tandem/docs/01-navigation-memory.md`.
Profiles in `~/.claude/tandem/sites/<host>.md` (OUTSIDE git; override `TANDEM_DATA_DIR`). The SOURCE OF TRUTH are the `.md` files; the index is DERIVED from their frontmatter, not kept separately.
Invoke it by its path within the plugin (`scripts/map.sh`); there's no bin on PATH for map.
1. **When you start operating a site**: if a profile already exists, it usually reaches you on its own — a `PostToolUse` hook on `browser_navigate` injects the host's profile the first time you navigate to it in the session (`scripts/hook-inject-profile.mjs`). If it didn't arrive (or you want to re-read it): `map.sh show <host>`. If there's no profile and the work isn't trivial → offer the human to do a recon and save it. 2. **Before trusting a route's locators** (cheap re-check): validate with `fingerprint.mjs check <host> <route>` (structural signal, small JSON), NOT with a targeted `browser_snapshot` (it weighs ~18× the whole profile). `match` → trust that route's `sel:` values WITHOUT a snapshot (see "Frugal flow"). `drift` → point 4. No fingerprint yet → a one-off targeted snapshot, and capture the fingerprint for next time. 3. **After a recon worth keeping**: draft the profile, show it to the human, and only with their OK write it. 4. **If a locator fails** (drift): do NOT try to repair it. Re-derive live, update the profile line with the new anchor and today's date, and tell the human about the change. Rule: *a wrong cached click is worse than a slow click*.
1. Explore with the `browser_*` tools (targeted snapshot, `browser_evaluate` for data, navigating routes). Don't dump raw DOM into the profile: abstract it. 2. Draft using the structure below. Mark each line: `[verified YYYY-MM-DD]` (you lived it now) or `[hypothesis]` (inferred, untested). 3. **Show it to the human. They confirm/correct.** Until then it isn't saved. 4. Write to `$(map.sh path <host>)`. Set `created`/`updated` in the frontmatter.
from the accessibility tree. **Never** position/index nor `eNN` refs (they're ephemeral).
accept the element if the set matches, not just the primary. (Idea stolen from Similo: several weak weighted signals beat a single strong anchor.)
stores HOW to get there and WHAT to look for, not the dump.
= a Playwright selector the agent passes as `target` to act WITHOUT a snapshot. Generate the syntax with `scripts/selector.mjs` (NOT by hand — the quote/regex escaping is easy to mistype): `selector.mjs <role> <name> [--regex] [--anchor]`. Two classes:
For long/fragile names use `--regex` (substring) instead of the exact literal.
use, e.g. `role=row[name=/^{id}/]`. A common prefix (`^TCK-`) matches N rows → the action is strict and throws; that's why it's parameterized to the concrete id.
include them in the value). Notes go in `primary:`/`corroborates:`.
`generic` (no `role=row`/`cell`) and duplicate the list for responsive. Verify LIVE before anchoring by `role=row`; if there's none, anchor by stable class + `text=` + `>> visible=true`. The `selector.mjs` helper (v1) only covers `role=…[name]` — these cases are written by hand for now.
Instead of trusting how old the `[verified]` tag is, compare the structural SKELETON of the page against the one you saved. If it changed → that route's locators are suspect, time to re-check/re-record (the date doesn't tell you that: a page untouched for 6 months is still valid; one that changed yesterday is stale even if the tag is from yesterday).
Engine: `scripts/fingerprint.mjs {capture|check} <host> <route-key>` (JSON signals via stdin). Sidecar `sites/<host>.fingerprints.json` (machine
A Claude Code plugin marketplace by bgmacris. One plugin today — tandem: a Chrome browser shared in real time between you and Claude Code.
Repo: bgmacris/quimera-ai