Skip to content

chore: mirror every Claude skill into .agents and guard the parity - #1373

Merged
vivek7405 merged 4 commits into
mainfrom
chore/1372-agents-skill-parity
Aug 10, 2026
Merged

vivek7405 merged 4 commits into
mainfrom
chore/1372-agents-skill-parity

Conversation

@vivek7405

@vivek7405 vivek7405 commented Aug 10, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #1372

Summary

Three committed Claude skills (webjs-ready-for-dev, webjs-scaffold-sync, webjs-instagram-post) had no .agents/skills symlink, so Antigravity loaded a different skill set from Claude Code. A fourth, webjs-blog-write, was symlinked but missing from the documented list, so the symlink set and the documented set had drifted apart independently. Nothing asserted the three sets agree, which is why the gap kept reopening.

This adds the three missing relative symlinks, moves the workspace rules file to the path Antigravity actually reads, documents all ten skills there, and adds a repo-health test so the sets cannot drift again.

What changed

  • Three symlinks under .agents/skills/, each storing the relative target ../../.claude/skills/<name>, created with ln -s so git records mode 120000. git ls-files -s .agents/skills now shows exactly ten.
  • .agents/AGENTS.md moved to .agents/rules/workflow.md (git records a rename). Nothing documents reading .agents/AGENTS.md; Antigravity's rules reference names .agents/rules/, which is the path root AGENTS.md:36 already advertises and the filename the scaffold already ships. A grep found zero references to the old path from any test, script, workflow, or doc, so the move breaks nothing. The file is retitled, its provenance sentence corrected, its skill list grown from six entries to ten, and it gains an ## Enforcement gates section.
  • test/repo-health/agent-skill-parity.test.mjs, six assertions covering both drift directions plus the two tracked exceptions.
  • framework-dev.md documents the canonical-plus-mirror layout, the ln -s mode requirement, the two non-mirror entries, and why hooks stay Claude-only.

Review

Two rounds. Round 1 found four wrong facts in the new ## Enforcement gates section: it named the wrong CI checks as the merge gate, listed four of the seven tool-call hooks, described the hook directory as PreToolUse only, and stated the worktree rule unconditionally while an older section above it still called it conditional. The delta round then found two more in the paragraph that fix rewrote, both from paraphrasing hook trigger regexes: staging packages/cli/lib satisfies the scaffold gate rather than tripping it, and two of the three gates called "any edit" are scoped much narrower than that.

Both rounds landed on the same paragraph, which is the useful signal. Restating a derived trigger condition in a second file is the defect generator, so the final version states the workflow requirement and points at root AGENTS.md for the conditions, rather than tracking regexes it cannot keep in sync. Every fact that survives was re-derived from live branch protection and .claude/settings.json.

Deferred items, closed here

Nothing from this work is left as a follow-up. Three things flagged along the way are fixed in this PR:

  • test/repo-health/no-committed-symlinks.test.mjs enumerated tracked links from the index but resolved targets from HEAD, so a STAGED symlink threw a raw fatal: instead of being judged, leaving the guard blind exactly when a link is being added. It reads the blob by oid now. Proven by staging an absolute symlink and watching it get reported rather than crash.
  • Root AGENTS.md still advertised GEMINI.md and .github/copilot-instructions.md as bridges the scaffold ships. Both were removed in feat(cli): remove redundant per-agent instruction files from webjs create templates #1368, so CLAUDE.md is the only one left.
  • blog/ai-first-is-plumbing.md, blog/stop-ai-agents-breaking-your-code.md, and blog/why-webjs.md described the per-agent rule and hook files that same change deleted. Corrected, including the first post's own closing question, which this consolidation answered.

Deliberately excluded

.agents/hooks.json and a scripts/sync-hooks.js generator, both rejected on the merits in the issue. These are settled decisions rather than deferred findings, so building either would reverse a deliberate call, not close a gap. The two engines disagree on the blocking protocol, the context-injection shape, and the tool vocabulary, so a mirror is a protocol port rather than a config copy, and a committed generated copy would be the duplicated rule set root AGENTS.md rules out. Nothing under .claude/hooks/ is touched. The underlying need is covered instead by the new ## Enforcement gates section, which names the two layers that already bind every agent regardless of engine.

