Run Fledgeplan agents on GitHub Actions
Fledgeplan agents do their work through Axowl’s MCP tools: they read your repository and propose changes as pull requests. The agent itself — Claude Code — has to run somewhere. With this setup it runs on your repository’s GitHub Actions, started by Axowl whenever an agent has work. Nothing has to stay on at your desk.
Who pays for what. GitHub Actions minutes are billed to your GitHub account. Claude usage is billed to your own Anthropic account or Claude subscription. Axowl does not charge for, resell or relay Claude usage.
Set it up
Section titled “Set it up”You need a GitHub account and the repository connected through the Axowl GitHub App (a pasted access token cannot start workflows for you).
-
Allow GitHub Actions for the repository. Axowl asks in three places — they all change the same switch: when you connect the repository (client → Repository tab), when you connect Fledgeplan, and any time in App group → Settings → GitHub Actions. It is off by default; while it is off Axowl never writes or starts a workflow in that repository.
-
Install the workflow file. In the same place, press Install. Axowl commits
.github/workflows/fledgeplan-agent.ymlto the default branch. Agents cannot change this file. -
Add your Claude credential to GitHub as a secret of the repository environment
fledgeplan(repository → Settings → Environments). Either one:ANTHROPIC_API_KEY— a key from Claude Console. Recommended for teams.CLAUDE_CODE_OAUTH_TOKEN— fromclaude setup-tokenon your own computer (Claude Pro, Max, Team or Enterprise). Subscription limits assume ordinary individual use, so frequent agent runs can hit them.
Axowl only checks that a secret with one of these names exists; it never sees the value. If both are set, the API key is used.
-
Choose the runner (optional). GitHub-hosted is the default. Self-hosted runs on your own runner with the labels
self-hostedandfledgeplan— use it when code must not leave your network. After changing the runner, install the workflow file again.
What the workflow does — and does not
Section titled “What the workflow does — and does not”| Trigger | workflow_dispatch only — started by Axowl. No pull_request, push or comment triggers, so a fork cannot run it. |
| Repository permissions | None. permissions: id-token: write only, to prove its identity to Axowl. |
| Code | Not checked out. The agent reads and writes the repository through Axowl’s MCP tools, as pull requests. |
| Claude | Claude Code, a pinned version, with --allowedTools mcp__axowl — no shell or file tools — and at most 60 turns per run. |
| Limits | 30 minutes per run. Duplicate wake-ups within 2 minutes are folded into one by Axowl. |
How a run proves who it is
Section titled “How a run proves who it is”The run asks GitHub for an OpenID Connect token with the audience axowl-fledgeplan and sends it to
POST /mcp/github-oidc/token. Axowl checks GitHub’s signature and that the token comes from your connected repository
(by numeric id), from fledgeplan-agent.yml on the default branch, started by workflow_dispatch. Only then does it
return a 60-minute MCP token for that one run. When the run reports its result (POST /mcp/github-oidc/report) or is
found stopped, that token stops working immediately, even if time is left.
When a run stops
Section titled “When a run stops”Every stop is shown in App group → Settings → GitHub Actions with the reason, what to do, and buttons to open the right
settings page or Run again. If the run belonged to a story, the story’s activity gets an agent_run entry, and the
person testing that story is notified — the organization Owner when there is no story or tester. The same reason on
the same repository is announced at most once an hour. Axowl operations is alerted as well.
| Reason | Meaning |
|---|---|
app_uninstalled | The Axowl GitHub App was removed, or the repository was taken out of it. |
workflow_missing | fledgeplan-agent.yml is missing or was changed. Install it again. |
actions_disabled | Actions is turned off for the repository or the workflow. |
permission_missing | The App’s updated permissions (Actions: read and write) are not approved yet. |
dispatch_refused | GitHub refused to start the workflow for another reason. |
actions_not_allowed | An agent had work but GitHub Actions is turned off for this repository in Axowl. |
not_started | No run appeared within 5 minutes of Axowl’s request. |
queued_too_long | The run waited more than 10 minutes for a runner (self-hosted runner offline). |
actions_billing | GitHub did not start the job: Actions minutes or spending limit used up, or a payment failed. |
oidc_refused | The run could not prove which repository and workflow it came from. |
claude_credential_missing | Neither secret is set in the fledgeplan environment. |
claude_auth | Claude rejected the credential (wrong or deleted key, expired or revoked token). |
claude_limit | Credit balance, usage limit or rate limit reached. |
claude_error | Claude stopped with another error, including running out of turns. |
runner_failed | The run failed on GitHub; the last log lines are shown. |
timed_out | The run hit its 30-minute limit. |
cancelled | Someone cancelled the run on GitHub. |
no_report | The run ended on GitHub without reporting its result. |
ci_watch_gave_up | Axowl could not see CI finish on the agent’s pull request for 3 hours, so the agent was not woken. |
ended_silently | The run finished, but the agent put a question in its closing note instead of asking through Axowl. Read the note on the story card, answer it, then run again. |
App group API
Section titled “App group API”All under /api/org/{slug}/app-groups/{groupId}/agent-runner (signed-in organization member holding the permission shown):
GET /— per repository: the Actions switch, runner, workflow status, why it is blocked, the last stop; plus recent runs. Needsorg.git_repository.list.PUT /repos/{linkId}—{ "actionsAllowed": true, "runner": "github" | "self-hosted" }. Needsorg.git_repository.update.POST /repos/{linkId}/install— install the workflow file. Refused with409and"code": "ACTIONS_NOT_ALLOWED"while the switch is off. Needsorg.git_repository.update.GET /repos/{linkId}/secrets— whetherANTHROPIC_API_KEY/CLAUDE_CODE_OAUTH_TOKENexist (names only). Needsorg.git_repository.read.POST /runs/{runId}/retry— run a stopped run again. Needsorg.git_repository.update.
The client’s repository switch is also at PUT /api/org/{slug}/applications/{appId}/repository/actions ({ "allowed": true }, org.git_repository.update).