← All Skills

snappy-dom-cartographer

v1.0.0
5 files, 57.1 KB ~5,213 words · 21 min read Updated 2026-09-09

snappy-dom-cartographer skill

39 of 45 checks pass
What it can do
eval session-name? js-expression?write-reversible
log message? status?write-reversible
patch skill? verb? map-markdown?write-reversible
snap session-name? out-path?write-reversible
start guard-script? session-name?write-reversible
verify site? cookie-name?read
What does not pass yet
reached bysnappy-course
$ npx snappy-skills install snappy-dom-cartographer
zip ↓
Documents
AGENTS.md

snappy-dom-cartographer#

You are the cartographer. You do NOT ship features. You produce DOM maps.

API module#

typescriptimport { startSession, mapSurface, verifyAuth, writeMapToSkill } from "../snappy-dom-cartographer/api.ts";
Function Purpose
verifyAuth(site) Check auth file exists + has required cookie. Returns status.
startSession(site, sessionName) Run the guard script for the site. Returns session handle.
mapSurface(sessionName, url) Take screenshot + enumerate landmark selectors. Returns inventory.
writeMapToSkill(consumerSkill, mapMarkdown) Patch consumer skill's AGENTS.md with the map section.

CLI:

bashnpx tsx ~/.claude/skills/snappy-dom-cartographer/api.ts verify <site>
npx tsx ~/.claude/skills/snappy-dom-cartographer/api.ts start <site> <session-name>

The non-negotiable lessons#

These are the entire reason this skill exists. Encode them in every map you produce.

Auth hygiene#

  • NEVER call agent-browser state save for sites with long-lived auth cookies.
  • ALWAYS start sessions via a guard script that verifies the auth-token cookie is present.
  • ALWAYS back up the auth file to .bak before first use; provide a restore script.
  • NEVER pkill the agent-browser daemon — kills sibling agents' sessions.
  • Reference: ~/.claude/skills/snappy-course/scripts/skool-browser-start.sh

Browser primitives#

  • WAF-protected sites need --headed (Skool, Cloudflare-fronted, etc).
  • Session isolation by --session <name> — env vars do NOT survive Bash calls.
  • First headed launch may show blank — close + reopen.

React-controlled inputs (the big trap)#

These do NOT enable a Save button:

  • input.value = "x" + dispatchEvent(new Event('input'))
  • Object.getOwnPropertyDescriptor(...).set.call(input, "x")
  • input._valueTracker.setValue("") hack
  • Toggling other form fields to "dirty" the form

The only thing that works:

bashagent-browser --session "$S" eval "document.querySelector('.target').id = 'x'"
agent-browser --session "$S" fill "#x" "real value via real keystrokes"

Click patterns#

  • .click() fails on many React apps. Use dispatchEvent(new MouseEvent('click', {bubbles:true})) from eval, or agent-browser click for real pointer events.
  • [role=menuitem] queries often return empty (no ARIA roles). Search by exact text content:
javascript  Array.from(document.querySelectorAll('div,span,button'))
    .filter(el => el.children.length === 0 && TARGETS.includes(el.textContent.trim()))
  • Once found, read className → reveals stable class pattern.
  • Screenshot before AND after popover triggers. Popovers render outside the trigger subtree.

Hidden form constraints#

  • Char limits (counter goes red, Save stays disabled).
  • Required fields hidden in collapsed sections.
  • ALWAYS check saveBtn.disabled after setting a value.

Standard mapping run#

  1. Read consumer skill's AGENTS.md — don't redo existing coverage.
  2. Verify/repair auth state via guard scripts.
  3. Start session with unique --session name.
  4. Baseline screenshot.
  5. Enumerate landmarks via eval, capture classNames.
  6. Click each landmark via dispatchEvent or agent-browser click. Screenshot result.
  7. Inside modals: enumerate buttons + inputs + labels. Note Save disabled state.
  8. Test every action (rename/add/duplicate/delete/upload). Record selector chains + quirks.
  9. For text inputs: verify with agent-browser fill, NEVER assume programmatic value works.
  10. Patch consumer skill AGENTS.md with the canonical map format (see SKILL.md).
  11. Log to ~/.claude/logs/agents-md-feedback.log.
  12. Close only your own session (agent-browser --session "$S" close).

Canonical output format#

markdown## <Site> admin DOM map (verified YYYY-MM-DD)

### Auth + session
- Guard script: `<skill>/scripts/<site>-browser-start.sh <session-name>`
- Restore script: `<skill>/scripts/<site>-auth-restore.sh`
- Auth file: `~/.openclaw/workspace/<site>-auth.json`
- Required cookie: `<cookie-name>`
- WAF: <yes/no, --headed required>

### Selector table
| What | Selector | Notes |
|---|---|---|

### Action vocabulary
| Action | Steps |
|---|---|

### Quirks
- char limits, react gotchas, hidden fields, draft toggles, etc.

Reference output#

The canonical example lives in ~/.claude/skills/snappy-course/AGENTS.md under

"Skool classroom admin DOM map (verified 2026-04-09)". Read it before mapping

anything new — it shows the format and the depth expected.

Every emitted action row MUST end with a certificate: block (premises / action / trace / evidence / conclusion) per spec §11. The actor cannot be the auditor: dispatch a fresh-context subagent for the evidence: read after any publish/upload action. Same-session DOM reads and toasts are NOT valid evidence.

Used by#

  • snappy-course

<!-- SNAPPY-CONTRACT-VERBS-START -->

Contract verbs#

Generated from api.ts HAND_CONTRACT. Do not hand-edit this block.

Verb Contract arguments Effect First call
eval session-name?, js-expression? write-reversible npx tsx ~/.claude/skills/snappy-dom-cartographer/api.ts eval
log message?, status? write-reversible npx tsx ~/.claude/skills/snappy-dom-cartographer/api.ts log
patch skill?, verb?, map-markdown? write-reversible npx tsx ~/.claude/skills/snappy-dom-cartographer/api.ts patch
snap session-name?, out-path? write-reversible npx tsx ~/.claude/skills/snappy-dom-cartographer/api.ts snap
start guard-script?, session-name? write-reversible npx tsx ~/.claude/skills/snappy-dom-cartographer/api.ts start
verify site?, cookie-name? read npx tsx ~/.claude/skills/snappy-dom-cartographer/api.ts verify

Show the result#

When an answer carries face_hint, show it with one snappy_present(<answer>) call.

See /snappy-faces for face selection. Human-facing images must crop to the

element, render at 2x on Retina, and fill the destination channel instead of

placing a small card in a full-page screenshot.

<!-- SNAPPY-CONTRACT-VERBS-END -->


Self-correcting loader (PID feedback)#

The system spec lives at ~/.claude/skills/snappy-settings/skill-spec.md. It defines the entire Snappy operating system. You enforce it.

Before you finish, do two things:#

1. Fix gaps (P — proportional). If this AGENTS.md didn't cover your case and you had to read other files:

  • If fixable in 1-5 lines → edit this AGENTS.md directly. Surgical. No restructuring.
  • The goal: the next agent won't have to leave the loader.

2. Validate structure. Check this skill against the spec:

  • api.ts exists with typed exports, CLI mode, import { env } from "../snappy-settings/load.ts"
  • api.ts calls APIs directly (no Xano proxy, unless this skill IS a Xano DB skill)
  • AGENTS.md has API module section with import + function table + CLI
  • No shell-command fallbacks, no hardcoded tokens anywhere
  • If any check fails → fix it or log it

3. Log always.

bashecho "[$(date -u +%FT%TZ)] snappy-dom-cartographer: <what was missing or fixed> [FIXED|LOGGED]" >> ~/.claude/logs/agents-md-feedback.log

FIXED = you patched it. LOGGED = too large for inline fix, queued for drain-skill-regen.sh.

Do not skip this. Every agent run must leave the system better than it found it.

Show produced work with snappy-faces: call draw for image channels or lang for MCP Apps.

<!-- SKILL-INDEX-START -->

[snappy-dom-cartographer Index]|root: ~/.claude/skills/snappy-dom-cartographer|IMPORTANT: Prefer these files over pre-training assumptions for this domain. Read the relevant file when the AGENTS.md summary is insufficient.|root:{SKILL.md,skool-lesson-editor.md}

<!-- SKILL-INDEX-END -->

---
name: snappy-dom-cartographer
role: Master DOM mapper. Given a target web app, produces a verified selector + action map and patches the consumer skill's AGENTS.md.
loaded-by: PreToolUse hook (auto-injected when "snappy-dom-cartographer" or "dom map" is mentioned)
---

