feat: add the check-forge-version skill (ENG-124) - #22
Merged
Conversation
Users have no way to learn that their installed plain-forge is behind the published one, so they keep following skills and rules from a superseded release without knowing it. check-forge-version reports whether the plain-forge on this machine is current. It enumerates every directory plain-forge can install into (both scopes, all agent layouts), reads the installed version from each .plain-forge/manifest.json, resolves the latest version from npm, and emits a PASS / WARN / FAIL verdict. For a stale install it surfaces the exact `npx plain-forge update` command and asks the user to run it — the skill never runs the update itself and modifies nothing on disk. The subject is the tooling, not any project: the skill reads no .plain files, needs no project in the working directory, and does not invoke load-plain-reference. The deterministic work lives in scripts/check-forge-version.mjs, which mirrors bin/cli.mjs for both the install-path model (including the two global paths that break the usual pattern, ForgeCode's ~/forge and OpenCode's ~/.config/opencode) and the dotted-numeric version comparison. The verdict is both the first line of stdout and the exit code, so callers need not parse the body. It falls back from the registry endpoint to `npm view` for hosts on an internal mirror. The script locates the install it is executing from by walking up its own path, instead of trusting cwd. Run from its own directory — the natural reading of `node scripts/check-forge-version.mjs` — it would otherwise scan the skill folder as a project root and report NONE from inside a live install, which is the worst possible failure mode for this check. That walk skips the source repo, whose forge/ dir also holds a skills/ subtree and would otherwise be reported as an unmanaged install. load-plain-reference now opens with a call to action to run the check on its first invocation in a session — it is the near-universal entry point for spec work, and a stale forge ships the stale rules it routes to. The check informs the user; it does not block authoring.
The first cut buried the recommendation. A stale install was reported as a
neutral aside ("Run this to bring 1 install(s) current"), which reads as
optional housekeeping — so a user can see the report and reasonably carry on.
Running an outdated plain-forge is not something to shrug at: the skills and
rules are the product, and once superseded, specs authored against them may
not match what the current codeplain renderer expects. The report now says so.
- The script leads the non-PASS case with "ACTION REQUIRED — please update
plain-forge before continuing", states that continuing is not recommended
and why, and tells the user the fix is one command that cannot touch their
own content. An unconfirmed version is called out as one to treat as
outdated until proven otherwise.
- SKILL.md tells the agent to lead with the recommendation rather than report
it in passing, to ask the user directly to update before continuing, and —
if the user declines — to name the stale install as the first suspect for
anything surprising that follows. It still never runs the update.
- load-plain-reference carries the same message at the point it matters, since
it is the gate in front of the rules a stale install would serve.
Report prose is now wrapped at render time rather than at hardcoded string
boundaries, so it no longer breaks mid-sentence, and counts are pluralized.
PASS output is unchanged and stays a single quiet line.
NejcS
approved these changes
Aug 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Users have no way to learn that their installed plain-forge is behind the published one, so they keep following skills and rules from a superseded release without knowing it. This adds a skill that tells them.
check-forge-versionenumerates every directory plain-forge can install into (both scopes, all agent layouts), reads the installed version from each.plain-forge/manifest.json, resolves the latest version from npm, and emits aPASS/WARN/FAILverdict. For a stale install it surfacesnpx plain-forge updateand asks the user to run it — the skill never runs the update itself and modifies nothing on disk.The subject is the tooling, not any project: it reads no
.plainfiles, needs no project in the working directory, works in an empty dir, and deliberately does not invokeload-plain-reference.Contents
forge/skills/check-forge-version/SKILL.md— frontmatter validated byskill-creator'svalidate-metadata.py(1020/1024 chars, third person, positive + negative triggers).forge/skills/check-forge-version/scripts/check-forge-version.mjs— the deterministic half. Zero dependencies, Node ≥ 18.forge/skills/load-plain-reference/SKILL.md— a call to action to run the check on its first invocation in a session. It is the near-universal entry point for spec work, and a stale forge ships the stale rules it routes to. Informs and recommends; does not block authoring.Design notes
The script mirrors
bin/cli.mjsrather than re-deriving anything — the install-path model (including the two global paths that break the usual pattern, ForgeCode's~/forgeand OpenCode's~/.config/opencode), the.agentsdedupe across three agent labels, the manifest-less fallback via the four flagship skills, andcompareVersions' dotted-numeric semantics. Keep them in sync.The verdict is both the first line of stdout and the exit code, so callers need not parse the body. The registry endpoint falls back to
npm viewfor hosts on an internal mirror.Messaging is deliberately insistent (
fa6596f). The first cut reported a stale install as a neutral aside, which reads as optional housekeeping; the report now leads withACTION REQUIRED, says why continuing is not recommended, and notes the fix is one command that cannot touch the user's own content.PASSstays a single quiet line.Two bugs caught by testing it as installed
Both fixed in
ee84478, and both only surfaced by running the skill the waySKILL.mdtells the agent to:node scripts/check-forge-version.mjs— the script scanned the skill folder as a project root and reportedNONEfrom inside a live install. It now locates its own install by walking up its own path. A false "not installed" is the worst failure mode for this check.UNMANAGEDinstall, sinceforge/also contains askills/subtree. It now excludes the tree sitting next to the package's ownpackage.json, while still recognising ForgeCode's~/forge.Testing
npm test— 58/58 passing. No CLI behaviour changed, sotest/cli.test.mjsneeded no updates; the new skill is content the installer copies like any other.Verified against a real install built with the CLI in a temp
HOME/cwd, from four invocation sites (skill dir, project root, unrelated dir, source checkout):PASS/ CURRENTFAIL/ STALEWARN/ INDETERMINATEWARN/ UNMANAGEDNONENot exercised: the
ERRORpath (exit 3) needs the registry andnpm viewto both fail. The fallback logic is simple but untested.Notes for review
update, followingcheck-plain-env's precedent), and it does not hard-block — the user is asked and may decline, and authoring continues.updateshort-circuits when the manifest version equalspackage.json's, so editingforge/and runningupdatere-copies nothing. Useuninstall+install.