chapter: 05·part: The Individual (one workflow)

Engines: Choosing the Agent's Brain

Select and configure Copilot, Claude, Codex, Gemini, or Pi, control CLI/model selection, and distinguish portable intent from engine-specific runtime requirements.

Objective

By the end of this chapter you can select and configure one of gh-aw's five built-in engines, control its CLI version and model selection, and distinguish portable workflow intent from engine-specific runtime requirements.

This chapter targets the inspected gh aw v0.88.7 (fixed release). We keep the Repo Assistant's triage mission and its existing Claude example, then examine what swapping its brain does — and does not — preserve.

Concept: engine-neutral by design

A workflow has two separable parts: what you want done (the Markdown intent and the safe-outputs boundary) and who does the thinking (the coding-agent CLI and the model it invokes). gh-aw keeps these apart on purpose. The engine is a pluggable component, so you can reuse the task and governed-output pattern without tying them to a vendor's API.

Why decouple the brain?

Tying automation to one vendor's model is a bet you might regret. Prices change, your org standardizes on a provider you already pay for, or a model you depend on is deprecated. Keeping the task separate reduces the rewrite. But portable intent is not an interchangeable security contract: changing engines may require different authentication, tools, model names, and network access (AI Engines at v0.88.7).

This is the same “prose is the source” idea from Chapter 3, viewed from the other side. Your intent can survive a change of engine, while you recompile and review the runtime that implements it. The event-driven mission from Chapter 4 need not change just because the agent does.

Keep three choices separate: the engine supplies the tool-using agent, its CLI version is an executable dependency, and its model supplies inference. The version and model settings let you control these independently. Pinning a CLI reduces dependency drift; controlling model selection makes comparisons more meaningful. Neither makes inference deterministic. Cost also has separate scopes: main-agent inference, threat detection, and Actions compute are not one budget (billing; detection budget).

In gh-aw: the engine: field and its options

The engine: frontmatter field implements that separation of portable intent from execution: it selects the coding agent that interprets your Markdown. Copilot is the default, so its selection can be omitted (built-in engines).

Frontmatter excerpt — the selection used in Chapter 2's complete triage source
engine: copilot

The five built-in engines

The target lists Copilot, Claude, Codex, Gemini, and Pi as built-ins. Authentication below is for inference, not permission to write to the repository. Store static keys as Actions secrets, never literal values in a workflow (authentication).

v0.88.7 built-ins: standard live-run authentication paths and compiled CLI defaults before overrides
Engineengine:Inference authenticationCLI default
GitHub Copilot CLI (default)copilotOrg-billed Actions token with copilot-requests: write, or COPILOT_GITHUB_TOKEN1.0.80
Claude Code (Anthropic)claudeANTHROPIC_API_KEY or Anthropic WIF2.1.247
OpenAI CodexcodexCODEX_API_KEY or OPENAI_API_KEY; the former takes precedence when both are present0.150.1
Google Gemini CLIgeminiGEMINI_API_KEY or Google WIF0.55.1
PipiCopilot authentication by default; provider-specific key for an Anthropic or OpenAI/Codex model0.84.3

These versions come from the target's version constants and compiled defaults, not a live query for the newest CLI releases.

OpenCode, Aider, Crush, Cursor, DeepSeek Harness, Kiro, and Pydantic AI integrations are unsupported samples, with no gh-aw compatibility or maintenance commitment. Other integrations need an owner-maintained definition imported at a pinned tag or commit, and object-form engine.id matching that definition. There is no arbitrary scalar engine: custom. Treat such imports as dependencies to review, as in Chapter 11 (imported-engine contract).

The object form: version and model

When you need more than the default, engine: becomes an object. Its version selects a CLI release; its model selects the model for that engine. They control different sources of change:

Frontmatter excerpt from examples/ch05/repo-assistant-claude.md — the existing CLI and model pins, unchanged
engine:
  id: claude
  version: "2.1.70"
  model: claude-sonnet-4.5

Omitted version does not mean “always install latest.” The table records compiler defaults; Copilot's target installer can also select a compatible cached CLI at runtime before using its fallback. An explicit engine.version overrides that selection, an expression-backed version resolves at runtime, and a custom engine.command can bypass normal CLI installation. Review the generated install steps and runtime inputs, not just the metadata (target installation logic; version configuration).

