Create your first plugin
Petti 1.4 · Plugin API v1 · Experimental
This plugin counts selected text and adds a cell preview. It never reads a database directly or changes a value.
Download the complete Text Tools example, or create the following folder and files using a plain-text editor. Extract the ZIP before installing.
TextTools.petti-plugin/
manifest.json
main.js
1. Describe the package
Save this as manifest.json. Use your own reverse-domain identifier for a new plugin. The example ID is for this tutorial; do not reuse a bundled Petti ID or install two packages with the same ID.
{"id":"dev.example.text-tools","name":"Example Text Tools","version":"1.0.0","apiVersion":1,"type":"extension","entry":"main.js","permissions":["selection.read","clipboard.write"]}
version is your package’s numeric major.minor.patch version. apiVersion: 1 selects Petti’s API contract. entry points to a contained .js file. type describes the package; it does not grant capabilities. The permissions array controls access. Here, selection.read supplies the selected text and clipboard.write permits the user’s Copy Result action.
2. Register behavior
petti.registerCommand({
id: "text-length",
title: "Count Selected Text",
run(context) {
const text = context.selection.text;
if (text === null) throw Error("Select one loaded text cell before opening the palette.");
return {title: "Text length", text: String(Array.from(text).length) + " Unicode code points"};
}
});
petti.registerCellPreviewer({
id: "text-length-preview",
title: "Text Length",
storageTypes: ["text"],
preview(value) {
return {title: "Text length", text: String(value.byteCount) + " UTF-8 bytes; " + String(Array.from(value.text).length) + " Unicode code points"};
}
});
The host exposes the global petti object. Registration describes actions; it should not perform work on the user’s database. The command receives a context when explicitly invoked. The previewer receives only the selected value, not a database connection.
Array.from(text).length counts Unicode code points, not bytes or user-perceived grapheme clusters. For example, some emoji sequences contain multiple code points. The preview also reports the supplied UTF-8 byte count. This distinction is intentional.
3. Install and approve
- In Petti 1.4, choose Tools → Command Palette… (⌘⇧P).
- Choose Install Local Plugin…, select TextTools.petti-plugin and review the installation.
- Expand Installed plugins, choose Enable for Example Text Tools and review its permissions.
- Close the palette, select one loaded text cell, then reopen it and run Count Selected Text.
A cell containing Hello should return 5 Unicode code points. With no text selected, the command should show the supplied error. For the previewer, select the cell, press Space and choose Plugin Preview → Text Length. Copy Result is an explicit action, not an automatic clipboard write.
4. Edit and reload
Installation copies reviewed bytes into ~/Library/Application Support/Petti/Plugins/. Editing your original download does not update the installed copy. For local development, disable the plugin, edit your own installed package, then reopen the palette to rediscover it and approve the changed content. The installer does not overwrite an existing package ID. Keep a separate source copy and do not edit Petti’s signed application bundle.
There is no hot reload or persistent global JavaScript state. Each invocation gets a fresh runtime. Continue with testing and debugging before sharing a package.