Skip to content

feat: add the check-forge-version skill (ENG-124) - #22

Merged
zanjonke merged 2 commits into
mainfrom
feat/check-forge-version-skill
Aug 28, 2026
Merged

feat: add the check-forge-version skill (ENG-124)#22
zanjonke merged 2 commits into
mainfrom
feat/check-forge-version-skill

Conversation

@zanjonke

Copy link
Copy Markdown
Collaborator

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-version 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 npx plain-forge update 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: it reads no .plain files, needs no project in the working directory, works in an empty dir, and deliberately does not invoke load-plain-reference.

Contents

  • forge/skills/check-forge-version/SKILL.md — frontmatter validated by skill-creator's validate-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.mjs rather than re-deriving anything — the install-path model (including the two global paths that break the usual pattern, ForgeCode's ~/forge and OpenCode's ~/.config/opencode), the .agents dedupe across three agent labels, the manifest-less fallback via the four flagship skills, and compareVersions' 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 view for 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 with ACTION REQUIRED, says why continuing is not recommended, and notes the fix is one command that cannot touch the user's own content. PASS stays 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 way SKILL.md tells the agent to:

  1. Run from its own directory — the natural reading of node scripts/check-forge-version.mjs — the script scanned the skill folder as a project root and reported NONE from 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.
  2. That walk then reported the source repo as an UNMANAGED install, since forge/ also contains a skills/ subtree. It now excludes the tree sitting next to the package's own package.json, while still recognising ForgeCode's ~/forge.

Testing

npm test — 58/58 passing. No CLI behaviour changed, so test/cli.test.mjs needed 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):

Installed Verdict Exit
latest PASS / CURRENT 0
behind FAIL / STALE 1
prerelease WARN / INDETERMINATE 2
manifest removed WARN / UNMANAGED 2
empty dir NONE 4

Not exercised: the ERROR path (exit 3) needs the registry and npm view to both fail. The fallback logic is simple but untested.

Notes for review

  • Two deliberate non-changes, easy to reverse if you disagree: the skill only reports (never runs update, following check-plain-env's precedent), and it does not hard-block — the user is asked and may decline, and authoring continues.
  • Local iteration gotcha worth knowing: update short-circuits when the manifest version equals package.json's, so editing forge/ and running update re-copies nothing. Use uninstall + install.

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.
@zanjonke
zanjonke requested a review from NejcS August 28, 2026 07:24
@zanjonke zanjonke changed the title feat: add the check-forge-version skill feat: add the check-forge-version skill (ENG-124) Aug 28, 2026
@zanjonke
zanjonke merged commit fb0ee71 into main Aug 28, 2026
3 checks passed
@zanjonke
zanjonke deleted the feat/check-forge-version-skill branch August 28, 2026 07:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants