# copilot-setup-steps.yml: the rules, runners and limits

> copilot-setup-steps.yml preinstalls what Copilot cloud agent needs. The job rules, runner options, secrets and limits GitHub documents, in one place.

Source: https://latchkey.dev/learn/agent-ci/copilot-setup-steps  
Updated: 2026-11-12

`copilot-setup-steps.yml` is a workflow at `.github/workflows/copilot-setup-steps.yml` with one job, named `copilot-setup-steps`, whose steps GitHub runs before Copilot cloud agent starts work, so the agent begins with your toolchain and dependencies installed. It applies only to sessions that run on GitHub Actions, and GitHub honors only six keys of that job.

GitHub's documentation now calls the Copilot coding agent Copilot cloud agent, and the setup steps file is now one of three places a session can get its environment from. That is the first thing to check when setup steps seem to be ignored: the file can be fine while the session never ran on Actions.

Where Copilot fits beside other agents is on [CI for Cursor and Copilot coding agents](/learn/agent-ci/ci-for-cursor-and-copilot-coding-agents). Here it is only the file: what GitHub runs, in what order, on which runners, with which secrets, and what it ignores.

## First, check the session runs on Actions

GitHub now runs a Copilot session in one of two hosted environments. Cloud is a sandbox GitHub hosts; Actions is a GitHub Actions job on a GitHub-hosted runner or one you configure. Where a client lets you choose, Cloud is the default, the choice is made when the session starts and cannot be changed afterwards, and a different environment means a new session.

Setup steps, larger runners, self-hosted runners and the Windows environment all exist only on the Actions path. So do Agents variables: in a cloud sandbox only Agents secrets are available. If your repository depends on any of these, choose Actions when you delegate the task, or the agent starts in a sandbox that never read your file. A third option, a custom environment, registers a Linux machine or codespace you manage yourself.

## The rules for the file

The path is fixed and the job name is the mechanism: GitHub's own example carries the comment that the job MUST be called `copilot-setup-steps` or it will not be picked up. The file also has to be on the default branch before it triggers at all, so a branch that adds it changes nothing until it merges.

Only six job keys count: `steps`, `permissions`, `runs-on`, `services`, `snapshot` and `timeout-minutes`, the last capped at 59. Anything else is ignored rather than rejected. A `fetch-depth` on `actions/checkout` is overridden so the agent can roll back commits, and if you do not check out the code at all, Copilot clones it after your steps finish. Give the job `contents: read` only if a step clones; Copilot gets its own token for its own work.

The `push` and `pull_request` path filters are what make the file testable: a pull request that edits it runs it as an ordinary check, and once merged you can run it from the Actions tab.

```.github/workflows/copilot-setup-steps.yml
name: Copilot Setup Steps
on:
  workflow_dispatch:
  push:
    paths:
      - .github/workflows/copilot-setup-steps.yml
  pull_request:
    paths:
      - .github/workflows/copilot-setup-steps.yml
jobs:
  # The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot.
  copilot-setup-steps:
    runs-on: ubuntu-latest
    timeout-minutes: 30
    permissions:
      contents: read
    services:
      postgres:
        image: postgres:17
        env:
          POSTGRES_PASSWORD: postgres
        ports:
          - 5432:5432
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
        with:
          node-version: "22"
          cache: npm
      - run: npm ci
```

## What happens when a step fails

This is the behavior that surprises people most, because nothing goes red. GitHub documents that if any setup step returns a non-zero exit code, Copilot skips the remaining setup steps and begins working with the environment in whatever state it reached. The session continues; the agent just has less than you meant to give it, and it falls back to discovering dependencies by trial and error, which GitHub's own documentation calls slow and unreliable.

Two habits follow. Order the steps so the one that matters most, usually the dependency install, comes first after checkout and toolchain setup, rather than after an optional cache warm-up. And treat the file's own `pull_request` run as its test: a failure there is visible as a check, whereas a failure inside a session only shows up in the session logs.

## Secrets are Agents secrets, not Actions secrets

Copilot cloud agent does not receive Actions, Codespaces or Dependabot secrets. It has its own type, Agents secrets and variables, set at repository or organization level under Settings, Secrets and variables, Agents. On the Actions path they are exposed as environment variables, including to the steps in `copilot-setup-steps.yml`; names prefixed `COPILOT_MCP_` go only to MCP servers. Secrets you once put in a repository's `copilot` environment were migrated to the repository-level Agents type automatically.

Because they arrive as environment variables, a private registry needs no `secrets.` expression in the workflow. An `.npmrc` that reads the token from the environment is enough for `npm ci` in the setup steps and for every install the agent runs afterwards.

