GitHub Copilot can act as a coding agent: assign it to an issue and it opens a pull request with working code. This post shows how to trigger that automatically from a GitHub Actions workflow — including the one token setup step that isn’t obvious.
Why You Can’t Use GITHUB_TOKEN
The first question people ask when they see this is: why do you need a separate token? Can’t you use the built-in GITHUB_TOKEN?
No — and the reason is specific. When a GitHub Actions workflow creates or modifies an issue using GITHUB_TOKEN, GitHub intentionally prevents that action from triggering further automation. This is an anti-loop safeguard: if GITHUB_TOKEN could trigger other workflows, a poorly written workflow could accidentally create an infinite loop of Actions runs.
Assigning an issue to @copilot is exactly that kind of trigger — it starts a Copilot coding agent session. So GitHub blocks it when the request comes from GITHUB_TOKEN.
The fix is to use a fine-grained personal access token (PAT) that belongs to a real user account. Requests from a user token are treated as human actions, not automated Actions activity, and the Copilot assignment goes through.
Creating the Fine-Grained Token
Advertisement
A fine-grained PAT is a scoped token tied to your GitHub account that you can restrict to specific repositories and specific permissions. It’s more secure than a classic PAT because you can limit exactly what it can do.
Step 1 — Open Token Settings
Go to github.com/settings/personal-access-tokens/new.
You need:
- Token name: something descriptive, e.g.
copilot-issue-trigger - Expiration: set a reasonable expiry; you’ll need to rotate it when it expires
- Resource owner: your personal GitHub account (or your org, if the repo lives there)
- Repository access: select Only select repositories, then pick the repo you want Copilot to work in
Step 2 — Set Repository Permissions
Under Repository permissions, you only need one permission:
| Permission | Access level | Why |
|---|---|---|
| Issues | Read and Write | To create the issue and assign it to @copilot |
Advertisement
That’s it. You do not need Contents, Pull Requests, or Workflows access on this token — those are permissions that Copilot itself uses when it acts on the repo, under its own identity.
gh issue create. Limit it to Issues write access on a single repository — nothing more. Step 3 — Add the Token as a Repository Secret
- Go to your repository → Settings → Secrets and variables → Actions
- Click New repository secret
- Name it
COPILOT_PAT - Paste in the fine-grained token you just created
The name COPILOT_PAT is what the workflow will reference.
The Workflow
Here’s the complete workflow that uses this token to trigger Copilot:
name: AI Blog Post Generator
on:
workflow_dispatch:
jobs:
trigger-copilot:
runs-on: ubuntu-latest
steps:
- name: Create Copilot coding task
env:
GH_TOKEN: ${{ secrets.COPILOT_PAT }}
run: |
DATE=$(date -u +%Y-%m-%d)
INSTRUCTIONS="Write a blog post about an interesting tech topic. \
Match the tone and style of existing posts in blog/_posts/. \
At the very end of the post, after a horizontal rule (---), add a footnote: \
<small>⚠️ <em>This post was generated by AI and may contain errors or \
inaccuracies. Always verify technical details from primary sources.</em></small>"
printf '%s' "${INSTRUCTIONS}" > /tmp/issue-body.txt
ISSUE_URL=$(gh issue create \
--repo "${{ github.repository }}" \
--title "AI Blog Post - ${DATE}" \
--body-file /tmp/issue-body.txt \
--assignee "@copilot")
echo "Created Copilot task: ${ISSUE_URL}"
A few things worth calling out:
-
GH_TOKEN: ${{ secrets.COPILOT_PAT }}— theghCLI picks up the token from this environment variable. This is how you pass the fine-grained PAT toghwithout hardcoding it. -
--assignee "@copilot"— this is what activates the Copilot agent. GitHub recognises@copilotas a special assignee that triggers a coding agent session. -
--body-file /tmp/issue-body.txt— the instructions go into the issue body via a temp file rather than directly as a shell argument, which avoids quoting issues with long strings. -
workflow_dispatch— the trigger is manual for now. You can change this toschedulefor fully automated runs (see below).
Making It Fully Automatic
Advertisement
The workflow_dispatch trigger requires you to manually click Run workflow in the Actions tab. If you want Copilot to generate a post on a schedule — say, every Monday morning — swap the trigger:
on:
schedule:
- cron: '0 8 * * 1' # Every Monday at 08:00 UTC
workflow_dispatch: # Keep this so you can also trigger manually
Keeping workflow_dispatch alongside schedule is good practice — it lets you trigger a one-off post without waiting for the schedule.
Writing Good Instructions for Copilot
The issue body is Copilot’s brief. The agent reads it, then browses your repository to understand conventions before writing anything. A few things that make instructions more effective:
Tell it what to look at:
Look at existing posts in
blog/_posts/to understand the front matter format, writing tone, and post structure before writing.
Specify the front matter fields you use:
Advertisement
Use YAML front matter with
title,icon(a Font Awesome class), andtags.
Tell it about the AI disclaimer:
End every post with a
---horizontal rule followed by:<small>⚠️ <em>This post was generated by AI...</em></small>
Give it creative latitude:
Pick a topic from recent tech news, or write a tutorial on a developer tool. Prefer topics relevant to web development, GitHub Actions, or open-source tooling.
The more context you give Copilot about your site’s conventions, the better the generated posts match your existing content. You can also create a .github/copilot-instructions.md file in your repository with standing instructions that apply to every Copilot session — not just this workflow.
Example: How This Blog Uses It
Advertisement
This is exactly how this blog auto-generates posts. A scheduled workflow creates an issue, assigns it to @copilot, and Copilot opens a pull request with a new Markdown file in blog/_posts/. The entire pipeline runs in the cloud — you can kick it off from a phone.
The AI blog generation flow overview covers the broader picture of how posts go from Copilot’s PR to a live Jekyll page on GitHub Pages.
Troubleshooting
gh issue create fails with a 403 or permissions error
Check that the fine-grained PAT has Issues: Read and Write for the correct repository. Also confirm the token hasn’t expired — fine-grained tokens have mandatory expiry dates.
The issue is created but Copilot never starts working
Make sure your GitHub account has an active Copilot subscription. Copilot coding agent is only available on paid Copilot plans (Individual, Business, or Enterprise). Also check that Copilot is enabled for the repository under Settings → Copilot.
Copilot creates the post but ignores the instructions
The issue body is Copilot’s primary input. Make it more explicit — state the front matter fields by name, describe the file naming convention (YYYY-MM-DD-slug.md in blog/_posts/), and link to an existing post as a reference.
The token works locally but fails in Actions
Make sure you added the token as a repository secret (not an environment secret), and that the secret name in the workflow (COPILOT_PAT) matches exactly — secret names are case-sensitive.
Advertisement
Summary
| Step | What to do |
|---|---|
| 1 | Create a fine-grained PAT with Issues: Read and Write on your repo |
| 2 | Add the PAT as a repository secret named COPILOT_PAT |
| 3 | Create a workflow that calls gh issue create --assignee "@copilot" using the PAT |
| 4 | Write clear instructions in the issue body |
| 5 | Trigger manually or on a schedule |
| 6 | Review and merge the PR Copilot opens |
The only non-obvious part is the fine-grained token — everything else is standard GitHub Actions. Once the token is in place, the workflow is a handful of lines of shell script.