PluginsCreate a marketplace

Create a marketplace

A marketplace is a list you publish so others can find your plugins. It is one JSON file, marketplace.json, that gives the catalog a name and lists each plugin with a pointer to where its files live. Anyone who adds your marketplace can then browse it in /plugin and install from it with syntic plugin install <plugin>@<marketplace>.

This page walks through writing a marketplace, choosing where each plugin comes from, and checking your work before you share it. For hosting, access control and updates, see Host a marketplace. Every field is listed in the Marketplace reference.

A first marketplace

Make a folder

Put the catalog file at the root of a folder. Plugins can sit next to it:

acme-plugins/
  marketplace.json
  plugins/
    formatter/
      .syntic-plugin/plugin.json
      commands/format.md
    release-helper/
      .syntic-plugin/plugin.json
      skills/release/SKILL.md

Each plugin folder is an ordinary plugin with its own manifest. See Create a plugin if you have not built one yet.

Write marketplace.json

{
  "name": "acme",
  "plugins": [
    {
      "name": "formatter",
      "source": "./plugins/formatter",
      "description": "Formats the files you touched",
      "category": "editing",
      "tags": ["format", "style"]
    },
    {
      "name": "release-helper",
      "source": "./plugins/release-helper",
      "description": "Release chores: changelog, version bump, tag"
    }
  ]
}

The top-level name is how people refer to your catalog: formatter@acme. Each entry needs a name; everything else is optional.

Add it and install from it

syntic plugin marketplace add ./acme-plugins
syntic plugin list --available
syntic plugin install formatter@acme

marketplace add reads the file, saves the catalog under the name it declares, and prints how many plugins it found.

Rules for entries

A few rules keep installs predictable.

  • Names are plain. Marketplace and plugin names may use letters, digits, ., _ and -. Anything else (a slash, a space, ..) is refused, because the name becomes a folder on disk.
  • Names are unique. Two entries with the same name in one catalog is an error.
  • Give the entry and its plugin.json the same name. The entry name is what users type and what the installed folder is called; it also becomes the prefix of the plugin’s slash commands. Keeping the plugin’s own plugin.json name identical avoids confusion in /plugin and syntic plugin details.
  • Relative paths stay inside. A source may not contain a .. step or be an absolute path. Write relative paths from the folder that holds marketplace.json, starting with ./.
  • An empty source is an error. Leave the field out instead; the plugin is then taken from the marketplace’s own location (useful when one repository is both the marketplace and its only plugin).
⚠️

A relative ./plugins/... source resolves next to marketplace.json only for a marketplace that someone added as a folder on disk. For a marketplace added from GitHub or another git host, point each entry at the repository and folder instead, for example acme/acme-plugins//plugins/formatter. The // form clones only that folder.

Choose a plugin source

An entry’s source accepts the same source strings as syntic plugin marketplace add, plus a folder suffix:

You wantWrite
A folder next to a local marketplace.json./plugins/formatter
A whole GitHub repositoryacme/formatter-plugin
A GitHub repository at a branch or tagacme/formatter-plugin@v2 or acme/formatter-plugin#v2
An exact commitacme/formatter-plugin@<40-character commit id>
One folder of a larger repositoryacme/monorepo//plugins/formatter
Any git hosthttps://git.example.com/team/formatter.git or git@git.example.com:team/formatter.git
A GitLab projectgitlab:acme/formatter
A .zip over https, optionally pinnedhttps://downloads.example.com/formatter-1.2.0.zip#sha256=<64 hex>
An npm packagenpm:@acme/formatter or @acme/formatter

How each one is fetched:

  • Git sources are cloned shallowly. A branch or tag is cloned directly; a 40-character commit id is fetched and then checked out exactly. A //folder suffix uses a sparse checkout, so only that folder is downloaded and kept.
  • Zip archives must be served over https. With a #sha256= pin, a download whose digest does not match is refused. An archive whose files sit inside one top-level folder is unwrapped.
  • npm packages are read from the public registry. The tarball must carry a sha512 integrity value and match it. npm itself never runs, so no install scripts or package dependencies run either.
  • A plain https URL that is not a .zip cannot hold a plugin. Use a zip, a git URL, or a package.

Set SYNTIC_PLUGIN_GIT_PROTOCOL=ssh to clone GitHub owner/repo sources over SSH instead of https, which helps with private repositories and SSH keys.

Check your work

Validate the file

syntic plugin validate ./acme-plugins --marketplace

validate reads marketplace.json from the folder (or a .syntic-plugin/marketplace.json inside it) without installing anything. It prints one line per problem, marked error or warning with the field it concerns, such as plugins.1.source. It exits with status 1 when there is any error.

What it catches:

Message is aboutMeaning
name missing or emptyThe catalog needs a name.
name impersonates the official marketplaceLook-alike spellings of Syntic’s own catalog names are refused. Pick another name.
plugins missingA warning: the catalog lists nothing yet.
plugins must be an arrayThe list is the wrong JSON type.
entry missing name / duplicate nameEach entry needs a unique name.
source is emptyRemove the field or give a real path.
source contains .. or is absoluteRewrite it relative to the catalog root.

Validate each plugin too:

syntic plugin validate ./acme-plugins/plugins/formatter

Problems that appear only on add or install

Validation looks at the file, not at the network. These show up later:

  • no marketplace.json in <repo>: git and local marketplaces must keep marketplace.json at the root of the repository or folder.
  • plugin <name> not listed in marketplace <name>: the name after @ matched a catalog, but no entry has that plugin name. Names are case-sensitive.
  • the source has no folder ...: the //folder part does not exist in the repository.
  • A missing plugin manifest: the fetched folder needs .syntic-plugin/plugin.json, a plugin.json at its root, or (for a one-skill plugin) a SKILL.md.
  • git is required ... but was not found: install git, or use a zip or npm source.

Try an edit before you publish

You do not need to reinstall after every change. Load the plugin folder directly for one session:

syntic --plugin-dir ./acme-plugins/plugins/formatter

When you change the catalog itself, refresh it and reinstall the plugin you changed:

syntic plugin marketplace refresh acme
syntic plugin update formatter@acme

Start over

syntic plugin marketplace remove acme

Removing a catalog forgets it but leaves its installed plugins in place. syntic plugin reconcile lists plugins whose catalog is gone, and syntic plugin reconcile --prune removes them.

Syntic’s own plugin collection

The Syntic Code source repository carries a marketplace named syntic-official, kept by the Syntic team. It lists four plugins:

PluginWhat it brings
code-reviewA review command and a reviewer agent that look at your working changes for bugs, risky edits and missing tests.
commit-commandsCommands that write a commit from your changes and draft changelog entries.
pr-review-toolkitA pull request review command with specialist agents for tests, error handling and API changes.
security-guidanceA secure-coding skill the agent applies while editing, plus a security check command.

It is not added to your machine automatically. If you have a copy of that folder, add it like any local marketplace:

syntic plugin marketplace add /path/to/syntic-cli/plugins/syntic-official
syntic plugin install code-review@syntic-official

Next steps