Skip to main content

Getting Started

This guide walks you from zero to a published, installable plugin in under five minutes. By the end you'll have:

  • A scaffolded plugin project on disk
  • A signed .tar.gz artifact
  • A GitHub release hosting it
  • A hub listing other SSG users can install from

Prerequisites​

RequirementWhy
ssg installed — see Getting Started (Pro subscription required)The plugin CLI lives in ssg.
GitHub CLI (gh auth login)Plugin publish creates a repo + release.
Ed25519 signing key (ssg keys generate)All plugins are signed; the key is what ~/.sigmashake/keys/ already contains.
Hub account with key registered (ssg keys register)The hub cross-checks your signing key against your account.
tar with -tzf and -tvzf support (GNU tar or bsdtar)Local install checks the tarball before it extracts it. ssg refuses busybox tar.

If you have already signed in with ssg auth login and gh auth login, you have everything except possibly the registered signing key — run ssg keys register to be sure.

1. Scaffold​

ssg plugins init my-cool-tool
cd my-cool-tool

You get a minimal project:

my-cool-tool/
├── plugin.toml
├── README.md
├── .gitignore
└── src/
├── index.html
├── app.js
└── style.css

Open plugin.toml and edit the metadata to taste:

id = "my-cool-tool"
version = "0.1.0"
name = "My Cool Tool"
description = "Surfaces blocked tool calls in a heatmap."
category = "observability"
entry = "index.html"
min_ssg_version = "0.29.0"

[[nav]]
label = "Block Heatmap"
path = "/plugins/my-cool-tool/"
section = "tools"
order = 100

Then edit src/index.html, src/app.js, and src/style.css to build whatever you want. The template app.js sends its request with the scoped plugin credential that the daemon injects into window.__SSG_PLUGIN_CONFIG__.token. That credential is not the dashboard token (see the trust model). A plugin can always read four endpoints: GET /api/health, GET /api/state/counters, GET /api/json/rules-stats and GET /api/json/mode. The current template fetches /api/json/status, which is not one of those four and is not a grantable route. Change that path to /api/json/mode to get a working call. Other routes need a capability grant from the operator.

2. Build​

ssg plugins build

This:

  1. Validates plugin.toml
  2. Bundles src/ → dist/
  3. Tars + gzips dist/ into dist/my-cool-tool-0.1.0.tar.gz
  4. Computes the SHA-256
  5. Signs the SHA-256 with your local Ed25519 key
  6. Writes the canonical dist/plugin.json manifest

You should see something like:

✓ Built my-cool-tool v0.1.0
Artifact: /Users/you/my-cool-tool/dist/my-cool-tool-0.1.0.tar.gz (8.2 KB)
Manifest: /Users/you/my-cool-tool/dist/plugin.json
SHA-256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Signed by: 302a300506032b6570032100…

Optional: a custom build step​

If you use Vite, esbuild, Webpack, etc., add a [build] section to plugin.toml:

[build]
command = "pnpm install --silent && pnpm build"

ssg plugins build will run that command before packaging. Whatever it writes into dist/ becomes the plugin bundle. The entry field still applies — dist/<entry> must exist or build fails.

3. Test locally​

Install the build locally:

ssg plugins install --from dist/

--from accepts one of these paths:

  • The project directory. The command uses its dist/ directory.
  • The dist/ directory. It must contain plugin.json and <id>-<version>.tar.gz.
  • A .tar.gz file. The command reads plugin.json from the tarball root. If the root has no plugin.json, it reads the plugin.json beside the tarball. Without either file, the install fails.

A directory with plugin.json and dist/<entry> also works.

A local install is unsigned. The CLI prints a warning each time. Use --force to replace an installed plugin with the same id.

To serve dist/ during development, symlink it into the SSG plugins root so the dashboard can serve it:

mkdir -p ~/.sigmashake/plugins/my-cool-tool
ln -sfn "$PWD/dist" ~/.sigmashake/plugins/my-cool-tool/dist
cp dist/plugin.json ~/.sigmashake/plugins/my-cool-tool/plugin.json
cat > ~/.sigmashake/plugins/my-cool-tool/.installed.json <<JSON
{
"id": "my-cool-tool",
"version": "0.1.0",
"installed_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"source_pack_id": null,
"source_repo": null,
"content_hash": "local",
"signing_fingerprint": "$(ssg keys show)",
"enabled": true,
"category": "observability",
"author_github": null,
"homepage_url": null,
"repo_url": null
}
JSON

ssg serve # opens http://127.0.0.1:5599

Your plugin shows up at /plugins/my-cool-tool/ and in the sidebar.

4. Publish​

When the plugin is ready to share:

ssg plugins publish

This:

  1. Re-runs the build to make sure your artifact and manifest are in sync
  2. Verifies you're authenticated with gh
  3. Creates github.com/<you>/ssg-plugin-my-cool-tool (private by default — you can flip it public on GitHub afterwards)
  4. Pushes your plugin source to that repo
  5. Creates a release v0.1.0 and uploads the tarball + plugin.json as release assets
  6. Opens hub.sigmashake.com/submit-plugin in your browser with every field pre-filled

The submit form double-checks that the signing fingerprint on the form matches the Ed25519 key registered to your hub account, then writes the plugin into the hub's marketplace index.

5. Install from the hub​

Once submitted, your plugin is immediately installable from any SSG dashboard:

ssg plugins install my-cool-tool

Or from the dashboard: go to Plugins → search my-cool-tool → click Install. The daemon verifies the signature against the hub's recorded fingerprint before extracting any code.

Updating​

To ship a new version:

# 1. Bump version in plugin.toml
sed -i '' 's/^version *=.*/version = "0.2.0"/' plugin.toml

# 2. Rebuild and publish — `publish` is idempotent
ssg plugins publish

Users uninstall + reinstall to pick up the new version (auto-upgrade lands in a later release).

Next steps​