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 replies with a triage comment and a label — all through a reviewed, safe-by-default boundary.
It really is a ten-minute win. You write your intent as a short Markdown file, compile it into an ordinary GitHub Actions workflow, and watch a coding agent do a job that used to need a human. Everything here targets gh aw v0.81.6 (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 triage is the canonical first agentic win. It is high-volume, low-stakes (a comment or a label is trivially reversible), and every action stays human-reviewable. 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. Install it, then confirm the version this chapter targets.
Install the extension and check the version
gh extension install github/gh-aw
gh aw version
# → gh aw version v0.81.6
1 · gh aw init — set up the repo once
Run this once per repository. 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 (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 heavily commented template of every frontmatter option.
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.
Compile a single workflow (offline, no secrets)
gh aw compile .github/workflows/repo-assistant-triage.md
Two properties make this the workhorse of the book. First, compilation is offline: it never calls an engine or touches GitHub, so it needs no network and no secrets — which is exactly why every example here is compile-verified. Second, strict mode is on by default. Strict mode does not make you fill in boilerplate; it refuses unsafe choices: top-level write permissions (route writes through safe-outputs: instead), unpinned actions, wildcard network egress, and deprecated fields. Everything else has a safe default — omit engine: and you get Copilot; omit permissions: and the agent is read-only; omit network: and you get a curated egress allowlist (the same one network: defaults selects). So the smallest valid workflow is really just a trigger plus a body, with any writes routed through safe-outputs:. Our example still spells out permissions:, engine:, and network:, because being explicit is clearer in a teaching example. Those guardrails are not friction — they are the safe-by-default posture from Chapter 1, enforced at compile time.
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). Unlike compile, this is a live run: it executes on GitHub's servers against a real repository and needs the engine's secret configured. That is why it is the one step in this chapter the book does not compile-verify.
Manually dispatch the workflow (live run — needs the engine secret)
gh aw run repo-assistant-triage # dispatch it by hand
gh aw run repo-assistant-triage --dry-run # validate without triggering a real run
The engine: Copilot by default
The engine: key selects which coding agent runs the workflow — the “judgment” that reads the issue and decides what to do. gh-aw supports Copilot, Claude, Codex, and Gemini, and Copilot is the default (Engines). If your team already has GitHub Copilot, there is no extra account to set up, which makes it the natural first-workflow engine. You can omit engine: entirely, but a teaching example keeps it explicit so you can see which engine ran.
Selecting the engine in frontmatter
engine: copilot # the default; shown explicitly for clarity
You will go deeper on choosing and configuring engines 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.
A first-workflow safe-outputs block: one comment, one allow-listed label
That is the whole safety story for a first workflow: the worst case is one comment and one label from a fixed list — never a code or settings change. 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 low-stakes and reviewable (a comment or a label, easily undone). Triage hits all three, which is why it is the pattern to start with. Doc nits and stale-issue nudges are close seconds.
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 write permissions 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.
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: a complete, compile-verified Repo Assistant that triages a newly opened issue. It is a single Markdown file — YAML frontmatter on top, a natural-language brief below. It targets gh aw v0.81.6.
examples/ch02/repo-assistant-triage.md — the complete workflow (frontmatter + body)
---
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. Every one is stable in v0.81.6 — no preview fields.
Key
Value
What it does
on
issues: { types: [opened] } + workflow_dispatch
Two triggers: the Repo Assistant wakes when a new issue is opened, and workflow_dispatch also lets you run it by hand to smoke-test it. Chapter 4 covers triggers in depth.
permissions
contents: read, issues: read
A read-only agent. It can read the repo and the issue, but cannot write anything itself.
engine
copilot
The coding agent that does the judgment — GitHub Copilot, the default engine, made explicit.
network
defaults
Explicit here for teaching clarity; if omitted, strict mode applies this same curated egress allowlist. Either way, the agent can only reach approved hosts.
The only writes permitted — at most one comment and one allow-listed label, each applied by a separate scoped job.
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 file to prove it is valid. This is offline — no secrets, no network.
Compiling the example, with the exact successful output (exit code 0)
Zero errors, zero warnings. The compiler wrote repo-assistant-triage.lock.yml next to the Markdown; its metadata records "compiler_version":"v0.81.6", "strict":true, and "agent_id":"copilot", and the agent job's permissions are contents: read — read-only, exactly as declared. The writes live in separate safe-output jobs. You commit both files: the .md you author and the .lock.yml that runs (How They Work).
Run it
The true end-to-end path is simply to push the workflow and open a test issue — it triggers on issues: { types: [opened] }, so the Repo Assistant wakes on its own and replies with a comment and a label. To smoke-test on demand instead, dispatch it manually. This is the live-run step: it runs on GitHub Actions and needs Copilot authentication (the copilot-requests: write permission or a COPILOT_GITHUB_TOKEN secret) configured.
Manually dispatching the Repo Assistant (live run — needs Copilot auth at run time)
gh aw run repo-assistant-triage
When it runs, the Repo Assistant posts something like this on the new issue — a one-line restatement, the category it chose, the details it still needs, and one label:
Illustrative triage comment (the agent's exact wording varies from run to run)
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 CLI version you're on (`repo-assistant --version`)
- a minimal CSV that reproduces it
I've applied the **bug** label so a maintainer can pick it up.
Triage is judgment work — high-volume, low-stakes, reviewable — which makes it the ideal first agentic win.
The authoring loop is init → new → compile → run. You write intent in Markdown; gh aw compile turns it into an Actions workflow.
Two artifacts, one source of truth. The .md is what you edit; the .lock.yml is what runs. Commit both.
Copilot is the default engine. Compiling is offline and free; Copilot authentication (the copilot-requests: write permission or a COPILOT_GITHUB_TOKEN secret) is needed only at run time.
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.