A dependency-free reference plugin for Snapr's local post-capture plugin system. It accepts image and video captures, creates a Markdown metadata report, and returns the report to Snapr as a file artifact.
This repository is both a working sample and the first-version plugin development guide. Fork it when starting a plugin of your own.
- A cross-platform
snapr.plugin.jsonmanifest - Repository-relative Python runners for macOS and Windows
- One JSON request from Snapr over stdin
- Status, progress, result, and error events over stdout as line-delimited JSON
- A file artifact written inside Snapr's per-run output directory
- A dependency-free
unittestsuite
- Snapr with local plugin support
- A trusted Python 3 installation, used only to create this repository's virtual environment
Snapr does not search the system PATH when it runs a plugin. Each platform runner must point to an executable inside the plugin repository. The example uses .venv/bin/python on macOS and .venv\Scripts\python.exe on Windows.
Clone this repository, then create its local Python environment.
python3 -m venv .venvpy -3 -m venv .venvNo packages need to be installed. Next:
- Open Snapr Settings → Plugins.
- Choose Register Plugin and select this repository directory.
- Capture an image or video.
- In the floating preview, choose More → Post Process, or press
Cmd/Ctrl+P. - Run Create Example Report.
- Choose Reveal to locate the generated
report.mdfile.
Snapr registers the repository in place. You can edit or update the clone and use Reload in Settings without registering it again.
snapr-plugin-example/
├── snapr.plugin.json # Plugin metadata, runners, and actions
├── plugin.py # stdin/stdout protocol implementation
└── tests/
└── test_plugin.py # Dependency-free protocol test
Snapr reads snapr.plugin.json from the repository root.
{
"manifestVersion": 1,
"id": "dev.snapr.example",
"name": "Snapr Plugin Example",
"version": "0.1.0",
"description": "Creates a Markdown metadata report to test the Snapr plugin lifecycle.",
"runners": {
"darwin": { "command": ".venv/bin/python", "args": ["plugin.py"] },
"win32": { "command": ".venv/Scripts/python.exe", "args": ["plugin.py"] }
},
"actions": [
{
"id": "create-example-report",
"name": "Create Example Report",
"description": "Generate a Markdown report and sample artifacts.",
"accepts": ["image", "video"]
}
]
}Runner commands and arguments must be repository-relative paths. Absolute paths and .. traversal are rejected. Snapr currently supports darwin and win32, and action input kinds image and video.
Snapr starts the configured runner with the repository as its working directory. It writes exactly one JSON object followed by a newline to stdin.
{
"protocolVersion": 1,
"runId": "unique-run-id",
"pluginId": "dev.snapr.example",
"actionId": "create-example-report",
"input": {
"kind": "image",
"path": "/absolute/path/to/capture.png"
},
"outputDirectory": "/absolute/path/to/snapr-managed-output",
"config": {}
}The runner writes line-delimited JSON events to stdout and flushes after every event. Do not write logs or other text to stdout; use stderr for diagnostics.
{ "type": "status", "message": "Reading capture metadata" }{ "type": "progress", "current": 2, "total": 3, "message": "Writing Markdown" }current, total, and message are optional, but current and total should be emitted together when showing determinate progress.
{
"type": "result",
"artifacts": [
{
"kind": "file",
"path": "report.md",
"title": "Example Markdown report",
"mediaType": "text/markdown"
},
{
"kind": "notification",
"title": "Complete",
"message": "Example plugin completed"
}
]
}File and image artifact paths must be relative to outputDirectory. Snapr rejects missing files, directories, absolute paths, path traversal, and symlinks that escape the output directory.
Supported artifact kinds:
| Kind | Required field | Host actions |
|---|---|---|
file |
path |
Copy Path, Reveal |
image |
path |
Open, Copy Image, Reveal |
text |
text |
Copy |
url |
url (http or https) |
Open Link, Copy Link |
notification |
message |
Displayed with completion status |
{ "type": "error", "message": "Input file not found", "code": "example_failed" }Catch runner errors and emit a final error event. A plugin run should emit either one final result event or one final error event.
- Fork or copy this repository.
- Change the manifest
id,name,version, description, and actions. - Keep every runner executable and script inside the repository.
- Read one request line from stdin.
- Write generated files only inside
outputDirectory. - Emit protocol events as line-delimited JSON on stdout.
- Add tests for every action before registering the repository in Snapr.
Plugin IDs and action IDs may contain lowercase letters, digits, ., _, and -, and must start with a letter or digit. Action IDs must be unique within a manifest.
Snapr plugins are local programs with the same user permissions as Snapr. Register and run only repositories you trust, inspect runner changes before pulling updates, and keep dependencies pinned when your plugin uses third-party packages.
Snapr validates manifests and returned artifacts, but it does not sandbox plugin processes.
.venv/bin/python -m unittest discover -s tests -v.venv\Scripts\python.exe -m unittest discover -s tests -v