Manifest Reference
A plugin has two manifest shapes:
| File | Who writes it | When |
|---|---|---|
plugin.toml | You | Edited by hand at the plugin root. |
dist/plugin.json | ssg plugins build | Generated at build time — never edit. |
plugin.json is canonical: that's what the SSG daemon and the hub consume.
plugin.toml is the ergonomic surface — TOML so author-facing fields can be
grouped into tables, and so build-only fields like [build].command don't bleed
into the runtime manifest.
plugin.toml
# Required identity
id = "my-plugin"
version = "0.1.0"
name = "My Plugin"
description = "A one-line summary (≤ 160 chars)."
category = "tools"
entry = "index.html"
min_ssg_version = "0.29.0"
# Optional icon — relative to dist/, or a data: URL.
# icon = "logo.svg"
# At least one [[nav]] entry is required.
[[nav]]
label = "My Plugin"
path = "/plugins/my-plugin/"
section = "tools"
order = 100
# Optional build step. Anything that writes to dist/ works.
[build]
command = "pnpm install --silent && pnpm build"
Required fields
| Field | Type | Constraints |
|---|---|---|
id | string | Slug: [a-z0-9][a-z0-9-]{1,39}. Mounts at /plugins/<id>/. Immutable — choose carefully. |
version | string | Semver (0.1.0, 1.0.0-rc.1). |
name | string | Human display name. |
description | string | ≤ 160 chars. Shown in the marketplace card. |
category | string | One of tools, observability, productivity, integrations, developer. |
entry | string | Relative path inside dist/ of the SPA entry HTML. Default index.html. |
min_ssg_version | string | Semver. Install refuses on older SSG. |
[[nav]] | table-array | At least one. Each contributes a sidebar entry. |
Optional fields
| Field | Type | Notes |
|---|---|---|
icon | string | Path inside dist/ (logo.svg) or data: URL. |
[build].command | string | Run from plugin root before packaging. |
[[nav]] entries
| Field | Type | Notes |
|---|---|---|
label | string | Sidebar text. |
path | string | Must start with /plugins/<id>/. |
section | string | tools (default), activity, or settings. |
order | number | Lower sorts higher. Default 100. |
plugin.json (generated)
ssg plugins build writes this file into dist/plugin.json. It adds three
runtime-critical fields the TOML doesn't have:
| Field | How it's filled |
|---|---|
artifact_url | Blank locally; ssg plugins publish rewrites it to the GitHub release asset URL. |
artifact_sha256 | SHA-256 of the .tar.gz produced this build. |
artifact_signature | Ed25519 signature over artifact_sha256, signed with ~/.sigmashake/keys/signing.key. |
signing_fingerprint | The corresponding public key (hex SPKI). |
Example (truncated):
{
"id": "my-plugin",
"version": "0.1.0",
"name": "My Plugin",
"description": "A one-line summary.",
"entry": "index.html",
"artifact_url": "https://github.com/you/ssg-plugin-my-plugin/releases/download/v0.1.0/my-plugin-0.1.0.tar.gz",
"artifact_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"artifact_signature": "0badcafe…",
"signing_fingerprint": "302a300506032b6570032100…",
"min_ssg_version": "0.29.0",
"nav": [
{"label": "My Plugin", "path": "/plugins/my-plugin/", "section": "tools", "order": 100}
]
}
Tarball layout
The artifact is a gzipped tarball with this layout at root:
./dist/
./dist/<entry> # the file referenced by manifest.entry
./dist/... # everything else under dist/
./plugin.json # (optional) embedded copy — installer falls back to fetching from manifest_url
The installer rejects tarballs without ./dist/<entry> — that's the single
mandatory invariant. Everything else inside dist/ is served at
/plugins/<id>/<path> verbatim with appropriate MIME detection.
Size cap
Artifacts must be ≤ 50 MB. Larger plugins should host bulk assets off the plugin tarball (CDN, R2) and lazy-load them at runtime.
Forward compatibility
The plugin manifest parser tolerates unknown fields — newer SSG versions can add fields without breaking older plugins, and newer plugins can carry extra metadata without breaking older SSG installs. Don't rely on this for anything load-bearing.
Validation
You can validate a plugin.toml without doing a full build:
ssg plugins build --dry-run # (planned — same validation, no tar)
For now, just run ssg plugins build — it'll fail fast with a clear error if
anything is malformed.