pelagia-portal/automation
Hardik cc62a9ddf6 docs(automation): note Forgejo 10 broken-PR quirk and close/reopen fix
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 17:05:52 +05:30
..
claude-issue-watcher.ps1 fix(automation): ASCII log prefix to avoid console encoding garble 2026-06-11 16:50:02 +05:30
README.md docs(automation): note Forgejo 10 broken-PR quirk and close/reopen fix 2026-06-11 17:05:52 +05:30
register-watcher-task.ps1 feat(automation): issue-to-deploy pipeline — Report Issue button, Claude watcher, tag-triggered deploy 2026-06-11 16:39:43 +05:30
watcher.config.example.json feat(automation): issue-to-deploy pipeline — Report Issue button, Claude watcher, tag-triggered deploy 2026-06-11 16:39:43 +05:30

Automated issue-to-deploy pipeline

End-to-end flow from a user clicking Report Issue in the portal to a fix running in production:

Portal header (bug icon)                          [App/components/layout/report-issue-button.tsx]
        │  server action → Forgejo API
        ▼
Forgejo issue  (labels: portal, claude-queue)     [git.pelagiamarine.com/shad0w/pelagia-portal]
        │  polled every 10 min by Windows Scheduled Task "PelagiaClaudeIssueWatcher"
        ▼
claude-issue-watcher.ps1 (this folder)            [dev PC, runs headless Claude Code]
        │  Claude implements + verifies fix in C:\...\src\pelagia-autofix
        │  watcher pushes branch claude/issue-N and opens a PR (label: claude-pr)
        ▼
Human review: merge the PR, then create a release tag vX.Y.Z
        │  tag push triggers .forgejo/workflows/deploy.yml
        ▼
forgejo-runner on pms1 (pm2: forgejo-runner, label "host")
        │  checks out the tag in ~/pms, pnpm install + build + prisma migrate deploy
        ▼
pm2 restart ppms  →  live at pms.pelagiamarine.com

Components

Piece Where Notes
Report Issue button App/components/layout/report-issue-button.tsx + report-issue-actions.ts Any signed-in user; files issue with portal + claude-queue labels
Forgejo helper App/lib/forgejo.ts Needs FORGEJO_URL, FORGEJO_REPO, FORGEJO_TOKEN env (token scope: write:issue)
Issue watcher automation/claude-issue-watcher.ps1 Config in watcher.config.json (gitignored — copy from the example). Logs in automation/logs/
Scheduled task automation/register-watcher-task.ps1 Registers PelagiaClaudeIssueWatcher, every 10 min, single-instance
Deploy workflow .forgejo/workflows/deploy.yml Triggers on v* tags; runs on the host runner
Runner pms1 ~/forgejo-runner, pm2 process forgejo-runner Registered as pms1-host with labels host, docker

Issue label lifecycle

claude-queueclaude-workingclaude-pr (PR opened, awaiting review) or claude-failed (no verified fix; reason posted as an issue comment).

To retry a failed issue, re-add the claude-queue label. To queue any manually-created issue for Claude, just add the claude-queue label.

Releasing

After merging a Claude PR (or any change) on master:

git pull
git tag v0.2.0          # semver: bump patch for fixes, minor for features
git push pms1 master --tags

The runner deploys the tag and restarts the app. Watch progress under Actions on the Forgejo repo, or pm2 logs forgejo-runner on pms1.

Operational notes

  • The watcher runs Claude Code with --dangerously-skip-permissions inside the dedicated pelagia-autofix clone — never point workDir at your main checkout.

  • Watcher only works issues while this PC is on; queued issues are picked up on the next run after boot (-StartWhenAvailable).

  • Tokens: portal-report-issue (write:issue, used by the app) and claude-watcher (write:issue + write:repository, used by the watcher). Both belong to the shad0w Forgejo account. Rotate via docker exec -u 1000 forgejo forgejo admin user generate-access-token ....

  • Server-side env for the button lives in ~/pms/App/.env on pms1 (FORGEJO_URL=http://127.0.0.1:3001 so it does not depend on the tunnel).

  • Known Forgejo 10 bug: clicking Update branch on a PR (or pushing to its head branch) can make the page show "This pull request is broken due to missing fork information" even though the PR is fine (API still reports mergeable: true). Fix: close and reopen the PR — via the UI, or:

    $h = @{ Authorization = "token <claude-watcher token>" }
    Invoke-RestMethod -Method Patch -Headers $h -ContentType application/json `
      -Uri https://git.pelagiamarine.com/api/v1/repos/shad0w/pelagia-portal/pulls/<N> -Body '{"state":"closed"}'
    Invoke-RestMethod -Method Patch -Headers $h -ContentType application/json `
      -Uri https://git.pelagiamarine.com/api/v1/repos/shad0w/pelagia-portal/pulls/<N> -Body '{"state":"open"}'
    

    Fixed upstream in newer Gitea/Forgejo — resolves itself if Forgejo is upgraded past v10.