Use deliberate dependency updates rather than version: latest. The explicit Claude 2.1.70 pin still compiles on v0.88.7 and is retained here; that is not an endorsement that it is the best operational pin today. Pinning improves repeatability, but does not by itself certify supply-chain safety or model availability.

Top-level model selection and per-engine precedence

The target adds a top-level model field, letting you express model selection alongside a simple engine selection:

Configuration excerpt — top-level model selection, compile-checked in the v0.88.7 model-top-level.md probe; not a complete workflow
engine: copilot
model: auto

engine.model remains valid and wins when both scopes are set. An interim deprecation was reversed: the target restores the per-engine override rather than requiring you to remove it (override restoration).

Configuration excerpt — the v0.88.7 model-precedence.md probe emits claude-sonnet-4.6, not auto; not a complete workflow
model: auto
engine:
  id: copilot
  model: claude-sonnet-4.6

With no explicit Copilot model, the generated fallback is now auto, after configured runtime model variables, rather than v0.81.6's claude-sonnet-4.6 (fallback change; runtime overrides). Automatic selection does not hold the effective model or its cost constant. The probes establish syntax and precedence, not access to a named model or measured performance.

Authentication is part of the engine contract

For Copilot organization billing, your organization needs a Copilot subscription and the policy allowing Copilot CLI usage billed to the organization. You must explicitly declare copilot-requests: write under top-level permissions:, recompile, and deploy the updated lock. The compiler does not add this permission to arbitrary source. In this mode the Actions token authenticates inference and the PAT is ignored for inference; it is not a fallback if org access fails. This permission does not grant repository writes (billing prerequisites).

For the personal/seat path, store a fine-grained PAT in COPILOT_GITHUB_TOKEN: resource owner your user account, account permission Copilot Requests: Read, and an account with Copilot entitlement. GH_AW_GITHUB_TOKEN is a separate GitHub-operations fallback, not a substitute for Copilot inference authentication. Activation rejects OAuth tokens beginning gho_ in either secret; do not reuse an interactive CLI session token. Claude's CLAUDE_CODE_OAUTH_TOKEN is unsupported and ignored, not a substitute for ANTHROPIC_API_KEY (token types and scopes).

For Pi, unprefixed or copilot/ models use Copilot authentication; anthropic/ uses the Anthropic key, and openai/ or codex/ uses the OpenAI/Codex key. But Pi's default threat detector still runs on Copilot, regardless of the main model's provider. The target engine: pi probe passes with a warning: without the org-billing permission, detection needs COPILOT_GITHUB_TOKEN. Another provider's key alone is not enough (Pi detection authentication).

When to pick which engine (capability, cost, availability)

Choose by the task's required capabilities, your approved identity path, and provider access — then evaluate cost. The target feature matrix gives useful starting points, not a quality ranking:

Consider…When…
Copilot (default)you need native custom-agent selection (engine.agent) or continuation mode (max-continuations), and have a working Copilot authentication path.
ClaudeAnthropic is already an approved provider and Claude's tool support fits your task.
CodexOpenAI access fits your tooling or budget, and the workflow does not depend on per-command Bash allowlisting.
GeminiGoogle's identity path fits your organization; per-command Bash restrictions are supported.
Piyou want provider selection behind one CLI and can accommodate proxy-based tools rather than native MCP integration, plus Copilot authentication for the default detector.

Turn limits are not a reason to choose Claude alone. Top-level max-turns is the cross-engine invocation cap enforced by the Agentic Workflow Firewall (AWF) proxy, with a built-in fallback of 500. The deprecated nested engine.max-turns alias is Claude-specific; do not generalize it to other engines. Top-level max-ai-credits also works across engines, with a main-agent fallback of 1000 AIC before overrides. Detection has its own budget, and Actions compute is billed separately: this is not a complete bill cap (scoped defaults; Chapter 13).

