Files
claude-code-action/docs/forgejo.md
T
Vlad MocanuandClaude Opus 4.6 07e0384538 docs: replace instance-specific values with placeholders in forgejo.md
Replace hardcoded bot_id "48" and bot_email "claude@wxs.ro" with
generic placeholders in Quick Start and setup examples so readers
don't copy instance-specific values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:56:37 +02:00

16 KiB

Forgejo Platform Support

This action supports Forgejo (and Forgejo Actions) as an alternative to GitHub. The same action code runs on both platforms — platform detection is automatic or explicitly configured.

Prerequisites

  • Forgejo instance with Forgejo Actions enabled
  • Forgejo runner registered and operational (e.g., a grunt or ubuntu-latest runner)
  • Anthropic API key or Claude Code OAuth token for Claude API access
  • Forgejo token with repo access (automatically available as github.token in workflows, or use a dedicated bot user)

Quick Start

1. Add Secrets

Add secrets at the organization level (Settings > Actions > Secrets) so all repos can share them:

  • ANTHROPIC_API_KEY — Your Anthropic API key (starting with sk-ant-)
  • CLAUDE_BOT_TOKEN — API token for the dedicated bot user (see Dedicated Bot User below)

2. Create Workflow

Create .forgejo/workflows/claude.yml:

name: Claude Assistant
on:
  issue_comment:
    types: [created]
  pull_request_review_comment:
    types: [created]
  issues:
    types: [opened, assigned, labeled]
  pull_request_review:
    types: [submitted]

jobs:
  claude-response:
    runs-on: grunt # Your Forgejo runner label
    steps:
      - uses: https://git.wxs.ro/actions/claude-code-action@v1 # Or your mirror URL
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          platform: "forgejo"
          github_token: ${{ secrets.CLAUDE_BOT_TOKEN }}
          bot_id: "YOUR_BOT_ID" # Replace with your bot's Forgejo user ID (see step 5 below)
          bot_name: "claude-bot"
          bot_email: "claude@yourdomain.com" # Must match the bot user's registered email

3. Agent Mode (Automation)

For automation workflows triggered by workflow_dispatch, push events, or schedules:

name: Claude Automation
on:
  workflow_dispatch:
    inputs:
      task:
        description: "Task for Claude"
        required: true

jobs:
  run-claude:
    runs-on: grunt
    steps:
      - uses: https://git.wxs.ro/actions/claude-code-action@v1
        with:
          prompt: ${{ github.event.inputs.task }}
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          platform: "forgejo"
          github_token: ${{ secrets.CLAUDE_BOT_TOKEN }}
          bot_id: "YOUR_BOT_ID" # Replace with your bot's Forgejo user ID
          bot_name: "claude-bot"
          bot_email: "claude@yourdomain.com"

Platform Detection

The action detects the platform using a three-tier strategy:

Priority Method Details
1 Explicit input platform: "forgejo" in workflow — most reliable
2 FORGEJO env var Set to "true" by Forgejo runner v7.0+
3 GITHUB_SERVER_URL heuristic If the URL doesn't contain github.com, assumes Forgejo

Recommendation: Always set platform: "forgejo" explicitly. Auto-detection works but the explicit input eliminates ambiguity.

Differences from GitHub

Authentication

Aspect GitHub Forgejo
Default auth GitHub App OIDC token exchange Direct GITHUB_TOKEN / FORGEJO_TOKEN
Token setup Automatic via Claude GitHub App Manual — provide github_token input
App token revocation Automatic cleanup step Skipped (no app token)
Bot identity claude[bot] (ID: 41898282) Dedicated bot user via bot_id/bot_name/bot_email inputs

On Forgejo, there is no OIDC token exchange with Anthropic. The action uses the workflow token (github.token) or a user-provided github_token directly.

API Differences

Feature GitHub Forgejo
GraphQL API Used for PR/issue data fetching Not available — REST API only
Data fetching Single GraphQL query per entity 5-8 parallel REST API calls
Actor validation Checks for bot/app accounts Skipped — no bot accounts on Forgejo
GitHub MCP server ghcr.io/github/github-mcp-server included Skipped — GitHub-specific
CI/Actions MCP Full GitHub Actions API Works via Octokit REST + GITHUB_API_URL
Permission check getCollaboratorPermissionLevel() repos.get() fallback (workflow tokens lack collaborator endpoint)
Git ref lookup git.getRef() (/git/ref/heads/...) repos.getBranch() (/git/refs is plural on Forgejo)

