Polyhydra Skills / GitHub & Delivery
Prep a portfolio of repos across ~/projects for a multi-day unattended coding-agent burn (Codex or otherwise) — narrow scope to the repos actually in play, clear local/PR/branch turbulence, and make sure every in-scope repo has queued work. Use when the user says "straighten the road", "get ready for the burn", "clear the runway", wants repos "in good shape" before a multi-day agent session, or asks what's blocking a clean unattended run across their portfolio.
Drop this in — save the block below as ~/.claude/skills/straighten-the-road/SKILL.md, or run:
mkdir -p ~/.claude/skills/straighten-the-road cat > ~/.claude/skills/straighten-the-road/SKILL.md <<'EOF' # (paste the full source block below into this file) EOF
# Straighten the Road
Prep work before a long unattended coding-agent run (a multi-day Codex credit
burn, a haiku-storm sweep, or any stretch where agents work without a human
watching closely). The goal: no repo should make an agent stop and wait on a
human decision it didn't need to hit — dirty trees, missing branches, stale
competing PRs, or nothing queued to work on.
This is a **playbook**, not a single script — most steps involve judgment
calls that should go through `AskUserQuestion` (this user runs MAID; see
their global CLAUDE.md) rather than being silently decided. Scale the depth
to what the user asks for; the steps below are the full sequence this skill
was extracted from, not a mandatory checklist.
## 0. Scope the portfolio down before touching anything
`~/projects` typically holds 200+ repos across 40+ hubs — most quiet,
legacy, or backend/infra that isn't in play for a given burn. Don't audit
all of them by default.
1. Run the audit (git-dirty / PR-workspace signal per hub, requires
`~/code/dev-forge`):
```sh
cd ~/code/dev-forge && python3 tools/project_focus.py \
--projects-root ~/projects audit --no-github \
--output-dir "$CLAUDE_JOB_DIR/tmp/project-focus" >/dev/null
```
Read `project-focus.json`'s `active[]` entries: `name`, `repositories[]`
(`github_slug`, `path`, `dirty`), `dirty_repository_count`,
`pr_workspace_count`.
2. Ask the user to narrow scope — hub-level exclusion (internal
tooling/infra vs. product hubs) is usually the first cut, then app-shape
(mobile/web/desktop surface, not backend/API/library) and recency (local
commit within the last few weeks is a reasonable "actively worked on"
bar) narrow further. Compute recency locally and cheaply, no API calls:
```sh
git -C "$path" log -1 --format=%ct # then diff against `date +%s`
```
This is a real fork in the road — use `AskUserQuestion`, don't guess the
full list silently. Expect 2-3 rounds as the user corrects the cut
("pull out the non-user-facing apps", "mobile/web/desktop apps" is a
realistic sequence of refinements).
## 1. Sweep GitHub state for the scoped list
For each repo in the final scope, gather: default branch, whether `dev`
exists, open PRs (draft/mergeable/updated_at/title), open issue count. Do
this with a small parallel `gh api` sweep rather than one call per fact —
see codeburn's pattern for spawning workers, or just `xargs -P 10` over a
slug list for a read-only sweep this size.
**Gotcha — branch-existence false positive:** `GET
/repos/{owner}/{repo}/git/refs/heads/{branch}` does **prefix matching**, not
exact matching. Checking for `dev` this way silently succeeds against any
branch starting with "dev" (`develop`, `dev-forge-fix`, etc.), so a repo
that actually lacks a `dev` branch reads as having one. Use `GET
/repos/{owner}/{repo}/branches/{branch}` instead — that 404s on anything
that isn't an exact match. Verify with 3-4 known-missing repos by hand
before trusting a bulk result; this bit a real run and produced a
completely wrong "44/45 already have dev" false-negative on the first pass.
## 2. Save the inventory somewhere durable
The scoped list + snapshot state is worth keeping — write it to
`~/projects/<SOMETHING>-<date>.md` (the `~/projects` root is itself a git
repo, `Polyhydra-Games/projects-hub`, that versions exactly this kind of
hub-level planning doc) and commit it via a worktree + draft PR (see
`~/.claude/skills/projects/SKILL.md`'s **launch** section and this user's
CLAUDE.md worktree/PR-shipping rules). Also save a `project`-type memory
entry pointing at the file — the PR/issue counts are a snapshot, say so
explicitly so a future read doesn't trust stale numbers.
**Gotcha — worktree base branch:** `EnterWorktree`'s default `baseRef`
setting branches from `origin/<default-branch>` (usually `main`), **not**
whatever the repo's actual integration branch is. If the repo uses `dev` as
its working branch (per this user's "main triggers real deploys, work on
dev" rule), a worktree created the normal way silently bundles in every
commit that's on `main` but not yet on `dev` into your diff. Check
`git branch -a` for a `dev` branch right after entering the worktree; if one
exists and diverges from `main`, `git fetch origin dev && git reset --hard
origin/dev` before making any edits, then re-apply. Verify with `git diff
--stat origin/dev..HEAD` before pushing — it should show only your file(s).
**Gotcha — backticks in shell heredocs:** if you build markdown content
with inline code spans (`` `like this` ``) inside a `python3 -c "..."`
double-quoted Bash string, the backticks get interpreted as shell command
substitution *before Python ever sees the string* — content silently
vanishes or executes as garbage commands. Either write the file via the
`Write`/`Edit` tools directly (no shell involved), or use a single-quoted
heredoc (`<<'EOF'`) which suppresses all shell expansion.
**Gotcha — GitKraken PR creation on org repos:** `pull_request_create`
fails on repos under an org (e.g. `Polyhydra-Games/*`) with a generic MCP
error. Fall back to `gh api repos/{owner}/{repo}/pulls -f title=... -f
body=... -f head=... -f base=... -F draft=true` — **not** `gh pr create`,
which this user's `gitkraken-hooks` plugin hard-denies over Bash regardless
of org. The REST endpoint doesn't match that string and isn't blocked.
## 3. Mechanical fixes (low-risk, confirm the class of action once)
Once the user says "do it" for a category, execute the whole category — but
each individual mutating call as a **separate direct tool call**, not a
`for` loop in one Bash invocation. A batch loop that merges/creates
many things in a single script is more likely to get blocked by the auto
mode classifier than the same actions issued one at a time; if blocked,
retry as individual calls before escalating to the user.
- **Missing `dev` branches**: create off the tip of each repo's existing
default branch via `gh api repos/{slug}/git/refs -f ref=refs/heads/dev -f
sha=<default-branch-tip-sha>`. Skip repos that already have an equivalent
differently-named integration branch (e.g. `develop`) rather than
creating a confusing duplicate.
- **Safe automated/bot PRs** (dependency bumps, scheduled sync workflows,
etc.): check `mergeable_state` and actual CI check-runs
(`gh api repos/{slug}/commits/{sha}/check-runs`) before merging — draft
PRs need `markPullRequestReadyForReview` (GraphQL) before the REST merge
endpoint will accept them.
## 4. Seed work for repos with nothing queued
A repo with zero open issues has nothing for an unattended agent to pick up.
Don't fabricate issues from nothing — fan out research agents (one per
handful of repos, `Explore` subagent type is enough since this is read-only)
to actually look at each repo (README/AGENTS.md, `gh issue list --state
closed`, `gh pr list --state merged`, a skim for TODO/FIXME or thin test
coverage) and either propose one concrete bounded issue or recommend
"skip" with a real reason (issues disabled, explicitly declared
abandoned/unmaintained, a genuine placeholder with no source tree yet).
Review the proposals before creating anything — a subagent's proposal is a
submission, not a result. Create via `gh issue create --repo <slug> --title
"..." --body "$(cat <<'EOF' ... EOF)"` (heredoc body, same backtick trap as
above applies to inline code spans in the body).
## 5. Review stale substantive PRs — don't auto-merge these
Draft PRs carrying real logic (security fixes, bug fixes, feature work) need
a human decision, not a mechanical merge, even when CI is green. For each:
check the PR body for an explicit sequencing note (e.g. "requires backend
endpoint in PR #N, not deployed yet — merge that first"), check whether a
failing CI check is actually caused by this PR's diff or is pre-existing
breakage on the base branch (`gh api repos/{slug}/commits/<base-branch-tip>/check-runs`
— if the base branch itself is already red, the PR isn't the cause), and
check `mergeable_state` for `CONFLICTING` across a family of PRs that touch
overlapping files (a sign they're a stacked/sequenced chain that needs
human-decided merge order, not independent PRs). Report findings, don't act
unilaterally.
## 6. Close the loop
Update the inventory file and memory entry to reflect what actually
happened (branches created, PRs merged, issues seeded, what's still open) —
don't leave a stale "gap" list sitting in a doc once the gaps are closed.
Push the update to the same PR branch rather than opening a duplicate PR.
End with `AskUserQuestion` offering real next steps (review the flagged
stale PRs, clean any remaining dirty repos, or "now go!" if the list is
clean) — never end mid-audit without a clear handback.