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.mdEach 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@acmemarketplace 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
namein 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.jsonnameidentical avoids confusion in/pluginandsyntic plugin details. - Relative paths stay inside. A
sourcemay not contain a..step or be an absolute path. Write relative paths from the folder that holdsmarketplace.json, starting with./. - An empty
sourceis 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 want | Write |
|---|---|
A folder next to a local marketplace.json | ./plugins/formatter |
| A whole GitHub repository | acme/formatter-plugin |
| A GitHub repository at a branch or tag | acme/formatter-plugin@v2 or acme/formatter-plugin#v2 |
| An exact commit | acme/formatter-plugin@<40-character commit id> |
| One folder of a larger repository | acme/monorepo//plugins/formatter |
| Any git host | https://git.example.com/team/formatter.git or git@git.example.com:team/formatter.git |
| A GitLab project | gitlab:acme/formatter |
A .zip over https, optionally pinned | https://downloads.example.com/formatter-1.2.0.zip#sha256=<64 hex> |
| An npm package | npm:@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
//foldersuffix 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
sha512integrity 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
.zipcannot 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 --marketplacevalidate 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 about | Meaning |
|---|---|
name missing or empty | The catalog needs a name. |
name impersonates the official marketplace | Look-alike spellings of Syntic’s own catalog names are refused. Pick another name. |
plugins missing | A warning: the catalog lists nothing yet. |
plugins must be an array | The list is the wrong JSON type. |
entry missing name / duplicate name | Each entry needs a unique name. |
source is empty | Remove the field or give a real path. |
source contains .. or is absolute | Rewrite it relative to the catalog root. |
Validate each plugin too:
syntic plugin validate ./acme-plugins/plugins/formatterProblems 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 keepmarketplace.jsonat 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//folderpart does not exist in the repository.- A missing plugin manifest: the fetched folder needs
.syntic-plugin/plugin.json, aplugin.jsonat its root, or (for a one-skill plugin) aSKILL.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/formatterWhen you change the catalog itself, refresh it and reinstall the plugin you changed:
syntic plugin marketplace refresh acme
syntic plugin update formatter@acmeStart over
syntic plugin marketplace remove acmeRemoving 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:
| Plugin | What it brings |
|---|---|
code-review | A review command and a reviewer agent that look at your working changes for bugs, risky edits and missing tests. |
commit-commands | Commands that write a commit from your changes and draft changelog entries. |
pr-review-toolkit | A pull request review command with specialist agents for tests, error handling and API changes. |
security-guidance | A 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-officialNext steps
- Put the catalog where your team can reach it: Host a marketplace.
- Roll it out to everyone and set limits: Plugins for your organization.
- Look up every field: Marketplace reference.
- All commands in one place: Plugin commands.