What plugins are
BetaYou add a plugin when Wrengle doesn't already do something you want: a calculator, a converter, a checklist, or a tool that acts on text you select in a note. A plugin is a local folder — you point Wrengle at one yourself, or build one with Plugin Builder and approve it before Wrengle installs it.
Two kinds of plugin
A WASM action runs from the editor's Actions menu. Select text, open Actions, and choose it; the action returns a result, or it proposes a change to your note for you to approve.
A view-only plugin opens in its own tab — the kind of small tool
described above. Run it with the Open <label> command from the
command palette.
A plugin can also add rows to the command palette, the slash menu, context menus, keybindings, the status bar, or settings pages. Wrengle calls these UI contributions.
What a plugin can and cannot do
Local WASM action plugins execute WASM in a sandboxed runtime, and every plugin starts with no access to anything. A plugin's manifest lists the capabilities it may ask for, but that list is a request, not a grant — you decide whether to allow each one, and your decision applies only to that one plugin installation and its exact loaded code.
A plugin cannot write to a note directly. When an action wants to change one, it creates a proposal, and the editor shows you the change before anything reaches your vault.
View-only plugins execute local HTML and JavaScript in a sandboxed tab. Every
view has a mandatory host-owned offline policy: direct network requests are blocked,
along with WebSockets, WebRTC, navigation, forms, nested frames, and external
resources. The httpHosts capability gates only host-bridge HTTP made by WASM
actions; it never relaxes a view's offline policy.
Local plugin code is trusted local code, the same as any program you run on your machine — load only folders you trust.
There is no marketplace. Every plugin is local code, whether you point Wrengle at it yourself or approve one Plugin Builder generated for you; nothing installs or updates itself from the internet.
Make one
You don't need to write code. Open Plugin Builder from the New tab (+) menu or the command palette, describe what you want in plain language, and review the result before it installs. See Build one with the Builder.
You can also hand a plugin idea to an LLM you already use and get back a ready-to-load folder. See Build one by describing it.
If you'd rather write a WASM action yourself — the SDK, host calls, and grant examples — see Writing one by hand.
How plugins load
A plugin folder needs a plugin.toml file and at least one contribution — a
WASM action, a view, or a UI contribution.
For a hand-written or LLM-generated plugin, add its folder under Settings → Plugins → Developer → Dev plugin paths, or point at a parent folder under Watched plugin folders so every plugin inside it loads automatically. The in-app Plugin creator adds its generated folder as a dev path for you.
Wrengle also scans a legacy internal plugin directory you never point it at directly — this is where Plugin Builder installs the plugins you approve. If a plugin you added under Dev plugin paths or Watched plugin folders shares an id with one already in that directory, yours takes precedence.
App surfaces
| Surface | Purpose |
|---|---|
| Settings → Plugins → Developer → Plugin creator | Generate a local action or view plugin folder from a typed template, with manifest ids and requested capability grants previewed before creation. |
| New tab (+) menu or command palette -> Plugin Builder | Open a focused project workspace for Builder-created plugins, create or iterate on static custom views and offline feature apps from plain-language prompts, use automatic plugin-scoped JSON state for offline apps, reset app state from the actions menu for stateful installed apps without removing plugin files or history, automatically run checks and smoke preview before Apply, apply approved offline changes on this device, open the installed view tab, review prompt-first approved history, roll back to a prior approved version after confirmation, enable or disable Builder-created plugins, and delete installed Builder-created apps with their managed plugin files, approved prompt history, rollback points, linked Builder conversations, and installed app state. |
| Settings → Plugins → My plugins | Review, enable, disable, or delete Builder-created plugins installed on this device and link back to Plugin Builder; broader developer controls remain in Settings. |
| Settings → Plugins → Developer → Dev plugin paths | Add trusted local plugin folders and reload. |
| Settings → Plugins → Developer → Watched plugin folders | Add trusted parent folders whose immediate child plugin folders are loaded automatically, with root diagnostics shown after reload. |
| Settings → Plugins → Loaded plugins | Confirm registered plugin actions, plugin views, and accepted UI contributions. |
| Settings → Plugins → Management → Plugin permissions | Review, grant, deny, or revoke plugin capability decisions for each local plugin installation. |
| Settings → Plugins → Management → Plugin keys | Set, update, or delete OS-keychain secret values for aliases declared by plugin manifests; secret values are not displayed after entry. |
| Settings → Plugins → Management → Plugin state | Reset plugin-scoped local JSON state for developer/manual plugin installations; stateful Builder-created apps use Reset app state from Plugin Builder. |
| Settings → Plugins → Developer → Plugin diagnostics | Inspect manifest, missing-WASM, view-entry, action registration, and UI contribution errors. |
| Editor selection toolbar -> Actions | Run WASM actions against selected text, or send selected text to views with accepts_selection = true. |
| Command palette | Open plugin views as Open <label> commands with plugin-name attribution, and run accepted plugin palette contributions. |
| Slash menu | Run accepted plugin slash-menu contributions from the editor. |
| Context menus | Run accepted plugin file-tree and editor-selection context menu rows. |
| Keybindings | Run conflict-checked plugin keybindings for reusable plugin commands. |
| Status bar | Show accepted static plugin status buttons. |
| Settings → Plugins subpages and docked panels | Render sandboxed plugin views in host-owned settings or dock placements. |
Consent and write proposals
Declarations are not grants. Manifest [[capabilities]] entries describe the
host APIs a plugin may ask to use, but Wrengle does not grant those APIs just
because they appear in plugin.toml. Grants are explicit user decisions scoped
to this app install, the plugin id, the canonical local path, the currently
declared grant keys, and the exact loaded code fingerprint. The fingerprint
covers the manifest, WASM runtime, and view HTML bytes captured at reload.
Changing any of those bytes makes positive grants pending until you approve the
new code again. Plugin state and keychain values remain in their stable
plugin-and-path storage namespace across an approved update.
Plugin actions do not receive declared host capabilities automatically. When a local action is confirmed, Wrengle checks its capability grants. If any requested grant is pending, denied, or revoked, the editor shows Plugin permissions with the action's requested capabilities. You can grant the selected capabilities and run, run without changing grants, or cancel without running the action. Running without grants leaves enforcement to the host API: calls that need missing grants return capability-denied errors instead of bypassing consent.
Write host functions do not mutate notes or blocks directly. They create app-mediated write proposals scoped to the plugin id, canonical local path, exact code fingerprint, and current vault-open session. Closing, switching, or reopening even the same vault invalidates proposals from the earlier session. Changing the loaded plugin code also makes an existing proposal stale. After a plugin action returns, the editor can keep the preview open with pending write proposals. Note proposals show unified diff rows; block proposals summarize the queued block operations. The user approves or denies each proposal from the editor before any write is applied; nothing changes until you approve the proposal in Wrengle.
Settings trims leading/trailing whitespace and stores the path string without resolving it. After reload, the UI may also show a fully resolved version of that path. Prefer absolute paths unless the app process is running from the repository root.
Current limits
- No marketplace or remote installation flow is available.
- Plugin Builder creates local custom views and stateful feature apps. It does not create networked plugins, marketplace listings, or generated WASM tools in this release.
- A Builder-created app reaches the workspace only through the reads and write proposals its generated manifest declares, and a write is always a proposal you approve.
- No public stability guarantee exists for plugin manifests, SDK APIs, host functions, view bridge messages, UI contribution schemas, or generated creator templates.
- Runtime dynamic UI contribution registration is not available. Contributions are manifest-declared and visible after plugin reload or app reload.
- Host-command UI targets are limited to
openSearch,newNote,toggleTerminal,focusEditor,openSettings, andshowNotification. - Plugins cannot inject components into Wrengle's own interface or take over arbitrary host chrome; custom UI stays in sandboxed plugin views.
- Arbitrary process execution is not available.
- Process-plugin manifests are not supported.
- WASM action plugin folders must contain both
plugin.tomland the builtplugin.wasmnamed by[runtime].entry. - View-only plugin folders must contain
plugin.tomland the declared single HTML entry file for each view. - Watched plugin roots load immediate child plugin folders only. The root folder itself is not treated as a plugin unless it is also added as an individual developer plugin path.
plugin.wasmis generated by the plugin author and is not committed for the WASM examples.- Host access is capability-gated; plugins do not get direct filesystem, process, or keychain access outside declared host functions.
- Every manual, developer, and Builder-created view receives the same mandatory
offline policy. Direct network requests are blocked.
httpHostsgrants only Wrengle host-bridge HTTP calls made by WASM actions and does not relax the view policy. - Plugin secrets are stored in the OS keychain under namespaces keyed to the plugin id and the exact local folder the plugin was loaded from. Plugin JSON state is isolated by that same pair. At startup, Wrengle preloads only aliases for the current installed identity whose exact loaded code still has a matching secret grant. Removed, revoked, or differently rooted plugin identities are excluded. Preloading does not run the plugin or grant any declared capability. A denied or locked item leaves that plugin's secret-dependent work unavailable in Limited mode without showing a Keychain prompt when the action runs. Builder-created offline apps receive plugin-scoped JSON state automatically, and Wrengle keeps that local app data with the installed Builder app until the user resets app state or deletes the app. Builder drafts declare expected state keys before Apply, and installed Builder app calls are limited to those declared state keys. Manual local plugins use the same isolated plugin state host API when their manifest requests it and the user grants it. Plugin state is local to this device and is not a sync or backup boundary.
Secret-alias changes made while Wrengle is open use non-interactive Keychain operations. If the operating system would need to ask again, the change fails closed, the plugin cannot use the old session authority, and Settings requires an explicit reconnect, or a new launch when the current plugin configuration still authorizes preflight, instead of presenting a dialog over the plugin.
Views
Plugins can also declare custom-UI views — single self-contained HTML files
that Wrengle renders in a sandboxed iframe tab. Views are a deliberate
first-party extension of the developer preview. The first view plugin,
examples/plugins/json-compare, provides side-by-side JSON diffing with no
build step.
See Views (custom plugin UI) for the [[views]] manifest block,
the bridge protocol, and constraints, and the
JSON Compare tutorial for an annotated walkthrough
of the reference plugin.
UI contributions
Plugins can declare host-rendered entries for the command palette, slash menu, context menus, keybindings, status bar, plugin settings pages, and docked panels. Contributions can target same-plugin actions and views or the small explicit host-command allowlist. Settings pages and panels render sandboxed plugin views; they are structured plugin targets, not generic host commands.
See UI contributions for the surface table, target syntax, host-command allowlist, reload behavior, disable policy, audit behavior, and examples.
Adoption gate
Distribution, public stability promises, additional contribution points, and expanded permission UX are not part of this release.