Bun Installation

The upstream action uses oven-sh/setup-bun. On Forgejo, this is replaced with a universal curl install because Forgejo runners pre-fetch all uses: action references before evaluating if: conditions, causing failures for GitHub-hosted actions that aren't mirrored.

Comment URLs

Comment tracking URLs (job links, branch links, PR creation links) use Forgejo URL patterns instead of GitHub patterns. This is handled automatically.

Action Inputs

The platform input is the only Forgejo-specific addition:

platform:
  description: "Platform to run on: 'auto' (default auto-detects), 'github', or 'forgejo'"
  required: false
  default: "auto"

All other inputs work identically on both platforms. See the Usage Guide for the full list.

On GitHub, Claude gets its own identity via the GitHub App (claude[bot]). On Forgejo, there's no such mechanism — by default the action runs under whatever token you provide, meaning commits and comments appear as the human user.

Creating a dedicated bot user solves this:

  • Clear attribution: Commits and comments show as claude-bot, not your personal account
  • Least privilege: The bot token has only the permissions Claude needs
  • Audit trail: Easy to distinguish human actions from bot actions in repo history
  • Security: If the action is compromised, only the bot's scoped token is exposed

Setup Steps

1. Create the bot user

Go to Site Administration > User Accounts > Create User Account or use the admin API:

  • Username: claude-bot
  • Email: e.g., claude@yourdomain.com
  • Password: any strong password (you'll use API tokens, not password login)
  • Uncheck "Require user to change password"
  • Leave "Admin" unchecked
  • Optionally set a display name and avatar to distinguish from human users

2. Add to organizations via teams

For each organization where Claude should operate:

  1. Go to Org Settings > Teams > New Team
  2. Create a team named Claude with:
    • Permission: Write
    • Access: All Repositories (so new repos are automatically covered)
  3. Add claude-bot to the team's Members

3. Generate a scoped API token

Log in as claude-bot, go to Settings > Applications, and create a token:

  • Token Name: claude-code-action
  • Scopes:
    • repo — read/write (issues, PRs, comments, branches, commits)
    • user:read — needed for API identity
    • Leave admin, organization, package unchecked

4. Store the token as an org-level secret

Add the token as CLAUDE_BOT_TOKEN at the organization level (Settings > Actions > Secrets) with visibility set to "All repositories". This way all repos in the org share the same secret.

5. Get the bot user's ID

You'll need the Forgejo user ID for the bot_id input:

curl -s "https://your-forgejo-instance/api/v1/users/claude-bot" | jq '.id'

6. Configure the workflow

- uses: https://git.wxs.ro/actions/claude-code-action@v1
  with:
    anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
    platform: "forgejo"
    github_token: ${{ secrets.CLAUDE_BOT_TOKEN }}
    bot_id: "YOUR_BOT_ID" # Replace with the ID from step 5
    bot_name: "claude-bot"
    bot_email: "claude@yourdomain.com" # Must match the bot user's registered email

The bot_email input overrides the default noreply email format. When it matches the bot user's registered email in Forgejo, commits will be linked to the bot's profile in the UI.

Token Rotation

Forgejo API tokens can expire. Plan for rotation:

  1. Set a calendar reminder for before the token expires
  2. Generate a new token by logging in as claude-bot (same scopes as above)
  3. Update the org secret CLAUDE_BOT_TOKEN with the new token value
  4. No code changes needed — the workflow reads the secret at runtime

Alternatively, generate a token without an expiration date (if your Forgejo instance allows it).

Included CI Workflows

This fork includes four Forgejo-native workflows in .forgejo/workflows/:

claude.yml — Tag Mode (@claude Mentions)

Responds to @claude mentions on issues, PR review comments, and PR reviews. Also triggers on issue assignment and label events. This is the main interactive workflow for using Claude on Forgejo.

ci.yml — Tests, Formatting, Type Checking

Runs on push to main and pull requests. Three parallel jobs:

  • test — bun test (with GITHUB_SERVER_URL override so GitHub-context unit tests pass)
  • prettier — bun run format:check
  • typecheck — bun run typecheck

test-action.yml — Action Self-Test

Tests the action itself on Forgejo in agent mode. Runs weekly and on PRs that modify src/, action.yml, or .forgejo/. Validates:

  • Platform detection returns "forgejo"
  • Token authentication works
  • Claude Code executes successfully
  • Output file is produced

upstream-sync.yml — Upstream Sync Check

Runs weekly. Compares main with upstream/main (anthropics/claude-code-action). If upstream has new commits:

  • Creates or updates an issue with the upstream-sync label
  • Includes commit log, diff stats, and merge instructions
  • Lists conflict-prone files

Merging Upstream Changes

This fork is designed for easy upstream merges. Only 4-5 files have Forgejo-specific modifications, and changes are placed at function entry points using an early-return pattern.

Merge Process

# Fetch latest upstream
git fetch upstream main

# Merge into your main branch
git merge upstream/main

# If conflicts occur, they'll be in these files:
#   - src/entrypoints/run.ts (platform branch at top)
#   - src/modes/tag/index.ts (data fetcher swap)
#   - src/mcp/install-mcp-server.ts (platform routing)
#   - action.yml (platform input, bun install)

# Resolve conflicts, keeping both the upstream changes and
# the Forgejo platform branches at function entry points

# Run tests to verify
bun test

# Push
git push origin main

Conflict Mitigation

All Forgejo changes follow the early-return pattern — platform-specific logic is placed at the top of functions, before the existing GitHub code. This means:

  • Upstream changes to the GitHub code path rarely conflict with Forgejo additions
  • When conflicts do occur, they're localized to the few lines where the platform branch starts
  • Resolution is straightforward: keep both the platform check and the upstream changes

What Happens When Upstream Adds New Features

New upstream features that use GraphQL or GitHub-specific APIs won't automatically work on Forgejo. The Forgejo data fetcher (src/forgejo/data/fetcher.ts) would need REST equivalents added. The action will still run — features that depend on missing data will simply lack that context.

E2E Test Results

Both execution modes have been validated end-to-end on a Forgejo instance (git.wxs.ro):

Mode Trigger Status Details
Agent mode workflow_dispatch Validated Platform detection, token auth, Claude execution, output file — all green
Tag mode issue_comment (@claude) Validated Issue context (title + body) read correctly, platform detected as forgejo, tracking comment created with spinner then updated with response (31s), job link URL correct

Tag Mode Verified Capabilities

  • @claude trigger phrase detected in issue comments
  • Issue body and title fully visible to Claude
  • Tracking comment created with progress spinner, then updated with final response
  • Forgejo job run URL correctly formatted in tracking comment
  • Branch creation works via repos.getBranch() API (Forgejo uses /git/refs not /git/ref)
  • Permission check passes via repos.get() fallback

Not Yet E2E Tested

  • PR review comment triggers (pull_request_review_comment)
  • PR review triggers (pull_request_review)
  • Label triggers (issues with labeled action)
  • Assignee triggers (issues with assigned action)
  • Branch creation + code changes from tag mode (issue asked a question, no code changes needed)

Known Limitations

  • Git ref API: Forgejo uses /git/refs (plural) instead of GitHub's /git/ref (singular). The action handles this by using repos.getBranch() on Forgejo for branch SHA lookups.
  • User display name fetch: GET /users/{username} returns 403 without read:user scope. Non-fatal — falls back to login name.
  • pull_request_target event: May not exist in Forgejo. The action degrades gracefully (maps to pull_request).
  • GitHub MCP server: The ghcr.io/github/github-mcp-server Docker image is GitHub-specific and is skipped on Forgejo.
  • Commit signing: SSH signing has not been tested on Forgejo. The use_commit_signing option (GitHub API signing) won't work since it uses GitHub's commit API.
  • downloadJobLogForWorkflowRun: Forgejo's Actions API may lack this endpoint. The CI MCP server attempts it via Octokit REST but may return limited data.
  • Bot filtering: allowed_bots checks won't match claude[bot] since Forgejo has no bot accounts. Actor validation is skipped entirely on Forgejo.

Troubleshooting

"Resource not accessible by integration" errors

This usually means the token lacks permissions. On Forgejo:

  • Use a personal access token with repo scope via the github_token input
  • The default github.token in Forgejo workflows may have limited permissions depending on your runner configuration

Tests fail with platform detection errors

Unit tests assume GitHub context by default. When running on a Forgejo runner, set GITHUB_SERVER_URL=https://github.com before running tests (the CI workflow handles this automatically).

Bun installation fails

If curl -fsSL https://bun.sh/install | bash fails on your runner, pre-install Bun on the runner image or use the path_to_bun_executable input to point to a custom Bun binary.

Upstream workflows run and fail

If .github/workflows/ from upstream are executing on your Forgejo runner, configure the runner to only read from .forgejo/workflows/. This is a runner-level setting — see your Forgejo instance's runner configuration.