GitHub Agentic Workflows: Complete Tutorial

Agents, MCP & Agentic DevelopmentAcademy lesson 88Cluster 7 · Lesson 13 of 13Advanced21 min readVersion-sensitive
Published
Updated
Last technically verified
GitHub Agentic Workflows: Complete TutorialAgents, MCP & Agentic Development13Advanced/github-copilot/agents/agentic-workflows/

Every agent in this cluster so far has needed a person to start it. Agentic workflows are the step where that stops being true: a markdown file, compiled into a GitHub Actions workflow, that runs on a schedule or an event and does agentic work without anyone present.

That is a meaningful line to cross, and the design reflects it. Repository permissions are read-only unless you explicitly grant more, and everything the workflow can write is declared up front as a safe output — an issue, a comment, a pull request — rather than being a general ability to act.

How it works

From markdown to a running automation
  1. Write the markdownHuman judgementFrontmatter for configuration, prose for the task.
  2. Compile itgh aw compile produces a .lock.yml under .github/workflows/.
  3. Review the compiled workflowHuman judgementIt is an ordinary Actions workflow. Read it.
  4. Commit both filesHuman judgementSource and lock, so the workflow is reviewable.
  5. It runs on its triggerSchedule, issue event, pull request event.
  6. The agent does the workRead-only repository access unless granted more.
  7. Safe outputs are producedAn issue, a comment, a pull request — validated.
  8. A human reads the resultHuman judgementAnd decides what to do about it.

Steps marked Human judgement are the ones that do not get delegated — they are where you decide whether what Copilot produced is actually right.

The compilation step is the interesting part of the design. You are not writing a prompt that runs directly; you are writing a specification that becomes an ordinary Actions workflow, which you can read, review and reason about like any other file in .github/workflows/.

The file format

Below the frontmatter, ordinary markdown describes the task. That prose is the instruction the agent works from, and everything Cluster 6 says about writing instructions applies — be specific, say what done looks like, state what not to do.

Safe outputs are the whole security model

This is the design decision that makes the feature reasonable, and it is worth understanding rather than merely using.

An unconstrained agent in CI would be an agent with a token, running unattended, able to do whatever that token permits. Safe outputs invert that: the workflow does its work with read-only access, and the specific writes it may produce are declared in advance and validated.

Declared write operations

  • create-issueOpens an issue. Title prefix and labels can be constrained.
  • add-commentComments on the triggering issue or pull request.
  • create-pull-requestProposes changes as a pull request, which a human reviews.
  • update-issueChanges labels or fields on an issue.
  • update-filesWrites files, routed through the declared output rather than a direct push.

Three properties follow, and each is doing real work.

The write path is enumerated. A workflow whose frontmatter declares create-issue can open an issue. It cannot push a commit, close a pull request or change a setting, because those are not among the outputs it declared.

The constraints are structural. A title prefix and a label set are enforced, not requested. An agent that decides a different label would be better cannot apply one.

Reading the frontmatter tells you the blast radius. This is the reviewability property that matters most. You do not have to reason about what the prose might lead the agent to do; you read five lines and know what it can produce.

A first workflow

The best first agentic workflow is a report. Nothing changes, someone reads the result, and the cost of it being wrong is a wasted five minutes.

---
on:
  schedule: weekly
permissions:
  contents: read
  issues: read
engine: copilot
tools:
  - github
safe-outputs:
  create-issue:
    title-prefix: "[docs] "
    labels: [documentation, agent-generated]
---

# Weekly documentation drift check

Compare the reference pages under `docs/reference/` against the code
they describe.

For each page:

1. Identify the module or command it documents.
2. Read that code.
3. List every statement in the page that no longer matches — parameter
   names, defaults, return values, flags, error conditions.

Report only what you verified against the code. If you cannot determine
current behaviour, say so rather than guessing.

## Output

Open one issue summarising the findings. Group by page. For each
finding give the page, the line or section, what the page says, and what
the code says.

If nothing has drifted, open no issue.

Several deliberate choices in that file.

Permissions are read-only. contents: read, issues: read. Nothing else is granted, so nothing else is possible.

One safe output. It can open an issue. That is the entire set of things it can do to your repository.

The label declares provenance. agent-generated tells anyone reading the issue what produced it, which matters when the findings are wrong.

The empty case is stated. “If nothing has drifted, open no issue.” Without this, a weekly workflow produces a weekly issue whether or not there is anything in it, and weekly issues nobody needs are how automation gets muted.

It is told not to guess. The same rule as the documentation agent, for the same reason: an unattended agent has nobody to ask.

A second workflow: triage

Once the report pattern works, event-triggered workflows are the natural next step.

