npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

agentic-microformats

v0.11.0

Published

Reference implementation of the Agentic Microformats specification

Readme

agentic-microformats

Reference implementation of the Agentic Microformats specification (v0.2.0) — a TypeScript library for extracting data-agent-* annotations from HTML.

Works with any DOM implementation that satisfies a minimal structural interface: the browser DOM, or linkedom server-side.

Install

npm install agentic-microformats

Give your agent web-operation in ~20 lines (operate)

operate() is the episode runtime: it observes the page (graph + content + WebMCP tools), asks your model what to do, safety-gates and executes the action, re-observes, and loops — until the agent answers. It is model-agnostic (you supply decide) and environment-agnostic (you supply the transport, so auth is your session, and parse is linkedom server-side or document in a browser).

import { operate } from 'agentic-microformats';
import { parseHTML } from 'linkedom';

const result = await operate({
  task: 'Add two of the cheapest product to the cart',
  start: 'https://shop.example/',

  // YOUR model. Given the page state, return one action.
  decide: async (state) => {
    const reply = await myLLM(`Task: ${state.task}
Tools: ${JSON.stringify(state.tools)}
History: ${JSON.stringify(state.history)}
Return one JSON action: {"type":"navigate|invoke|answer", ...}`);
    return JSON.parse(reply);
  },

  // YOUR transport — carries the user's session/cookies (this is how auth works).
  fetchPage:   (url) => fetch(url, { credentials: 'include' }).then(async r => ({ html: await r.text(), url: r.url })),
  sendRequest: (req) => fetch(req.url, { method: req.method, headers: req.headers,
                                         credentials: 'include', body: JSON.stringify(req.body) })
                          .then(async r => ({ status: r.status, body: await r.json().catch(() => null) })),

  parse: (html) => parseHTML(html).document.documentElement,

  // Safety is fail-closed: high-risk / human-preferred / un-hinted-mutating
  // actions call this; cross-origin endpoints are refused outright.
  onConfirm: ({ tool, prepared }) => askTheHuman(`Run ${tool}?`, prepared),
  origin: 'https://shop.example',
});

console.log(result.answer, result.steps);

The library owns the loop and the safety gates (fail-closed confirmation, same-origin enforcement, re-observation after each mutation). You own the model and the session. mode: 'browser' drives the real form.requestSubmit() instead of an HTTP call.

Use it with your existing SDK (OpenAI / Anthropic / MCP)

Already using function-calling? Get the tools in your SDK's format and execute the model's calls through the same fail-closed safety gates:

import { extractAll, toOpenAITools, toAnthropicTools, toMCPTools, executeTool, AgentDOM } from 'agentic-microformats';

const dom = new AgentDOM(root);
const result = dom.extractAll();

const tools = toOpenAITools(result);      // or toAnthropicTools / toMCPTools
const reply = await openai.chat.completions.create({ model, messages, tools });

for (const call of reply.choices[0].message.tool_calls ?? []) {
  const out = await executeTool(dom, call.function.name, JSON.parse(call.function.arguments), {
    origin: location.origin,
    sendRequest: myAuthedFetch,                    // your session
    onConfirm: ({ tool, prepared }) => askHuman(tool, prepared),
  });
  // out.ok / out.refused (cross-origin or unconfirmed) / out.result
}

MCP keeps the safety hints as native tool annotations (readOnlyHint/destructiveHint/idempotentHint); OpenAI/Anthropic fold them into the description, where the model reads them.

Failures come back typed, so recovery is a rule, not a guess:

const out = await executeTool(dom, name, args, opts);
if (!out.ok && out.error) {
  const e = out.error;            // { kind, retryable, retryAfter?, requiresFreshState? }
  if (e.kind === 'conflict') { /* re-read the page, then retry */ }
  else if (e.retryable && toolIsIdempotent) { await sleep(e.retryAfter ?? 1); /* retry */ }
  else if (e.kind === 'auth') { /* re-authenticate */ }
  else { /* validation / forbidden / not-found → surface to the user */ }
}

retryable describes the error (does the server invite another attempt); whether the action is safe to repeat is the separate idempotentHint. Retry only when both hold — or, for a conflict, re-read state first.

Lower-level extraction

import { AgentDOM } from 'agentic-microformats';

