p24-infra Issue-Pipeline Cron — Operations
Autonomous nightly that processes p24-infra’s own GitHub issue pipeline
(triage → Design → Review) via the /process-issues skill. This is the
p24-infra analogue of the et-operational-platform claude-nightly cron.
At a glance
| Field | Value |
|---|---|
| Host | IONOS vps-i1 (217.154.82.162) |
| Schedule | 0 23 * * * — 23:00 UTC daily |
| Cron file | /etc/cron.d/p24-infra-nightly |
| Wrapper | /root/p24-infra-nightly.sh (server-local, not in repo) |
| Runs as | claude-runner (root cron drops privileges via runuser) |
| Working clone | /home/claude-runner/p24-infra (branch dev) — dedicated, NOT the live /opt/p24-infra deployment checkout |
| Skill | /process-issues (--allowedTools Bash,Read,Edit,Write,Glob,Grep) |
| Log | /var/log/p24-infra-nightly.log |
| Repo | radieu/p24-infra (PRs target dev) |
Scheduled at 23:00 UTC to stay clear of the et-app claude-nightly (02:07 UTC
Mon–Fri) and the 02:00–04:00 UTC GitHub-Actions backup window.
What it does each run
- Refreshes the dedicated clone to
origin/dev(reset --hard+pull), injecting the GitHub token at runtime and storing the remote tokenless. - Runs
claude -p "/process-issues"asclaude-runner. The skill triages new issues, posts Code-change-design comments, implementsDesign-ready issues, and opens PRs todev— all viagh. - Logs start/finish to
/var/log/p24-infra-nightly.log. Does not commit anything into the repo itself; the skill creates its own branches/PRs.
Design rationale
- Dedicated clone, not
/opt/p24-infra— the/optcheckout is the live deployment copy (carries uncommitted local state); issue processing must not switch branches or commit there. - Everything runs as
claude-runner— Claude Code refuses--dangerously-skip-permissionsas root, and running git as root would leave root-owned objects in.gitthat block laterclaude-runnercommits (the exact failure that broke the et-app nightly — see that cron’s history).
Prerequisites (already satisfied on vps-i1)
claude-runnerOAuth creds valid at/home/claude-runner/.claude/.credentials.json(with a refresh token, so they self-renew)./home/claude-runner/.claude-envexportsGITHUB_TOKEN,TRELLO_API_KEY,TRELLO_TOKEN. The wrapper also exportsGH_TOKEN=$GITHUB_TOKENforgh.ghCLI present; token haspush/adminonradieu/p24-infra.
Caveat — no PowerShell
The /process-issues skill is written with PowerShell helper snippets, but
pwsh is not installed on vps-i1. Claude adapts these to gh/bash at
runtime (the same as the et-app nightly), so this is not a blocker. If pipeline
state-field updates ever prove unreliable, install PowerShell or port the
Set-PipelineState helper to gh api in the skill.
Run manually / test
# Full run (as cron does)
/root/p24-infra-nightly.sh >> /var/log/p24-infra-nightly.log 2>&1
# Watch
tail -f /var/log/p24-infra-nightly.logTroubleshooting
| Symptom | Likely cause / fix |
|---|---|
Failed to authenticate. API Error: 401 | claude-runner OAuth expired with empty refresh token. Copy a valid .credentials.json from /root/.claude/ → /home/claude-runner/.claude/, chown claude-runner, chmod 600. |
detected dubious ownership | A git op ran as the wrong user. The wrapper runs everything as claude-runner; ensure nobody runs git in the clone as root. |
insufficient permission for adding an object in .git/objects | Root-owned objects in the clone. chown -R claude-runner:claude-runner /home/claude-runner/p24-infra/.git. |
| Nothing processed | Check gh issue list --repo radieu/p24-infra --state open; confirm token still valid. |