```.npmrc
# .npmrc, committed; NPM_TOKEN is an Agents secret
@your-org:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${NPM_TOKEN}
```

## Runners: larger, self-hosted and Windows

`runs-on` moves the agent off the default `ubuntu-latest`, and each destination comes with conditions. Copilot cloud agent is only compatible with Ubuntu x64 and Windows 64-bit runners; macOS is not supported anywhere. Organization owners can also set a default runner type and switch off repository overrides, in which case your `runs-on` has no effect.

| Runner | What GitHub requires | Example `runs-on` |
| --- | --- | --- |
| Larger GitHub-hosted | Larger runners set up for the organization; with Azure private networking, outbound access to the Copilot hosts | `ubuntu-4-core` |
| Self-hosted | Ephemeral single-use runners recommended (ARC or the Runner Scale Set Client); integrated firewall disabled, or the agent is blocked; your own network controls | your ARC scale set name |
| Windows | Self-hosted or larger runners; the integrated firewall is not compatible with Windows | your Windows runner label |

> The hosts a self-hosted or privately networked runner must reach, besides the standard Actions hosts, are `uploads.github.com`, `user-images.githubusercontent.com`, and whichever of `api.individual.githubcopilot.com`, `api.business.githubcopilot.com` and `api.enterprise.githubcopilot.com` match the Copilot plans in use, per the GitHub Docs page read on 2026-11-12.

## services and snapshot

`services` works as it does in any job, which is the cleanest way to give the agent a real database or cache to run integration tests against instead of letting it mock one. `snapshot` is the less obvious key: in workflow syntax it generates a custom image, with each successful run of a job carrying it producing a new image version. It belongs to GitHub's custom images feature for larger runners, so read that documentation before relying on it here.

The same file also configures Copilot code review's environment, which reuses `copilot-setup-steps.yml` unless you add a separate `copilot-code-review.yml`. Split them when review needs less than the agent does.

```.github/workflows/copilot-setup-steps.yml, a larger runner with Git LFS
jobs:
  copilot-setup-steps:
    runs-on: ubuntu-4-core
    timeout-minutes: 45
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          lfs: true
```

## Where these rules come from

GitHub's Copilot documentation, read on 2026-11-12, and nothing else: the environment pages, the secrets and variables page, the organization runner page and the workflow syntax reference listed below. No recorded run backs this page, and neither evidence file in this repository has an entry for it. A session's setup log belongs to one repository and one Copilot plan, so the rules are quoted from the pages that define them rather than inferred from a log.

## FAQ

### Why is my copilot-setup-steps.yml not being used?

Three causes cover nearly every case. The file is not on the default branch yet, the job is not named exactly `copilot-setup-steps`, or the session ran in a cloud sandbox, where setup steps do not apply. Check the session logs: when the setup job runs, its steps appear there.

### Can Copilot coding agent use self-hosted runners?

Yes, through `runs-on` in the setup steps file, on Ubuntu x64 or Windows 64-bit runners. GitHub recommends ephemeral single-use runners, requires you to disable the integrated firewall for self-hosted use, and asks you to allow the Copilot API hosts through your own network controls.

### How do I give Copilot coding agent access to secrets?

Add them as Agents secrets, at repository or organization level. They reach the agent as environment variables, including inside `copilot-setup-steps.yml`, while names starting with `COPILOT_MCP_` are passed only to MCP servers. Actions secrets are not passed to the agent.

### What is the maximum timeout for copilot-setup-steps?

59 minutes. `timeout-minutes` is one of the six keys GitHub honors on the `copilot-setup-steps` job, and the documentation gives 59 as its maximum value.

## References

- [GitHub Docs: configure the development environment for agents on GitHub Actions (read 2026-11-12)](https://docs.github.com/en/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/customize-the-agent-environment)
- [GitHub Docs: about cloud sandboxes, choosing where Copilot runs](https://docs.github.com/en/copilot/concepts/security-governance-and-network-settings/about-cloud-sandboxes)
- [GitHub Docs: configure secrets and variables for Copilot cloud agent](https://docs.github.com/en/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/configure-secrets-and-variables)
- [GitHub Docs: configuring runners for Copilot cloud agent in your organization](https://docs.github.com/en/copilot/how-tos/administer-copilot/manage-for-organization/configure-runner-for-coding-agent)
- [GitHub Docs: workflow syntax, jobs.<job_id>.snapshot](https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax)

---

Latchkey runs CI/CD that repairs its own failures. Agent entry points: https://latchkey.dev/agent.txt, https://latchkey.dev/openapi.json, https://latchkey.dev/llms.txt