const agentDom = new AgentDOM(document.documentElement);
const { meta, resources, actions } = agentDom.extractAll();
const prepared = agentDom.prepareAction(actions[0], undefined, { origin: location.origin });
// prepared.confirmationRequired / prepared.blocked — the safety gates (spec §3.2, §12.5)

Narrowing the graph before it hits context (0.11.0)

A catalog page's graph is mostly repetition: on the demo shop the same add_to_cart block is 52% of every product resource, byte-identical across all six except the SKU. Two tiers cut that down, kept separate because they carry very different risk.

Lossless — re-encode, drop nothing. Always safe:

import { extractAll, toGraph, compactGraph, expandGraph } from 'agentic-microformats';

const result = extractAll(document.documentElement);
const compact = compactGraph(toGraph(result));   // repeated actions → one template
// expandGraph(compact) round-trips byte-identically to toGraph(result)

Lossy — narrow to the task. Only the caller holds the intent, so only the caller can authorize the loss:

import { selectTools, toCompactGraphJSON } from 'agentic-microformats';

const selection = selectTools(result, 'Add 3 units of the USB-C Charger 65W to the cart');
selection.narrowed;  // true
selection.reason;    // 'intent matched 1/6 resources; kept 1'
const json = toCompactGraphJSON(result, selection);   // 66% smaller than the full graph

selectTools fails open: an intent it cannot rank confidently returns the whole graph, and reason always says which branch ran. Notably it refuses to narrow aggregate intents — "add the cheapest product" ranges over the entire collection, and pruning it to the items whose text matches "cheapest" would destroy the answer. Page-level actions are never dropped, so an agent can always navigate off a page whose narrowed view turned out to be wrong, and a pruned graph carries a selection block telling the model it is seeing a filtered view.

Measured on the 13-task agent benchmark: 47% fewer graph bytes overall, and the selector picked the correct product in 6/6 named-entity tasks. See spec/graph-serialization.md §5 for the wire format.

Modules

| Module | Purpose | |---|---| | extract | Resources, actions, properties, page meta | | select | Intent-driven graph narrowing + lossless action-template hoisting | | coerce | Typehint-driven value coercion (currency, dates, integers, …) | | trust | Trust regions (data-agent-trust) and data-agent-ignore — untrusted subtrees are skipped | | params | Parameter extraction, min/max constraints, nested dotted-path bodies | | hints | Interaction hints: role, risk, reversibility, cost, human-preferred | | observe | MutationObserver-based annotation change feed (browser only) |

Content observation (0.4.0) — no annotation required

extractContent(root) reads what a page says — title, authors, dates, publisher, section, keywords, word count, language, excerpt, and a heading outline — bridged from Schema.org JSON-LD, Microformats2, Open Graph, and semantic HTML that the page already carries. Every field is grounded: { value, source, selector }. Try it on any article:

npx agentic-microformats <url> --content

This is the "own the layer WebMCP lacks" direction: a portable, server- renderable, grounded reading an agent uses before and after it acts. See spec/content-observation.md.

WebMCP binding (0.5.0)

toWebMCPTools(extractAll(root)) compiles the actions into WebMCP tool descriptors — JSON Schema inputs, standard MCP tool annotations (readOnlyHint / destructiveHint / idempotentHint / humanConfirmationHint), and a binding that defaults to the real HTML control (form.requestSubmit()), not a shadow endpoint. registerWebMCPTools(result, navigator.modelContext) registers them live and enforces the fail-closed confirmation gate. Inspect any page:

npx agentic-microformats <url> --webmcp

See spec/webmcp-binding.md. This is the interaction half of the pivot: the same annotations a zero-JS agent reads statically also drive live WebMCP invocation in a capable browser — Agentic Microformats does not compete with WebMCP's runtime, it feeds it.

API stability

The public surface is tiered — Stable (extraction core, canonical graph, validation, safety primitives), Beta (the consumer runtime: operate, the SDK adapters, typed errors, content, WebMCP), and Experimental. Depend on the tier, not the version number; both breaking changes made so far landed in Beta, never in Stable. Full contract and the path to 1.0 in STABILITY.md.

Spec coverage

Implements core spec v0.3.x (data-agent-idempotent, endpoint origin policy, conformance profiles, monotonic trust) plus the 0.4.0 content observation layer. The proposed vocabulary in spec/advanced.md and the workflow/async example attributes are not implemented — they are not part of the released spec.

License

MIT