GitHub Actions integration¶
steer ships a few kinds of GitHub Actions integration. Two are installed by
default — claude.yml (keeps CI Claude consistent with local sessions) and
Dependabot (keeps dependencies patched, and manages the resulting PRs); the last
is an opt-in recipe for unattended automation.
claude.yml — the @claude mention workflow (default)¶
/steer:init and /steer:adopt install .github/workflows/claude.yml (source:
plugins/steer/templates/github/workflows/claude.yml). It runs
anthropics/claude-code-action@v1
when someone mentions @claude on an issue or PR.
Why it loads the steer plugin¶
steer's whole premise is "org standards in every session" — injected by a SessionStart hook the moment the plugin loads. Without extra wiring, the in-CI agent would run as a stock, standards-less Claude: no stack defaults, no Definition of Done, no spec/drift discipline. The shipped workflow closes that gap by loading the plugin in CI through the action's purpose-built inputs:
Once the plugin installs, its SessionStart hook injects rules/* exactly as it
does locally — the in-CI agent and the local agent are governed by the same
rules, with no duplicated system prompt.
settings.json does not work in CI
Do not try to load steer in CI via a .claude/settings.json
enabledPlugins / extraKnownMarketplaces block (the mechanism used for
local sessions). Those are gated behind an interactive trust dialog that
headless/print mode skips, so they load nothing and fail silently
(anthropics/claude-code #13096).
The action's plugins / plugin_marketplaces inputs are the only CI path.
Credentials¶
| Credential | Kind | Required | Purpose |
|---|---|---|---|
ANTHROPIC_API_KEY |
secret | always | Anthropic API auth for the action. A 401 in the log means it is missing, wrong, or mis-scoped. |
STEER_APP_ID / STEER_APP_PRIVATE_KEY |
variable / secret | while the marketplace repo is private | Credentials for a shared GitHub App with read-only access to element22llc/e22-plugins. A product repo's default GITHUB_TOKEN is scoped to that repo only and cannot clone another org repo, so the plugin_marketplaces fetch needs this. The workflow mints a short-lived (1 h, auto-revoked), repo-scoped token via actions/create-github-app-token and rewrites github.com clones to use it. If STEER_APP_ID is unset the steps no-op and the clone goes anonymous (correct once the marketplace is public). |
A GitHub App is used in preference to per-repo personal access tokens: it is one
org-controlled credential, distributed once as an organization variable + secret (so
no per-repo setup), mints short-lived auto-expiring tokens scoped to just the
marketplace repo, and is not tied to a person who might leave. Rotation and
revocation are a single org-level action. The scaffold README.md →
"steer marketplace GitHub App" carries the one-time setup steps for org owners.
Verify by mentioning @claude and confirming the reply reflects steer standards
(e.g. it cites the Definition of Done) — that proves the plugin loaded, not just
that the action ran. The workflow log's system/init event also lists loaded
plugins. See the scaffold README.md → "GitHub Actions secrets" for the
product-repo-facing version of this.
Dependabot — dependency updates + scoped auto-merge (default)¶
/steer:init and /steer:adopt install two files (sources under
plugins/steer/templates/github/):
.github/dependabot.yml— thegithub-actionsecosystem is enabled live (every scaffolded repo ships workflows); thenpm/pip/dockerblocks are commented out for init/adopt to uncomment per detected stack (mirroring howci.ymlgates stack steps). Updates are grouped, and major bumps areignored — they're deferred to a deliberatepolicy/versions.ymldecision..github/workflows/dependabot-auto-merge.yml— auto-approves Dependabot patch/minor PRs, waits for the requiredcicheck, then merges that single PR. Major bumps are never auto-merged; they get a "left for a human" comment.
The review-gate exception¶
steer normally requires a human-approved PR before anything lands on main. The
auto-merge workflow is a deliberate, documented exception: dependency bumps
don't touch application logic, so the human review is waived. It is not a
waiver of the tests — the workflow waits for the required ci check to go green
before it merges, so a bump that breaks tests, lint, or the version-pin scan never
lands. CI, not a human, is what guarantees the bump is safe. The exception is
declared in policy/branch-protection.yml and the scaffold README.md
branch-protection section.
Auto-merge is scoped to Dependabot — no repo-wide switch
The merge is gated by the workflow's if: github.actor == 'dependabot[bot]'
guard and uses a direct single-PR merge. It deliberately does not enable
GitHub's repo-wide allow_auto_merge setting, which would expose an auto-merge
button to every PR. gh pr checks --watch --required watches only required
checks, so the job never deadlocks on its own non-required run.
/steer:protect enables the repo settings the exception relies on — Dependabot
alerts and security updates (so security PRs get opened) — alongside secret
scanning. It configures settings only; the merge itself is enacted by the workflow.
/steer:sync keeps both files wired (the dependency-automation capability).
Production promotion gate¶
Branch protection covers more than the default branch. policy/branch-protection.yml
also describes a long-lived prod branch, and /steer:protect applies
protection to every entry in its protected_branches list, not just main.
This is how the deployment standard enforces its
production gate without GitHub Enterprise. Promotion to production is a reviewed
PR from main into prod; the required-review approval on that PR is the
production approval — it stands in for the deployment-environment approvals that
only GitHub Enterprise provides. Merging the prod PR auto-deploys production, and
nothing is ever pushed to prod directly.
/steer:protect reads protected_branches and configures each branch's rules
(required PR, required ci check, no direct pushes); /steer:sync keeps the
policy file and the protection in step as the plugin evolves. See
Deployment & environments for the full
promotion model.
Agentic workflows (gh aw) — optional, opt-in¶
GitHub Agentic Workflows (gh aw) is a
GitHub Next tool for authoring CI automation as natural-language Markdown that
compiles to a standard Actions .lock.yml. It can run unattended — on
repository events or a schedule, with no @claude mention — something
claude.yml (which only reacts to @claude) and the local skills cannot do.
steer ships one example workflow,
plugins/steer/templates/github/agentic/triage.md (unattended issue triage that
runs when an issue is opened/reopened and classifies it against the steer label
taxonomy and Issue Types). It is not installed by /steer:init or
/steer:adopt and is not in MANIFEST.md — you opt in deliberately.
Why it is not in the default scaffold¶
- gh-aw is a self-described research demonstrator — "not a product, not even a technical preview." Committing it into every product repo would couple steer's deterministic, SHA-pinned, human-gated posture to a preview tool.
- It overlaps with steer's own issue lifecycle.
/steer:issues triage(via/steer:tracker-sync) already triages interactively. Run one of the two, not both, or you double-triage every issue. - It introduces a second agent engine and a manual compile step (
.lock.yml) that the team owns and must keep current (gh aw update).
The recipe¶
- Install the CLI:
gh extension install github/gh-aw. - Copy
plugins/steer/templates/github/agentic/triage.mdinto your repo's.github/workflows/and adapt it. - Compile:
gh aw compile triage.md→ producestriage.lock.yml. - Review the generated lock file before trusting it — confirm the only
write-backs are the declared
safe-outputs(the example is advisory-only: it relabels, sets the Issue Type, and comments, but never closes issues or resolves product/technical questions — those stay human-gated) and confirm every action it references is SHA-pinned (gh-aw pins by default; keep it). - Set
ANTHROPIC_API_KEY(the example uses the Claude engine, consistent with local sessions) and commit both files.
See the authorization model for why the human gate on merge/close/deploy is preserved here.