Skip to content

GitHub Issues tracker provider - #380

Merged
andrewklingelhofer merged 1 commit into
mainfrom
github-tracker-provider
Jul 19, 2026
Merged

GitHub Issues tracker provider#380
andrewklingelhofer merged 1 commit into
mainfrom
github-tracker-provider

Conversation

@andrewklingelhofer

Copy link
Copy Markdown
Contributor

Summary

Adds a third issue-tracker provider, github, alongside Linear and Jira. Critters can now poll GitHub Issues in configured repos, claim them by status, run phases, and report outcomes back — using the newly-GA issue fields API for statuses on org repos, with automatic status:* label fallback on personal repos.

  • src/tracker/github.ts — full IssueTracker implementation over plain fetch (no new deps, no GraphQL). Task identity is owner/repo#N everywhere. Status mode is detected per repo at init: org single-select issue field (default Status) when available, status:<Name> labels otherwise. Field values are set by option name via POST (never PUT, which would clobber other fields). updateStatus never throws. Rate-limit responses throw digit-free messages so isPermanentTrackerError classifies them as retryable. Blockers via the issue-dependencies API, gated on the embedded summary count.
  • WebhookPOST /webhook/github reusing the shared HMAC verifier (X-Hub-Signature-256); signed issues events on configured repos with trigger labels kick a debounced single-issue poll. Closed issues never trigger. Dashboard hooks page + env-var list gain github entries (server-side only — no bundle regen).
  • buildProviderConfig() — single ProviderConfig construction point; fixes three latent bugs where any non-jira provider silently became Linear (config-reload, cli-clean) and the daemon switch had no default case.
  • Identifier safetysanitizeIdentifier() (owner/repo#42owner-repo-42, no-op for Linear/Jira) applied to branch names, work dirs, plan/checkpoint paths (prompts + all runners), log/attachment names, the logs CLI, and logger regexes; /api/logs/<id> now URL-decodes.
  • Configgithub: block (repos, statusField, statusMap, statusTypes), GITHUB_TOKEN, GITHUB_WEBHOOK_SECRET, credential validation, statusType-bucket warning.

Notes

  • Dual status mode and webhook inclusion were explicit design decisions; limitations (no attachment uploads, field-mode human edits discovered by polling, api.github.com only) are documented in the README's new "GitHub Issues as a ticket source" section.
  • Reviewed with a spec-first pass (42 edge cases) and a deep review against the spec; all confirmed findings fixed (identifier casing canonicalization, closed-issue webhook guard, cli-clean prefix ordering, anchored HTTP-status classification, PATCH body hygiene).
  • Two items need one live-API smoke check before production use (mocks can't settle them): that the issues list endpoint embeds issue_field_values, and that the ensureStatus options PATCH round-trips existing option colors.

Test plan

  • bun test — 1009 pass / 0 fail (74 new cases: tracker modes/behaviors, webhook signature+extractor+endpoint, health logs decoding, config validation, utils sanitize, cli-clean identifier extraction)
  • bun run typecheck
  • bun run lint
  • Live smoke against a real org repo (see Notes)

🤖 Generated with Claude Code

Add a third issue-tracker provider ("github") alongside Linear and Jira:

- src/tracker/github.ts: GitHubTracker over plain fetch (no new deps).
  Task identity is owner/repo#N everywhere. Statuses are dual-mode,
  detected per repo at init: org repos use the org's single-select
  issue field (GA issue fields REST API); personal repos and unreadable
  orgs degrade to status:<Name> labels. Field values are set by option
  name via POST (PUT would clobber other fields). updateStatus never
  throws. Rate-limit responses throw digit-free messages so the
  permanent-error classifier retries them. Blockers via the issue
  dependencies API.
- Webhook: POST /webhook/github (HMAC via the shared verifier),
  issues events on configured repos with trigger labels poll the issue;
  closed issues never trigger.
- buildProviderConfig(): single ProviderConfig construction point
  (fixes any-non-jira-is-linear in config-reload/cli-clean and the
  daemon switch's missing default case).
- Config: github: block (repos, statusField, statusMap, statusTypes),
  GITHUB_TOKEN / GITHUB_WEBHOOK_SECRET, credential validation.
- sanitizeIdentifier(): owner/repo#42 -> owner-repo-42 for branches,
  work dirs, plan/checkpoint paths, log and attachment names; /api/logs
  now URL-decodes identifiers. No-op for Linear/Jira.
- Dashboard hooks page + env-var list gain github entries (server-side
  only, no bundle regen).
- Tests: 70+ new cases (tracker, webhook, health, config, utils,
  cli-clean). Docs: README GitHub section, configuration.md, CLAUDE.md.

Co-Authored-By: Claude Fable 5 <[email protected]>
@andrewklingelhofer
andrewklingelhofer merged commit fd5b440 into main Jul 19, 2026
1 check passed
@andrewklingelhofer
andrewklingelhofer deleted the github-tracker-provider branch July 19, 2026 00:20
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.

1 participant