---
on:
  issues:
    types: [opened]
permissions:
  contents: read
  issues: read
engine: copilot
tools:
  - github
safe-outputs:
  add-comment:
  update-issue:
    labels: [needs-info, bug, enhancement, question]
---

# Triage a newly opened issue

Read the issue that triggered this run and the repository's
`triage-conventions` skill.

Decide which single label best fits: `bug`, `enhancement`, `question`,
or `needs-info` when the report is missing what a maintainer would need
to act.

If information is missing, add one comment asking for exactly what is
missing — version, reproduction steps, and observed versus expected
behaviour. Ask only for what is actually absent.

Do not close issues. Do not assign anyone. Do not speculate about
causes.

The label list in safe-outputs is the important line. It is not a suggestion about which labels to use — it is the set of labels this workflow can apply. A workflow that decided wontfix was appropriate has no mechanism to apply it.

The compiled workflow

gh aw compile turns the markdown into a .lock.yml under .github/workflows/. That file is what Actions actually runs.

Read it before committing it. Not once as a curiosity — the first time you compile each workflow. It is an ordinary Actions workflow, and everything you already know about reading those applies: what permissions the job requests, what it checks out, what it runs, what secrets it references.

Commit both files. The markdown is the source; the lock file is what runs. Committing only one leaves you either unable to regenerate or running something nobody wrote.

Recompile after editing. An edited markdown file with a stale lock file produces the confusing situation where the behaviour does not match the source, and nothing warns you.

Review lock file changes in pull requests. A diff to a .lock.yml is a diff to an automation with repository access. It deserves the same attention as any other workflow change.

What to automate

The good candidates share a shape.

Reports. Documentation drift, dependency status, test coverage trends, stale branches, issues with no activity for a quarter. The output is information and nothing more; a human reads it and decides whether anything should happen.

Triage. Labelling, asking for missing detail, routing to the right area. These are bounded decisions with a small set of possible outcomes and a correction that costs one click when it gets one wrong.

Checks that produce a proposal. A workflow that opens a pull request with a suggested fix, which someone reviews before it goes anywhere. The review step is fully intact, so the risk profile is exactly that of any other pull request in your repository — which is a risk profile your team already understands.

Periodic questions nobody remembers to ask. “Which of our dependencies have had a major release since we last looked?” makes a genuinely useful weekly issue, and it is a task no person has ever volunteered for in the history of software.

And the poor candidates.

Anything that lands unattended. A workflow that merges, deploys or publishes is the thing this design’s read-only default exists to discourage.

Anything requiring judgement you have not written down. An unattended agent cannot ask, so it decides, and its decision is the most plausible one rather than yours.

High-frequency triggers on expensive work. Every push is not a good trigger for an agentic run. The cost is real and the value decays quickly with frequency.

Anything where a wrong output is expensive to correct. A wrong issue is noise. A wrong comment on a stranger’s bug report is a small public embarrassment that somebody has to apologise for.

Writing the prose well

The markdown below the frontmatter is an instruction to an agent that cannot ask you anything, running when you are not there. That raises the bar on a few things that are merely nice elsewhere.

Say what done looks like, precisely. A scheduled workflow has no natural stopping point. “List every statement that no longer matches” terminates; “review the documentation” does not.

Give the output a shape. Grouped by page, with the page, the claim and the reality. A specified structure means the output is scannable and comparable week to week, which is what makes a recurring report readable at all.

State the empty case, always. This is the single most important line in a scheduled workflow. Without it you get an issue every week regardless, and a report that fires whether or not it has anything to say is a report people stop opening.

Forbid the adjacent temptations. “Do not close issues. Do not assign anyone. Do not speculate about causes.” Each of those is something an agent might reasonably decide to do while being helpful.

Say what to do when it cannot determine something. Unattended agents cannot ask, so the alternative to an explicit instruction is a confident guess.

Point at repository context rather than restating it. Referencing a skill — “read the repository’s triage-conventions skill” — keeps the workflow short and means the conventions live in one place where they also help humans.

Why this is not just an Actions workflow

The obvious question is what this offers over a normal workflow calling an API, and the answer is narrower than the enthusiasm but real.

An ordinary workflow executes rules you wrote. It is deterministic, cheap and correct within its rules, and it cannot do anything you did not anticipate — which is a strength for most automation and a hard ceiling for some tasks.

The tasks above that ceiling share a shape: they need a judgement that cannot be expressed as a rule. “Does this documentation still describe the code” has no regular expression. “Is this bug report missing what a maintainer would need” is not a schema check. “Which of these dependency updates actually matter to us” depends on how the dependency is used.

