docs/manifest-spec.md is the normative spec for version 1. init writes the file, and setup, doctor and ci read it through lib/manifest/schema.mjs. The shell-syntax rule below is exercised end to end by tests/unit/setup-plan.test.mjs, which turns a command containing shell syntax into a manual step rather than spawning it. The validator has no dedicated test of its own yet, so docs/VERIFICATION.md is the place to check before relying on a rule stated here.Purpose
init writes the manifest, setup and doctor read it on another machine, and ci turns it into a GitHub Actions matrix. The brief requires the format to be simple, versioned, documented, and not tied to Claude so other coding agents can adopt it. The plugin has no runtime dependencies, so the format must be parseable with the Node standard library.
Principles
- JSON only. One file,
synchrobuilder.json, at the repository root. UTF-8, LF, two-space indent when the plugin writes it. No comments in the file; explanations go inhintanddescriptionfields, which the tooling shows to humans. - Integer version. A top-level
"version": 1. Readers reject a higher major version with a clear message and accept lower ones with defaults. Additive changes do not bump the version; removals and semantic changes do. - Exact runtime versions.
runtimes[].versionis an exact version string. Setup installs or verifies exactly that version; doctor reports the difference. Ranges are not allowed in v1, because "works on my machine" is the bug being removed. A semver range may be added asallowedRangein v2 without a version bump. - Env var names and descriptions only. A value field is not part of the schema, and the writer refuses to serialize one.
- Commands are plain argument strings without shell syntax. The runner splits them with a small, documented tokenizer (quotes and backslash escapes only) and spawns the program directly. The validator rejects these with a message pointing at the audit rule that explains why:
&&,||,|,;,>,<,&, a backtick,$VAR,${VAR},$(...)and a line break. A project that needs a shell pipeline puts it in a Node script and calls that. - Per-OS overrides are limited.
os.windows,os.macosandos.linuxmay overridecommandsandruntimesonly. Nothing else is per-OS, on purpose. - Extensions carry an
x-prefix. Unknown top-level keys are allowed only with that prefix, which keeps the door open for other tools without silently accepting typos. - Nothing mentions Claude. The file never names Claude, hooks or the plugin.