Use Bun and the plugin kit:
bunx @ericsanchezok/synergy-plugin-kit create my-plugin --template workbench-panel
cd my-plugin
bun installAvailable templates are tool-ui, workbench-panel, navigation, api-connector, and theme-icon.
The generated project exports one definition from src/index.ts:
import z from "zod"
import { capability, definePlugin, event, operation, workbenchPanel } from "@ericsanchezok/synergy-plugin"
export default definePlugin({
id: "my-plugin",
version: "0.1.0",
description: "My Synergy plugin",
assets: [{ source: "src/prompts", target: "runtime/prompts" }],
capabilities: [capability("workspace.read"), capability("ui.hostActions")],
contributions: [
event({ id: "data.changed", payload: z.object({ reason: z.string() }) }),
operation({
id: "data.get",
type: "query",
input: z.object({}),
output: z.object({ value: z.string() }),
requires: ["workspace.read"],
async handler(_input, context) {
return { value: (await context.workspace?.read?.("data.txt")) ?? "" }
},
}),
workbenchPanel({
id: "main",
label: "My Plugin",
surface: "side",
cardinality: "singleton",
component: { source: "./src/ui.tsx" },
}),
],
})Do not create plugin.json in the source project. Validation rejects it.
synergy-plugin build
synergy-plugin validate --runtime-discovery
synergy-plugin test
synergy-plugin packbuild recreates dist/, bundles executable handlers, compiles trusted Solid UI, copies declared assets, and writes generated metadata and integrity hashes. validate --runtime-discovery imports the packaged runtime only in the explicit validation step and checks that its handler IDs exactly match generated executable contributions. pack archives the already-built dist/; it never installs dependencies at install time.
Use top-level assets for files that executable code needs at runtime. Each entry maps a project-relative source file or directory to a package-relative target. Targets must be unique and remain inside the package. Asset contents are covered by integrity.json and participate in the build generation, so changing a prompt, schema, or other runtime resource creates a new generation. Do not rely on source-tree-relative paths from a bundled runtime.
The package contains:
plugin.json
integrity.json
permissions.summary.json
runtime/index.js # only when executable code exists
ui/index.js # only when trusted components exist
declared assets
Build first, then register the project or its dist directory:
synergy plugin add file:///absolute/path/to/my-pluginFor a directory spec, Synergy uses dist/plugin.json when it exists. The Plugins workspace shows the registration under both Installed and Development. A local registry package is different: it is a catalog artifact and appears under Discover when the Local registry source is selected.
If the generated manifest or permissions have not been approved, the plugin remains disabled as Needs approval. Review the server-generated permissions and approve with:
synergy plugin approve my-pluginApproval records are tied to publisher identity and the structured access grant. Metadata, code, handler, asset, and changelog-only rebuilds keep the existing grant. Removing access or narrowing known constraints updates silently. New Host Services, broader constraints, trusted UI, broader operation exposure, or an unknown constraint change require confirmation of only the added/broadened access. A source or signer change requires publisher confirmation.
Use an isolated Synergy instance with an explicit SYNERGY_HOME, then run:
synergy-plugin dev --server-url http://127.0.0.1:PORTThe watcher builds into generation directories under dist/dev/. A successful build updates the generation pointer and asks the isolated server to reload atomically. A failed build leaves the previous generation active. Live reload refuses to contact a server unless SYNERGY_HOME is explicitly set. Dev generation hot reload is separate from approval, config schema, and migration behavior.
Sign the built package and prepare a marketplace entry:
synergy-plugin sign my-plugin-0.1.0.synergy-plugin.tgz
synergy-plugin publish-market --repo https://github.com/owner/my-pluginPublishing is an explicit command. Build, validate, test, and pack never mutate a remote registry. See Marketplace.