Skip to content

Route prompts to matching skills + fix check-ignore git env leak in worktrees#156

Merged
vivek7405 merged 3 commits into
mainfrom
feat/skill-router-hook
May 31, 2026
Merged

Route prompts to matching skills + fix check-ignore git env leak in worktrees#156
vivek7405 merged 3 commits into
mainfrom
feat/skill-router-hook

Conversation

@vivek7405

@vivek7405 vivek7405 commented May 31, 2026

Copy link
Copy Markdown
Collaborator

Summary

Closes #154
Closes #155

Two related fixes to agent tooling and test isolation, found while investigating why a skill (the issue-filing workflow) was silently skipped during a session.

1. Deterministic skill routing (#154)

Skills are model-invoked, so a relevant one can be skipped when a prompt reads as research or a question but the work it leads to is governed by a skill. (This happened: a "can we add prefetch, verify in remix, let me know" request was treated as pure research, so the issue-filing workflow never ran.) Skill descriptions and AGENTS.md prose are advisory; only a hook is deterministic, the same posture block-prose-punctuation.sh takes for the em-dash rule.

  • .claude/hooks/route-skills.sh (new): a UserPromptSubmit hook. On every prompt it keyword-matches the text against each skill's documented triggers (webjs-file-issue, webjs-start-work, webjs-list-todos, use-railway) and injects a directive to invoke the matched skill via the Skill tool before other work, plus a standing generic policy to check the available skills whenever a task matches one. The policy is generic across ALL skills, not a rule about filing GitHub issues specifically.
  • .claude/settings.json: registers the hook.
  • AGENTS.md: documents it in the agent-config table and a new subsection.
  • test/hooks/route-skills.test.mjs (new): covers each skill's triggers, the no-match standing-only case, single-route-per-skill.

Honest limitation (documented in the hook + AGENTS.md): a hook CANNOT force a Skill tool-call. UserPromptSubmit can only inject additionalContext. So keyword-matched prompts route deterministically, but genuinely-ambiguous prompts lean on the always-injected standing policy rather than a mechanical guarantee. The hook never blocks a prompt.

2. check-ignore git env leak (#155)

The gitignore-vendor-not-ignored rule shells out to git check-ignore with cwd set to the target app dir, but inherited the process git environment. When webjs check (and thus npm test) runs inside a pre-commit hook from a linked worktree, git exports GIT_WORK_TREE / GIT_DIR / GIT_INDEX_FILE into the hook env, and those override cwd-based repo discovery, so the probe consulted the outer repo instead of the temp fixture. Net effect: the pre-commit test suite could not pass from any git worktree (the workflow this session needed).

Fix: strip GIT_DIR / GIT_WORK_TREE / GIT_INDEX_FILE / GIT_PREFIX before spawning git check-ignore (and in the initGit test helper) so cwd is authoritative. Added a regression test that leaks GIT_WORK_TREE at the real repo and asserts the rule still reads the temp app's gitignore. Verified: with the env-clear reverted, the regression test fails; with it, the full suite passes from a worktree.

Test plan

vivek7405 added 2 commits June 1, 2026 00:16
The gitignore-vendor-not-ignored rule shells out to git check-ignore with
cwd set to the target app dir but inherited the process git environment.
When webjs check (and thus npm test) runs inside a pre-commit hook from a
linked worktree, git exports GIT_WORK_TREE / GIT_DIR / GIT_INDEX_FILE into
the hook env, and those override cwd-based repo discovery, so the probe
consulted the outer repo instead of the temp fixture. Net effect: the
pre-commit test suite could not pass from any git worktree.

Strip GIT_DIR / GIT_WORK_TREE / GIT_INDEX_FILE / GIT_PREFIX before spawning
git check-ignore (and in the initGit test helper) so cwd is authoritative.
Add a regression test that leaks GIT_WORK_TREE at the real repo and asserts
the rule still reads the temp app gitignore.

Closes #155
Skills are model-invoked, so a relevant one can be skipped when a prompt
reads as research or a question but the work it leads to is governed by a
skill. Skill descriptions and AGENTS.md prose are advisory; only a hook is
deterministic, the same posture as block-prose-punctuation.sh for the
em-dash rule.

route-skills.sh runs on every prompt, keyword-matches against each skill's
documented triggers, and injects a directive to invoke the matched skill
before other work, plus a standing generic policy to check skills whenever
a task matches one. A hook cannot force a Skill tool-call (Claude Code only
lets UserPromptSubmit inject context), so keyword cases are deterministic
and ambiguous prompts lean on the always-injected policy.

Closes #154
@vivek7405 vivek7405 self-assigned this May 31, 2026
The check.js env-strip fix shipped without its guard test (an Edit was
lost). This adds the test: it leaks GIT_DIR/GIT_WORK_TREE at the real repo
the way a worktree pre-commit hook does, then asserts the rule still reads
the temp app's gitignore. Verified it fails when env: gitEnv is removed
from check.js and passes with it.

Refs #155
@vivek7405

Copy link
Copy Markdown
Collaborator Author

Self-review: missing regression test added

The review caught a real blocker: I claimed a regression test for the GIT_* env-leak fix but it never landed (an Edit was dropped mid-session, so only the initGit helper change shipped and the production fix was uncovered). Fixed in 6484c04: the test leaks GIT_DIR/GIT_WORK_TREE at the real repo the way a worktree pre-commit hook does, then asserts the rule still reads the temp app's gitignore. Counterfactual-verified: it fails when env: gitEnv is removed from check.js, passes with it.

On the other points: the GIT_COMMON_DIR omission is harmless (it has no effect without GIT_DIR, which is already stripped), confirmed. The keyword-routing over-fire on subject-matter prompts is by design: the hook only injects advisory context and never blocks (exit 0), so a spurious nudge is ignorable, which is the stated inform-not-gate contract.

@vivek7405

Copy link
Copy Markdown
Collaborator Author

Review round 2: clean

Re-reviewed after adding the regression test. Verified the counterfactual genuinely holds (test fails if env: gitEnv is removed from check.js), the finally block restores GIT_* unconditionally so a thrown assertion cannot leak into sibling tests, and no other test in the suite reads GIT_* env so there is no cross-test pollution. The env rest-destructure correctly excludes the named keys. Nothing outstanding.

@vivek7405 vivek7405 merged commit 9a83ea2 into main May 31, 2026
5 checks passed
@vivek7405 vivek7405 deleted the feat/skill-router-hook branch May 31, 2026 19:30
vivek7405 added a commit that referenced this pull request May 31, 2026
* chore: release @webjsdev/core 0.7.3 and @webjsdev/server 0.8.3

Release debt accumulated since the 0.7.2 / 0.8.2 release (#149):

core 0.7.3 (patch): the two client-router fixes from #151 and #157
(JS-handled forms and links were hijacked by the router despite
e.preventDefault).

server 0.8.3 (patch): #161 (modulepreload hints no longer point at
server-only or template-embedded files the auth gate 404s) and #156
(webjs check no longer leaks a git env var across worktrees).

Both stay in a single minor line; all in-repo dependents pin ^0.7.0 /
^0.8.0, so no dependent range edits are needed. Lockfile regenerated.

* chore: release @webjsdev/cli 0.10.0 (webjs vendor surface)

cli 0.9.1 shipped without the `webjs vendor` command surface that
#105 and #89 added (pin / unpin / list / audit / outdated / update,
the --from multi-CDN selector, and --download caching). That is
feature-level work, so a minor bump.

create-webjs and webjsdev are thin shims that delegate to cli; widen
their `@webjsdev/cli` range from ^0.9.0 to ^0.10.0 so the workspace
keeps linking the local cli (a minor bump falls outside the old caret).
They are not in the changelog auto-publish system, so they carry no
changelog entry of their own. Lockfile regenerated.
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.

check.js git check-ignore inherits GIT_* env, breaks in worktree pre-commit Enforce skill invocation via UserPromptSubmit routing hook

1 participant