By the end of this chapter you can install the gh aw CLI and ship a working Repo Assistant: an agentic workflow that reads a newly opened issue, decides what kind of issue it is, and requests a triage comment and at most one allowed label — through a reviewable, permission-scoped boundary.
The ten-minute win is a small authoring loop: write your intent as a short Markdown file, compile it into an ordinary GitHub Actions workflow, then try it on a test issue. Have the prerequisites ready first; allow extra time for account setup and the live Actions run. This chapter targets the fixed gh aw v0.88.7 release (Public Preview).
Open your repository's issue tracker. Somewhere in there is a new issue with no label, a vague title, and no reproduction steps — and it has been sitting for a week. Reading it, deciding whether it's a bug, a feature request, or a question, asking for the missing detail, and routing it to the right place is real work. It's just rarely the work that reaches the top of anyone's day.
Triage is judgment work, not a pipeline
Traditional CI/CD is built to “do exactly what you tell them, every time, in the same way” (How They Work). That determinism is exactly what you want for a build or a release. Triaging an issue is the opposite kind of task: there is no lookup table that maps every possible issue to the right response. You have to infer intent from unstructured prose and pick a context-dependent action. That is judgment work — the kind of task “where exact reproducibility doesn't matter, such as triaging issues, drafting documentation, researching dependencies, or proposing code improvements for human review” (FAQ).
That is why carefully scoped triage can be a strong first agentic win. It is high-volume judgment work with reviewable outputs. Comments and labels are manageable first operations when both the information involved and their downstream effects are low-risk; editing or deleting them does not undo information disclosure or consequences already set in motion. GitHub Next even names the pattern: Continuous Triage — “label, summarize, and respond to issues using natural language” (Continuous AI). And it is additive: agentic workflows sit alongside your deterministic pipelines, which do not change at all (FAQ).
Meet the overnight teammate
Picture a tireless teammate who owns exactly one small, recurring job. It wakes on an event, does that job, proposes the result for your review, and goes back to sleep. That is the mental model for an agentic workflow — and it is the book's running example, the Repo Assistant. It is modeled on GitHub Next's real “Repo Assist,” a repository assistant that labels issues, answers questions, and proposes fixes “all while the maintainer stays in control through pull request review” (Continuous AI).
One workflow equals one teammate equals one job. That is deliberate: it is not a general chatbot you prompt ad hoc, and it is not an unsupervised autonomous agent. It is a standing, event-driven task-owner that proposes rather than acts with free rein.
Where this sits in the outer loop
As Chapter 1 established, the inner loop is the fast, interactive coding you do in your editor; the outer loop is your repository's ongoing collaborative life — issues, PRs, reviews, releases — that keeps moving after you close the laptop. Continuous AI applies AI to that outer loop the way CI/CD automated integration and deployment, and gh-aw is how you do it. Your first workflow is simply the smallest slice of that loop: one new issue, triaged.
The gh aw CLI turns that overnight-teammate idea into four small steps: init the repo once, new to scaffold a workflow, compile your Markdown into a real Actions workflow, and run it. You author intent in Markdown; the compiler produces the reviewable YAML that actually executes.
Install and verify
gh aw is a GitHub CLI extension. Choose the compiler version before starting the authoring loop so you can reproduce the chapter's checks. If you already have the extension, check gh aw version first and reuse it only if it reports exactly v0.88.7. A mismatched installation must not silently become this exercise's compiler.
Pinned extension route — install in a fresh, dedicated CLI environment with no existing gh-aw extension
gh extension install github/gh-aw --pin v0.88.7
gh aw version
The actual version command must print gh aw version v0.88.7. Stop on an installation error or a version mismatch; an unpinned install is not a way to select this chapter's target. If your personal extension is another version, keep it intact and use a dedicated environment or the isolated option below.
Use one invocation throughout. The command blocks below use the verified extension route, gh aw. If you selected isolation, replace that prefix in every command with & $aw — for example, & $aw compile --strict .github/workflows/repo-assistant-triage.md. Do not switch back to gh aw, which still invokes your personal extension.
1 · gh aw init — set up the repo once
Run this once in your practice repository's checkout. It is non-interactive and does not ask for an engine or configure any secrets. It prepares the repo so you can author, compile, and run — for example, marking generated *.lock.yml files in .gitattributes and adding helper skills and editor settings (v0.88.7 CLI Commands).
One-time repository setup
gh aw init
2 · gh aw new — scaffold a workflow
gh aw new <workflow-id> creates a single Markdown workflow at .github/workflows/<workflow-id>.md, pre-populated with a commented starter template (CLI Commands).
Create a new workflow file
gh aw new repo-assistant-triage
# creates .github/workflows/repo-assistant-triage.md
3 · gh aw compile — Markdown becomes a workflow
Compilation is the heart of the loop. gh aw compile turns each <file>.md into the GitHub Actions lock file that actually runs, <file>.lock.yml. With no argument it compiles every workflow in .github/workflows/. You never hand-edit the lock file — you change the Markdown and recompile.
Strictly compile the saved workflow — no engine secret required
gh aw compile --strict .github/workflows/repo-assistant-triage.md
Compilation invokes no model or coding engine and needs no engine secret. That makes it a useful check before spending inference credits, but not an offline guarantee. Dependency and ref resolution can access the network or GitHub, using GitHub authentication where needed. The compiler writes the adjacent lock and can also create pin caches such as .github/aw/actions-lock.json and update .gitattributes. Review those generated changes too (Compilation Process).
Strict mode is on by default. Passing --strict makes the security gate explicit, even if a workflow tries to opt out. It enforces action pinning and network constraints and refuses repository-write permissions for the agent; route those writes through safe-outputs: instead. These are checks on the declared execution boundary, not proof that the agent's judgment will be correct (target compiler).
Omit engine: and you get Copilot; omit permissions: and the agent's repository access is read-only; omit network: and you get the curated default egress policy. Our example spells out all three and explicitly bounds its safe outputs, because the safe-by-default posture from Chapter 1 should be visible in the source you review.
The result is inspectable orchestration, not deterministic inference. At run time, both the main agent and the default threat detector perform AI reasoning. Chapter 3 opens the generated graph; Chapter 7 explains the detection boundary (Threat Detection).
4 · gh aw run — trigger it on GitHub
gh aw run dispatches a compiled workflow on GitHub Actions using its workflow_dispatch trigger — so a workflow must declare one to be runnable this way (ours does). This is a live run, not a compilation check: it needs the deployed lock, permission to dispatch Actions, and working engine authentication. The unchanged sample uses the PAT path described below; no live run was performed for this chapter's target evidence (CLI Commands).
Manually dispatch the deployed workflow — live run, needs the sample's Copilot PAT
gh aw run repo-assistant-triage
For a non-executing dispatch check, use gh aw run repo-assistant-triage --dry-run. It does not trigger a workflow or call the engine, but can still query GitHub; it is not a test of provider access or issue-triage behavior.
The engine: Copilot by default
The engine: key selects which coding agent does the judgment work: reading the issue and deciding what to request. The target's built-ins are Copilot, Claude, Codex, Gemini, and Pi, and Copilot is the default (Engines). Copilot is a natural starting point for an eligible Copilot user, but you still need to configure runtime authentication. You can omit engine:; this example keeps the selection visible.
Frontmatter excerpt from examples/ch02/repo-assistant-triage.md — not a standalone workflow
engine: copilot
The task's intent is portable, but changing engines also means reviewing authentication, tool enforcement, model availability, and network paths — not merely changing a key and a secret. You will go deeper in Engines (Chapter 5).
First look: safe-outputs
Here is the piece that makes an overnight teammate safe to trust. The agent step runs read-only. Anything it wants to change — post a comment, add a label — it requests as structured output, and a separate, permission-scoped job validates and applies it. The agent proposes; a mediated boundary disposes.
Frontmatter excerpt from examples/ch02/repo-assistant-triage.md — at most one comment and one allow-listed label, not a standalone workflow
This bounds the authorized triage operations to a comment and a label from a fixed list, rather than code or settings changes. It does not guarantee a correct or harmless comment, or require a human to approve it before posting: reviewable is not the same as pre-approved by a maintainer. This is a first look only; the full mechanism (sanitization, per-operation caps, targets, staged mode) is the subject of Safe Outputs (Chapter 6), and the threat model behind it is Defense in Depth (Chapter 7).
A good first workflow shares three traits: the task is judgment work (there is no exact rule to follow), it is high-volume and recurring (so throughput matters), and every action is reviewable and low-risk in context (consider both the information it may disclose and the downstream effects it may trigger). Choose a practice repository where triage meets all three, and comments and labels make manageable first operations. Doc nits and stale-issue nudges are close seconds under the same conditions.
When to wait
Agentic workflows are additive, not universal. Reach for something else when:
The task must be exactly reproducible. Builds, tests, and releases must do the same thing every time — keep those as deterministic CI/CD. Agentic workflows augment those pipelines; they do not replace them.
The action is high-stakes or hard to reverse without review — publishing a release, deleting data, force-pushing. If a mistake cannot be shrugged off, it is not a first workflow.
You would have to grant broad repository-write permissions to the agent to make it work. In strict mode that fails to compile — and it is usually a sign the scope is wrong, not that the guardrail is. Do not confuse those permissions with the separate copilot-requests billing scope.
One workflow is trying to do everything. Prefer one teammate, one job. Start with one or two workflows and expand as patterns emerge (FAQ).
The outcome must be correct 100% of the time with no human in the loop. The value here is throughput on reviewable proposals, not unsupervised perfection.
Here is the whole thing: the unchanged Repo Assistant source that passed the gh aw v0.88.7 strict-compilation preflight. It is a single Markdown file — YAML frontmatter on top, a natural-language brief below. Save this complete file as .github/workflows/repo-assistant-triage.md in your practice checkout, replacing the starter template. The examples/ path is the book's source location, not where Actions discovers deployed workflows.
examples/ch02/repo-assistant-triage.md — complete, unchanged workflow (frontmatter + body); live execution needs Copilot PAT authentication
---
on:
issues:
types: [opened]
workflow_dispatch:
permissions:
contents: read
issues: read
engine: copilot
network: defaults
safe-outputs:
add-comment:
max: 1
add-labels:
allowed: [bug, enhancement, question, documentation]
max: 1
---
# Repo Assistant — triage a new issue
You are the **Repo Assistant**. A new issue was just opened in this repository.
Read the triggering issue's title and body, then triage it:
1. Decide what kind of issue it is (a bug report, a feature request, a question,
or a documentation gap) and how a maintainer should treat it.
2. Post **one** short, friendly triage comment that (a) restates the request in a
sentence, (b) names the category you chose and why, and (c) lists any missing
information the reporter should add.
3. Apply **at most one** label from the allowed set that best matches the issue.
If the issue is empty or too vague to categorize, post a comment asking for the
missing details and do not apply a label.
This workflow demonstrates **safe-outputs**: the agent runs read-only and never
writes to GitHub directly — it *requests* a comment and a label, which gh-aw
applies from separate, permission-scoped jobs.
Reading the frontmatter
Five keys, each doing one job. These fields compile under v0.88.7 strict mode; the example needs no experimental opt-ins.
Key
Value
What it does
on
issues: { types: [opened] } + workflow_dispatch
The issue event supplies the title, body, and issue target. Manual dispatch permits a smoke test but is not an issue-opened event. Chapter 4 covers triggers in depth.
permissions
contents: read, issues: read
Read-only repository authority. The agent can read the repo and issue, but holds no direct repository-write permission.
engine
copilot
The coding agent that does the judgment — GitHub Copilot, the default engine, made explicit.
network
defaults
Explicit here for teaching clarity; omission selects the same curated default agent-egress policy. This runtime policy is not a claim that compilation is offline.
At most one triage comment and one allow-listed label, applied outside the agent by permission-scoped jobs. The allowlist does not create missing labels.
The body underneath is just the brief you would give a new teammate: who they are, what to read, and the three steps to take — with an explicit fallback for an empty issue. That prose is the editable source of truth; the agent reads it at run time.
Compile it
Compile the deployment copy in your practice checkout with the version you verified above. No engine secret is needed; keep --strict and inspect both diagnostics and the generated lock.
Compile the complete workflow saved under .github/workflows
gh aw compile --strict .github/workflows/repo-assistant-triage.md
The preflight compiled an isolated copy, emitted a nonempty lock, and reported no warnings. It also printed an informational org-billing tip: declaring permissions.copilot-requests: write would select a different authentication path, subject to org policy. The tip did not change the source or validate billing. The displayed path and size belong to that captured fixture, not a universal output-size promise.
Target lock inspection records "schema_version":"v4", "compiler_version":"v0.88.7", "strict":true, "agent_id":"copilot", and "engine_versions":{"copilot":"1.0.80"}. The source has not changed, but compiler defaults, dependency pins, and generated job contents have. Read the emitted permissions and mediated-write jobs rather than reusing an old lock. In your practice repository, commit both the .md you author and the regenerated .lock.yml that runs, reviewing generated setup and pin-cache changes alongside them (Compilation Process).
Evidence boundary: this is compilation evidence, not a successful deployment. No engine request, billing transaction, live issue output, or run latency was measured. Optional scanners and Docker image validation were not covered.
Run it
The end-to-end test is to deploy the workflow and open a test issue. Before this live step:
Configure the sample's PAT path. Create a fine-grained PAT owned by your user account with Account permissions → Copilot Requests: Read and an eligible Copilot entitlement. In the practice repository, use Settings → Secrets and variables → Actions to add it as COPILOT_GITHUB_TOKEN. Keep its value out of the Markdown and commit history (Authentication).
Confirm Issues and Actions are enabled, and that the labels bug, enhancement, question, and documentation already exist. This source only permits choosing from them; it does not enable label creation (Safe Outputs).
Review and push the Markdown and its freshly compiled lock under .github/workflows/, landing them on the practice repository's default branch through your normal review process.
Open a small test issue with an account permitted to trigger the workflow, then inspect its Actions run and any resulting comment and label. That event supplies the issue this brief expects. To smoke-test dispatch on demand instead, use the CLI from the same practice checkout:
Instructional live command — requires the deployed lock and Copilot PAT; not executed for this chapter
gh aw run repo-assistant-triage
For a test issue about a CSV-export bug, the intended result might look like this: a short restatement, the chosen category, missing details, and an allowed label. This is instructional, not a captured issue comment or evidence that a label was applied:
Illustrative triage outcome — no live run was performed; wording and categorization can vary
Thanks for the report! This reads as a **bug**: the exporter drops the last
row of large CSV files. To dig in, I'd need two more details:
- the exporter version you're using
- a minimal CSV that reproduces it
I've applied the **bug** label so a maintainer can pick it up.
You have the path from intent to a compiled Repo Assistant; deploying and observing an issue-triggered run completes the win. To recap:
Triage is judgment work — a strong first agentic win when the selected information and downstream effects are low-risk and the outputs remain reviewable.
The authoring loop is init → new → compile → run. Select and verify the fixed compiler first, and keep using that executable throughout.
Two artifacts, one source of truth. The .md is what you edit; the .lock.yml is what runs. Commit both.
Strict compilation is not inference. It needs no engine secret, but can access the network and write generated artifacts. Optional validation, scanners, and live execution are separate checks.
Copilot is the default engine. This unchanged recipe needs COPILOT_GITHUB_TOKEN and an eligible entitlement for a live run. Org billing requires explicit workflow permission, enabled org policy, and a deployed recompiled lock — not just a compiler PASS.
Safe by default. The agent is read-only; every write goes through safe-outputs — for a first workflow, one comment and one allow-listed label.
What's next. You have seen the loop from the outside. Anatomy & the Compile Model (Chapter 3) opens the hood: what the frontmatter really means, and what gh aw compile generates inside that .lock.yml. If you skipped the framing, revisit Chapter 1 for the outer loop and Continuous AI.