Files GitHub issues via a configured GitHub App so they're attributed to a bot identity rather than a personal account. Pure Node stdlib APIs run with Bun; no dependencies, no build step. Maintainer tool.
Requires claude-code-hermit ≥1.2.34. Before installing or running hermit-scribe 0.1.1, upgrade core with /claude-code-hermit:hermit-evolve.
claude plugin marketplace add gtapps/claude-code-hermit
claude plugin install hermit-scribe@claude-code-hermit --scope localThe plugin requires a GitHub App with Issues: Read & write permission installed on the target repo.
- GitHub Settings → Developer settings → GitHub Apps → New GitHub App.
- Name the App (this name becomes the bot identity on filed issues). Set Homepage URL to anything; disable Webhook.
- Permissions → Repository permissions → Issues:
Read & write. - Create GitHub App. Note the App ID on the settings page.
- Private keys → Generate a private key. Save the
.pem. - Install App, choose account/org, select target repo(s).
- The installation URL is
github.com/settings/installations/{INSTALL_ID}. Note the ID.
Store the key in a gitignored location:
mv ~/Downloads/<your-app>.*.pem .claude.local/hermit-scribe-key.pem| Var | Description |
|---|---|
HERMIT_GH_APP_ID |
App ID from the App's settings page |
HERMIT_GH_APP_INSTALL_ID |
Install ID from the installation URL |
HERMIT_GH_APP_KEY_FILE |
Absolute path to the .pem private key |
HERMIT_GH_REPO |
Optional. Target owner/repo. Default: gtapps/claude-code-hermit |
Set them in your project .env (loaded by Docker hermit via env_file:) or in .claude/settings.local.json env block for interactive sessions.
Run /hermit-scribe:hatch after configuring the env vars above. It appends or version-refreshes the Issue Filing block in your CLAUDE.md/CLAUDE.local.md, stamps _hermit_versions["hermit-scribe"] in .claude-code-hermit/config.json, and seeds an autoMode.environment entry for api.github.com (context for the auto-mode classifier, not a standing permission grant — filing is always operator-confirmed regardless). Re-run hatch after an upgrade to refresh the block.
Trigger phrases:
file PROP-007 as a GH issueopen an issue for PROP-012report this to the trackerfile a GH issue for [description]
For proposal-backed issues: the skill globs .claude-code-hermit/proposals/PROP-NNN-*.md, reads frontmatter (id, title, category, session) and the ## Context / ## Problem / ## Proposed Solution / ## Impact body sections, then builds a Conventional Commits title (<type>(<scope>): <title>, e.g. feat(homeassistant-hermit): integrate HA History API). Type is derived from category (bug → fix, infrastructure/investigation → chore, otherwise → feat); the recognized scope vocabulary is derived from the keys of _hermit_versions in .claude-code-hermit/config.json, scanned against explicit mentions in the proposal text first (plugins/<slug>/ paths or whole-word slug occurrences), falling back to the lone activated fleet hermit when no explicit target appears, with the claude-code- prefix stripped. Scope is omitted when signals are absent or ambiguous. The body is translated to English at the GitHub boundary (technical identifiers, code, and frontmatter are preserved verbatim) and a Filed via hermit-scribe · proposal={id} · session={session} footer is appended.
For ad-hoc issues: supply title and body directly. The operator's title is passed through verbatim (no CC enforcement); translation and sanitization still apply.
All issues get the hermit-filed label. Proposal-backed issues also receive a type label derived from category (bug → bug; infrastructure/investigation → chore; otherwise enhancement) and, when a single plugin scope was resolved, a scope label matching the stripped slug (e.g. homeassistant-hermit). These labels must already exist on the target repo — unknown ones are silently dropped or auto-created by GitHub, so filing never errors on a missing label.
Before filing, the skill runs --check {id} automatically. If a matching issue already exists (matched by proposal={id} in the footer), the skill shows the existing URL and asks whether to skip or proceed. Re-filing after overriding writes the new URL into the proposal's gh_issue: field (latest wins).
Before showing the preview, the skill passes the draft through the issue-sanitizer subagent. It strips anything personal or specific to the operator's machine and project unless it's clearly part of an upstream hermit plugin (claude-code-hermit, claude-code-dev-hermit, claude-code-homeassistant-hermit, claude-code-fitness-hermit, hermit-scribe) or the hermit state tree (.claude-code-hermit/...). Secrets, .env content, connection strings, internal hostnames/IPs, and non-public URLs are always stripped even when they look technical. Stripped content is replaced with <redacted>.
The operator can un-redact specific items during the preview step if a particular value is load-bearing for the issue.
The cleaned title and body are shown to the operator before filing as a single message (body fully inlined, confirmation prompt last). The operator can confirm, edit (iterative — re-previews until satisfied), or cancel.
| Error | Cause |
|---|---|
HERMIT_GH_APP_KEY_FILE='...' does not exist |
Key file path wrong or missing — check .env |
GH 401: Bad credentials |
Wrong App ID, install ID, or key file |
GH 404 |
App not installed on target repo, or repo name typo |
GH 422 |
Empty title or GitHub validation error |
HERMIT_GH_REPO must be "owner/repo" |
Malformed repo path (more than one /) |
*.pemis gitignored. Private key never committed.- Key is read at runtime; never appears in session files, proposals, or memory.
- Missing env vars produce a clear error and non-zero exit. No silent no-ops.
- Sandbox:
file-issue.tsmakes two HTTPS calls toapi.github.com. The hermit's standard sandbox profile has unrestricted network; custom profiles that restrict outbound HTTPS need to allowapi.github.com.
hermit-scribe/
├── agents/
│ └── issue-sanitizer.md redacts non-hermit content from draft body
├── scripts/
│ └── automode-env.ts seeds autoMode.environment entry for api.github.com
├── skills/hatch/
│ └── SKILL.md version-gated setup/refresh: block + version stamp + autoMode seed
└── skills/hermit-scribe/
├── SKILL.md trigger phrases + filing flow
└── file-issue.ts stdlib: JWT → install token → POST /issues; --check flag
file-issue.ts is a single-shot script run with Bun: signs an RS256 JWT from the App private key, exchanges it for an installation access token at POST /app/installations/{id}/access_tokens, then POST /repos/{owner}/{repo}/issues with the derived label set (hermit-filed always, plus any extra labels passed as trailing positional args). Two HTTPS round-trips per invocation. Bun is required (Claude Code already provides it).