That is the category agentic workflows serve, and the boundary is worth respecting in both directions. A linter should stay a linter — replacing a deterministic check with a probabilistic one is a downgrade dressed as progress. But a check nobody has written because it could not be written as rules is a genuine gap, and this is the first mechanism that fills it while remaining reviewable, permission-bounded and visible in the repository like any other automation.

Triggers worth knowing

The on field takes the same triggers an ordinary Actions workflow does, and the choice shapes everything about how the workflow behaves.

Schedules produce reports. Nothing is waiting on the result, the cadence is yours to choose, and the failure mode is an issue nobody reads rather than a blocked contributor.

Issue and pull request events produce responses. Someone is on the other end, which raises the bar: a triage comment arrives while the person who filed the issue is still paying attention, so a wrong or unhelpful one is visible in a way a wrong weekly report is not.

Manual triggers are underrated. A workflow you invoke deliberately gets the benefit of the compiled, reviewed, permission-bounded design without the unattended part, which is a good middle step while you are still calibrating.

The pattern worth avoiding is a high-frequency trigger on expensive work. Every push is technically a trigger; it is almost never a good one, because the value of an agentic check does not scale with how often it runs and the cost does.

Cost and limits

Agentic runs consume inference, and unattended things run more often than attended things.

max-ai-credits caps spend per run, defaulting to 1,000 AI credits. gh aw logs shows recent runs with duration and token usage, and gh aw audit RUN-ID inspects an individual run’s cost. Look at both after the first week — a schedule that seemed reasonable in the abstract sometimes looks different once it has run seven times.

Two habits keep this proportionate.

Prefer weekly to daily, and daily to per-event, unless the frequency is doing real work. Most reporting tasks are just as useful weekly.

Scope the task. “Check the reference documentation” is bounded. “Review the repository” is not, and an unbounded task on a schedule is an unbounded cost on a schedule.

Testing before you schedule it

A workflow on a weekly schedule that turns out to be wrong is wrong seven times before anyone notices the pattern. Test first.

Run it manually. gh aw run executes the workflow without waiting for its trigger. Do this several times before committing to a schedule.

Run it against a repository you can afford to litter. The first run of a triage workflow will label things. Better if those things are in a scratch repository.

Check the output is what you would have written. Not “is it reasonable” — is it the report you actually want, in the shape you want it, at a length you would read? A report that is technically correct and four times too long will be ignored, which is the same outcome as being wrong.

Test the empty case deliberately. Run it against a state where there is genuinely nothing to report. The correct output is nothing at all. If it produces an issue saying everything is fine, that instruction is not landing, and you have just learned it before it filled your issue tracker.

Check the run cost. gh aw logs after a few runs tells you what a run actually costs, which is the number to multiply by your schedule.

Security review

An agentic workflow is automation with repository access that reads untrusted content and produces public output. Each of those deserves a specific check.

The capstone configuration

Putting the cluster together, a repository that has adopted all of it looks like this.

A repository with the full configuration
.github/
├── aw/
│   ├── stale-docs-check.md      weekly report, one safe output
│   └── triage-new-issues.md     event-triggered, narrow labels
├── agents/
│   ├── reviewer.agent.md        read-only, team-specific checks
│   ├── docs.agent.md            markdown only, no shell
│   └── infra.agent.md           validates, never applies
├── skills/
│   ├── api-testing/             how this project tests endpoints
│   ├── review-checklist/        order of attention in review
│   └── triage-conventions/      how issues get labelled
├── copilot-instructions.md      rules for every request
└── mcp.json                     shared servers, no credentials

Read that tree as a set of answers to different questions.

Instructions answer how do we work here — the rules that hold whoever is working and whatever they are using.

Skills answer how is this job done — procedures available to any agent, and to any person.

Agents answer who is working and what may they touch — roles with tool boundaries.

MCP configuration answers what can they reach — enumerated, credential-free, reviewed.

Workflows answer what happens without us — read-only, with an enumerated write path.

Notice also that every file is committed. All of it is reviewable, versioned and visible in a pull request, which means the configuration of your automation gets the same treatment as your code. A team that arrives at this tree gradually, reviewing each addition, ends up somewhere very different from one that copies it in a single commit.

Rolling it out

The pattern that works is the same one from the rest of this cluster, applied to automation.

One workflow first, producing a report. Let it run for a few weeks. Read the output. Decide whether the information is actually useful before adding another.

Then event-triggered, with narrow outputs. Triage is a good second step because the outcomes are small and reversible.

Then proposals. A workflow that opens pull requests, reviewed by a human like any other.

Stop there for a long time. The next step after proposals is unattended change, and there is rarely a good reason to take it. The value in this feature is almost entirely in the first three.

