How openmonkey works

Everything is public

Creating a script and publishing it are the same action. There are no private scripts. Every version is immutable once published, and every fork records its lineage. The registry is a plain JSON API — see /llms.txt.

Publishing a script

Sign in with your passkey, then paste your script at /publish. The metadata block supplies the name and description, and a @match or @include line is required. The script is public the moment you submit, served at its own .user.js URL, and gets a slug derived from its name.

To edit an existing script, hit Edit on its page (or open /publish?slug=<slug>): the latest code loads into the form, and submitting publishes a new immutable version. Authors only — for anyone else the form offers a fork with your changes, lineage recorded.

Everything the publish page does goes through the public JSON API, so scripts, CLIs, and agents can publish the same way: POST /api/scripts with {"code": "..."} and your proc.io session cookie. The full API is described in /llms.txt.

The shortest path of all: install openmonkey anywhere (TPX), go to the page you want to change, and open its panel (your manager's menu command, or the floating 🐵 button). Describe the change; the model sees the page you're on — URL, title, real DOM — generates a script with working selectors, publishes it here, and opens it for install. It matches every site by necessity, which by our own norm earns it a warn: scan it, and see that it talks only to TPX and this registry, only when you ask.

Prefer starting from the registry? Install openmonkey composer (TPX): it adds a "Generate with my model" box to the publish page and an "Edit with my model" box to every script page. Describe the script you want, or the change you want made to the one you're looking at; a metered TPX grant you approve writes the result into the publish form, you review it, you publish it. Scripts that need inference do the full OAuth flow themselves (dynamic client registration, PKCE, popup approval) using /oauth/tpx on this site as the redirect relay — a pattern any script here is welcome to copy.

Installing

Every script is served at /scripts/<slug>.user.js, the URL shape every userscript manager understands. Click Install on a script page and Userscripts for Safari, Tampermonkey, or Violentmonkey takes over. See /install. At serve time the registry fills in @downloadURL, @updateURL, and @homepageURL (when the author omitted them), so your manager registers the canonical URL and picks up new versions on its normal update checks.

The scan norm

Your own scripts you can trust, you wrote them. Before running anyone else's, have it security-scanned on your behalf, by your model: feed the exact source to your own endpoint (tokenpony or any OpenAI-compatible API) and publish the verdict back to the registry with POST /api/versions/:id/scans:

The easiest way to follow the norm is with a userscript, naturally: openmonkey scanner (TPX) is hosted on this registry, adds a "Scan with my model" button to every script page, runs the audit through a metered TPX budget you approve in an OAuth popup (no API keys to copy), and publishes the verdict. It is a script you didn't write, so scan it first — by hand, or with a model, before the button exists.

A new version of a script is new code: verdicts never carry over, each version is scanned on its own. Verdicts are published to the script's page (which model, which verdict, whose scan) so trust accumulates in the open. Since installs happen in third-party managers, the registry can't block a bad install; it makes the verdicts impossible to miss instead. The registry lifecycle is model-checked with TLA+; the spec lives in the repo under specs/.

Script format

Standard Greasemonkey-style metadata blocks. @match/@include are required — a script that runs everywhere is a script that gets a warn.

// ==UserScript==
// @name         Wider GitHub
// @description  Make GitHub use the full window width
// @version      1.0.0
// @match        https://github.com/*
// ==/UserScript==
(function () {
  const s = document.createElement("style");
  s.textContent = ".container-xl { max-width: 100% !important; }";
  document.head.appendChild(s);
})();