PluginsManifest reference

Plugin manifest reference

Every plugin describes itself in a JSON file called plugin.json. This page lists every field Syntic Code reads from it, with types, defaults and how each one is used.

Where the manifest lives

Syntic Code looks in the plugin folder for, in order:

  1. .syntic-plugin/plugin.json
  2. plugin.json at the root

The first one found is used. If there is neither, but the folder has a SKILL.md at its root, the folder still loads as a plugin: its name is the folder’s name, its version is 0.0.0, and its only component is that skill.

Unknown fields

Fields the loader does not know are ignored, so a manifest written for a newer version still loads on an older one. The flip side is that a misspelled field ("command" instead of "commands") is silently ignored at load time. Run the validator to catch these.

Validate

syntic plugin validate ./my-plugin          # a folder or the manifest file itself
syntic plugin validate ./my-plugin --json   # machine-readable result
FindingSeverity
Not valid JSON, or not a JSON objecterror
name missing or emptyerror
A component path containing .., or absolute (/…, ~…, C:…)error
dependencies not an array, or an entry that is not a non-empty stringerror
name not lowercase letters, digits and hyphenswarning
version, description or author missingwarning
category, categories, tags, keywords, strict or source presentwarning: these belong in the marketplace entry

Errors make the command exit with code 1. Warnings do not.

At load time the rules are a little looser than the validator: only name and version must be present and non-empty. A manifest without version passes the validator with a warning but does not load. Always set a version.

Fields

Identity and metadata

FieldTypeRequiredMeaning
namestringyesThe plugin’s id within its marketplace. Used in name@marketplace, as the command and agent prefix, and in its data folder name. Use lowercase letters, digits and hyphens.
versionstringyesThe version recorded at install and shown by update. Semantic versioning recommended. Also used by syntic plugin tag.
descriptionstringnoOne or two sentences shown in listings.
authorstring or objectno"Jane Doe", or { "name": "...", "email": "...", "url": "..." }. In the object form, name is required.
homepagestringnoProject web page.
repositorystringnoSource repository address.
licensestringnoLicense name or SPDX id.
keywordsarray of stringsnoKept with the manifest. Search and categories come from the marketplace entry, so the validator suggests putting them there.

Behaviour

FieldTypeDefaultMeaning
defaultEnabledbooleantruefalse installs the plugin switched off. A plugin installed as someone’s dependency is switched on regardless.
dependenciesarray of strings[]Plugins this one needs: "name" (same marketplace) or "name@marketplace". A trailing @^x.y constraint is accepted and ignored. See Dependencies.
settingsobjectnoneDefault settings. Only agent is honoured. If the plugin also has a root settings.json, that file is used instead. See Default settings.
monitorsarray of objectsnoneBackground watchers. See monitors.
userConfigobjectnoneOptions users can set. See userConfig.
channelsanynoneAccepted and kept, but not used yet.

Component paths

These say where the plugin’s components are. Each is optional; without it, the component’s default location is used when it exists.

FieldDefault locationWhat each path may be
skillsskills/A skill folder (with SKILL.md), or a folder of skill folders
commandscommands/A .md file, or a folder whose .md files are commands
agentsagents/A .md file, or a folder of them
outputStylesoutput-styles/A .md file, or a folder of them
hookshooks/hooks.jsonA JSON file of hooks
mcpServers.mcp.jsonA JSON file of MCP servers
lspServers.lsp.jsonA JSON file of language servers

outputStyles, mcpServers and lspServers also accept the spellings output_styles, mcp_servers and lsp_servers.

Path rules

  • One path or several. Each field takes a string or an array of strings: "commands": "./cmds" or "commands": ["cmds/release.md", "cmds/hotfix.md"].
  • Relative to the plugin folder. A leading ./ is fine.
  • Must stay inside. A path containing .., or one that is absolute, is skipped at load time without a message. validate reports it as an error.
  • Must exist. Paths that do not exist are skipped.
  • Replaces the default. Naming a path for a component means its default location is no longer read for that component. To keep both, list both: "commands": ["commands", "extra-commands"].
  • Markdown folders are flat. For agents and outputStyles, a folder contributes the .md files directly inside it. (Commands found through the standard commands/ layout may be nested; sub-folders become part of the name.)
  • Skill folders need SKILL.md. In a folder of skills, only sub-folders that contain one count.
  • Server files may be wrapped. mcpServers files may be { "mcpServers": { … } } or a bare map; lspServers files may be { "lspServers": { … } } or a bare map; hooks files may be { "hooks": { … } } or the bare event map. A file that does not parse is skipped.