When a run goes wrong

Unattended automation fails differently from interactive work, mostly because nobody is watching at the moment it happens.

Nothing was produced. The workflow ran and no issue appeared. Usually correct behaviour — the empty case working as intended — and worth confirming rather than assuming. gh aw logs shows whether the run happened at all.

Something wrong was produced. An issue with bad findings, a label that is clearly incorrect. The correction is cheap by design, which is the point of restricting outputs to things that are cheap to correct. Fix the instruction, not the output.

The same wrong thing happens every run. This is the useful signal. A recurring error is an instruction problem, and the fix belongs in the markdown or in a skill rather than in a note to whoever reads the reports.

It stopped running. Scheduled workflows in repositories with no recent activity can be disabled by GitHub, the same as any Actions schedule. Check the workflow’s status before debugging the content.

The cost is higher than expected. gh aw audit RUN-ID breaks down an individual run. Usually the cause is an unbounded task rather than an unexpected price.

What preview status means for you

This matters more than the usual boilerplate, because the feature is young enough that the practical advice differs from the eventual advice.

Expect field names to change. Frontmatter keys have moved during preview. A workflow that stops compiling after an extension update is the likely form this takes.

Pin nothing to prose you read once. Including this page. The verified date at the top of the article is there because these specifics have a short half-life.

Do not build a critical process on it yet. A weekly report that breaks for a fortnight is an inconvenience. A triage process your team depends on breaking is a different matter.

Do use it. The design is sound and the read-only default plus enumerated outputs make experimenting cheap. Preview is a reason to keep the blast radius small, not a reason to wait.

Where this fits

It is worth placing this against the other surfaces, because the boundaries are not obvious.

Versus the cloud agent. The cloud agent does a task you delegated, once. An agentic workflow does a task on a trigger, repeatedly, with no delegation. Use the cloud agent for work; use a workflow for a check.

Versus an ordinary Actions workflow. A deterministic workflow is better whenever the task is deterministic. A linter should be a linter. Agentic workflows earn their place when the task needs judgement that cannot be expressed as rules — “does this documentation still match the code” has no regular expression.

Versus a custom agent. A custom agent is a role you invoke. A workflow is an automation that invokes itself. The same underlying capability, with the human at a different point.

Common questions

Is this generally available? No — it is in public preview, and both the frontmatter schema and the CLI behaviour are still changing between releases.

Which models can it use? The engine field selects the provider. Availability depends on your account and configuration.

Can it run on pull requests from forks? Treat this with the same caution you would give any Actions workflow handling untrusted contributions, and then some: the content is being read by a model that acts on what it reads.

Do I have to use the CLI? gh aw compile is how the lock file is produced. The commands worth knowing are add, compile, run, logs and audit.

Can two workflows run on the same trigger? Yes, and it is usually a sign they should be one workflow. Two agents forming independent opinions about the same newly opened issue produces contradictory comments, which is a confusing first experience for whoever filed it.

Should the compiled lock file be in review? Yes. It is an Actions workflow with repository access, and a diff to it is a change to your automation regardless of how small the markdown change was that produced it.

What if I need something safe outputs do not cover? That is usually the signal that the task should not be unattended. Have the workflow open a pull request or an issue proposing the change, and let a person carry it out.

Can workflows use my custom agents and skills? Support for the various customization mechanisms differs by surface and is still settling in preview. The pillar’s matrix records what is documented; check current documentation before depending on it.

The end of the cluster

Thirteen lessons, and the through-line has been one idea in several forms.

Agent mode gives you a diff to review. The cloud agent gives you a pull request. Custom agents give you a tool boundary. Skills give you knowledge without capability. MCP gives you reach, and the tool list gives you back the control that reach costs. Agentic workflows give you automation whose write path is enumerated in five lines of frontmatter.

Every one of those is the same move: make the thing the agent can do smaller than the thing it might decide to do. The instructions explain, and the configuration is what holds.

If you build nothing else from this cluster, build the habit underneath it — commit before you start, decide what done looks like, and give the agent the narrowest set of tools that can get there.

Next

Governing all of this across an organisation — who may run which agent, which MCP servers are permitted, and what the audit trail contains — is Cluster 8, which covers Copilot security, code review and enterprise administration.

Back to the cluster overview for the surface matrix and the vocabulary. If you want the sharpest available permission model, Cluster 5 covers Copilot CLI’s per-tool approval. And Cluster 6 covers the instructions every agent here inherits — which remains the highest-leverage thing most teams have not done.

Sources

Every version-sensitive claim on this page was checked against first-party documentation. Only sources actually used are listed.

Primary sources