diff --git a/ai-development/claude-code-plugins.mdx b/ai-development/claude-code-plugins.mdx index a480a4f..c665fe3 100644 --- a/ai-development/claude-code-plugins.mdx +++ b/ai-development/claude-code-plugins.mdx @@ -58,11 +58,14 @@ Workflow logic. Anything that's "how Claude Code should approach a task" lives h The rules layer these plugins operate within. - + + The full skill lifecycle — phases, exit modes, known reliability gaps. + + Scheduled Claude.ai routines — the cron side of the same ecosystem. - - The Copilot equivalent — reusable agentic workflows. + + Reusable GitHub Actions workflows that drive the cloud half of the pipeline. Plugins, hooks, full README. diff --git a/ai-development/skills/codeql-resolution.mdx b/ai-development/skills/codeql-resolution.mdx new file mode 100644 index 0000000..4ec23cd --- /dev/null +++ b/ai-development/skills/codeql-resolution.mdx @@ -0,0 +1,75 @@ +--- +title: "CodeQL resolution" +description: "CodeQL alerts are a separate gate from CI checks. /resolve-codeql is the skill that closes them automatically so /ship can complete." +tier: 2 +--- + +> CodeQL is not in `statusCheckRollup`. If you only check CI, you miss the CodeQL gate. `/resolve-codeql` fixes that. + +CodeQL is GitHub's static-analysis security scanner. It runs on every PR via the `Analyze (actions)` or `Analyze (javascript)` jobs (depending on what's enabled for the repo). When it finds a violation, it posts a **code-scanning alert** that blocks merge — but **does not** show up in `gh pr checks` or in the `statusCheckRollup` of a `gh pr view --json` query. Branch protection treats the alert as a separate signal. + +## Why this matters for `/ship` + +If `/finalize-pr` only queried `statusCheckRollup`, a PR could look ready (`statusCheckRollup.state: SUCCESS`) and still be blocked at merge time by an open CodeQL alert. The skill's Phase 3 explicitly runs a second, separate gate for CodeQL — using the REST code-scanning API, not GraphQL. + +```bash +gh api repos///code-scanning/alerts \ + --jq '[.[] | select(.state == "open")] | length' +``` + +If the result is non-zero, the PR is **not** ready, regardless of what CI says. + +## What `/resolve-codeql` does + +`/resolve-codeql fix` is the auto-resolution skill invoked by `/finalize-pr` Phase 2 when alerts exist: + + + + Lists all open alerts for the repo, with rule ID, severity, and file:line. + + + For each alert: is it a real vulnerability, an intentional pattern that should be suppressed, or a false positive? + + + Real → patch the code with a fix that addresses the rule. Intentional → add a CodeQL inline suppression with a justification comment. False positive → dismiss via the API with `"reason": "false positive"`. + + + Signed via the App installation token, attributed to `JacobPEvans-claude[bot]`. + + + The push triggers a fresh CodeQL run automatically. Wait for it to complete before re-querying alert state. + + + +## Why GraphQL doesn't show CodeQL state + +The GraphQL `pullRequest` schema's `statusCheckRollup` aggregates check runs and status contexts. CodeQL alerts live in a separate `repository.codeScanningAlerts` connection — they're attached to the repo's default branch baseline, not to the PR's check run set. + +A canonical query for the PR-readiness gate (from [`gh-cli-patterns`](https://github.com/JacobPEvans/claude-code-plugins/blob/main/github-workflows/skills/gh-cli-patterns/SKILL.md)) reads `statusCheckRollup` for CI, then does a **separate** REST call for CodeQL. Both must be clean for a PR to be considered ready. + +## Async timing + +CodeQL runs are slower than most CI checks — often 2–5 minutes after a push. This timing mismatch is why `/finalize-pr` Phase 2.6 (the fix in flight) introduces an explicit wait-for-async-checks step: poll at 30-second intervals up to 5 minutes, only advance to Phase 3 when all known check kinds have a terminal status. Without this, `/finalize-pr` could treat a still-running CodeQL run as a hard failure and bail out. + +## What `/resolve-codeql` will NOT do + +- **Won't dismiss real alerts as false positive.** Dismissals require justification and are reserved for genuine FPs. +- **Won't disable a CodeQL query.** Adjusting the CodeQL config is a deliberate human change. +- **Won't loop indefinitely.** Capped at 3 fix attempts per PR per invocation — beyond that, surfaces the unfixed alerts for a human. + +## Where to go next + + + + The orchestrator that invokes `/resolve-codeql` as part of Phase 2. + + + The plugin home for `/resolve-codeql` and the rest of the toolchain. + + + The full plugin source. + + + The upstream CodeQL documentation for query authoring and config. + + diff --git a/ai-development/skills/overview.mdx b/ai-development/skills/overview.mdx new file mode 100644 index 0000000..d456c11 --- /dev/null +++ b/ai-development/skills/overview.mdx @@ -0,0 +1,37 @@ +--- +title: "Skills" +description: "Local Claude Code slash-commands that pick up where the cloud pipeline stops. Use them from a session when you are the one iterating on a PR." +tier: 1 +--- + +> Cloud pipelines get a PR opened, reviewed, and CI'd without you. Skills are what you run from a Claude Code session when you are the one driving a PR to merge. + +A **skill** in this catalog is a slash-command shipped by [`JacobPEvans/claude-code-plugins`](/ai-development/claude-code-plugins). The plugin repo carries the source — each skill is a folder with `SKILL.md`, prompts, and supporting scripts; this section carries the human-readable narrative for the load-bearing ones. + +Skills are the local-execution counterpart to the [cloud pipelines](/automation/cloud-pipelines/overview) and [scheduled routines](/automation/scheduled-routines/overview). When the cloud finishes the job, you do not run a skill. When the cloud opens a draft PR but cannot drive it all the way (CodeQL alert needs human triage, review threads need negotiation, CI flake needs a retry strategy), you `/ship` it from a session. + +## What is documented here + +| Skill | Use when | +| --- | --- | +| [`/ship` and `/finalize-pr`](/ai-development/skills/ship-and-finalize) | You have a PR open and want it driven to a fully-mergeable state in one command | +| [`/resolve-codeql`](/ai-development/skills/codeql-resolution) | A PR is blocked on a CodeQL alert that does not show up in `gh pr checks` | + +More skills exist in `claude-code-plugins`; only the ones that participate in the issue → mergeable PR flow are written up here. The full catalog (commands, hooks, agents, skills) lives on the [claude-code-plugins page](/ai-development/claude-code-plugins). + +## Where to go next + + + + The source repo and full plugin catalog. + + + The event-triggered half — what skills do not have to do because the cloud already handled it. + + + Where each skill plugs into the broader flow. + + + The voice and commit-shape rules every skill applies before pushing. + + diff --git a/ai-development/skills/ship-and-finalize.mdx b/ai-development/skills/ship-and-finalize.mdx new file mode 100644 index 0000000..7c3aab9 --- /dev/null +++ b/ai-development/skills/ship-and-finalize.mdx @@ -0,0 +1,126 @@ +--- +title: "/ship and /finalize-pr" +description: "The local Claude Code skill that drives a PR to a fully-mergeable state. Phases, exit modes, and the reliability gaps being closed." +tier: 2 +--- + +> One command. Commit, push, open the PR, fix CodeQL, resolve threads, fix CI, verify everything is green. Never merges. That's a human decision. + +`/ship` is the local escape hatch for the cloud pipeline. The cloud pipeline ([ai-workflows](/automation/cloud-pipelines/ai-workflows), [claude-code-routines](/automation/scheduled-routines/claude-code-routines)) gets a PR opened and reviewed without you. `/ship` is what you run from a Claude Code session when **you** are the one iterating on a PR and want it driven to a ready-to-merge state in one command. + +## What `/ship` does + +`/ship` is a thin orchestrator. It detects uncommitted changes (commits them), discovers recently-created PRs, then for each PR invokes `/finalize-pr` — which is where the real work happens. + +```text +/ship + ├─ Step 0: verify git repo + ├─ Step 1: commit any uncommitted changes; discover PRs in scope + ├─ Step 1.5: build a context brief from the conversation + ├─ Step 2: invoke /finalize-pr per PR, sequentially + └─ Step 3: re-verify each PR with live GitHub state before reporting +``` + +## What `/finalize-pr` does + +`/finalize-pr` is the loop. Five phases per PR: + +{/* Shape: linear chain. Boundary crossings: 0. Ranks: 5×1. */} +{/* Aspect: ~3:1 (LR). Pass. */} + +```mermaid +%%{init: {'theme':'base','look':'handDrawn','themeVariables':{'fontFamily':'Geist','fontSize':'14px','primaryColor':'#102937','primaryTextColor':'#F4EFE6','primaryBorderColor':'#4FB3A9','lineColor':'#4FB3A9','secondaryColor':'#0B1D2A','tertiaryColor':'#1A2A38','clusterBkg':'rgba(79,179,169,0.08)','clusterBorder':'#4FB3A9'}}}%% +flowchart LR + P1([1. Discover]) + P2([2. Resolve loop]) + P3{3. Verify gate} + P4([4. Update metadata]) + P5([5. Report ready]) + + P1 --> P2 --> P3 --> P4 --> P5 + P3 -.->|gate fails| P2 + + classDef ai fill:#102937,stroke:#E06B4A,stroke-width:2px,color:#F4EFE6; + classDef auto fill:#102937,stroke:#F4EFE6,stroke-width:1.5px,color:#F4EFE6; + classDef gate fill:#102937,stroke:#E06B4A,stroke-width:2.5px,color:#F4EFE6; + + class P1,P2,P4 ai + class P5 auto + class P3 gate + + linkStyle 0,1,2,3 stroke:#4FB3A9,stroke-width:2px; + linkStyle 4 stroke:#E06B4A,stroke-width:1.5px,stroke-dasharray:4 3; +``` + +| Phase | What it owns | +| --- | --- | +| 1. Discover | Resolve which PR(s) to act on (current branch, all, or org-wide) | +| 2. Resolve loop | Start CI monitor in background; in parallel: invoke `/resolve-codeql fix`, `/resolve-pr-threads`, merge-conflict resolution; once CI completes, run `/simplify` once on the cumulative changes | +| 3. Verify gate | Re-query live GitHub state — `state`, `mergeable`, `mergeStateStatus`, `reviewDecision`, `statusCheckRollup.state`, all `reviewThreads.isResolved`, CodeQL alert count | +| 4. Update metadata | A subagent updates PR title, description, linked issues | +| 5. Report ready | Emit the canonical PR status block; wait for human merge | + +## What it never does + +- **Never merges.** Merge is always a human decision. +- **Never approves.** No auto-approval of PRs. +- **Never crosses org boundaries** in org-wide mode. +- **Never bypasses branch protection.** + +## Subagents in the call chain + +```text +/ship → /finalize-pr → /resolve-codeql fix + → /resolve-pr-threads → superpowers:receiving-code-review + → /simplify + → haiku subagent (PR metadata update) + → background CI monitor (Task tool) +``` + +Each subagent runs scoped to its task and reports back. The orchestrator re-verifies live state — never trusts a subagent's self-report as ground truth. + +## Known reliability gaps + +`/ship` has been ending prematurely without leaving PRs fully mergeable. Root causes traced to the current `SKILL.md` files: + +| Failure mode | Why it happens | +| --- | --- | +| Exits "blocked" when a fix could have continued | Phase 3 → Phase 2 loop is prose with no enforced iteration counter — subagents treat it as advisory | +| Treats async-pending checks as failures | Phase 3 aborts on `statusCheckRollup.state ≠ SUCCESS`, but Phase 2 can't fix a pending check | +| Silent subagent failure passes through | After `/resolve-codeql` and `/resolve-pr-threads`, skill advances without re-querying state to confirm fixes landed | +| CI monitor dies silently | Background Task agent can fail without propagating | +| All Phase 3 aborts treated identically | Some failures are agent-fixable, some are wait, some require humans (`REVIEW_REQUIRED`) | + +Fix in flight: explicit iteration counter (cap 5), wait-for-async-checks phase, post-fix verification of subagent work, CI-monitor failure fallback, and a failure-mode taxonomy that maps each `mergeStateStatus`/`reviewDecision` to a handler. After the fix, every `/ship` invocation reports one of three categories with a specific reason — never silent half-finalization: + +- **Ready to merge** — all gates clean +- **Ready except human gate** — only `REVIEW_REQUIRED` remaining +- **Ship aborted** — specific gate stuck with manual-action suggestion + +Tracked as a PR against [`claude-code-plugins`](https://github.com/JacobPEvans/claude-code-plugins). + +## When to use `/ship` vs the cloud pipeline + +| Situation | Use | +| --- | --- | +| Issue is filed, you want a PR drafted without thinking | [`ai-workflows`](/automation/cloud-pipelines/ai-workflows) (the cloud pipeline triggered on issue open) | +| You're editing a PR locally and want CI/threads/CodeQL handled in one command | `/ship` from your Claude Code session | +| You want a daily org-wide sweep | [`claude-code-routines`](/automation/scheduled-routines/claude-code-routines) (cron-scheduled) | +| You want to know if a PR is *really* ready to merge | `/finalize-pr ` directly — gives you the canonical gate output without re-running fixes | + +## Where to go next + + + + Why CodeQL is fixed separately from CI checks, and what `/resolve-codeql` does. + + + The plugin home for `/ship`, `/finalize-pr`, and all the supporting skills. + + + The full skill definition. + + + Phases, gates, and the merge prohibition. + + diff --git a/architecture/ai-pipeline.mdx b/architecture/ai-pipeline.mdx index f284263..fdc6ee3 100644 --- a/architecture/ai-pipeline.mdx +++ b/architecture/ai-pipeline.mdx @@ -108,7 +108,7 @@ Every other PAL tool has a native Claude Code equivalent; for single-model calls -See [AI Development · Overview](/ai-development/overview) for what each one does in detail. +See [AI Development · Overview](/ai-development/overview) for what each one does in detail. For the actual triggers, callers, and skill mechanics that drive this pipeline end-to-end, see [Automation · Overview](/automation/overview). ## Observability layer diff --git a/automation/cloud-pipelines/ai-workflows.mdx b/automation/cloud-pipelines/ai-workflows.mdx new file mode 100644 index 0000000..d939855 --- /dev/null +++ b/automation/cloud-pipelines/ai-workflows.mdx @@ -0,0 +1,108 @@ +--- +title: "ai-workflows" +description: "Sixteen reusable GitHub Actions workflows that turn issues into draft PRs, fix CI failures automatically, and gate merges. Consumer repos wire thin callers." +tier: 2 +--- + +> One repo of reusable workflows. Every consumer repo writes ten-line callers and inherits the entire pipeline. + +[`JacobPEvans/ai-workflows`](https://github.com/JacobPEvans/ai-workflows) ships 16 reusable GitHub Actions workflows (`on: workflow_call:`) that consumer repos invoke with `uses:` references. The AI orchestration, prompts, and rate guards live in the upstream workflow; the consumer caller declares the trigger and inherits secrets. + +## Event-triggered workflows + +These run on GitHub events. Wire one caller per workflow you want. + +| Workflow | Trigger | What it does | +| --- | --- | --- | +| `issue-triage.yml` | `issues: [opened]` | Categorizes, deduplicates, labels new issues | +| `issue-resolver.yml` | `issues: [opened]` | Creates a draft PR when the issue is well-scoped and not excluded by labels | +| `ci-fix.yml` | `workflow_run` of your CI workflow, `conclusion: failure` | Reads the failed log, pushes a fix commit | +| `final-pr-review.yml` | `pull_request_review: [submitted]` | Final merge-readiness gate before human merge | +| `project-router.yml` | `issues/pull_request: [opened, labeled]` | Routes items to GitHub Projects with smart field assignment | +| `post-merge-docs-review.yml` | `push: [main]` → dispatch | After merge, audits docs touched by the commit, creates fix PRs | +| `post-merge-tests.yml` | `push: [main]` → dispatch | After merge, analyzes the code changes and drafts targeted tests | +| `issue-linker.yml` | `pull_request: [opened, closed]` | Links open issues to PRs on open; closes resolved issues on merge | +| `notify-ai-pr.yml` | `pull_request: [opened]` from a bot | Slack notification when an AI-authored PR opens | + +## Scheduled workflows + +These run on cron — typically called with `schedule:` and a manual `workflow_dispatch:`. + +| Workflow | Default schedule | What it does | +| --- | --- | --- | +| `code-simplifier.yml` | Daily 04:00 UTC | DRY enforcement, dead code removal, drafts PRs | +| `best-practices.yml` | Weekly Wed 03:00 UTC | Audit creating actionable recommendations | +| `next-steps.yml` | Daily 05:00 UTC | Analyzes merge momentum, suggests next logical action | +| `issue-sweeper.yml` | Weekly Mon 06:00 UTC | Scans open issues, comments on progress, closes resolved | +| `issue-hygiene.yml` | Weekly Mon 07:00 UTC | Detects duplicates, links merged PRs, flags stale issues | +| `label-sync.yml` | Weekly Sun 05:00 UTC | Syncs canonical labels from the `.github` repo to consumers | +| `repo-orchestrator.yml` | `workflow_dispatch` | Multi-repo hub-and-spoke dispatcher for ad-hoc operations | + +## What's deprecated or disabled + +| Workflow | Status | Replacement | +| --- | --- | --- | +| `claude-review.yml` | DEPRECATED 2026-04-04. All jobs gated `if: false`. | External Gemini + Copilot PR reviews | +| `pr-issue-linker.yml` | Auto-triggers explicitly disabled (`workflow_dispatch` only) | `issue-linker.yml` | + +Wiring a caller for a deprecated workflow is a no-op — the consumer caller runs, the upstream silently skips. Don't. + +## How a caller looks + +A consumer caller is the smallest YAML that declares a trigger, sets permissions, and forwards to the upstream: + +```yaml +name: Issue Triage +on: + issues: + types: [opened] +permissions: + contents: read + id-token: write + issues: write +jobs: + run: + uses: JacobPEvans/ai-workflows/.github/workflows/issue-triage.yml@main + secrets: inherit +``` + +Permission shape varies per workflow — `issue-resolver` needs `pull-requests: write`, `ci-fix` needs `actions: read`, `post-merge-*` needs `actions: write` for the re-dispatch. The [canonical caller templates](https://github.com/JacobPEvans/ai-workflows/blob/main/docs/GETTING_STARTED.md) list the exact permission block for each. + +## Versioning + +Per the [CI/CD policy](/infrastructure/cicd/policy#dependency-versioning), JacobPEvans self-references use `@main` or a major tag like `@v0` — never minor/patch pins. The full SemVer tags exist (`@v0.15.1`) and are tracked by Renovate, but consumers should ride a moving ref so upstream improvements land without a Renovate PR per repo. + +## Authentication + +Every reusable workflow uses [`anthropics/claude-code-action@v1`](https://github.com/anthropics/claude-code-action), authenticated directly against the Anthropic API: + +- `secrets.ANTHROPIC_API_KEY` — Anthropic API key. Spend draws from the included monthly automation credits on the Claude subscription that backs these workflows. + +OAuth tokens from a Claude Code subscription session are **explicitly forbidden** in unattended CI — they violate the [Claude Code Terms of Service](https://www.anthropic.com/legal/terms). OpenRouter is supported as a fallback provider (set `secrets.OPENROUTER_API_KEY` and `secrets.OPENROUTER_BASE_URL`) but is no longer the default. The provider matrix lives in [AUTHENTICATION.md](https://github.com/JacobPEvans/ai-workflows/blob/main/docs/AUTHENTICATION.md). + +## Commit signing + +Every AI workflow mints a `JacobPEvans-claude` GitHub App installation token immediately before calling the action, then hands it in as `github_token` with `use_commit_signing: true`. Commits land web-flow-signed and attributed to the bot. The App credentials (`GH_APP_CLAUDE_BOT_PRIVATE_KEY`, `GH_APP_CLAUDE_BOT_ID`) are distributed by `secrets-sync` to every repo in the `_github_app_repos` anchor. + +## Where to go next + + + + Caller templates for every workflow, with the correct permission blocks. + + + The post-merge dispatch pattern, bot guards, and other recurring shapes. + + + Anthropic API key setup, cost controls, fallback providers, why not OAuth. + + + The e2e runbook for checking a freshly-wired repo end to end. + + + Exactly which six callers are wired on `JacobPEvans/docs` and why. + + + How ANTHROPIC_API_KEY and the App credentials land on each consumer repo. + + diff --git a/automation/cloud-pipelines/overview.mdx b/automation/cloud-pipelines/overview.mdx new file mode 100644 index 0000000..0d16775 --- /dev/null +++ b/automation/cloud-pipelines/overview.mdx @@ -0,0 +1,39 @@ +--- +title: "Cloud pipelines" +description: "Event-triggered automation that runs in GitHub Actions per consumer repo. Issues become draft PRs, CI failures get fixed, merge readiness is gated." +tier: 1 +--- + +> Event in (`issues.opened`, `workflow_run`, `pull_request`). PR out. Every step runs on GitHub-hosted runners or RunsOn spot, attributable to the AI-bot App identity. + +Cloud pipelines are the **event-driven** half of the automation surface. Something happens in GitHub (an issue is filed, a CI run fails, a PR is opened), the reusable workflows in [`JacobPEvans/ai-workflows`](/automation/cloud-pipelines/ai-workflows) react, and the result lands as a draft PR or a commit on an existing PR — signed by [`JacobPEvans-claude[bot]`](/infrastructure/cicd/git-signing) and ready for review. + +The cron-driven sibling — work that runs on a schedule rather than in response to an event — is documented under [Scheduled routines](/automation/scheduled-routines/overview). + +## How they fit + +| Trigger | Reusable workflow | Outcome | +| --- | --- | --- | +| `issues.opened` (label: `agentic-implement`) | `issue-resolver.yml` | Draft PR implementing the issue | +| `workflow_run` on `CI`, `conclusion: failure` | `ci-fix.yml` | Fix commit pushed back to the failing PR | +| `pull_request` opened or `synchronize` | `code-simplifier.yml`, `final-pr-review.yml` | Review comments + an auto-merge nudge when ready | +| `gh-aw` action SHA stale (Mon/Thu schedule) | `gh-aw-pin-refresh.yml` | PR refreshing pinned action SHAs | + +The full caller catalog and the post-merge dispatch chain live on the [ai-workflows page](/automation/cloud-pipelines/ai-workflows). + +## Where to go next + + + + Sixteen reusable workflows, the consumer-caller shape, auth + signing. + + + The cron-driven sibling. Org-wide, no per-repo wiring. + + + The end-to-end flow on `JacobPEvans/docs`, step by step. + + + How AI-authored commits land verified under the `JacobPEvans-claude[bot]` identity. + + diff --git a/automation/issue-to-pr-pipeline.mdx b/automation/issue-to-pr-pipeline.mdx new file mode 100644 index 0000000..a191384 --- /dev/null +++ b/automation/issue-to-pr-pipeline.mdx @@ -0,0 +1,129 @@ +--- +title: "Issue to PR pipeline" +description: "The eight-step cloud flow that turns a new GitHub issue into a draft PR with green CI, AI review, and a merge-readiness comment." +tier: 2 +--- + +> Open issue. Don't open the dashboard. Come back in five minutes to a draft PR ready for your eyes. + +The pipeline on this repo, [`JacobPEvans/docs`](https://github.com/JacobPEvans/docs), uses six thin caller files in `.github/workflows/` that delegate to reusable workflows in [`JacobPEvans/ai-workflows`](https://github.com/JacobPEvans/ai-workflows). Each caller is 10–30 lines; the AI work all lives in the upstream reusable workflow. + +## What runs, in order + +| Step | Trigger | Caller file | Reusable workflow | What it does | +| --- | --- | --- | --- | --- | +| 1 | `issues: [opened]` | `issue-triage.yml` | `ai-workflows/.github/workflows/issue-triage.yml@main` | Categorizes, deduplicates, labels | +| 2 | `issues: [opened]` | `issue-resolver.yml` | `ai-workflows/.github/workflows/issue-resolver.yml@main` | Creates a **draft PR** if the issue is well-scoped and not on the excluded-labels list | +| 3 | `pull_request: opened/synchronize/ready_for_review` | (no caller — handled by upstream reviewers) | external Gemini + Copilot reviews | Posts inline review comments | +| 4 | `workflow_run` on `CI`, `conclusion: failure` | `ci-fix.yml` | `ai-workflows/.github/workflows/ci-fix.yml@main` | Reads the failed CI log, pushes a fix commit (up to 2 attempts per PR, 5 per day) | +| 5 | `pull_request_review: [submitted]` | `final-pr-review.yml` | `ai-workflows/.github/workflows/final-pr-review.yml@main` | Final merge-readiness gate — checks TODOs, debugger artifacts, CI rollup | +| 6 | `issues: [opened, labeled]`, `pull_request: [opened, ready_for_review]` | `project-router.yml` | `ai-workflows/.github/workflows/project-router.yml@main` | Routes the item to the right GitHub Project with smart field assignment | +| 7 | `push: [main]` → re-dispatched as `workflow_dispatch` | `post-merge-docs-review.yml` | `ai-workflows/.github/workflows/post-merge-docs-review.yml@main` | After merge, audits docs touched by the commit and creates fix PRs if needed | +| 8 | Human clicks **Merge** | n/a | n/a | The only manual step | + +The deprecated `claude-review.yml` (removed 2026-04-04 in favor of Gemini + Copilot reviews) and the disabled-auto-trigger `pr-issue-linker.yml` are not wired. See [ai-workflows](/automation/cloud-pipelines/ai-workflows) for the full catalog and what's not active. + +## How the six callers connect + +{/* Shape: hub-and-spokes. 1 hub, 6 leaves stacked via invisible links. */} +{/* Aspect: ~4:3 (LR). Pass. */} + +```mermaid +%%{init: {'theme':'base','look':'handDrawn','themeVariables':{'fontFamily':'Geist','fontSize':'14px','primaryColor':'#102937','primaryTextColor':'#F4EFE6','primaryBorderColor':'#4FB3A9','lineColor':'#4FB3A9','secondaryColor':'#0B1D2A','tertiaryColor':'#1A2A38','clusterBkg':'rgba(79,179,169,0.08)','clusterBorder':'#4FB3A9'}}}%% +flowchart LR + R([docs repo]) + + subgraph callers[Caller files in .github/workflows/] + direction TB + A([issue-triage]) + B([issue-resolver]) + C([ci-fix]) + D([final-pr-review]) + E([project-router]) + F([post-merge-docs-review]) + A ~~~ B ~~~ C ~~~ D ~~~ E ~~~ F + end + + R --> A + + classDef host fill:#102937,stroke:#4FB3A9,stroke-width:2px,color:#F4EFE6; + classDef ai fill:#102937,stroke:#E06B4A,stroke-width:2px,color:#F4EFE6; + + class R host + class A,B,C,D,E,F ai +``` + +The hub is the consumer repo; each caller is a one-shot wrapper around an upstream reusable workflow. They run independently when their trigger fires. + +## What each caller actually contains + +A caller is the minimum YAML to declare a trigger, set permissions, and call the upstream: + +```yaml +name: Issue Triage +on: + issues: + types: [opened] +permissions: + contents: read + id-token: write + issues: write +jobs: + run: + uses: JacobPEvans/ai-workflows/.github/workflows/issue-triage.yml@main + secrets: inherit +``` + +Two patterns are slightly larger: + +- **`ci-fix.yml`** passes a `repo_context` and `ci_structure` describing what the repo is and what CI runs, so the AI knows what to fix. +- **`post-merge-docs-review.yml`** uses the [Post-Merge Dispatch Pattern](https://github.com/JacobPEvans/ai-workflows/blob/main/docs/PATTERNS.md#post-merge-dispatch-pattern) — a two-job file because `push` events aren't supported by `claude-code-action@v1`, so the caller re-dispatches as `workflow_dispatch`. + +## Secrets the pipeline needs + +Distributed automatically by [`secrets-sync`](/security/secrets-sync) when a repo is added to the `_github_app_repos` and `_all_repos` anchors in `secrets-config.yml`: + +| Secret / variable | Source | Purpose | +| --- | --- | --- | +| `ANTHROPIC_API_KEY` (secret) | `_all_repos` | Auth for `claude-code-action` to call the Anthropic API directly | +| `GH_APP_CLAUDE_BOT_PRIVATE_KEY` (secret) | `_github_app_repos` | Mints App tokens for signed commits attributed to `JacobPEvans-claude[bot]` | +| `GH_APP_CLAUDE_BOT_ID` (variable) | `_github_app_repos` | App identifier | + +Per [Git signing](/infrastructure/cicd/git-signing), every AI workflow mints a `JacobPEvans-claude` installation token immediately before calling `claude-code-action@v1`, then hands it in as `github_token` with `use_commit_signing: true`. Commits land web-flow-signed and attributed to the bot. + +## Rate and safety guards + +The reusable workflows enforce conservative defaults so a runaway loop can't burn cloud spend: + +- **`issue-resolver.yml`** — `max_attempts: 1` per issue, `daily_limit: 5` per repo, `excluded_labels: "type:security,type:feature,type:breaking,size:l,size:xl"` won't touch +- **`ci-fix.yml`** — `daily_run_limit: 5` per repo, max 2 fix attempts per PR +- **`final-pr-review.yml`** — `daily_run_limit: 5` +- **All workflows** — fork PRs blocked by `if:` guards, branch protection enforces the final merge gate + +## The pieces this doesn't include + +The cloud pipeline gets a PR to **draft + reviewed**. It does NOT: + +- Mark the PR ready for merge — that's a human decision +- Click the merge button — never automated +- Override branch protection or required reviewers +- Touch repos outside the current org boundary + +For the local iteration loop on a PR you're editing yourself, see [`/ship` and `/finalize-pr`](/ai-development/skills/ship-and-finalize). + +## Where to go next + + + + The full catalog of 16 reusable workflows, event-triggered + scheduled. + + + The cron half — six routines that scan the org and pick up loose ends. + + + Caller templates and the live workflow catalog. + + + Why direct Anthropic API, not OAuth tokens; cost controls; fallback providers. + + diff --git a/automation/overview.mdx b/automation/overview.mdx new file mode 100644 index 0000000..91cf046 --- /dev/null +++ b/automation/overview.mdx @@ -0,0 +1,70 @@ +--- +title: "Automation" +description: "How an issue becomes a merged PR with minimal human touch: ai-workflows in the cloud, claude-code-routines on cron, claude-code-plugins on the laptop." +tier: 1 +--- + +> File an issue. Walk away. Come back to a draft PR with green CI, AI review, and one human merge click left. + +This is the **issue → mergeable PR** pipeline. Three repos collaborate: `ai-workflows` runs on GitHub Actions per consumer repo, `claude-code-routines` runs on Anthropic's cloud cron, `claude-code-plugins` is the local Claude Code escape hatch. + +## The end-to-end shape + +{/* Shape: linear chain. Boundary crossings: 0. Ranks: 6×1. */} +{/* Aspect: ~2.5:1 (LR). Pass. */} + +```mermaid +%%{init: {'theme':'base','look':'handDrawn','themeVariables':{'fontFamily':'Geist','fontSize':'14px','primaryColor':'#102937','primaryTextColor':'#F4EFE6','primaryBorderColor':'#4FB3A9','lineColor':'#4FB3A9','secondaryColor':'#0B1D2A','tertiaryColor':'#1A2A38','clusterBkg':'rgba(79,179,169,0.08)','clusterBorder':'#4FB3A9'}}}%% +flowchart LR + I([Issue]) + T([AI triage]) + D([Draft PR]) + L([CI and review loop]) + G{Final gate} + M([Merged]) + + I --> T --> D --> L --> G --> M + + classDef src fill:#102937,stroke:#E06B4A,stroke-width:2px,color:#F4EFE6; + classDef ai fill:#102937,stroke:#E06B4A,stroke-width:2px,color:#F4EFE6; + classDef auto fill:#102937,stroke:#F4EFE6,stroke-width:1.5px,color:#F4EFE6; + classDef gate fill:#102937,stroke:#E06B4A,stroke-width:2.5px,color:#F4EFE6; + classDef sink fill:#102937,stroke:#F4EFE6,stroke-width:2px,color:#F4EFE6; + + class I src + class T,L ai + class D auto + class G gate + class M sink +``` + +A human files the issue and clicks merge. Everything in between runs without supervision. + +## The three layers + +| Layer | Where it lives | When it runs | What it owns | +| --- | --- | --- | --- | +| [Cloud pipelines](/automation/cloud-pipelines/overview) | GitHub Actions (per consumer repo) | Event-triggered (issues, PRs, CI failures) | Triage, draft PR creation, CI auto-fix, final review gate, project routing | +| [Scheduled routines](/automation/scheduled-routines/overview) | Anthropic cloud cron | Scheduled (cron 2×/day to weekly) | Org-wide maintenance: daily polish, issue solver, sentinel audit, weekly scorecard | +| [Skills](/ai-development/skills/overview) | Your laptop | Interactive (`/ship` from any Claude Code session) | The local escape hatch — finalize a PR you're iterating on | + +## Where to go next + + + + The eight-step cloud flow on a target repo. Which trigger fires which file, who reviews, what gates merge. + + + The 16 event-triggered reusable workflows behind the per-repo half of the automation surface. + + + Cron-scheduled Claude routines. Org-wide maintenance, no per-repo wiring. + + + Local Claude Code slash-commands — `/ship`, `/resolve-codeql` — that close the loop on a PR you are iterating on. + + + +## Source repos + +[`ai-workflows`](https://github.com/JacobPEvans/ai-workflows) · [`claude-code-routines`](https://github.com/JacobPEvans/claude-code-routines) · [`claude-code-plugins`](https://github.com/JacobPEvans/claude-code-plugins). The 30-second pitch lives at [AI pipeline](/architecture/ai-pipeline); this Automation section is the mechanics. diff --git a/automation/scheduled-routines/claude-code-routines.mdx b/automation/scheduled-routines/claude-code-routines.mdx new file mode 100644 index 0000000..8542565 --- /dev/null +++ b/automation/scheduled-routines/claude-code-routines.mdx @@ -0,0 +1,105 @@ +--- +title: "claude-code-routines" +description: "Six cron-scheduled Claude Code routines that watch the whole org without per-repo wiring. Pick up loose ends the event-triggered pipeline misses." +tier: 2 +--- + +> Cron, not events. Org-wide, not per-repo. One configuration, scans everything. + +[`JacobPEvans/claude-code-routines`](https://github.com/JacobPEvans/claude-code-routines) ships six prompt files that run on schedule inside Anthropic's cloud-hosted Claude Code sandbox. They discover repos under `$GH_OWNER` via `gh search`, do their work using `gh` CLI calls, and report results to Slack via the official Slack MCP connector. There is no per-repo wiring — drop a repo into the org and the routines pick it up on the next run. + +## The six routines + +| Routine | Schedule (CT) | What it does | +| --- | --- | --- | +| Morning Briefing | Daily 5:00 AM | Read-only activity summary: new PR reviews, opened issues, CI failures, anything that needs attention | +| The Sentinel | Daily 12:33 AM | Param/secret audit; picks one PR to review; flags operator-specific patterns | +| The Custodian | Daily 2:00 AM | Weighted-random maintenance: stale branch cleanup, missing labels, repo health audit | +| Issue Solver | Daily 7:00 AM + 7:00 PM | Picks one open issue, takes it from triage → draft PR in six phases | +| Daily Polish | Daily 11:00 PM | Deep-clean one repo per day: README gaps, missing `.gitignore`, CI config, test coverage | +| Weekly Scorecard | Mondays 5:00 AM | Portfolio health scores: repo count, open-issue median, CI pass rate, test coverage % | + +## How the Issue Solver picks work + +The most ambitious routine. Six phases, all running in the same sandbox session: + + + + Shell-only. `gh search issues` across `$GH_OWNER` for the last 90 days, open + unassigned. Scored via `jq` weights — `bug=+50`, `good-first-issue=+40`, `type:security=-40`, `type:breaking=-40`, recent-activity bonus. + + + Claude Sonnet classifies the top 5 by solvability + complexity (trivial/small/medium/large). + + + A read-only subagent reads the affected code and locates the exact lines that need changes. + + + Pre-flight secret scan (`grep -P` against known patterns). Creates a branch via `gh api repos/.../git/refs`. Pushes file changes via Contents API — the App installation token auto-signs every commit. + + + Best-effort CI polling at 30-second intervals up to 5 minutes. Records the final `ci_status` (passed / failed / pending / none). + + + Opens a **draft PR only** — never `--ready`, never auto-merge. If the issue is too complex, comments on the issue explaining what was tried and gives up cleanly. + + + +## How routines authenticate + +Each routine runs in Anthropic's cloud sandbox with pre-installed `gh` CLI. Authentication is via environment variables set in the cloud routine configuration at [claude.ai/code/routines](https://claude.ai/code): + +| Env var | Purpose | +| --- | --- | +| `GH_TOKEN` | GitHub PAT for `gh` CLI | +| `GH_OWNER` | The org or user to scan (e.g. `JacobPEvans`) | +| `GH_OWNERS` | The Sentinel uses this — a list of orgs to spot-check | + +Slack output goes through the official Slack MCP connector. The full operator-setup walkthrough lives in [`docs/CLOUD_ROUTINES_AUTH.md`](https://github.com/JacobPEvans/claude-code-routines/blob/main/docs/CLOUD_ROUTINES_AUTH.md) in the source repo. + +The local Claude Code that develops and deploys these routines is configured declaratively via [`nix-claude-code`](/nix/nix-claude-code) — plugin set, MCP wiring, permissions, and hooks all version-pinned in Nix. + +## Current deploy gotcha + +The native GitHub Actions deploy (`.github/workflows/deploy-routines.yml`) is **disabled** because `anthropics/claude-code-action@v1` does not carry the organization UUID binding that the Routines API requires — `RemoteTrigger` calls fail with `Unable to resolve organization UUID`. + +**Workaround in use today**: a local `deploy-routine-changes` skill (under `.claude/skills/` in the routines repo) drives `RemoteTrigger get/update/create` calls during interactive Claude Code sessions. The interactive harness has the org binding the GHA runner lacks. The fallback is the [`/schedule update`](https://claude.ai/code) CLI flow if `RemoteTrigger` breaks in interactive mode too. + +When Anthropic fixes the OAuth token to carry org UUID, the workflow can be restored. Until then, deploys are manual + interactive. + +## What routines do NOT do + +| Won't | Why | +| --- | --- | +| Merge any PR | Same merge prohibition as `/finalize-pr` | +| Open non-draft PRs | Human review is always the gate | +| Cross org boundaries | Owner derived from current config only | +| Touch archived or fork repos | `gh search` filters them out | +| Run during incidents | No event-driven escape hatch — wait for next cron tick | + +## Where this fits relative to ai-workflows + +| If you want… | Use… | +| --- | --- | +| A PR draft within minutes of opening an issue | `ai-workflows/issue-resolver.yml` event-triggered caller | +| A daily sweep that catches issues the event flow missed | `claude-code-routines` Issue Solver | +| To audit health across the whole org | `claude-code-routines` Sentinel + Weekly Scorecard | +| To fix CI failure on a PR you're iterating on right now | `/ship` from a local Claude Code session | + +The two systems are complementary — ai-workflows handles the per-event reaction, claude-code-routines handles the org-wide sweep. + +## Where to go next + + + + The six prompt files, schedule manifest, deploy notes. + + + Operator setup — env vars, Slack MCP, token strategy. + + + The event-driven half of the same ecosystem. + + + The per-repo cloud flow that runs in parallel. + + diff --git a/automation/scheduled-routines/overview.mdx b/automation/scheduled-routines/overview.mdx new file mode 100644 index 0000000..db988b0 --- /dev/null +++ b/automation/scheduled-routines/overview.mdx @@ -0,0 +1,38 @@ +--- +title: "Scheduled routines" +description: "Cron-driven Claude Code sessions that watch the whole org. Pick up loose ends the event-triggered pipeline misses." +tier: 1 +--- + +> Time in (cron). Org-wide scan out. One configuration, every repo under `$GH_OWNER`, no per-repo wiring. + +Scheduled routines are the **cron-driven** half of the automation surface. The event-triggered cloud pipelines react to things that already happened in a single repo; the routines run on a schedule, scan the whole org, and pick up loose ends — stale READMEs, missing `.gitignore` rules, unresolved review threads, weekly summaries — that nothing else watches for. + +The event-driven sibling is documented under [Cloud pipelines](/automation/cloud-pipelines/overview). + +## What runs on a schedule + +The routines live in [`JacobPEvans/claude-code-routines`](/automation/scheduled-routines/claude-code-routines) as a small set of prompt files. Each one runs inside Anthropic's cloud-hosted Claude Code sandbox on its own schedule, discovers repos via `gh search`, does its work using `gh` CLI calls, and reports results to Slack. + +There is no per-repo wiring. Add a repo to the org and the routines pick it up on the next scheduled run. + +## How the install is managed + +The local Claude Code that runs these routines is configured declaratively in Nix via [`dryvist/nix-claude-code`](/nix/nix-claude-code) — plugins, marketplaces, skills, hooks, MCP servers, and permissions as composable home-manager modules. Reproducible across machines, rolled back with one command. + +## Where to go next + + + + The routine catalog, schedules, and operator setup. + + + Declarative Claude Code via home-manager modules. How the routine host stays reproducible. + + + The event-triggered sibling that handles per-repo issues and CI failures. + + + Where routines fit relative to the rest of the issue-to-PR flow. + + diff --git a/docs.json b/docs.json index 5b4addd..e9fdbfc 100644 --- a/docs.json +++ b/docs.json @@ -122,6 +122,7 @@ "nix/nix-home", "nix/nix-ai", "nix/nix-devenv", + "nix/nix-claude-code", "nix/package-placement" ] }, @@ -131,7 +132,36 @@ "ai-development/overview", "ai-development/repo-boundaries", "ai-development/ai-assistant-instructions", - "ai-development/claude-code-plugins" + "ai-development/claude-code-plugins", + { + "group": "Skills", + "pages": [ + "ai-development/skills/overview", + "ai-development/skills/ship-and-finalize", + "ai-development/skills/codeql-resolution" + ] + } + ] + }, + { + "group": "Automation", + "pages": [ + "automation/overview", + "automation/issue-to-pr-pipeline", + { + "group": "Cloud pipelines", + "pages": [ + "automation/cloud-pipelines/overview", + "automation/cloud-pipelines/ai-workflows" + ] + }, + { + "group": "Scheduled routines", + "pages": [ + "automation/scheduled-routines/overview", + "automation/scheduled-routines/claude-code-routines" + ] + } ] }, { diff --git a/nix/nix-claude-code.mdx b/nix/nix-claude-code.mdx new file mode 100644 index 0000000..e12d7c5 --- /dev/null +++ b/nix/nix-claude-code.mdx @@ -0,0 +1,79 @@ +--- +title: "Declarative Claude Code" +description: "Claude Code as composable home-manager modules. Plugins, marketplaces, skills, hooks, MCP, and permissions declared in Nix and rolled back atomically." +tier: 2 +--- + +import { RepoMeta, RepoFit } from "/snippets/repo-summary.mdx"; + +> Declare the Claude Code you want. Apply. Roll it back with one command. Reproduce it on every machine. + + + +`nix-claude-code` ships [Claude Code](https://www.anthropic.com/claude-code) as composable home-manager modules. Marketplaces, plugins, statusline themes, hooks, MCP servers, and permission rules are all declared as Nix data — version-pinned in `flake.lock`, atomically rolled back with `darwin-rebuild --rollback`, identical across macOS and Linux. + +## What you get + +- **Every marketplace, wired up.** Anthropic's official marketplaces (`claude-plugins-official`, `anthropic-agent-skills`) plus 15+ curated community marketplaces, refreshing automatically. +- **Plugins as data.** Every plugin you enable lands in `programs.claude.enabledPlugins`, pinned by `flake.lock`, rolled back with the rest of your generation. +- **Permissions you can read.** Auto-approved tools, deny lists, and the WebFetch allowlist as structured Nix data — the same data feeds Codex, Gemini, and any other AI agent you wire up. +- **Statusline themes.** Pick `powerline`, `ccstatusline`, or `daniel3303` with a single option. +- **MCP plumbing.** Surface `programs.claude.mcpServers` from your favorite MCP runtime; they wire into Claude's `settings.json` exactly as the [official plugin reference](https://code.claude.com/docs/en/plugins-reference) specifies. +- **Built on Anthropic's spec.** Reads `.claude-plugin/marketplace.json` and `.claude-plugin/plugin.json` per the upstream contract — no proprietary formats. + +## How it fits + +| Feeds into | Consumes | +| --- | --- | +| [User environment](/nix/nix-home) (home.packages), [AI tooling](/nix/nix-ai) overlay, scheduled-routine host | [ai-assistant-instructions](/ai-development/ai-assistant-instructions) rule set, [claude-code-plugins](/ai-development/claude-code-plugins) marketplace | + + +The declarative path to a Claude Code install. If you want a single fully-configured Claude Code that survives a workstation wipe, this is the layer that produces it. + + +The four-repo Nix split each owns a slice of the install: + +- [`nix-darwin`](/nix/nix-darwin) — system layer (macOS, Homebrew, security) +- [`nix-home`](/nix/nix-home) — user dev environment (shell, git, linters, credentials) +- [`nix-ai`](/nix/nix-ai) — AI tool ecosystem (Claude Code binary, Gemini CLI, MCP servers, MLX modules) +- [`nix-devenv`](/nix/nix-devenv) — reusable per-language project shells +- **`nix-claude-code` (this page)** — declarative Claude Code *configuration* on top of the binary that `nix-ai` packages + +`nix-ai` answers "where does the Claude Code binary come from?"; `nix-claude-code` answers "which plugins, hooks, MCP servers, and permissions should it have when it starts?". + +## Getting started + + + + Add `nix-claude-code.url = "github:dryvist/nix-claude-code"` to your flake `inputs`. Set `nix-claude-code.inputs.nixpkgs.follows = "nixpkgs"` and the same for `home-manager` so versions stay aligned. + + + `nix flake init -t github:dryvist/nix-claude-code#minimal` (or `#flake-parts` if you already use flake-parts). The minimal template is the fastest way to see the wiring. + + + Set `programs.claude.enabledPlugins`, `programs.claude.mcpServers`, and `programs.claude.permissions` in your home-manager config. Run `home-manager switch` or `darwin-rebuild switch`. + + + `darwin-rebuild --rollback` (or the home-manager equivalent) reverts the entire Claude Code install — plugin set, permissions, hooks, MCP wiring — to the previous generation in one command. + + + +## Where to go next + + + + The binary layer this configures. + + + Where the home-manager modules attach to your user env. + + + The marketplace this can install plugins from. + + + The cloud cron sibling that uses the same Claude Code install pattern. + + + Modules, templates, full README. + + diff --git a/security/scrubbed-values.mdx b/security/scrubbed-values.mdx index 41b0b56..92e0ab0 100644 --- a/security/scrubbed-values.mdx +++ b/security/scrubbed-values.mdx @@ -22,6 +22,14 @@ tier: 2 Never write a real value even in a "wrong" example — the example becomes committed text. Use `${USER}`, `${REPO_ROOT}`, `${MAINTAINER_EMAIL}`, `${NAS_HOST}`, `` for shape stand-ins where the placeholder needs to look like a variable. +## Cost and subscription references + +The same posture applies to monetary costs and subscription tiers. + +- **Never name a specific AI subscription tier** (`Claude Max`, `ChatGPT Pro`, `GitHub Copilot Business`). Marketing tiers change names; the broadcast of personal-spend decisions has no business in public docs. Use the generic noun — `Claude subscription`, `ChatGPT subscription`, `Copilot subscription` — and describe the *mechanism* (`included monthly automation credits`, `metered API usage`) if it matters. +- **Never state a monetary cost as `$N/day`.** The canonical unit on this site is monthly, with the per-instance figure and the instances-per-month count visible so the math is reviewable: `~$X per instance × ~Y instances/month ≈ ~$Z/month`. If you do not know the instance frequency, say `a small fixed monthly cost` instead of inventing one. +- Schedule frequencies (`2×/day`, `weekly`) and rate limits (`5 attempts per PR per day`) are not costs and stay as-is. + ## Portable path references **Never commit absolute user paths** (`/Users/{username}/*`, `/home/{username}/*`, `$HOME/*`, `~/*`). diff --git a/tools/automation.mdx b/tools/automation.mdx index 9591952..3f28cbd 100644 --- a/tools/automation.mdx +++ b/tools/automation.mdx @@ -77,4 +77,10 @@ These five skills are filed as GitHub issues and tracked in the `enhancement` + The broader plugin ecosystem this skill draws from. + + The other half of the automation story — the issue → mergeable PR pipeline that runs across every JacobPEvans repo. + + + The Claude Code skill that takes a PR through CI, CodeQL, threads, and the final merge gate. +