monitors

"monitors": [
  { "name": "ci", "command": "${SYNTIC_PLUGIN_ROOT}/bin/watch-ci", "description": "CI status", "when": "launch" }
]
FieldTypeRequiredMeaning
namestringyesIdentifies the monitor within the plugin.
commandstringyesShell command to run, with the plugin’s environment.
descriptionstringnoLabel for the running watch. Default <plugin>: <name>.
whenstringnolaunch (default) or skill:<skill-name>. Any other value drops the monitor.

Entries missing name or command are skipped.

userConfig

A map from option key to its definition:

"userConfig": {
  "registry": { "type": "string", "default": "https://registry.example.com" },
  "token": { "type": "string", "required": true, "sensitive": true },
  "port": { "type": "number", "min": 1, "max": 65535 },
  "verbose": { "type": "boolean", "default": false },
  "include": { "type": "directory", "multiple": true }
}
FieldTypeDefaultMeaning
typestring, number, boolean, file or directoryrequiredThe value’s type. file and directory are stored as text.
requiredbooleanfalseMust have a value. A default counts as a value.
sensitivebooleanfalseA secret: stored in the system credential store and never put into text the model reads.
multiplebooleanfalseThe value is a list. On the command line, separate items with commas. At least one item is needed when the option is required.
min, maxnumbernoneInclusive bounds for number options.
defaultanynoneUsed until the user sets a value.

Where values are stored

KindLocation
Plain values~/.syntic/plugins/.options/<plugin@marketplace>.json, readable only by you
Sensitive valuesThe system credential store, under plugin-option:<plugin@marketplace>:<key>

Using a value

InWriteNotes
Command and skill bodies, agent prompts${user_config.KEY}Sensitive values are left unreplaced.
MCP and language server command, args, cwd, url, headers, env${user_config.KEY}Sensitive values included. Unknown keys stay as written.
Hook commands, inline shell, monitors$SYNTIC_USER_CONFIG_KEY or ${user_config.KEY}The placeholder becomes a quoted variable reference, so the value cannot inject shell code.

Plugin variables

VariableValue
SYNTIC_PLUGIN_ROOTThe installed plugin folder (replaced on update).
SYNTIC_PLUGIN_DATA~/.syntic/plugins/data/<id>/, kept across updates.
SYNTIC_USER_CONFIG_<KEY>Each option’s value; the key upper-cased with other characters turned into _.
SYNTIC_SKILL_DIRIn a SKILL.md command body, that skill’s folder.
SYNTIC_SESSION_IDIn command bodies, the current session id.

In text the model reads and in server settings, ${NAME} is replaced before use. In anything run by a shell, the variables are exported in front of the command instead, and the plugin’s bin/ is added to the front of PATH. Only these exact SYNTIC_ names are recognised.

A complete example

{
  "name": "release-helper",
  "version": "1.5.0",
  "description": "Release chores: version bumps, changelog, tags",
  "author": { "name": "Platform team", "email": "platform@example.com" },
  "homepage": "https://docs.example.com/release-helper",
  "repository": "https://github.com/acme/tools",
  "license": "MIT",
  "defaultEnabled": true,
  "dependencies": ["core"],
  "commands": ["commands", "extra-commands"],
  "mcpServers": "config/servers.json",
  "monitors": [
    { "name": "ci", "command": "${SYNTIC_PLUGIN_ROOT}/bin/watch-ci", "when": "skill:ship" }
  ],
  "userConfig": {
    "registry": { "type": "string", "default": "https://registry.example.com" },
    "token": { "type": "string", "required": true, "sensitive": true }
  }
}

Marketplace entries and the manifest

The marketplace entry that lists a plugin has its own fields (name, source, description, category, tags, strict). They describe the plugin in the catalog. What loads is always decided by the plugin’s own plugin.json. See the marketplace reference.