- _hermes_api_post sends X-Hermes-Session-Id so each fork sync uses a fresh gateway transcript (was: derived session reused 200k-token history across upstream tips, making later runs pay growing context) - SYNC_CLAUDE_TIMEOUT 2700→3600: a fresh session needs ~25min/120 calls to resolve 17 files + verify + commit; 2700s cut the HTTP call while the agent was still committing - salvage-on-timeout: when the agent call ends early (timeout/transport) but the merge is already committed (MERGE_HEAD gone), finish+push it instead of aborting — verified live: 17 conflicts resolved by agent, push ok, fork 27 ahead / 0 behind - _sync_finish_merge blocks committing files that still carry conflict markers (guard against git add of unresolved files) - tests: 68/68 (session header, salvage completed merge, abort unfinished, marker guard; fake-leak hardening in _install_git_fake)
PR Queue Worker
pr-queue-worker.py — the orchestration cron that watches open PRs across all
repos where the PR-Agent GitHub App is installed and drives the full lifecycle:
- Open PR found → ensure a PR-Agent review exists (fabricates a webhook to
pr-agent.asepharyana.my.idif not) - Toolchain pin guard → closes dependabot PRs that bump pinned toolchain
majors (see
TOOLCHAIN_PINSmap — typescript/eslint/@tsparticles/…) instead of waiting on them forever - AI auto-fix → runs the Hermes agent via the local gateway API server
(
POST /v1/chat/completionson127.0.0.1:8642,API_SERVER_KEY) on the PR head for up toAI_FIX_MAX_TURNSturns, commits locally, then the worker pushes the fix - Safety analysis → parses the review body for security/major-issue blockers; score must be ≥ 6/10
- CI gate → waits for the required check to pass (closes stale dependabot
PRs stuck failing CI for >
STALE_CI_CLOSE_DAYS) - Approve + merge
Upstream Fork Auto-Sync
Since 2026-09-21 the same 5-minute tick also syncs every repo in the App
installation whose GitHub metadata says fork: true: new upstream (parent)
commits are merged (never rebased) into the fork's default branch, gated by
a per-repo interval (default 1 hour; UPSTREAM_SYNC config block).
- Conflicted merge → the Hermes agent (via the gateway API server) resolves
it (merge-reconciler rules: merge hunks by hand, never wholesale
--ours/--theirs, run the repo's own typecheck/tests before committing). The agent never pushes — the harness does. - Clean merge → one Hermes quality pass over the merged files, committed as
fix: auto-fix code quality [skip ci]. - Protected default branch → detect from the push result (GH006 /
required-status-check) and fall back to opening an
upstream-sync-*PR that the normal pipeline (review → AI fix → CI → approve → merge) finishes. - CI safety → after a direct push the worker verifies the fork's CI at our merge commit; a red CI at OUR merge sha (still the tip, no human commits on top) force-reverts to the pre-merge sha. Watch stops after 6 h.
- Push credentials → owner PAT (gh CLI) first because the App lacks
workflows:write; App token is the fallback. Clones use the App token. - State →
/tmp/pr-queue-sync-state.json(skip/interval/pending-verify), workdirs/tmp/pr-queue-sync-work/. - Notifications → same
pr-agent-opsDiscord webhook: synced, PR opened, reverted, skipped-once.
Manual/dev:
python3 scripts/pr-queue-worker.py --sync-status
python3 scripts/pr-queue-worker.py --sync-only asepharyana/shiro-neko --dry # stops before push
python3 scripts/pr-queue-worker.py --sync-only asepharyana/shiro-neko
Tests: python3 scripts/test_pr_queue_sync.py (51 assertions; no network —
gh_api/git/Hermes API/push are monkeypatched).
Deployment
- Cron: Hermes cron job
04f13b9fdadc, every 5 minutes - Live path:
~/.hermes/scripts/pr-queue-worker.py(cron reads this file — keep it in sync with this repo copy) - Secrets: NOT in this file. Hydrated at import from
~/.hermes/.env(PR_AGENT_APP_ID,PR_AGENT_KEY_PATH,PR_AGENT_WEBHOOK_SECRET,PR_AGENT_WEBHOOK_URL). The GitHub App private key lives at~/.hermes/keys/pr-agent-key.pem(gitignored, never commit).
Sync note
This repo is the canonical version. The live cron copy under ~/.hermes/scripts/
is what actually runs — after editing here, cp scripts/pr-queue-worker.py ~/.hermes/scripts/pr-queue-worker.py and verify with:
/home/code/hermes-agent/.venv/bin/python3 -m py_compile ~/.hermes/scripts/pr-queue-worker.py
timeout 90 /home/code/hermes-agent/.venv/bin/python3 ~/.hermes/scripts/pr-queue-worker.py