feat(github-app): inject github-app-auth rule via SessionStart symlink - #590
jack-nsheaps[bot] wants to merge 1 commit into
Conversation
Add a rules/ directory to the github-app plugin and a sync-rules.sh SessionStart hook (mirroring the agentic-behavior/common-sense pattern) that symlinks the plugin's rules into project .claude/rules/github-app. The new github-app-auth rule tells the agent it has GitHub App auth available and MUST use the app's token (which grants access to whatever the app is installed in, not just the session's repos) when committing, creating PRs, or calling the GitHub API. https://claude.ai/code/session_01DQvZRoDrJdhBStk4ycvrGE
Plugin Version PreviewPreview only — plugin versions and
|
There was a problem hiding this comment.
### 👍 Clean, low-risk addition that follows the established rules-injection pattern — looks ready to merge
   
✅ sync-rules.sh is a verbatim copy of the proven agentic-behavior variant — only name/link fields differ
✅ shared-lib dependency declared in plugin.json (script sources hook-logging.sh)
✅ All rule references exist (github-app-token, github-app-session-env, github-app-git-identity skills + bin/generate-token.sh)
✅ hooks.json valid; sync-rules.sh added as a 2nd hook in the existing SessionStart matcher (the preferred shape)
⚠️ SPEC.md PreToolUse line inaccurately claims rules-sync — non-blocking, see inline
🖱️ Click to expand for full details
sync-rules.sh is a verbatim copy of the proven agentic-behavior variant — only name/link fields differ✅
shared-lib dependency declared in plugin.json (script sources hook-logging.sh)✅ All rule references exist (
github-app-token, github-app-session-env, github-app-git-identity skills + bin/generate-token.sh)✅ hooks.json valid;
sync-rules.sh added as a 2nd hook in the existing SessionStart matcher (the preferred shape)PreToolUse line inaccurately claims rules-sync — non-blocking, see inlineCode Quality
The new sync-rules.sh is a byte-for-byte copy of plugins/agentic-behavior/hooks/scripts/sync-rules.sh with only the four expected substitutions (PLUGIN_NAME, header comments, log prefix, LINK_NAME). I diffed the two files to confirm — no unexpected drift. Reusing a battle-tested script verbatim is the right call here (DRY relative to the existing pattern). The symlink logic correctly: creates .claude/rules/, replaces a stale symlink, refuses to clobber a real directory (warns + exits 0), and fails soft via hook_fail + exit 0 so a broken symlink never blocks the session.
The shared-lib dependency is declared in plugin.json, and the _wait_for_shared_lib/data-dir-resolution pattern matches the shared-libs rule in the repo. bash -n and jq empty both pass.
Documentation Accuracy
The new github-app-auth.md rule is accurate: every skill it names (github-app-token, github-app-session-env, github-app-git-identity) and the bin/generate-token.sh path it references all exist on disk. The "grants access to everything the app is installed in, not just session scope" framing is consistent with the repo's auth.md philosophy.
One minor inaccuracy in SPEC.md: the PreToolUse hook line picked up the "Also syncs the plugin's rules … on session start" note because bin/sync-plugin-specs.sh applies the single top-level hooks.json description to every event line. The PreToolUse hook (github-token-check.sh) doesn't sync rules. Flagged inline with a suggested event-neutral wording. Non-blocking — it's consistent with how agentic-behavior treats its combined descriptions, and the SPEC auto-regenerates on merge.
Security
N/A — no new secret handling, network calls, or privilege changes. The rule is advisory text; the script only creates a symlink within the project's own .claude/rules/.
Versioning
Correctly left unbumped — CI auto-bumps github-app (0.6.0 → 0.6.1) on merge per the repo's versioning rule, matching the version-preview bot comment.
Recommended follow-ups (non-blocking):
- Consider making the hooks.json
descriptionevent-neutral so the generatedPreToolUseSPEC line stays accurate (see inline suggestion). Alternatively, a longer-term improvement tobin/sync-plugin-specs.shcould derive per-event descriptions rather than reusing one string — but that's well outside this PR's scope.
Footnotes
-
Workflow Run: github.com/nsheaps/ai-mktpl/actions/runs/27234759036 ↩
-
Persistent data directory reference: code.claude.com/docs/en/plugins-reference ↩
| - `SessionStart` (`bash`) — GitHub App token lifecycle: generate on session start, refresh before expiry via PreToolUse hook | ||
| - `PreToolUse` (`bash`) — GitHub App token lifecycle: generate on session start, refresh before expiry via PreToolUse hook | ||
| - `SessionStart` (`bash`) — GitHub App token lifecycle: generate on session start, refresh before expiry via PreToolUse hook. Also syncs the plugin's rules into project .claude/rules/ via symlink on session start. | ||
| - `PreToolUse` (`bash`) — GitHub App token lifecycle: generate on session start, refresh before expiry via PreToolUse hook. Also syncs the plugin's rules into project .claude/rules/ via symlink on session start. |
There was a problem hiding this comment.
PreToolUse line now reads "Also syncs the plugin's rules into project .claude/rules/ via symlink on session start" — but the PreToolUse hook is github-token-check.sh, which only checks/refreshes the token; it does not sync rules, and "on session start" is contradictory for a PreToolUse hook.
Root cause: bin/sync-plugin-specs.sh (scan_hooks) reuses the single top-level description field from hooks/hooks.json for every event line. So appending the rules-sync note to that shared description leaks it onto the PreToolUse line too.
This mirrors the existing convention (e.g. agentic-behavior/SPEC.md applies one combined description to all its hook lines), so it's not strictly a regression — but agentic-behavior phrases its description as a neutral union of behaviors rather than one pinned to a specific event. If you want the SPEC to stay accurate, consider keeping the hooks.json description event-neutral, e.g.:
| - `PreToolUse` (`bash`) — GitHub App token lifecycle: generate on session start, refresh before expiry via PreToolUse hook. Also syncs the plugin's rules into project .claude/rules/ via symlink on session start. | |
| - `PreToolUse` (`bash`) — GitHub App token lifecycle (generate on session start, refresh before expiry) plus rules-sync into project .claude/rules/ via symlink on session start. |
(Same wording would then apply cleanly to the SessionStart line on 18.) Purely a documentation nicety — nothing functional. The SPEC is also auto-regenerated on merge, so it'll re-derive from whatever hooks.json description ends up being.
What this does
Adds a rules-injection mechanism to the github-app plugin, mirroring how
agentic-behaviorandcommon-senseinject their rules: aSessionStarthook symlinks the plugin'srules/directory into the project's.claude/rules/github-app, so the rules load as context automatically.The new rule (
github-app-auth) tells the agent it has GitHub App auth available via this plugin, that the app's token grants access to whatever the app is installed in (not just the repos in the current session scope), and that it MUST use that app auth when committing, creating PRs, or interacting with the GitHub API.Changes
plugins/github-app/rules/github-app-auth.md— new ruleplugins/github-app/hooks/scripts/sync-rules.sh— newSessionStartsymlink hook (project-scope variant, copied fromagentic-behavior)plugins/github-app/hooks/hooks.json— wiressync-rules.shas a secondSessionStarthookplugins/github-app/SPEC.md— adds a## Rulessection (also auto-regenerated by the sync-plugin-specs workflow on merge)Status
Complete. Validated locally:
mise run validate✅ (github-app passed)mise run lint✅ (Prettier clean)jq/bash -n✅.claude/rules/github-app -> .../plugins/github-app/rulesand the rule resolved through the symlink.Version not manually bumped — CI auto-bumps github-app on merge to main per the repo's versioning rule.
What to review
sync-rules.shas a second hook in the existingSessionStartmatcher is the preferred shape (vs. a separate matcher block).🤖 Opened by an AI agent (Jack) on behalf of @nsheaps.