Skip to content

machine contract

For agents

This site is built to be read by machines as well as people. The tools are deterministic functions that run entirely in your browser — no backend. What you type is never transmitted; when you pass input in a URL, the fragment (#) keeps it client-side. Below is the contract: where the machine-readable surfaces live, how to call a tool in the page, and what happens automatically where the browser supports WebMCP.

Machine-readable surfaces

/for-agents.md

the agent contract as markdown — machine surfaces, in-page tool API, URL invocation, WebMCP

/for-agents/playground

agent playground — exercise the WebMCP catalog and in-page tool API against a live pass/fail scorecard

/SKILL.md

agent skill / how-to — the drive contract plus every tool's params, return shape and a worked example

/lab/skill-oracle.md

the skill oracle lab item as markdown — its live API endpoints and WebMCP tools

Every content page has a markdown mirror: /about.md, /now.md, /projects.md, /blog/<slug>.md, and this page at /for-agents.md. Tool and lab pages expose JSON manifests instead — see /tools/<slug>.json.

In-page tool API

Each tool page hydrates a small island and then exposes its API on window.__tools[slug]:

  • run(input) — calls the underlying pure function and returns its result, or a Promise you should await (e.g. hash). input is a plain object whose accepted fields are documented per tool by describe() and in each /tools/<slug>.json manifest.
  • describe() — returns { slug, params, returns } (plus async, guide and example/examples where the tool has them) so you can discover a tool's contract at runtime. It is derived from the same schema module that generates /tools/<slug>.json and /SKILL.md, so the three never disagree.

The page's #tool-output element (a stable, aria-live selector) shows results from the UI and #fragment URL-invocation paths — handy if you would rather read the rendered DOM. A direct run() call does not update it; read run()'s return value instead.

// on a live tool page, after hydration
window.__tools["base64"].describe();
const result = await window.__tools["base64"].run({ input: "…" });
// `result` is the answer; #tool-output reflects the UI / #fragment path

A self-contained agent skill — the drive contract plus every tool's params, return shape and a worked example — lives at https://aaronchartier.com/SKILL.md. Fetch it once instead of hydrating each page to discover schemas.

URL invocation

Documented parameters pre-fill a tool's inputs and run on load — a URL alone can drive a tool, no scripting required. Prefer the fragment (#); the browser never sends it to the server, so the input stays client-side. Each tool's parameters are listed in its describe() and its /tools/<slug>.json manifest.

https://aaronchartier.com/tools/base64#input=hello

A ?query form also works for back-compat, but prefer the # form — the fragment stays client-side.

WebMCP

Where the browser exposes the experimental Web Model Context Protocol (WebMCP) at document.modelContext (or navigator.modelContext on older preview runtimes), every page registers the tool catalog — every live tool with a headless run, read-only, since those tools are deterministic and side-effect-free. The interactive PDF editor (sign) has no headless run and is not registered: it stays page-only, via window.__tools.sign on its page. WebMCP is not in stable browsers yet; where it is absent this is a no-op, and the in-page window.__tools API above is the path that works today.

Proving ground

Prove the contract above end-to-end: the playground detects your WebMCP runtime, enumerates the catalog, runs the tools against pinned values, and grades three agent challenges — all on a live pass/fail scorecard.

/for-agents/playground— markdown mirror at/for-agents/playground.md.

This page as markdown:/for-agents.md. Start at thetools index, or read thellms.txtandagents.json manifests directly. Contact:[email protected].