Files
Vlad MocanuandClaude Opus 4.6 fba53fc8a0 chore: anonymize internal URLs for public release
Replace git.wxs.ro with forgejo.example.com in tests and docs.
Add public repo guidelines to CLAUDE.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 16:36:34 +02:00

7.3 KiB

CLAUDE.md

Public Repository

This repo is open-source and synced to Codeberg. When making changes:

  • Never commit sensitive data — no internal URLs, tokens, credentials, private infrastructure details, or instance-specific configuration in src/, action.yml, base-action/, or docs/. The .forgejo/workflows/ directory is the only place with instance-specific config (runner labels, bot IDs, internal URLs) and that's fine — users write their own workflows.
  • Keep Forgejo support generic — all Forgejo code must work for any Forgejo instance, not just ours. Don't hardcode assumptions about our setup. Use action inputs and environment variables for instance-specific values.
  • Use generic URLs in tests — test fixtures use forgejo.example.com as the sample Forgejo URL. Never use real instance URLs in src/ or test/ code.

Commands

bun test                # Run tests
bun run typecheck       # TypeScript type checking
bun run format          # Format with prettier
bun run format:check    # Check formatting

What This Is

A GitHub Action that lets Claude respond to @claude mentions on issues/PRs (tag mode) or run tasks via prompt input (agent mode). Mode is auto-detected: if prompt is provided, it's agent mode; if triggered by a comment/issue event with @claude, it's tag mode. See src/modes/detector.ts.

How It Runs

Single entrypoint: src/entrypoints/run.ts orchestrates everything — prepare (auth, permissions, trigger check, branch/comment creation), install Claude Code CLI, execute Claude via base-action/ functions (imported directly, not subprocess), then cleanup (update tracking comment, write step summary). SSH signing cleanup and token revocation are separate always() steps in action.yml.

base-action/ is also published standalone as @anthropic-ai/claude-code-base-action. Don't break its public API. It reads config from INPUT_-prefixed env vars (set by action.yml), not from action inputs directly.

Key Concepts

Auth priority: github_token input (user-provided) > GitHub App OIDC token (default). The claude_code_oauth_token and anthropic_api_key are for the Claude API, not GitHub. Token setup lives in src/github/token.ts.

Mode lifecycle: detectMode() in src/modes/detector.ts picks the mode name ("tag" or "agent"). Trigger checking and prepare dispatch are inlined in run.ts: tag mode calls prepareTagMode() from src/modes/tag/, agent mode calls prepareAgentMode() from src/modes/agent/.

Prompt construction: Tag mode's prepareTagMode() builds the prompt by fetching GitHub data (src/github/data/fetcher.ts), formatting it as markdown (src/github/data/formatter.ts), and writing it to a temp file via createPrompt(). Agent mode writes the user's prompt directly. The prompt includes issue/PR body, comments, diff, and CI status. This is the most important part of the action — it's what Claude sees.

Things That Will Bite You

  • Strict TypeScript: noUnusedLocals and noUnusedParameters are enabled. Typecheck will fail on unused variables.
  • Discriminated unions for GitHub context: GitHubContext is a union type — call isEntityContext(context) before accessing entity-specific fields like context.issue or context.pullRequest.
  • Token lifecycle matters: The GitHub App token is obtained early and revoked in a separate always() step in action.yml. If you move token revocation into run.ts, it won't run if the process crashes. Same for SSH signing cleanup.
  • Error phase attribution: The catch block in run.ts uses prepareCompleted to distinguish prepare failures from execution failures. The tracking comment shows different messages for each.
  • action.yml outputs reference step IDs: Outputs like execution_file, branch_name, github_token reference steps.run.outputs.*. If you rename the step ID, update the outputs section too.
  • Integration testing happens in a separate repo (install-test), not here. The tests in this repo are unit tests.
  • allowed_tools needs Bash sub-patterns: Bare Bash in allowed_tools makes the tool available but individual commands still require interactive approval (which can't happen in CI). Use sub-patterns like Bash(git:*), Bash(bun:*), Bash(curl:*) to pre-approve command families. Tag mode adds --allowedTools to claudeArgs itself; agent mode relies on run.ts passing ALLOWED_TOOLS_INPUT as options.allowedTools to the SDK.

Forgejo Platform Support

This fork adds Forgejo support via a lean adapter pattern — only 4 genuinely different areas have Forgejo-specific code:

  • src/platform/detector.ts — Three-tier platform detection (explicit input > FORGEJO env > GITHUB_SERVER_URL heuristic) with cross-validation that rejects Forgejo override on github.com
  • src/forgejo/token.ts — Direct token handling (skips OIDC exchange)
  • src/forgejo/data/fetcher.ts — REST-based data fetching (replaces 3 GraphQL queries with 5-8 parallel REST calls)
  • src/forgejo/comment-logic.ts — Forgejo URL patterns for tracking comments

All other src/github/ modules work on Forgejo via Octokit REST as-is (permissions, comments, branches, git config, context, formatter).

Bot identity on Forgejo: A dedicated claude user provides bot identity (like GitHub's claude[bot]). The bot_id, bot_name, and bot_email action inputs control git commit attribution. When bot_email is set, it overrides the default noreply email format — set it to the bot user's registered email so Forgejo links commits to the profile. See docs/forgejo.md for setup.

Key integration points (these files have platform branches and are merge-conflict surface):

  • src/entrypoints/run.ts — Platform branch at top for token setup
  • src/modes/tag/index.ts — Data fetcher swap (fetchForgejoData vs fetchGitHubData)
  • src/github/operations/comments/create-initial.ts — Platform-aware spinner/URL format
  • src/github/operations/comments/update-with-branch.ts — Forgejo branch link in tracking comment
  • src/github/operations/branch.ts — Uses repos.getBranch() on Forgejo (Forgejo has /git/refs not /git/ref)
  • src/github/validation/actor.ts — Bot-type check skipped on Forgejo; self-trigger guard only blocks comment/review events (issue_comment, issues, pull_request_review, pull_request_review_comment). PR, workflow_dispatch, and schedule events pass through even when actor matches bot_name.
  • src/entrypoints/update-comment-link.ts — Forgejo PR compare URL (expand=1 instead of quick_pull=1)
  • src/mcp/install-mcp-server.ts — Skips GitHub public MCP server on Forgejo

MCP server names stay the same (github_comment, github_ci, etc.) even on Forgejo — changing them would require updating hardcoded tool name lists in src/modes/tag/index.ts.

CI: .forgejo/workflows/ contains claude.yml (tag mode), ci.yml, test-action.yml, and upstream-sync.yml. Unit tests run with GITHUB_SERVER_URL=https://github.com override on Forgejo runners.

Code Conventions

  • Runtime is Bun, not Node. Use bun test, not jest.
  • moduleResolution: "bundler" — imports don't need .js extensions.
  • GitHub API calls should use retry logic (src/utils/retry.ts).
  • MCP servers are auto-installed at runtime to ~/.claude/mcp/github-{type}-server/.