When not to fiddle with engines

  • Don't switch without a concrete need. Start with the smallest supported configuration your team can authenticate. Clear instructions and appropriate tools still need attention even when you change the brain.
  • Don't discard enforcement to get a green compile. A strict Codex workflow with a restricted tools.bash command list is rejected because Codex would ignore that restriction at runtime. If the allowlist matters, choose Copilot, Claude, or Gemini; do not remove it or weaken strict mode (engine enforcement matrix; Chapter 8).
  • Don't assume the same YAML means the same runtime. Recheck authentication, tool transport and enforcement, model identifiers, and effective network paths. Keeping network: defaults in the source does not establish equivalent provider access or egress behavior (engine setup contracts).
  • Don't call an engine swap a model experiment. With auto, an unchanged prompt need not use the same model. For a deliberate comparison, select a model your account supports, control the other inputs, and record actual model and usage evidence using Chapter 12. This chapter reports no live model or cost comparison.

Worked example: switching the Repo Assistant's engine

Let's make portable intent concrete. The Claude Repo Assistant carries the same triage mission as Chapter 2: request one comment and at most one allowed label. We retain its task instructions and YAML, including CLI 2.1.70 and model claude-sonnet-4.5. This is an engine-selection illustration, not a controlled same-prompt comparison between engines.

Frontmatter excerpt from examples/ch05/repo-assistant-claude.md — unchanged YAML; prior source verification: strict compilation PASS on v0.88.7 with a restricted-secret review warning; use the complete Markdown source, not this excerpt alone
on:
  issues:
    types: [opened]
  workflow_dispatch:
engine:
  id: claude
  version: "2.1.70"
  model: claude-sonnet-4.5
permissions:
  contents: read
  issues: read
network: defaults
safe-outputs:
  add-comment:
    max: 1
  add-labels:
    allowed: [bug, enhancement, question, documentation]
    max: 1

In the configuration, the scalar engine: copilot becomes the Claude object. The triggers, read-only repository permissions, declared network: defaults, and explicit safe-output limits remain the same. The declared task boundary survives; that does not make the engine's authentication or generated runtime identical.

Reproduce compilation with the fixed v0.88.7 installation from Chapter 2, using a scratch Git checkout so generated locks and compiler side files stay out of your deployment until review:

Reproduction commands — check the installed target, then compile strictly without approving changes
gh aw version
# Expected: gh aw version v0.88.7
gh aw compile examples/ch05/repo-assistant-claude.md --strict --validate --no-check-update

The supplied target verification predates the explanatory-footer correction; the YAML and task instructions are unchanged. That run exited successfully and emitted a lock with compiler_version: v0.88.7, strict: true, Claude CLI 2.1.70, and model claude-sonnet-4.5. It also emitted this warning on stderr, even though the JSON result's warnings array was empty:

Selected stderr excerpt from the v0.88.7 strict + validate run — the warning remains part of the verification result
examples\ch05\repo-assistant-claude.md: warning: safe update mode detected unapproved changes

New restricted secret(s):
  - ANTHROPIC_API_KEY

Recap & what's next

You can now choose and configure the agent's brain with confidence:

  • Intent and the governed-output pattern are portable. Authentication, tool enforcement, network paths, and model behavior still need review when an engine changes.
  • The five target built-ins are Copilot (default), Claude, Codex, Gemini, and Pi. Imported samples have a separate owner-maintained support contract.
  • CLI version and model are different choices. The compiler has version defaults; explicit pins and runtime inputs affect reproducibility. Top-level model is available, engine.model wins per-engine precedence, and omitted Copilot model selection now falls back to auto.
  • Top-level max-turns works across engines; the deprecated nested alias remains Claude-specific. Choose an engine that enforces the restrictions your workflow needs, and budget for detection and Actions separately.
  • The Claude configuration's prior verification passed strict compilation with a secret-review warning. That is evidence of compiler compatibility, not approval of a credential, a model-availability check, or a successful live run.

What's next. That's Part I complete: you can author, compile, trigger, and power a workflow. But so far the Repo Assistant only ever proposed writes through safe-outputs: without our examining how. In Chapter 6: Safe Outputs — the opening of Part II — we open that boundary and see how permission-separated jobs apply the agent's proposed changes.