Build a plugin.
Teach Revive a new job.

A plugin is a manifest and a little JavaScript. It runs in Revive's sandbox, talks only through revive.*, and shows its results on the notch and in Revive's own cards.

Who can build

Plugins are in beta. Anyone can build and test one on their own PC in developer mode; publishing to the store is by invite while we review the first plugins closely.

  1. Write a manifest.json: who it is, what it may do, where it shows up.
  2. Write main.js with a handler for each hook.
  3. Test it on real files with plugin-test, or in Revive with developer mode on.
  4. Pack it with plugin-pack and fix every error and warning.
  5. Submit it. The store reviews it, signs it and lists it.

The manifest

manifest.json sits next to main.js (and an optional icon.png). Its permissions and data_use are exactly what the install card shows.

{
  "id": "yourname.price-check",
  "name": "Price Check",
  "version": "0.1.0",
  "publisher": "Your Name",
  "description": "Drop a product photo on the wheel: see its price on Example Shop.",
  "price": 0,
  "data_use": "Sends the photo you drop to Revive's AI to name the product, then the product's name to api.example-shop.com (on your own key) to look up its price.",
  "secrets": [
    { "id": "shop_key", "label": "Example Shop API key", "help_url": "https://example-shop.com/developers" }
  ],
  "permissions": {
    "net": ["api.example-shop.com"],
    "ai": ["vision"],
    "files": "dropped",
    "clipboard": true
  },
  "hooks": {
    "wheel": [
      { "id": "check", "label": "Check price", "description": "Name the product and look up its price", "accepts": ["image"] }
    ],
    "ask": []
  }
}
idReverse-domain id, letters, digits, dots, dashes: yourname.plugin-name. Never changes between versions.
nameA short name, up to 40 characters.
versionYour version, such as 1.0.0. Every new version is reviewed and signed again.
publisherYou or your company, as people will see it.
descriptionOne line for the install card and the store.
price0 for free, otherwise the price in US dollars.
data_usePlain words: what leaves the PC and where it goes. Required if the plugin uses the network or AI. Shown on the install card.
secretsKeys the person brings (their own API key): id, label and a help_url. Kept in Windows Credential Manager, never in your code.
permissions.netThe exact https hosts it may reach, such as api.example.com or *.example.com.
permissions.aiRevive's AI it may use: "vision", "text", "search" (text answered with live Google Search).
permissions.files"dropped" to read only the files given to it, or leave it out.
permissions.clipboardtrue if it may put text on the clipboard.
hooks.wheelOptions on the format wheel (and the shelf) for dropped files: id, label, description, accepts ("image", "pdf", "any").
hooks.askTools Revive's Ask and voice can call, in the same shape.

The code

Calls are synchronous and throw on failure, so wrap each one and finish politely. This example matches the manifest above.

// main.js: plain, readable JavaScript (no eval, no minified blobs).
revive.on("check", ({ files }) => {
  const photo = files && files[0];
  if (!photo) return revive.notch.done("Drop a product photo first", false);

  revive.notch.progress("Looking at the photo", 20);
  let product;
  try {
    product = revive.ai.vision(photo, "Name the product in this photo as a shop would list it.").text.trim();
  } catch (e) {
    return revive.notch.done("Couldn't look at the photo", false);
  }

  revive.notch.progress("Checking the price", 60);
  const key = revive.secrets.get("shop_key"); // null until the person adds their key
  if (!key) return revive.notch.done("Add your Example Shop key first", false);
  let r;
  try {
    r = revive.net.fetch("https://api.example-shop.com/v1/search?q=" + encodeURIComponent(product), {
      headers: { Authorization: "Bearer " + key },
    });
  } catch (e) {
    return revive.notch.done("Couldn't reach Example Shop", false);
  }
  const item = r.json && r.json.items && r.json.items[0];
  if (!item) return revive.notch.done("No price found for " + product, false);

  revive.notch.done("Found a price", true);
  revive.card({
    title: product,
    subtitle: "Found at Example Shop just now · prices change",
    rows: [{ label: "Example Shop", value: item.price, url: item.url }],
    buttons: [{ label: "Copy name", copy: product }],
  });
  return { product, price: item.price };
});

The revive API

The plugin's only door. Each call is checked against the manifest's permissions.

revive.on(hook, fn)Runs fn when a hook from the manifest is used. Wheel hooks get { files }. Return a small result, or nothing.
revive.notch.progress(title, pct)Shows what it's doing on the notch, with the edge glow.
revive.notch.done(title, ok)Finishes the run on the notch: ok true for done, false for a polite failure.
revive.card({ title, subtitle, rows, buttons })Describes a result card; Revive draws it in its own style. Rows: label, value, url. Buttons: label with url or copy.
revive.net.fetch(url, { method, headers, body })https GET or POST to a listed host only. Returns { status, text, json }. No redirects.
revive.ai.vision(file, prompt)Asks Revive's AI about a file it was given. Returns { text }.
revive.ai.text(prompt, { search: true })Asks Revive's AI; with search: true it answers using live Google Search. Returns { text }.
revive.files.read(file)Reads a file it was given for this run, and only those. Returns { name, size, mime, base64 }.
revive.storage.get(key) / set(key, value)A private 1 MB store for this plugin, kept across updates, deleted on uninstall.
revive.secrets.get(id)The person's own key for a secret declared in the manifest, or null if they haven't added it.
revive.clipboard.write(text)Puts text on the clipboard (needs permissions.clipboard).
revive.open(url)Opens one of the plugin's own listed sites in the browser.

Test and pack

Revive has a headless mode for developers. Run a hook on real files, then pack the folder into a .reviveplugin.

