Version shape is the single source of truth for the channel:
- X.Y.Z-beta.N → next (BRAT --beta consumers)
- X.Y.Z → main (Obsidian Community Plugins store)
bump-version.mjs is now branch-aware: a beta bump only updates
plugin/manifest.json + manifest-beta.json (root manifest.json +
versions.json stay pinned to the last stable). A stable bump
advances every file together.
version-check.yml enforces the branch ↔ channel invariant:
- PR into next: head must be > base (semver-aware), root manifest.json
+ versions.json must NOT have moved
- PR into main: head must be plain X.Y.Z (no beta suffix), all
manifests must agree
- Sync PRs (head=main → base=next) skip the workflow entirely
release.yml triggers on push to main AND next, picks prerelease vs
stable from the version shape, and gates: stable-on-next pushes
(promotion-staging commits) are skipped so only the eventual main
push publishes the stable release.
sync-main-to-next.yml automates the post-promotion sync: after a
push to main, it opens a PR main → next and enables auto-merge so
the histories rejoin without manual `git merge main` on next.
commitlint also skips on sync PRs (the autogenerated merge titles
don't follow Conventional Commits).
New npm scripts (run from plugin/):
- bump:beta:start → X.Y.Z → X.Y.(Z+1)-beta.0 (start of cycle)
- bump:beta → -beta.N → -beta.N+1 (within cycle)
- bump:stable → -beta.N suffix dropped (promotion)
CONTRIBUTING.md documents the lifecycle + promotion flow.
Self-test: this PR bumps next from 1.0.43 to 1.0.44-beta.0 using
the new bump:beta:start script — only the beta-channel files moved.
Issue #126 Phase G — enable BRAT --beta installs from this repo so
external testers can subscribe to the auto-update channel before the
1.0 community-store submission.
Changes:
- manifest-beta.json (NEW, root) — what BRAT --beta polls. Pre-1.0
it tracks manifest.json byte-for-byte (every merge IS a beta);
diverges from stable when a `next` branch is cut for post-1.0 work.
- plugin/scripts/bump-version.mjs — npm version flow now writes
manifest-beta.json alongside the existing four files. No new public
API; doc-comment updated to spell out the BRAT contract.
- plugin/package.json — `version` script `git add`s the new file.
- .github/workflows/version-check.yml — new `manifest-beta == manifest`
assertion guards against a hand-edit drifting the two channels apart.
Drop this assert when `next` branch is introduced.
- .github/workflows/release.yml — manifest-beta.json added to the
GitHub Release `files:` block so BRAT can fetch it as a release asset.
- README.md — Install section split into Option A (BRAT, recommended)
and Option B (manual). The previous one-line BRAT mention was easy
to miss; promoting it as the primary path matches the bug-bash flow
for the rest of Phase G.
- Version bump 0.4.125 → 0.4.126 (touches manifest.json,
manifest-beta.json, plugin/manifest.json, plugin/versions.json,
versions.json, plugin/package.json, plugin/package-lock.json).
Verified locally: bump-version.mjs syncs all four manifests + the new
beta to the same version; `diff manifest.json manifest-beta.json`
returns clean (CI assert will pass).
Closes the `manifest-beta.json` checkbox in Phase G of #126.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Obsidian's community plugin registry validator may look for
versions.json at the repo root alongside manifest.json. The
bump-version script and npm version lifecycle hook now sync
both root mirrors (manifest.json + versions.json) automatically,
and version-check CI asserts they stay in sync.
Also adds .nvmrc (Node 20) to pin the development runtime,
matching the engines field in plugin/package.json.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Obsidian's community plugin browser fetches manifest.json from the
repo root (raw.githubusercontent.com/<repo>/HEAD/manifest.json — the
same convention our own PluginMarketplaceInstaller uses). Plugin
source lives under plugin/ for repo-layout reasons (server/, proto/,
deploy/ siblings), so we mirror to root rather than restructure.
- bump-version.mjs writes both plugin/manifest.json and ./manifest.json
- version-check.yml asserts they stay byte-identical (catches drift
before submission to obsidianmd/obsidian-releases)
Required to submit to the community plugin store.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three pieces of release infrastructure that travel together:
1. `.github/workflows/version-check.yml`
On every PR, asserts that
- plugin/manifest.json and plugin/package.json agree on version
- the PR's manifest.json version is strictly greater than
base's (rejects same-or-lower)
Pure-shell semver compare; no external action.
2. `.github/workflows/release-on-merge.yml`
On every push to main, reads plugin/manifest.json, pushes the
matching X.Y.Z tag if missing, then waits up to 30 s for the
existing release.yml (which triggers on the tag) to publish a
release. Falls back to a `gh release create --generate-notes`
if release.yml is unavailable. Marked as pre-release while
pre-1.0 (toggle the IS_PRERELEASE env to flip).
3. `plugin/scripts/bump-version.mjs`
The npm `version` lifecycle script the package.json already
referenced but didn't actually have. Reads the version npm just
wrote into package.json and mirrors it into manifest.json +
versions.json (with manifest.minAppVersion as the value). Now
`cd plugin && npm version patch` updates all three files at
once and the version-check passes.
Bumps to 0.3.0 in this PR (this is itself a non-trivial PR adding
release infra, so a minor bump fits).
Note on the original question: `Plugin remote-ssh v0.X.Y loaded`
in the runtime log uses `this.manifest.version` — i.e. it reads
from manifest.json, the Obsidian convention for plugin runtime
metadata. The version-check workflow asserts manifest.json and
package.json agree, so the runtime log effectively shows the same
number npm sees.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>