~/tools/extensions/sdk
SDK de extensiones
¿Qué es esto?
Ocultar detalles
¿Qué es SDK de extensiones?
A Mentria extension is a single .html file — markup, styles and script in one document. There is no build step, no bundler and no upload: the file lives only on your device, in local storage, and runs on the site the moment you install it.
Trust model — read this once
Your extension runs inside an <iframe> (its own document), but that frame is same-origin with the host page. That is structural isolation, not a security sandbox: an installed extension can reach the host. The real safeguards are human ones — you install it yourself after a naming prompt, the source never leaves your device, and the file size is capped. Only install extensions you would be willing to run as your own code.
Inicio rápido
Copy the file below, drop it into the manager, and open it. It paints itself with the site theme, saves a note to its private storage, and raises a host toast — the three things almost every extension needs.
<script type="application/json" id="mentria-ext">
{
"id": "starter",
"name": "Starter",
"version": "1.0.0",
"icon": "✨",
"author": "you",
"description": "A minimal Mentria extension: theme tokens, a storage roundtrip, and a toast.",
"permissions": ["storage"],
"mounts": {
"tool": {},
"commands": [
{ "name": "starter", "usage": "starter [text]", "description": "open the starter extension" }
]
}
}
</script>
<style>
body { margin: 0; padding: 2rem; font-family: var(--ext-font, monospace);
background: var(--ext-bg, #0b0e11); color: var(--ext-fg, #e6edf3); }
input, button { font: inherit; padding: .5rem .8rem; border-radius: 6px; }
input { width: 100%; box-sizing: border-box; margin-bottom: .6rem;
background: transparent; color: inherit; border: 1px solid var(--ext-muted, #7d8590); }
button { background: transparent; cursor: pointer;
color: var(--ext-accent, #6ef3c5); border: 1px solid var(--ext-accent, #6ef3c5); }
</style>
<h1>My note</h1>
<input id="note" placeholder="type something, then Save…">
<button id="save">Save</button>
<script>
// window.mentria is injected by the run host before this script runs.
const { storage, theme, notify, args } = window.mentria;
// Paint the host theme onto our CSS variables.
const s = document.documentElement.style;
s.setProperty('--ext-bg', theme.bg);
s.setProperty('--ext-fg', theme.fg);
s.setProperty('--ext-accent', theme.accent);
s.setProperty('--ext-muted', theme.muted);
s.setProperty('--ext-font', theme.fontMono);
const box = document.getElementById('note');
// Storage roundtrip: last saved note, or text passed on the command line.
box.value = storage.get('note') || (args && args.args) || '';
document.getElementById('save').addEventListener('click', () => {
storage.set('note', box.value); // persisted under extdata.starter
notify('saved'); // host toast, bottom-center
});
</script>
Install it: open the manager, expand paste source, paste the file, and confirm the trust prompt. Because it declares mounts.tool it also gets a launcher tile, and its starter command shows up in the terminal.
Referencia
Manifest
The manifest is a JSON block with id="mentria-ext". It is the only required piece of structure; everything else is ordinary HTML.
| Field | Type | Req | Rules |
|---|---|---|---|
id | string | yes | kebab-case ([a-z0-9-]), 3–48 chars, unique. Reserved: extensions run tools feed search about comms. |
name | string | yes | 1–40 chars. Shown in the manager, launcher tile and run bar. |
version | string | yes | major.minor.patch (e.g. 1.0.0). Reinstalling a higher version triggers an update prompt. |
icon | string | no | An emoji (≤8 chars) or a data:image/… URI up to 8 KB. |
author | string | no | ≤200 chars. |
description | string | no | ≤200 chars. |
permissions | string[] | no | Up to 16 labels (≤32 chars each). Vocabulary: storage ai bluetooth usb serial network notifications share. Advisory only — surfaced in the trust prompt and the manager row; not enforced by a sandbox. |
mounts | object | no | Where the extension appears (below). |
mounts.tool | object | no | Present (usually {}) → a launcher tile plus the manager's open button. |
mounts.commands | object[] | no | Each { name, description, usage? } registers a terminal/palette command. name kebab-case 2–16 chars; description required; usage is an optional hint. Colliding names are skipped. |
mounts.widget | object | no | { key, label } → a live status tile on the home launcher (see Widgets). key (1–64 chars) is the storage key the tile watches; label (1–48 chars) names the tile. |
The host object — window.mentria
The run host injects a frozen window.mentria before your script executes. Everything an extension can do goes through it.
| Member | Shape | What it does |
|---|---|---|
manifest | object | A frozen copy of your parsed manifest. |
storage.get | (key) → value | Read from your extdata.<id> namespace. storage.get('note') |
storage.set | (key, value) → bool | Write any JSON value. Returns false when storage is full. storage.set('note', text) |
storage.remove | (key) → bool | Delete one key. storage.remove('note') |
storage.list | () → string[] | List your keys. storage.list() |
theme | { accent, bg, fg, muted, fontMono } | The site's live CSS token values. root.style.setProperty('--x', theme.accent) |
args | null | { cmd, args } | Set when opened via a command (#cmd=…&args=…); otherwise null. if (args) run(args.args) |
notify | (msg) → void | Host toast, bottom-center, first 120 chars. notify('saved') |
close | () → void | Leave the extension and return to the home launcher. close() |
The run frame is granted the feature policy bluetooth; usb; serial; camera; microphone, so those Web APIs work from inside an extension when the browser and user allow them.
Storage
Each extension owns a private namespace, extdata.<id>, reachable only through window.mentria.storage. It is backed by the browser's localStorage (via MentriaStore), so reads and writes are synchronous and every value must be JSON-serializable.
- Quota is real and shared:
localStorageis roughly 5 MB for the whole origin, split across every tool. Keep extension data small;storage.setreturnsfalseif the write would overflow. - Your data is covered by the site's encrypted local backup, and shows up in the Files tool grouped as extension: <id>.
- Removing the extension in the manager also clears its
extdata.<id>keys. - The whole
.htmlis stored too: over 512 KB warns at install, over 1536 KB is rejected outright.
Widgets
Declare mounts.widget and the home launcher shows a live status tile for your extension, named by label and linking to your run page. The tile renders the snapshot object stored under key in your own storage — e.g. storage.set('note', { text: 'bought milk', progress: 0.4 }) — and refreshes on every write.
| Snapshot field | Type | Req | Rules |
|---|---|---|---|
text | string | yes | The tile's value line. Trimmed, capped at 80 chars; must be non-empty. |
detail | string | no | A secondary line below the value. Trimmed, capped at 120 chars. |
progress | number | no | Drawn as a progress bar; clamped to 0–1. |
Anything else under that key — a plain string, an array, an empty text — is ignored silently: the tile simply stays hidden until the key holds a valid snapshot object.
Install & share
- Manager (/tools/extensions/): drop an
.htmlfile, choose a file, or paste the source. Every install shows a human trust prompt naming the extension, its version and its declared permissions; updates call out permissions the new version adds or drops, and installing an older version is labeled as a replacement, not an update. - Share over comms: from an installed row, share hands the file to an open comms session; the peer gets the same trust prompt, attributed from you, before anything installs. If comms is closed it points you there.
- Export: export downloads the stored source back out as
<id>.html, so an extension is always portable.