Test plan

  • node --test test/repo-health/agent-skill-parity.test.mjs passes, 6/6.
  • Counterfactual A: dropping one symlink from the index reds every committed .claude skill is mirrored naming webjs-scaffold-sync, and reds the documented-set assertion from the other direction.
  • Counterfactual B: removing one bullet from ## Custom Skills Usage reds symlinked but not listed naming webjs-blog-write.
  • test/repo-health/no-committed-symlinks.test.mjs and test/hooks/route-skills.test.mjs still pass, 26/26 together with the new file.
  • Counterfactual re-verified at 5dba1e2c after the doc rewrites, since those edits touched the very file the documented-set assertion reads. Still discriminating.
  • npm test: 4277/4283 pass. The five failures are the known linked-worktree baseline (the two test/bun/listener* files and three differential-elision assertions); all five pass on main in the primary checkout, and this branch touches no runtime code, so they are environmental.

Browser, e2e, smoke, and Bun parity are N/A: this touches no framework runtime code, nothing under packages/*/src or packages/cli/lib is staged, and no served byte differs. Docs surfaces: .agents/rules/workflow.md and framework-dev.md updated. Root AGENTS.md, the docs site, the marketing website, README.md, CONVENTIONS.md, and the scaffold templates need no change, since none describes this repo's internal agent-config mirror and webjs create output is byte-identical.

@vivek7405 vivek7405 self-assigned this Aug 10, 2026
@vivek7405

Copy link
Copy Markdown
Collaborator Author

Design decision: the parity test reads the index blob, not HEAD:<path>

The planned prototype resolved each symlink target with git cat-file -p HEAD:<path>. I moved it to git cat-file -p <oid>, taking the object id straight out of the git ls-files -s line the loop is already parsing. Two reasons.

The first is that HEAD:<path> cannot see a symlink that is staged but not yet committed, so the test would fail with a raw fatal: path ... exists on disk, but not in 'HEAD' at exactly the moment you are adding a skill and want the guard to tell you something useful. That is not hypothetical: the existing no-committed-symlinks.test.mjs reads HEAD: and threw that error at me while the three new links were staged, which is how I noticed.

The second is consistency. The test derives its whole set from git ls-files -s, which reports the INDEX. Reading targets from HEAD mixed two different snapshots in one assertion, and the oid form keeps both halves reading the same one.

Worth flagging that no-committed-symlinks.test.mjs has the same staged-file blind spot. I left it alone: it passes at HEAD and on this branch once committed, and rewriting a neighbouring test's git plumbing is not what this change is about.

One deviation from the planned text. The plan said to keep the webjs-start-work bullet verbatim, but its existing wording was on the webjs project board, and the prose-punctuation hook correctly refuses that lowercase spelling of the brand once the line is touched. It now reads "on the WebJs project board", which is the invariant 11 spelling.

@vivek7405 vivek7405 left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Went looking for whatever the new ## Enforcement gates section gets wrong, since it is the one substantive claim this PR adds and the whole reason the hooks mirror was rejected. It turned out to be the weakest part of the change: it is the only sentence in the file a non-Claude agent would read to decide what actually blocks a merge, and it named the wrong checks.

The symlink half is solid. Ten mirrors, every target relative and self-naming, the teaching directory still a real 15-file directory, and the new test covers both drift directions rather than just the missing-symlink one that prompted the issue. Reading the sets from git ls-files instead of the filesystem is the right call, since it makes the machine-local omarchy link invisible by construction rather than by a special case that would rot.

What I would keep an eye on is that this file is now what a non-Claude agent trusts about enforcement, and nothing tests its factual claims the way the new test covers its skill list. Four problems inline, all in that one file. Line anchors are on the current head, so they point at the corrected text; each thread carries what the line said when I flagged it.

Comment thread .agents/rules/workflow.md
Comment thread .agents/rules/workflow.md Outdated
Comment thread .agents/rules/workflow.md
Comment thread .agents/rules/workflow.md

@vivek7405 vivek7405 left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delta pass over the fix commit, since correcting a facts section is exactly where a new wrong fact gets introduced. It had: the rewritten self-check paragraph reverse-engineered each hook's trigger condition and got two of them backwards.

The rest of that commit holds up. I re-derived the five required contexts against live branch protection and the hook inventory against the settings file, and both are byte-accurate now.

The lesson I am taking from two rounds on the same paragraph is that restating a derived trigger in a second place is the defect generator here, not any particular wording of it. So the fix stops paraphrasing the regexes and states the workflow requirement, pointing at root AGENTS.md for the conditions. That file is the thing that moves when a gate changes, and this one no longer claims to track it.

Comment thread .agents/rules/workflow.md
Comment thread .agents/rules/workflow.md
Comment thread .agents/rules/workflow.md
@vivek7405
vivek7405 marked this pull request as ready for review August 10, 2026 09:49
@vivek7405

Copy link
Copy Markdown
Collaborator Author

Deferred items closed in the PR rather than filed as follow-ups

Three things were flagged during this work and pushed out. None of them is a follow-up issue now, they are all fixed here.

no-committed-symlinks.test.mjs enumerated tracked links from git ls-files -s, which reads the INDEX, then resolved each target as HEAD:<path>. Mixing the two snapshots meant a staged symlink threw a raw fatal: path ... exists on disk, but not in 'HEAD' instead of being judged, so the guard was blind at the exact moment someone adds a link and needs it. I had noted the blind spot earlier in this PR and left it, on the reasoning that rewriting a neighbouring test was out of scope. It is a one-line change to read the blob by oid, the same technique the new parity test uses, and it is worth more than the scope argument was. Proven by staging an absolute symlink into .agents/skills/ and watching the guard report it as machine-local rather than crash.

Root AGENTS.md still named GEMINI.md and .github/copilot-instructions.md as thin bridges the scaffold ships. Both were deleted from the templates in #1368, so CLAUDE.md is the only bridge left. I checked the template tree rather than trusting the sentence, which is the same mistake this PR already made twice with the enforcement facts.

Three blog posts described the per-agent rule files and per-agent hook copies that the same change removed, listing .cursorrules, .github/copilot-instructions.md, and the Gemini, Cursor, and opencode hook variants as things a scaffolded app ships. The issue deliberately left these alone because correcting them means touching published prose, which is a fair reservation. Fixing them won anyway: a published post that describes a scaffold layout the scaffold does not have is worse than one that is merely dated, because a reader checks the claim against a real webjs create and finds nothing.

The ai-first-is-plumbing correction turned out to be the interesting one. Its closing section had listed exactly this fragmentation as the open problem, saying that maintaining six near-identical files is brittle and that the answer is for AGENTS.md to become the universal contract. That is what happened, so the section now records the resolution and names the part that is still open, which is that the blocking tool-call gates only fire in one editor.

What I did not do, and why. The issue's Out of scope also rejected .agents/hooks.json and a sync-hooks.js generator on the merits, and recorded the Next.js single-directory-symlink inversion as a stronger design not worth its risk here. Those are settled decisions rather than deferred findings, so implementing either would reverse a call the issue made deliberately, not close a gap. Same for the rules file overlapping root AGENTS.md, which is a content question about what a non-Claude agent needs loaded, not drift.

Three skills had no .agents/skills symlink and a fourth was symlinked but
undocumented, so Antigravity saw a different skill set from Claude Code.
Move the workspace rules to the path Antigravity actually reads, list all
ten skills there, and add a repo-health test so the sets cannot drift again.
The new Enforcement gates section named the wrong CI checks as the merge
gate, listed four of the seven tool-call hooks a non-Claude agent has to
self-check, and described the hook directory as PreToolUse only. It also
stated the worktree rule unconditionally while an older section above it
still called it conditional, so the file said it two ways.
The self-check paragraph reverse-engineered each hook's trigger and got
two wrong: staging packages/cli/lib satisfies the scaffold gate rather
than tripping it, and the Bun gate needs a runtime-sensitive filename on
top of the path. Two of the three "any edit" gates were scoped wrong too.
State the workflow requirement and point at AGENTS.md, since restating a
derived trigger in a second place is what rotted here twice.
Three things were flagged and pushed out rather than fixed. All are in
scope now.

no-committed-symlinks enumerated the index but resolved targets from
HEAD, so a staged symlink threw a raw fatal instead of being judged,
leaving the guard blind exactly when someone adds one. It reads the
blob by oid now, matching the new parity test.

Root AGENTS.md still advertised GEMINI.md and copilot-instructions.md
as bridges the scaffold ships; both were removed in #1368, so CLAUDE.md
is the only one left.

Three blog posts still described the per-agent rule and hook files that
same change deleted. Corrected, including the ai-first post's own open
question, which this consolidation answered.
@vivek7405
vivek7405 force-pushed the chore/1372-agents-skill-parity branch from 8aaecd2 to 59588bc Compare August 10, 2026 13:29
@vivek7405
vivek7405 merged commit 10e39f5 into main Aug 10, 2026
10 checks passed
@vivek7405
vivek7405 deleted the chore/1372-agents-skill-parity branch August 10, 2026 13:30
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.

chore: add missing skill symlinks and update AGENTS.md documentation in .agents/skills

1 participant