:: Run one hook of an unpacked plugin folder on real files
revive --headless plugin-test <dir> <hook> [files]
revive --headless plugin-test .\price-check check .\photo.jpg

:: Lint the code and manifest, then pack it
revive --headless plugin-pack <dir> <out.reviveplugin>
revive --headless plugin-pack .\price-check price-check.reviveplugin

Packed files you make yourself are unsigned: Revive only installs them with developer mode on, clearly marked. The store signs the reviewed version.

Security policy (beta)

Revive fixes people's PCs, so its plugins must be safer than anything else they install. Most of this isn't a promise from the developer: Revive enforces it in code, and the store reviews the rest before a plugin is signed.

What Revive enforces

Only signed plugins install.reviveplugin files carry an Ed25519 signature by the Revive store key. Anything unsigned or changed after signing is refused ("Not a verified Revive plugin"). Developer mode in Settings allows unsigned local plugins, clearly marked.
A sandbox, not the PCPlugin code runs in an embedded QuickJS engine with no file system, processes, sockets, require, fetch or DOM. Its only door is revive.*.
Nothing it didn't ask forEvery revive.* call is checked against the manifest's permissions. Undeclared sites, AI, clipboard, files or keys are refused.
Only the files you give itrevive.files.read and revive.ai.vision only see the files dropped on, or chosen for, that run.
Only its listed sites, only httpsrevive.net.fetch reaches the exact hosts in permissions.net (or *.host), over https, GET and POST only, no redirects, 1 MB request and 2 MB response. Headers that impersonate the PC (Cookie, Host, Origin, Referer, Proxy-*) are blocked.
Keys never in codeA plugin that needs an API key declares it in secrets. The person enters their own key once; it's kept in Windows Credential Manager and read with revive.secrets.get(id). The packer refuses code with keys written into it.
It can't trick youPlugins don't draw their own UI: they describe a card (title, rows, buttons) and Revive draws it in its own style. They can't fake system dialogs, other apps or Revive itself.
Links open on your clickA plugin can open its own listed sites. Any other link only opens when you click it on the plugin's card.
Limits per run64 MB memory, 90 seconds, 30 web requests, 10 AI requests, 5 cards. A runaway plugin is stopped and the notch says so.
Its own storagerevive.storage is a private 1 MB store per plugin, kept across updates, deleted on uninstall.
No system changesPlugins can't reach Revive's fixes, the admin helper, the registry, services or settings. Those stay Revive's own, journalled and undoable.
You see what leaves the PCdata_use (required for any plugin using the network or AI) is shown on the install card in plain words, with every permission.
Kill switchRevive checks the store's revoked list every 6 hours. A revoked plugin (or version) is turned off at once and can't be turned back on.

What developers must follow

  1. Ask for the least. List only the sites, AI and permissions the plugin uses. The packer warns about permissions the code never uses; the store rejects them.
  2. Say plainly what leaves the PC. data_use names what is sent and where: "Sends the photo you drop to Google Lens (via SerpApi) to find the product." No vague words like "may share data with partners".
  3. No tracking. No analytics, fingerprinting, ad SDKs or calls home that the person didn't ask for. A plugin's network use must be its feature.
  4. No keys in code, ever. Use secrets. If your service needs a shared key, run your own small server and list it in permissions.net.
  5. Readable code. Ship bundled but not obfuscated JavaScript. No eval, no new Function, no encoded blobs. The store reviews the exact code it signs.
  6. Honest results. Show where every result came from (a link on the card) and when. Never say "guaranteed", "best", "virus-free" or "speeds up your PC" unless it's measured and true. Prices change: say "found at … just now".
  7. Respect sites' terms. Use official APIs. No scraping sites that forbid it, no bypassing logins, captchas or paywalls.
  8. Fail politely. Catch errors and finish with revive.notch.done("Couldn't …", false). Never loop on retries.
  9. Small and quick. A run should usually finish in seconds. Show progress with revive.notch.progress if it takes longer.
  10. People's data is theirs. Don't keep dropped files or results beyond what the feature needs. Don't send personal data (names, emails, files) anywhere data_use doesn't name.
  11. Paid plugins are fair. A clear price, no dark patterns, cancelling as easy as buying, and the plugin keeps working for what was paid.

If you build with AI (vibe coding)

AI-written plugins are welcome. They're held to the same rules, and these catch most of what AI gets wrong.

  • Read every line before you pack. You're the publisher, not the AI.
  • Never paste a real key into the chat or the code. Use secrets; the packer blocks keys it can find.
  • Check the permissions it wrote. AI tends to add sites "just in case". Remove every site the code doesn't fetch.
  • Check every URL it fetches. Make sure each one is an official API on a site you named in data_use, not a random mirror or scraper.
  • No eval, new Function, minified blobs or "obfuscation for protection". Ask the AI to remove them.
  • Ask it for error handling on every revive.* call, and test what happens offline, with a bad key, and with an odd file.
  • Test in developer mode on real files, then run revive --headless plugin-pack and fix every error and warning.
  • Don't let it invent claims. Read the card text it wrote; cut anything you can't show is true.

How a plugin gets to people

From your folder to someone's notch, with a review and a signature in between.

  1. Build and test with developer mode on (Revive Settings).
  2. Run revive --headless plugin-pack <folder> <out.reviveplugin>: the packer lints the code and the manifest.
  3. Submit it to the store. Review covers the code, the permissions against what the code does, data_use, claims, and a test run in Windows Sandbox.
  4. The store signs it with the store key and lists it. People download it and drop it on the notch.
  5. Every update is reviewed and signed again. Problems found later mean revocation: the plugin is turned off on every PC within hours.
Reporting a problem

Found a plugin breaking these rules, or a way around the sandbox? Email hello@revive.example. Sandbox escapes are fixed first.