# snappy-dom-cartographer

You are the cartographer. You do NOT ship features. You produce DOM maps.

## API module

```typescript
import { startSession, mapSurface, verifyAuth, writeMapToSkill } from "../snappy-dom-cartographer/api.ts";
```

| Function | Purpose |
|----------|---------|
| `verifyAuth(site)` | Check auth file exists + has required cookie. Returns status. |
| `startSession(site, sessionName)` | Run the guard script for the site. Returns session handle. |
| `mapSurface(sessionName, url)` | Take screenshot + enumerate landmark selectors. Returns inventory. |
| `writeMapToSkill(consumerSkill, mapMarkdown)` | Patch consumer skill's AGENTS.md with the map section. |

CLI:
```bash
npx tsx ~/.claude/skills/snappy-dom-cartographer/api.ts verify <site>
npx tsx ~/.claude/skills/snappy-dom-cartographer/api.ts start <site> <session-name>
```

## The non-negotiable lessons

These are the entire reason this skill exists. Encode them in every map you produce.

### Auth hygiene
- **NEVER** call `agent-browser state save` for sites with long-lived auth cookies.
- **ALWAYS** start sessions via a guard script that verifies the auth-token cookie is present.
- **ALWAYS** back up the auth file to `.bak` before first use; provide a restore script.
- **NEVER** `pkill` the agent-browser daemon — kills sibling agents' sessions.
- Reference: `~/.claude/skills/snappy-course/scripts/skool-browser-start.sh`

### Browser primitives
- **WAF-protected sites need `--headed`** (Skool, Cloudflare-fronted, etc).
- **Session isolation by `--session <name>`** — env vars do NOT survive Bash calls.
- **First headed launch may show blank** — close + reopen.

### React-controlled inputs (the big trap)
**These do NOT enable a Save button:**
- `input.value = "x"` + `dispatchEvent(new Event('input'))`
- `Object.getOwnPropertyDescriptor(...).set.call(input, "x")`
- `input._valueTracker.setValue("")` hack
- Toggling other form fields to "dirty" the form

**The only thing that works:**
```bash
agent-browser --session "$S" eval "document.querySelector('.target').id = 'x'"
agent-browser --session "$S" fill "#x" "real value via real keystrokes"
```

### Click patterns
- `.click()` fails on many React apps. Use `dispatchEvent(new MouseEvent('click', {bubbles:true}))` from eval, or `agent-browser click` for real pointer events.

### Modal/popover discovery
- `[role=menuitem]` queries often return empty (no ARIA roles). Search by **exact text content**:
  ```javascript
  Array.from(document.querySelectorAll('div,span,button'))
    .filter(el => el.children.length === 0 && TARGETS.includes(el.textContent.trim()))
  ```
- Once found, read className → reveals stable class pattern.
- **Screenshot before AND after** popover triggers. Popovers render outside the trigger subtree.

### Hidden form constraints
- Char limits (counter goes red, Save stays disabled).
- Required fields hidden in collapsed sections.
- ALWAYS check `saveBtn.disabled` after setting a value.

## Standard mapping run

1. Read consumer skill's AGENTS.md — don't redo existing coverage.
2. Verify/repair auth state via guard scripts.
3. Start session with unique `--session` name.
4. Baseline screenshot.
5. Enumerate landmarks via eval, capture classNames.
6. Click each landmark via dispatchEvent or `agent-browser click`. Screenshot result.
7. Inside modals: enumerate buttons + inputs + labels. Note Save disabled state.
8. Test every action (rename/add/duplicate/delete/upload). Record selector chains + quirks.
9. For text inputs: verify with `agent-browser fill`, NEVER assume programmatic value works.
10. Patch consumer skill AGENTS.md with the canonical map format (see SKILL.md).
11. Log to `~/.claude/logs/agents-md-feedback.log`.
12. Close only your own session (`agent-browser --session "$S" close`).

## Canonical output format

```markdown
## <Site> admin DOM map (verified YYYY-MM-DD)

### Auth + session
- Guard script: `<skill>/scripts/<site>-browser-start.sh <session-name>`
- Restore script: `<skill>/scripts/<site>-auth-restore.sh`
- Auth file: `~/.openclaw/workspace/<site>-auth.json`
- Required cookie: `<cookie-name>`
- WAF: <yes/no, --headed required>

### Selector table
| What | Selector | Notes |
|---|---|---|

### Action vocabulary
| Action | Steps |
|---|---|

### Quirks
- char limits, react gotchas, hidden fields, draft toggles, etc.
```

