init: centralized agent skills for Claude Code + Codex

- skills/ shared by both tools (open Agent Skills standard)
- portable cross-skill refs (root-relative, no ~/.claude hardcode)
- bin/link.sh bootstrap for non-Nix machines
- nix/home.nix + flake.nix for home-manager

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014SK5Lo7LQfwLRVdCv1A8uF
This commit is contained in:
naps62
2026-07-24 17:57:56 +00:00
commit f83a247de3
109 changed files with 48638 additions and 0 deletions
+133
View File
@@ -0,0 +1,133 @@
---
name: blitz
description: "Autonomously drive an entire tracker milestone to done — sweep every open issue (one subagent per issue, parallel where dependencies allow), fix bugs found along the way, then either deploy (safe to debug in prod) or spawn a local dev instance, and push a Home Assistant notification with the preview URL. Built for long unattended runs. Use when the user wants to blitz / sweep / complete a whole milestone, e.g. \"/blitz M0\"."
user-invocable: true
args:
- name: input
description: "A milestone identifier: its number/id (e.g. 3), or a substring of its title (e.g. M0). Omit to auto-pick the lowest-numbered open milestone with unclosed issues."
required: false
---
# Blitz — Milestone Autopilot
Milestone-scale sibling of `/yolo`. `yolo` ships one issue; **blitz drives a whole milestone to done, unattended** — sweeping its issues, fixing bugs it discovers, then shipping (deploy or local dev) and pinging the user's phone with a preview URL.
Design goal: keep working productively for long stretches while spiking an idea, so the user only steps in once there's something to preview.
**First:** read `linear-common/COMMON.md` (sibling skill, same skills root) for shared config, worktree, and implementation conventions. Everything there applies; this doc only adds the milestone orchestration on top.
This skill targets **`tracker: gitea`** (milestones live in the repo's Gitea tracker). For `tracker: linear`, treat a Linear **cycle or sub-project** as the milestone and adapt the API calls; the orchestration shape is identical.
---
## Roles
- **Orchestrator** = the main blitz thread (you). Owns the DAG, spawns subagents, merges branches, closes issues, runs the readiness gate, ships, notifies. Does *not* implement issues itself.
- **Issue subagent** = one `Agent` per issue (`isolation: "worktree"`). Implements exactly one issue via the yolo flow, returns a structured result. **One subagent per issue is the default and is incentivized** — do not batch multiple issues into one agent.
---
## 1. Setup
1. Load project config + `source ~/.env.claude` (for `$GITEA_TOKEN`). Set `BASE=$remoteBaseUrl`, `REPO=<owner>/<repo>` (from `git remote get-url origin`).
2. **Resolve the milestone** from `$ARGUMENTS`:
- `GET $BASE/api/v1/repos/$REPO/milestones?state=open` → match by id or title-substring (case-insensitive). No arg → lowest-numbered open milestone that still has open issues.
- Save `MS_ID`, `MS_TITLE`, and a slug (lowercase-hyphenated, e.g. `m0`).
3. **Integration branch** `blitz/<slug>` off `defaultBranch`. Create + push if absent, else check it out. Everything merges here; `defaultBranch` stays untouched until Ship.
4. kitty tab title `blitz/<slug>` (silent skip if unavailable).
## 2. Build the issue DAG
1. List the milestone's open issues: `GET $BASE/api/v1/repos/$REPO/issues?state=open&type=issues&limit=100`, filter to those whose `milestone.id == MS_ID` (or pass `&milestones=<MS_TITLE>`). `type=issues` excludes PRs.
2. For each, `GET .../issues/$N/dependencies` → its **blocked-by** set. Build the dependency graph.
3. Classify each issue:
- **Epic / tracking-only**: title contains "Epic" or body is a children checklist with no own implementation scope. Do NOT assign a subagent — it closes automatically when its children (its blockers) all close.
- **Workable**: everything else.
4. **Ready set** = workable, open issues whose every blocker is closed.
## 3. Execution pass (the loop body)
**Blitz drives its own loop — no external `/loop` needed.** The orchestrator thread stays alive and repeats the pass below until the milestone is done. Fan-out subagents run in the background; when they finish they re-invoke you, which advances the next wave naturally. Only use `ScheduleWakeup` as a fallback heartbeat when you're blocked waiting on something the harness can't notify you about (e.g. polling a deploy's health). Wrapping blitz in `/loop` is unnecessary and not the intended usage.
Each pass:
1. Recompute the **ready set** (§2.4).
2. **Fan out**: spawn one issue subagent per ready issue, **in parallel** (multiple `Agent` calls in a single message), `isolation: "worktree"`. Cap concurrency at a sane number (≈46). Each subagent prompt:
- "Implement Gitea issue #N (`<title>`) in this repo following the `/yolo` flow and `COMMON.md`. You are on integration branch `blitz/<slug>`; create branch `<slug>/N-<issue-slug>` **off it**. Read the issue body + its linked spec/epic; that plus the repo is your full context. Implement, run `buildCommand`, commit in logical steps. **Do not merge to any shared branch and do not close the issue** — push your branch and return the result. If you discover a bug or missing work outside this issue's scope, do not fix it silently; report it in `newFindings`."
- Force a structured return (schema): `{ issue, done, branch, summary, buildPassed, newFindings: [{title, body}] }`.
- **Strict rule**: never spawn a subagent for a blocked issue. Dependencies are load-bearing.
3. **Integrate serially** (orchestrator, to avoid parallel-merge conflicts): for each finished subagent whose `done && buildPassed`, merge its branch into `blitz/<slug>`, resolve conflicts, run `buildCommand`. If the merge or build breaks, fix on the integration branch (or bounce the issue back for another pass).
4. **Close** each successfully integrated issue on Gitea (`Closes #N` in the merge commit, or PATCH `state:closed`). Epics whose blockers are now all closed: close them too.
5. **Integration review (cadence-gated) — do NOT skip.** After each wave (or every ~3 integrated issues, whichever comes first), audit the *accumulated* diff of `blitz/<slug>` vs `defaultBranch` — not each issue in isolation. Run `/code-review` on that diff, or spawn a reviewer subagent, hunting the cross-issue drift that blind parallel work causes: inconsistent data shapes / contracts between issues, divergent naming, duplicated or conflicting logic, dead code, regressions, misbehavior. **Findings are top priority**: fix them (inline, or file + wire as blocking issues) *before* spawning the next fan-out wave. This is the load-bearing coherence check — parallel subagents can't see each other's work, so this is the only place drift gets caught.
6. **Fold in findings**: for each `newFindings` item and any bug you find, create a new Gitea issue in this milestone (`milestone: MS_ID`), wire dependencies if it blocks/relies on others, and let the next pass pick it up. Fix trivial bugs inline instead of filing.
7. Repeat passes until: no open workable issues, no open epics, the latest integration review is clean, and a full pass produced **no new findings**.
## 4. Readiness gate
Declare the milestone **ready** only when ALL hold:
- Every workable issue closed; every epic closed.
- `buildCommand` green on `blitz/<slug>`.
- A real smoke/verify of the app passes — drive the actual feature (use `/verify` or `/run`, or the project's verify skill), not just unit tests. This catches integration breakage the per-issue subagents couldn't see.
If the gate fails, file/fix the gap as a finding and run another pass.
## 5. Ship — deploy OR local dev
Pick the path per the milestone's nature and config. Resolve `deployPolicy`:
- Explicit: `.claude/linear.json``blitz.deploy` (a `{ "<slug>": "deploy" | "local" }` map) wins if present.
- Heuristic (when unset), **deploy only if ALL true**:
1. Milestone is user-facing / shippable — NOT a throwaway spike (check the milestone description for "throwaway"/"spike"/"disposable").
2. A deploy target is wired — a Dokploy app for this repo exists, or `blit.deployTarget` / `deployUrl` is configured.
3. Change is safe to debug in prod — static site or additive change, no destructive migration.
- **When genuinely unsure, choose LOCAL.** Never surprise-deploy to prod.
### Deploy path (safe to debug in prod)
1. Merge `blitz/<slug>``defaultBranch`, push.
2. Trigger the deploy via the **Dokploy MCP** for the configured app (`application-deploy` / `application-redeploy`, or `compose-deploy` for compose apps). Poll until healthy.
3. Preview URL = the app's Dokploy domain (`domain-byApplicationId`) or configured `deployUrl`.
### Local path (spike / not prod-safe)
1. Keep `blitz/<slug>` (do not merge to `defaultBranch` unless the change is trivially safe).
2. Launch a local dev instance in the background — use the `/run` skill, or run the app's dev server directly, **bound to `0.0.0.0`** (global rule: this VM is reached from other devices), e.g. `pnpm --dir <app> dev --host 0.0.0.0` with `run_in_background: true`.
3. Preview URL = `http://<LAN-IP>:<port>` (LAN IP, never `localhost`): `hostname -I | awk '{print $1}'`.
## 6. Notify (Home Assistant MCP)
Push to the user's phone so they know it's ready to look at. Default target `notify.mobile_app_pixel_7_naps` (override with `blitz.notifyService` in config):
```
mcp__ha-mcp__ha_call_service
domain: "notify"
service: "mobile_app_pixel_7_naps"
service_data:
title: "blitz: <MS_TITLE> ready ✅"
message: "<n> issues shipped · <deploy|local dev> · tap to preview"
data:
url: "<preview-url>" # opens the companion app at the URL
clickAction: "<preview-url>" # Android notification tap target
```
Then post a one-line summary + preview URL in the chat too, and **finish the run** — the self-driven loop ends here (cancel any pending `ScheduleWakeup` heartbeat with `stop: true`).
## 7. Autonomy & stop conditions
- Fully autonomous. Never ask the user except on a genuine blocker (missing credentials, architectural contradiction, an irreversible/destructive op, or a deploy that would break prod). **Away ≠ approval** — if you must ask, wait; don't decide for them.
- **Build it can't fix** after a few honest attempts, or a hard blocker: file a blocker issue in the milestone, send an HA notification describing the blocker (same call, title `blitz: <MS_TITLE> BLOCKED ⚠️`), and stop. Don't thrash.
- Never auto-deploy to prod when the ship decision is uncertain — fall back to local + notify.
- Idempotent: a re-run picks up where it left off (open issues + integration branch already reflect progress).
## Config (optional, `.claude/linear.json`)
```jsonc
{
"blitz": {
"deploy": { "m1": "deploy", "m0": "local" }, // per-slug override of the ship path
"deployTarget": "<dokploy app name or id>",
"deployUrl": "https://mapmatch.naps.pt", // preview URL for the deploy path
"devCommand": "pnpm --dir spike dev --host 0.0.0.0",
"notifyService": "mobile_app_pixel_7_naps"
}
}
```
All optional — sane fallbacks apply (heuristic ship decision, `/run` for local, default notify target).