Imported from dryvist/ai-workflows (
AGENTS.md). Install upstream withnpx skills add dryvist/ai-workflows. Copyright stays with the author.
ai-workflows
Reusable AI agent workflows for GitHub Actions. Consumer repos call these with thin ~10-20 line callers.
Architecture
This repo is the single source of truth for CI/CD automation workflows.
Each workflow is a GitHub reusable workflow (on: workflow_call) that consumer
repos invoke via uses: dryvist/ai-workflows/.github/workflows/<name>.yml@main.
Directory Structure
.github/
prompts/
*.md # Prompt files (one per workflow)
scripts/
render-prompt.sh # Shared: envsubst + GITHUB_OUTPUT
best-practices/ # Extracted JS scripts per workflow
ci-fail-issue/
ci-fix/
dep-review/
issue-backlog-sweep/
issue-linker/
issue-resolver/
post-merge-docs-review/
post-merge-tests/
pr-agent/
release-notes/
review-thread-resolver/
shared/
verification/
workflows/
*.yml # Pure YAML workflow definitions (no embedded content)
Workflow Types
There are three families, and they do not share a credential contract:
- Agentic workflows use the shared
run-ai-agentadapter, which selects Claude or Codex fromGH_ACTION_AI_AGENTand defaults to Claude. These are the workflows that edit a tree and open a pull request. pr-agent.ymlruns PR-Agent against the model router for PR-scoped review, code suggestions and descriptions. Its prompts live in the consumer repository's own.pr_agent.toml; see docs/pr-agent.md.- Router workflows (
thread-triage,docs-drift,repo-hygiene-digest) make one chat completion withactions/ai-inference(a.prompt.ymlbeside the workflow's scripts holds the messages and, where the answer is JSON, the schema). They takeLLM_ROUTER_BASE_URLandLLM_ROUTER_API_KEY— both secrets — and default to aself-hostedrunner, because only such a runner reaches the router.
A router workflow that cannot reach the router FAILS, releasing the runner:
the action's client retries a connection failure or 5xx twice and gives up,
and the job is capped at ten minutes. CI never waits for a model beyond that;
the router role's own fallback chain absorbs load. pr-agent picks the
router key and role by repository visibility
(LLM_ROUTER_OSS_API_KEY + oss_model on an open-source repo); every review
still runs on the self-hosted pool against the router. Never restore a
skip-and-succeed path: a green check that did no work is what these replaced.
Non-AI utility workflows (ci-fail-issue, review-thread-resolver) use plain
actions/github-script — see docs/PATTERNS.md "Non-AI Utility Workflow
Pattern".
- Prompts rendered via
render-prompt.sh+ step output (envsubst) - Static prompts: most workflows
- Dynamic prompts (ci-fix, post-merge-tests, post-merge-docs-review):
render-prompt.shwith named env vars - Write workflows (code-simplifier, next-steps, post-merge-*, ci-fix,
issue-resolver, pr-review-responder): the selected agent only edits files and
writes typed handoffs (no git or GitHub mutations). A fresh publisher job
lands a GitHub-VERIFIED commit/PR via
createCommitOnBranch(sharedscripts/shared/verified-commit.js). This is mandatory — nativeuse_commit_signingcannot target a branch on our workflow_run/issues/schedule/dispatch triggers. See docs/PATTERNS.md "Verified Commit & PR Pattern".
Supported event types: issues, issue_comment, pull_request,
pull_request_review, pull_request_review_comment, workflow_dispatch,
repository_dispatch, schedule, workflow_run. push is NOT supported —
post-merge workflows use the dispatch pattern (see docs/PATTERNS.md).
Bot guard: All agent steps allow the github-actions bot for
dispatch-triggered runs (which set
github.actor to github-actions[bot]). Cost control is handled by
consumer-level daily dispatch limits, not by blocking bots at the workflow
level. See docs/PATTERNS.md for the Bot Guard and AI Dispatch patterns.
AI Provenance: All PR-creating workflows (code-simplifier, next-steps,
post-merge-docs-review, post-merge-tests, issue-resolver) include a
standardized provenance footer in every PR body. See docs/PATTERNS.md for the
AI Provenance Pattern.
Consumer Repo Caller Pattern
name: Issue Sweeper
on:
schedule:
- cron: "0 6 * * 1"
workflow_dispatch:
permissions:
contents: read
issues: write
pull-requests: read
jobs:
sweep:
uses: dryvist/ai-workflows/.github/workflows/issue-sweeper.yml@main
secrets: inherit
Cross-repo Checkout
Workflows check out this repo for scripts and the immutable prompt catalog for prompt assets:
The scripts checkout is pinned to job.workflow_sha, the commit the called
workflow itself was loaded from, at any workflow_call nesting depth. Never
take the ref from an input, and never leave it empty (an empty ref: resolves
to the default branch silently). A dogfood caller in this repository runs on
the pull request's own commit for free. tests/workflow-checkout-ref.test.js
enforces both.
- uses: actions/checkout@v7
with:
repository: dryvist/ai-workflows
ref: ${{ job.workflow_sha }}
sparse-checkout: .github/scripts
path: .ai-workflows
- uses: actions/checkout@v7
with:
repository: dryvist/ai-llm-prompts
ref: 0431be6994d51169b9f705ddeba958eb8a4d0fc4
sparse-checkout: automation/ai-workflows-<name>.md
sparse-checkout-cone-mode: false
path: .ai-llm-prompts
Workflow Authoring Rules
File Format Separation
Never mix programming languages inline within workflow files. Each file must contain a single language:
.ymlfiles contain only YAML (workflow configuration).jsfiles contain only JavaScript- Prompt Markdown lives in
dryvist/ai-llm-prompts; this repo references immutable catalog files .json.templatefiles contain JSON config templates
Inline threshold: Scripts of 5 lines or fewer may be embedded directly in
YAML workflow steps. Scripts exceeding 5 lines must be extracted to a dedicated
file under .github/scripts/ and referenced via the cross-repo checkout
pattern.
Pattern for extracted scripts (actions/github-script):
- uses: actions/github-script@v9
with:
script: |
const run = require('./.ai-workflows/.github/scripts/<dir>/<name>.js');
await run({ github, context, core });
// .github/scripts/<dir>/<name>.js
module.exports = async ({ github, context, core }) => {
// All logic here — one file, one language
};
Pass GitHub Actions expression values (${{ }}) via env: on the step, then
read them with process.env in the script. Never interpolate expressions
inside .js files.
Concurrency
Never use cancel-in-progress: true in AI workflows. Cancelling an
in-progress run wastes tokens — always use cancel-in-progress: false to
queue runs instead.
A caller must not declare a concurrency: block that repeats the reusable
workflow's own group. A caller sharing the exact group produces an opaque
zero-job startup_failure that appears nowhere in the API.
Router workflows group per REPOSITORY, not per pull request: during an outage each waiting job holds a runner slot, and one repository must not be able to park the whole shared pool.
Authentication
Agentic workflows select their implementation with org/repo variable
GH_ACTION_AI_AGENT=claude|codex (default claude). Both agents talk to the
org's model router through the run-ai-agent adapter, which derives the
Messages route (Claude Code) and the Responses route (Codex) from one pair
of secrets: LLM_ROUTER_BASE_URL and LLM_ROUTER_API_KEY, both required. The
base URL is a secret, not a variable — a run log prints each step's
environment verbatim, and these repositories are public. pr-agent.yml and
the router workflows speak the OpenAI protocol to the router with the same
pair.
A model variable (GH_ACTION_AI_MODEL*, GH_ACTION_AI_CODEX_MODEL) names a
router role alias, never a vendor model id. GH_ACTION_AI_CODEX_EFFORT and
GH_ACTION_AI_CODEX_VERSION stay optional. See docs/AUTHENTICATION.md.
Agent jobs must not receive a write-capable GitHub token or App token. Publish comments, labels, commits, and PRs deterministically from a fresh job with the minimum required permissions.
Version Tags for Actions
Use version tags (@v7, @v4, @v1) for trusted first-party GitHub actions (actions/*, anthropics/*). SHA pinning is not required for these.
Testing
All JavaScript scripts in .github/scripts/ have unit tests in the tests/ directory.
Run bun test before pushing any changes to scripts.
- Test framework: bun:test (built-in, no external dependencies, no install step)
- Helpers:
tests/helpers.js(shared mock factories for github, context, core) - CI:
.github/workflows/test.ymlruns automatically on PRs touching scripts - E2E:
.github/scripts/verification/e2e-test.sh(manual — creates real GitHub events) - New scripts must include a test file in
tests/; test happy path + key failure modes