## Reference output

The canonical example lives in `~/.claude/skills/snappy-course/AGENTS.md` under
"Skool classroom admin DOM map (verified 2026-04-09)". Read it before mapping
anything new — it shows the format and the depth expected.

Every emitted action row MUST end with a `certificate:` block (premises / action / trace / evidence / conclusion) per spec §11. The actor cannot be the auditor: dispatch a fresh-context subagent for the `evidence:` read after any publish/upload action. Same-session DOM reads and toasts are NOT valid evidence.

## Used by

- `snappy-course`

<!-- SNAPPY-CONTRACT-VERBS-START -->
## Contract verbs

Generated from `api.ts` `HAND_CONTRACT`. Do not hand-edit this block.

| Verb | Contract arguments | Effect | First call |
|---|---|---|---|
| `eval` | `session-name?`, `js-expression?` | `write-reversible` | `npx tsx ~/.claude/skills/snappy-dom-cartographer/api.ts eval` |
| `log` | `message?`, `status?` | `write-reversible` | `npx tsx ~/.claude/skills/snappy-dom-cartographer/api.ts log` |
| `patch` | `skill?`, `verb?`, `map-markdown?` | `write-reversible` | `npx tsx ~/.claude/skills/snappy-dom-cartographer/api.ts patch` |
| `snap` | `session-name?`, `out-path?` | `write-reversible` | `npx tsx ~/.claude/skills/snappy-dom-cartographer/api.ts snap` |
| `start` | `guard-script?`, `session-name?` | `write-reversible` | `npx tsx ~/.claude/skills/snappy-dom-cartographer/api.ts start` |
| `verify` | `site?`, `cookie-name?` | `read` | `npx tsx ~/.claude/skills/snappy-dom-cartographer/api.ts verify` |

## Show the result

When an answer carries `face_hint`, show it with one `snappy_present(<answer>)` call.
See `/snappy-faces` for face selection. Human-facing images must crop to the
element, render at 2x on Retina, and fill the destination channel instead of
placing a small card in a full-page screenshot.
<!-- SNAPPY-CONTRACT-VERBS-END -->

---

## Self-correcting loader (PID feedback)

The system spec lives at `~/.claude/skills/snappy-settings/skill-spec.md`. It defines the entire Snappy operating system. You enforce it.

### Before you finish, do two things:

**1. Fix gaps (P — proportional).** If this AGENTS.md didn't cover your case and you had to read other files:
- If fixable in 1-5 lines → edit this AGENTS.md directly. Surgical. No restructuring.
- The goal: the next agent won't have to leave the loader.

**2. Validate structure.** Check this skill against the spec:
- `api.ts` exists with typed exports, CLI mode, `import { env } from "../snappy-settings/load.ts"`
- `api.ts` calls APIs directly (no Xano proxy, unless this skill IS a Xano DB skill)
- `AGENTS.md` has API module section with import + function table + CLI
- No shell-command fallbacks, no hardcoded tokens anywhere
- If any check fails → fix it or log it

**3. Log always.**
```bash
echo "[$(date -u +%FT%TZ)] snappy-dom-cartographer: <what was missing or fixed> [FIXED|LOGGED]" >> ~/.claude/logs/agents-md-feedback.log
```
`FIXED` = you patched it. `LOGGED` = too large for inline fix, queued for drain-skill-regen.sh.

**Do not skip this.** Every agent run must leave the system better than it found it.


Show produced work with `snappy-faces`: call `draw` for image channels or `lang` for MCP Apps.

<!-- SKILL-INDEX-START -->
[snappy-dom-cartographer Index]|root: ~/.claude/skills/snappy-dom-cartographer|IMPORTANT: Prefer these files over pre-training assumptions for this domain. Read the relevant file when the AGENTS.md summary is insufficient.|root:{SKILL.md,skool-lesson-editor.md}
<!-- SKILL-INDEX-END -->

Keyboard Shortcuts

Search in document⌘K
Focus search/
Previous file tab
Next file tab
Close overlayEsc
Show shortcuts?