← Plugin docs

Permissions

What each permission grants, and when to declare it.

Projelli plugins run in a sandboxed Web Worker. By default, a plugin can register commands, add toolbar buttons, add sidebar panels, add settings pages, persist its own key/value storage, and show notifications. Anything that touches the user's files, the editor, an AI provider, or the network requires an explicit permission, declared in manifest.json, that the user approves on install.

There are exactly 6 permissions. Pick the smallest set that lets your plugin work. Users see your permission list before they install, and a plugin asking for everything will get fewer installs than one asking for the minimum.

Summary

PermissionGrantsRisk
workspace:readList files and read file contents in the user's workspace.Reads private notes.
workspace:writeCreate, overwrite, or modify files in the workspace.Can corrupt or replace user data.
editor:selectionRead the selected text and the active document's content.Reads what the user is currently editing.
editor:writeReplace the selection or insert text at the cursor.Can change the active document.
ai:invokeCall the user's configured AI provider with a prompt.Spends the user's API credits.
networkMake HTTP requests from the worker to any URL.Can exfiltrate data, contact arbitrary servers.

The unconditional capabilities

These never require a permission. Use them freely:

If your plugin only uses these, declare an empty permissions array ("permissions": []). The Pomodoro example does exactly that.

The 6 declarable permissions

workspace:read

Grants: api.workspace.listFiles(path?) and api.workspace.readFile(path).

Declare it when: your plugin needs to scan the workspace for files (e.g. a backlinks indexer, a research aggregator) or read files other than the active document.

Risk: the plugin can read every file in the user's workspace, including private notes. Combined with network, the plugin can ship those files anywhere. Don't ask for this unless you actually need it.
"permissions": ["workspace:read"]

workspace:write

Grants: api.workspace.writeFile(path, content).

Declare it when: your plugin needs to create or overwrite files in the workspace (e.g. an export-to-PDF plugin that writes the result, a template plugin that scaffolds a folder).

Risk: the plugin can overwrite any file in the workspace, including files it didn't create. Always pair writes with confirmation flows or unique filenames; don't silently clobber user data.
"permissions": ["workspace:write"]

editor:selection

Grants: api.editor.getSelection() and api.editor.getContent().

Declare it when: your plugin needs to read what the user is currently editing. This is the most common permission for editor-enhancing plugins (word counters, grammar checkers, summarizers).

Risk: the plugin can poll and read the active document's full text. Combined with network or ai:invoke, that text leaves the machine.
"permissions": ["editor:selection"]

editor:write

Grants: api.editor.replaceSelection(text) and api.editor.insertAtCursor(text).

Declare it when: your plugin modifies the active document (e.g. translation, tone shift, snippet expansion).

Risk: the plugin can replace the user's selection or inject text at the cursor. Always trigger writes from explicit user actions (button click, command invocation), not from background polling.
"permissions": ["editor:selection", "editor:write"]

ai:invoke

Grants: api.ai.invoke({ prompt, system }). The call goes through the user's configured AI provider (Claude, OpenAI, or Gemini) using their stored API key. The plugin never sees the key.

Declare it when: your plugin needs to call an LLM. This is BYOK; the user pays their provider, not Projelli.

Risk: every call costs the user real money against their API plan. Don't loop, don't fire on every keystroke, don't pad prompts unnecessarily. Document expected token usage in your README.
"permissions": ["ai:invoke"]

network

Grants: api.network.fetch(url, opts?). The worker can make arbitrary HTTP requests.

Declare it when: your plugin needs to talk to a third-party API directly (not through the user's AI provider). Examples: pulling research from a knowledge base, posting to a project tracker, syncing to a remote service.

Risk: this is the most dangerous permission. The plugin can contact any URL, send any data, and act as a data exfiltration channel. Users will scrutinize this one. Document every endpoint your plugin contacts in your README.
"permissions": ["network"]

Best practices

What happens if a plugin tries to use a permission it didn't declare?

The API call rejects with a permission error. The plugin can catch it and degrade gracefully. The host doesn't crash and other plugins are unaffected.

Next: API reference →