* feat(skills): add webmcpify skill * style(skills): quote webmcpify description
6.4 KiB
Inventory — mapping a codebase into a tool manifest
Detect (Phase 0 details)
Establish, in this order:
- Stack:
package.jsondeps (react/vue/@angular/next/astro/eleventy…) or the absence of one (static HTML). Recordapp.stackandapp.typescript. - Start command + base URL:
dev/startscripts, framework defaults (vite→ 5173,next→ 3000, static → any file server). Verification needs a working local run — if the app can't be started, append the blocker topipeline.blockersand surface it at the gate; don't silently proceed to a verify phase that cannot run. - Auth model: none / session / role-based — plus how a test session signs
in, recorded per role under
app.authFixtures:obtain(the exact steps — seed command, login route),account, andenv(the env var names the fixture needs — never secret values in the manifest). The verify phase runs from this. Role-based apps need role-scoped registration (integrate.md§Auth) and a per-role verify pass. - Git baseline:
pipeline.baselineSha= HEAD,pipeline.baselineDirty=git status --porcelainpaths. Dirty files are untouchable for the whole run.
Building the area map
The area map is the unit of loop iteration. Sources, in order of preference:
router config (React Router, Next app//pages/, Vue Router, Angular routes) →
navigation UI (static/SSG) → feature folders (src/features/*). Keep areas
coarse: 5–30 for a big SaaS, 1–3 for a landing page. Split an area that turns out
too big; merge trivial ones.
What counts as a candidate tool
Walk each area's UI code and list user actions, not functions:
| UI pattern | Candidate tool | mutating |
readOnlyHint |
|---|---|---|---|
| Search/filter form or input | search_<noun> |
false | true |
| Data list/detail currently rendered | list_<noun> / get_<noun> |
false | true |
| Create/edit form with submit → API call | create_<noun> / update_<noun> |
"server" | — |
| Button triggering a server state change | <verb>_<noun> |
"server" | — |
| Preference/theme/localStorage toggle | <verb>_<noun> |
"client" | — |
| Multi-step flow (wizard, checkout) | start_<noun>_flow (initiation) |
false* | never |
| Contact/booking form (static sites) | declarative form annotation | "server" | — |
*Initiation tools only navigate/open the flow — the human completes it. They are
classified non-mutating (no data changes) but must NOT carry readOnlyHint:
they change UI state, and agents skip confirmations for hinted-read-only tools.
readOnlyHint: true is reserved for genuinely pure data reads.
mutating is tri-state: false | "client" (browser-local only: prefs, theme,
localStorage — nothing leaves the browser) | "server" (data leaves the browser).
"server" gets the full ceremony — per-tool approval, required cleanup,
dev/test-data-only verification; "client" may be batch-approved at the gate
(cleanup recommended). toolautosubmit is banned for both mutation classes
(ground rule 5).
Skip (do not inventory): login/logout/auth flows, payment execution, account deletion, user management, anything irreversible, file uploads (v1), and pure navigation agents can do anyway.
Tool budget, overlap, and priority (what keeps SaaS toolsets usable)
Agents degrade when many similar tools compete. Enforce while drafting:
- Budget: aim for ≤15 tools active in any app state (app-wide + current view).
If an area yields more candidates, keep the highest-value ones as
priority: 1and mark the restpriority: 2/3— the gate decides which waves ship. - Overlap rule: no two tools whose descriptions could plausibly match the same user request. Merge them (one tool, richer schema) or sharpen both descriptions until they are disjoint.
- Role/tenant coverage: for role-scoped apps, note per tool which roles can use
it (
auth: ["role:<name>", ...]); the toolset a given session sees must stay within budget too.
Naming and schema conventions (Google's, condensed)
- Verb-first, execution vs initiation honest:
create_eventacts immediately;start_event_creation_processmerely opens a form. The name must never lie. - Name ≤30 chars,
[a-zA-Z0-9_.-]; prefix with the app name if tools may coexist with other origins' tools in testing (myapp_search_tickets). - Description ≤500 chars, positive capability statement, no marketing. Param
descriptions ≤150 chars. The description must say exactly what
execute()does — agents make consent decisions from it. - Raw user input rule: schemas accept what the user would say ("11:00 to
15:00"), never ask the agent to compute or transform. Semantic enum values
(
"High", notpriority_id: 3). - Tools returning user-generated or external content get
untrustedContentHint: true.
Choosing kind
declarative— any standard<form>whose fields map 1:1 to the action's inputs: plain HTML, SSG-emitted, server-rendered, and framework-rendered forms (uncontrolled inputs), including fetch-submitted forms (they bridge results viarespondWith— seeintegrate.md).imperative— non-form actions (buttons, drag/drop, selections), actions whose inputs come from app state rather than form fields, and React/Vue controlled forms (agent-driven fill would bypass the framework's state).
Writing manifest entries
Fill EVERY field of the v3 schema:
route+auth(array of roles keying intoapp.authFixtures; verify runs once per role).annotations—readOnlyHint/untrustedContentHintper the candidate table; verify asserts them on the enumerated tool.examples— one valid + one invalid.invalid: nullis allowed ONLY for readOnly tools with no/empty params (verify then asserts dual-outcome); the convention for a non-null invalid on zero-param tools is{"unexpected": true}.expect— exactly ONE ofresult(substring of the resolved string) ornavigation(destination URL/pattern whenexecuteToolresolvesnull), plusui(a UI assertion a test can check).cleanup— required formutating: "server", recommended for"client".
The verify phase must be able to run from the manifest alone, without re-reading the codebase — that is what makes runs resumable by a different agent.
The completeness pass at the end of Phase 1: start the app (or read the rendered nav), enumerate what a user can do per screen, and diff against the manifest.