Skip to content
Development
Skill

/map

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

From plugin
quimera-ai
112 skills1 agent6 commands1 MCP
Install
$ npx -y skills add bgmacris/quimera-ai --skill map --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/map

Context 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

SKILL.md

map.SKILL.md
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."

tandem:map — per-site navigation memory

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`.

Store (engine: `scripts/map.sh`)

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.

  • `map.sh list` ............ table of profiles (host · updated · file)
  • `map.sh show <host>` ..... dumps the profile (accepts a full URL: normalizes to host)
  • `map.sh path <host>` ..... the file path (whether it exists or not) — for reading/writing
  • `map.sh index` ........... derived JSON index (to stdout + caches `sites/index.json`)

Invoke it by its path within the plugin (`scripts/map.sh`); there's no bin on PATH for map.

When to act (reflexes)

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*.

How recon is done (ASSISTED — never auto-save)

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.

Locator discipline (what keeps this from lying)

  • **Multi-anchor, stable properties.** Prefer a stable `id` if one exists; if not, role+name

from the accessibility tree. **Never** position/index nor `eNN` refs (they're ephemeral).

  • Save the **primary + 1-2 corroborants** (neighboring text, shortcut, container). On re-check,

accept the element if the set matches, not just the primary. (Idea stolen from Similo: several weak weighted signals beat a single strong anchor.)

  • **Lean and abstract.** Skeleton + locators + recipes. If a page is huge, the profile

stores HOW to get there and WHAT to look for, not the dump.

  • **Executable `sel:` (opt-in).** Besides the readable primary, a locator can carry a `sel:`

= 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:

  • **instance** (one element): direct `sel:`, e.g. `role=button[name="New ticket"]`.

For long/fragile names use `--regex` (substring) instead of the exact literal.

  • **template** (several: rows, list items): `sel:` with a slot the recipe fills in

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.

  • If an element has no unique role/name, do NOT give it a `sel:` (forcing positional CSS lies).
  • The `sel:` is ONLY the selector, no inline comments (`recipe.mjs`/`selector.mjs` would

include them in the value). Notes go in `primary:`/`corroborates:`.

  • **Not every "table" exposes ARIA.** Many SPAs render a `<table>` that the tree flattens to

`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.

Drift by signal (fingerprint, T015) — staleness by evidence, not by date

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

Read more
Ships withquimera-ai

A Claude Code plugin marketplace by bgmacris. One plugin today — tandem: a Chrome browser shared in real time between you and Claude Code.

Get the whole plugin
Stats
11
Stars
2
Forks
Maintained
Maintenance
JavaScript
Language
MIT
License
2mo ago
Last commit
2mo ago
Created

Repo: bgmacris/quimera-ai

Other skills on quimera-ai.