From Napkin
Makes web apps agent-ready by exposing UI as WebMCP tool manifests for AI agents, with phased inventory, integration, verification, and healing.
How this skill is triggered — by the user, by Claude, or both
Slash command
/napkin:webmcpify [inventory|integrate|verify|status|full] [scope notes][inventory|integrate|verify|status|full] [scope notes]The summary Claude sees in its skill listing — used to decide when to auto-load this skill
You are running the webmcpify pipeline. It takes an existing web application and
You are running the webmcpify pipeline. It takes an existing web application and
exposes its user-facing functionality as WebMCP
tools (document.modelContext — a proposed web standard incubated in the W3C Web
Machine Learning Community Group, currently a Chrome origin trial), so browser AI
agents can operate the app through structured tool calls instead of guessing at the DOM.
DETECT ──▶ INVENTORY ──▶ [HUMAN GATE: manifest approval] ──▶ INTEGRATE ──▶ VERIFY ──▶ HEAL ──▶ AUDIT
▲ loop per-area batches on big apps ▲ loop ▲ loop ▲ loop
└── per area └── per manifest entry ──┘
Everything you need ships inside this skill directory: phase guides in
references/, and vendorable code in templates/ (runtime, ambient types,
JS variant, React JSX typings, verification spec). Never assume files exist
outside the skill dir.
Out of scope (stop and say so): backend-only MCP servers (that's classic MCP, not WebMCP), automating third-party sites you don't control, and generic SEO work.
The user may pass an argument (/webmcpify <mode> or plain words):
| Argument | Run | Stop at |
|---|---|---|
(none) or full | all phases, resuming from current manifest state | done |
inventory / map | DETECT + INVENTORY loops only — zero code changes | present the manifest table for review |
integrate | INTEGRATE loop only (requires approved tools in the manifest) | integrated + built |
verify | VERIFY + HEAL loops on integrated/verified tools | green/skipped report |
status | read .webmcpify/manifest.json — read-only | report phase, per-status tool counts, and the recommended next command |
Any other text is scoping guidance (e.g. "only the checkout area", "read-only tools only").
mutating: false,
"client" (browser-local only: prefs, localStorage), or "server" (data
leaves the browser). Server-mutating tools require explicit per-tool human
approval recorded in the manifest; client-mutating tools may be approved as a
batch at the gate. Never expose destructive, irreversible, or payment actions
in a first integration.execute() may only call code
paths the UI already uses (same endpoints, same validation, same auth). Never
create new endpoints, never bypass existing checks, never put secrets in tools.document.modelContext.registerTool()
with AbortSignal lifecycle (feature-detect the deprecated navigator.modelContext
fallback). No third-party WebMCP runtime dependencies. Everything feature-detected:
the app behaves identically in browsers without WebMCP.toolautosubmit on state-changing forms — neither mutating: "client"
nor "server". Only on pure read forms (search, filter, availability)..webmcpify/ constantly;
assume your context can be wiped between any two steps. Write the manifest
atomically (write manifest.json.tmp, then rename over manifest.json).WebMCP is an evolving origin-trial API — the surface has already changed during the
trial (testing API removed 2026-07; navigator → document). Before Phase 2, if
network is available, pull Google's current official guides rather than relying on
memory:
npx -y modern-web-guidance@latest retrieve "webmcp,agentic-forms,agentic-javascript-tools"
If offline, use references/integrate.md — but prefer the live guides when they conflict.
.webmcpify/ in the target repo| File | Purpose |
|---|---|
manifest.json | Single source of truth (schema below; atomic writes) |
areas/<id>.tools.json | Sub-agent shard output during inventory fan-out (merged, then deleted) |
report.md | Human-facing running report; finalized at the end |
Resume rule: if manifest.json exists, resume — recompute nothing already
recorded. Merge leftover shards FIRST: any existing areas/<id>.tools.json
files are merged into the manifest (mark those areas inventoried, delete the
shards) before redispatching any sub-agents. Then continue at pipeline.phase,
the first pending area, or the first tool whose status is not terminal.
Terminal statuses: verified, skipped, rejected.
Phase transitions (make the atomic manifest write the moment the condition holds):
detect → inventory: app recorded, baselineSha/baselineDirty captured.inventory → gate: no area pending, completeness pass has run.gate → integrate: every discovered tool is approved/rejected, and
commitPolicy + commitWebmcpifyDir are set.integrate → verify: no approved tools remain (each integrated or terminal),
build green.verify → heal: verify loop visited every integrated tool and ≥1 is failed
(none failed → straight to audit).heal → audit: no tool failed and post-heal full re-verify passed.audit → done: every hunk mapped-or-flagged, report.md finalized.Manifest schema (Webmcpify Manifest v3):
{
"webmcpify": 3,
"app": { "stack": "react-vite", "typescript": true, "entry": "src/main.tsx",
"baseUrl": "http://localhost:5173", "startCommand": "npm run dev",
"authFixtures": { // how verify OBTAINS each session
"member": { "obtain": "npm run seed:test-user, then sign in at /login",
"account": "[email protected]",
"env": ["TEST_MEMBER_PASSWORD"] } // env var NAMES only — never secret values
} },
"pipeline": {
"phase": "inventory", // detect|inventory|gate|integrate|verify|heal|audit|done — transition rules above
"setup": { // PATHS created/modified per one-time setup step ([] = not done yet)
"runtimeVendored": ["src/webmcp/webmcpify.ts", "src/webmcp/webmcp.d.ts"],
"harnessInstalled": [".webmcpify/webmcp.spec.ts"],
"originTrialNoted": ["README.md"]
},
"baselineSha": "abc1234", // HEAD at pipeline start; null if no git
"baselineDirty": ["src/wip.ts"], // paths dirty at start — untouchable (ground rule 1)
"commitPolicy": null, // set at the gate: "commit-per-batch" | "no-commit"
"commitWebmcpifyDir": null, // set at the gate: commit .webmcpify/ itself? true | false
"blockers": [] // e.g. "app won't start locally: needs $API_KEY" — surfaced at the gate
},
"areas": [
{ "id": "checkout", "paths": ["src/features/checkout/"], "status": "pending" } // pending|inventoried
],
"tools": [
{
"id": "create_ticket",
"area": "tickets",
"kind": "imperative", // imperative | declarative
"mutating": "server", // false | "client" (browser-local only: prefs, localStorage) | "server" (data leaves the browser)
"priority": 1, // 1 = expose first; 2/3 = later waves
"description": "Creates a new ticket in the currently open project.",
"inputSchema": { /* JSON Schema */ },
"annotations": { "readOnlyHint": false, "untrustedContentHint": false }, // verify asserts these on the enumerated tool
"source": ["src/features/tickets/NewTicket.tsx:42"], // the UI code path it wraps
"route": "/projects/demo/tickets", // where verify navigates
"auth": ["role:member"], // "none" | "session" | ["role:<name>", ...] — keys into app.authFixtures; verify runs once per listed role
"examples": { "valid": { "title": "Test ticket" }, "invalid": {} },
// invalid: null ONLY for readOnlyHint tools with no/empty params —
// verify then asserts dual-outcome: rejects OR resolves with no side effect
"expect": { "result": "created", "navigation": null, "ui": "new row appears in the ticket list" },
// exactly one of result|navigation: result = substring of the resolved string;
// navigation = destination URL/pattern when executeTool resolves null (it navigated)
"cleanup": "delete the created ticket via the UI's own delete path (test data only)", // required for mutating:"server", recommended for "client"
"status": "discovered", // discovered|approved|rejected*|integrated|verified*|failed|skipped* (* = terminal)
"approval": null, // server-mutating tools, once approved: { "note": "...", "at": "2026-07-12",
// "productionSideEffect": null } — set only when verification unavoidably
// causes a real production effect (see VERIFY: production side-effect policy)
"attempts": 0, // heal-fix cycles; the triggering verify failure is attempt 0
"batchCommit": null, // sha under commit-per-batch — lands in the manifest one commit LATER
"notes": ""
}
],
"log": [ "2026-07-12 inventory: area checkout done, 4 candidates" ]
}
v2→v3 migration: resuming a "webmcpify": 2 manifest migrates in place on
first write — auth string → array; setup booleans → path arrays (false →
[]; true → recover paths from git/log, else null = done-but-unrecorded,
audit treats those files flag-only); mutating: true → "server"; add
annotations (defaults from the inventory table), blockers: [],
commitWebmcpifyDir: null, expect.navigation: null; then bump to 3.
Identify stack, build + dev-server commands, TypeScript or not, auth model
(including how verify obtains each test session → app.authFixtures), test
setup, and how the app starts locally; record under app. Record the git baseline:
pipeline.baselineSha = current HEAD and pipeline.baselineDirty = git status --porcelain paths (both null/[] without git). If the app cannot be started
locally, append the blocker to pipeline.blockers — integration may proceed, but
verification will be blocked and this must be surfaced at the gate. Details:
references/inventory.md.
Never map a large codebase in one pass.
areas with "pending".references/inventory.md) with ALL manifest fields filled,
including route, auth, annotations, examples, expect, and cleanup
(required for mutating: "server", recommended for "client") — the verify
phase runs from these fields alone. Append as "discovered", mark the area
"inventoried", write the manifest, repeat.
manifest.json. Each writes only
its own areas/<id>.tools.json shard — schema
{ "webmcpifyShard": 3, "area": "<id>", "tools": [ /* full v3 tool entries */ ] },
written atomically (tmp + rename). You (the coordinator) merge shards into
the manifest sequentially, then delete them; on resume, merge existing
shards FIRST before redispatching (Resume rule).pending areas remain, plus one completeness pass — walk the app's
navigation and ask "is any visible user action missing?"Present the manifest compactly (id, area, kind, mutating, priority, one-line description) — per-area batches on large apps. Ask the human to decide, in one exchange where possible:
approved vs rejected (rejected is terminal — rejected
tools are excluded from every later phase and from exit conditions).
mutating: "server" tools need individual acknowledgment → record in
approval; mutating: "client" tools may be approved as a batch.commit-per-batch (each integration batch committed,
revertable — recommended on a clean baseline) or no-commit (leave changes
uncommitted for the human to review/commit) → pipeline.commitPolicy. Also
whether .webmcpify/ itself should be committed (recommended: yes — it
documents the integration) → pipeline.commitWebmcpifyDir.pipeline.blockers (e.g. app won't start). If verifying a tool
will unavoidably cause a real production side effect (e.g. a mailer with an
Origin-allow-listed endpoint), get that approved HERE and record it in the
tool's approval.productionSideEffect — see VERIFY.Apply references/security.md to every mutating tool before presenting.
One-time setup first — record the created/modified file paths in
pipeline.setup (e.g. runtimeVendored: ["src/webmcp/webmcpify.ts", ...]):
vendor the runtime from this skill's templates/ (webmcpify.ts, or
webmcpify.js for non-TS projects, plus webmcp.d.ts for TS and
webmcp-jsx.d.ts for React TSX — keep the full MIT header; see
references/runtime.md) and note the origin-trial/flag requirement in the target
README (originTrialNoted). Then loop:
approved tools — one area or ≤5 tools.references/integrate.md: declarative attributes for standard
HTML forms (including framework-rendered and fetch-intercepted ones);
imperative registration via the vendored runtime for non-form or
controlled-state actions."integrated", write the manifest. Under commit-per-batch:
require a clean index before staging (unrelated staged changes → stop and
surface); stage only the batch's files by path — never git add -A, -u,
., or commit -a; commit feat(webmcp): expose <ids> (webmcpify). The
commit sha lands in batchCommit on the next manifest write — one commit
later (the manifest can't contain its own commit's sha). Never amend a
previous batch commit.approved tools remain.Set up once from templates/webmcp.spec.ts per references/verify.md (real headed
Chrome; production getTools()/executeTool() surface with legacy fallback probe).
Then loop over every integrated tool, using its manifest route, auth,
examples, expect, and annotations fields:
inputSchema
is a stringified JSON Schema — parse before comparing) and the manifest
annotations;cleanup) and one invalid example (invalid: null zero-param read tools:
dual-outcome assertion — see references/verify.md);expect
(a UI delta, or expect.navigation when execution resolves null).Pass → "verified". Fail → "failed" + failure note. Role-scoped tools: run the
loop once per role listed in auth, signing in via the matching
app.authFixtures entry.
Production side-effect policy — when a tool's verification unavoidably causes
a real production effect (e.g. an email actually sent), ALL THREE are required:
(1) the human approved it at the gate, recorded in approval.productionSideEffect;
(2) every test payload is marked [webmcpify verification]; (3) the effect is
listed in report.md. Without the recorded approval, don't execute the live
path — mark the tool skipped with a blocker note.
While any tool is "failed": diagnose via references/heal.md, fix only that
tool's integration — implementation-only fixes; if the fix would change the
approved contract (schema, description, mutating class, annotations,
expect), go back to the gate for re-approval instead of silently changing the
manifest. The triggering verify failure is attempt 0; increment attempts per
fix cycle and re-verify. At attempts = 3 → "skipped" with a clear blocker
note (an explicit escalation to the human, not a silent drop). Never widen the
diff or fake a pass. After healing, re-run verification once for all tools
with status integrated or verified (healing one tool can break another —
scope collisions).
Exit: every tool is verified, skipped, or rejected; build green.
git diff <baselineSha>..HEAD plus the index and untracked files under
commit-per-batch, or the working tree + index + untracked under no-commit.
Every hunk must map to a manifest entry or a recorded pipeline.setup path.
An unmapped hunk → flag it in the report with file/line and a suggested
disposition; never revert anything yourself. A hunk in a baselineDirty file
→ untouchable, flag only. Without a baselineSha, audit the files named in
manifest source fields and pipeline.setup paths (setup entries recorded as
null by the v2→v3 migration: fall back to flag-only for those files)..webmcpify/report.md: tool coverage per area, skipped/rejected tools
with reasons, security notes (which mutating tools exist, what guards them,
any recorded production side effects), how to test manually (flag, DevTools
WebMCP pane, inspector extension), and every blocker that needs a human.references/inventory.md — area mapping, naming/schema conventions, budgets/overlapreferences/integrate.md — declarative + imperative patterns per stackreferences/runtime.md — vendoring + wiring the templates/ runtimereferences/verify.md — harness setup: flags, surfaces, Playwright/Puppeteer, evalsreferences/heal.md — failure taxonomy → fixesreferences/security.md — the security checklist (apply before the gate and at audit)npx claudepluginhub ani1797/forge --plugin copilot-sdkDevelops MCP tools for websites and web apps via JS/TS injection and Chrome DevTools testing. For React/Vue/Next.js apps, userscripts (Notion/GitHub), Rails/Django/Laravel testing, vanilla JS/HTML.
Provides design patterns for building autonomous coding agents, covering tool integration, permission systems, browser automation, and human-in-the-loop workflows.
<!-- AUTO-GENERATED by export-plugins.py — DO NOT EDIT -->