sutram
For app authors With or without WebMCP

Let agents use your web app through commands, not clicks.

Sutram gives your app one standard way to expose what it can do. Agents call your commands as WebMCP tools, from JavaScript in a headless browser, or by typing into a terminal-like console. People can use the same console.

$ npm i @d34dman/sutram

Or press ` anywhere on this page.

Every way in

However an agent reaches the page, your commands are there

You register commands once. Sutram exposes them four ways, with the same schema, checks, handler and exit codes behind each one.

WebMCP tools

browsers with WebMCP

01

Each command becomes a tool with its JSON Schema and hints such as read-only or ask-first, and the list follows the page as commands come and go.

cart_add({ "sku": "V60-02", "qty": 2 })

JavaScript in the page

headless Chrome, Playwright, Puppeteer, browser agents

02

Sutram.tools() returns what a WebMCP agent would see, and Sutram.call() runs a tool. Consequential tools run only with { confirmed: true }.

await page.evaluate(() =>
  Sutram.call("cart_add", { sku: "V60-02", qty: 2 }));

The console

agents that type and read, and people

03

A terminal in the page: type a line, read text back. help, man and --json are built in. No screenshots, no hunting for buttons.

› cart add V60-02 --qty=2
Added 2 × V60 dripper, size 02.

A chat assistant

ChatGPT or Claude, with no browser access

04

The assistant gets a prompt built from the page's commands and answers with command lines. A person pastes them into the console and pastes the output back. Try it below.

```sh
cart add V60-02 2
cart status
```
Live demo

Try it on a tiny coffee shop

This page registers a handful of commands with Sutram. Click one, or open the console and type. The shop's buttons, the console and agents all run the same commands, and each run shows up below. Have a headless browser? Open DevTools and try await Sutram.call("cart_status").

Brew & Co. rendered from its own state

What an agent sees

    Who ran what registry.onResult()

    • Click a button or a command above.

    No browser access? Use ChatGPT or Claude. a prompt built from this page's commands

    See the prompt
    1. Send the prompt. The assistant answers with commands in a code block.
    2. Paste its commands into the console. Press `, then paste. All lines run in order, stop at the first error, and anything consequential asks you once.
    3. Send back what the console printed. Click Copy in the console's top bar and paste it into the chat. Repeat until it is done.
    How it works

    One definition, every shape

    A command is a name, a JSON Schema for its input, and a function. Sutram turns it into a tool for agents and a command line that agents and people can type. Your handler never knows who called it.

    Sutram.register({
      name: "cart add",
      provider: "cart",
      description: "Add a product to the cart",
      input: {                         // JSON Schema
        type: "object",
        properties: {
          sku: { type: "string" },
          qty: { type: "integer", minimum: 1, default: 1 },
        },
        required: ["sku"],
      },
      positional: ["sku", "qty"],
      annotations: {},                 // readOnly, consequential, …
      run: ({ sku, qty }) => cart.add(sku, qty),
    });

    Typed into the console

    › cart add V60-02 2
    › cart add --sku=V60-02 --qty=2
    › cart add -h
    › man cart add

    Called as a tool

    cart_add({ "sku": "V60-02", "qty": 2 })          // WebMCP
    Sutram.call("cart_add", { sku: "V60-02", qty: 2 }) // JavaScript
    // same schema, same checks, same handler
    Features

    Everything a command line should have

    You write the commands. Sutram does the rest, the same way for every app on the page.

    Agents without screenshots

    Agents call your app's own logic instead of reading pixels and guessing which button to click. Results come back as data.

    WebMCP · Sutram.call()

    Asks before it matters

    Mark a command consequential. The console asks, WebMCP hosts get the hint, and Sutram.call() waits for confirmed: true.

    readOnly · consequential

    Agents learn the app

    Help, manual pages and a status of the whole page are generated from your definitions, so they always match what the page can do right now.

    help · man · status

    The user's session, nothing more

    Commands run in the browser and call your own endpoints, so they can do exactly what the user could already do.

    no new API

    Data for agents, tables for people

    Return data. Agents and --json get it exactly as you returned it; people get tables and key: value lines.

    --json · --wide

    Small and plain

    ES modules, or one file from a CDN. A web component for the console. Works with any framework, or none.

    0 dependencies
    Get started

    Up and running in a minute

    No build step needed. Paste this into an HTML file and open it.

    Load Sutram

    From the CDN, or install @d34dman/sutram from npm and import it.

    <script type="module">
      import Sutram from "https://cdn.jsdelivr.net/npm/@d34dman/sutram@0.3/dist/sutram.js";
    </script>

    Register a command

    Give it a name, an input schema and a function.

    Sutram.register({
      name: "hello world",
      provider: "hello",
      description: "Say hello",
      input: { type: "object", properties: { who: { type: "string", default: "you" } } },
      positional: ["who"],
      annotations: { readOnly: true },
      run: ({ who }) => ({ text: `Hello, ${who}.` }),
    });
    Sutram.mountConsole();

    Call it

    Press ` and type hello world Ada. In a browser with WebMCP, agents get a hello_world tool. From a headless browser or DevTools:

    await Sutram.call("hello_world", { who: "Ada" });
    // → { code: 0, text: "Hello, Ada." }

    Building on Drupal?

    The Drupal module exposes menus, pages and node forms as commands: nav go "Content types", form node-article-form set title …, form node-article-form save.

    See the Drupal demo