Skip to Content
Agent computeGitHub integration
Raw

GitHub integration

Connecting the Aetherfy GitHub App

Aetherfy integrates with GitHub through a GitHub App. One installation of it covers every repository you grant that installation access to, and your Aetherfy account can hold several installations — your personal GitHub account, and one for each organization whose installation GitHub shows you.

afy github connect

The command prints and opens a GitHub authorization URL. Authorizing attaches every account the Aetherfy App is already installed on that you can reach; if it is installed nowhere yet, GitHub asks where to install it first, and repository selection happens on that installation screen — you choose there whether the Aetherfy App gets all repositories or a specific list. You can change that later from GitHub, and Aetherfy needs no action from you when you do, but the change is not without effect: see changing which repositories Aetherfy can see.

You can connect any organization GitHub shows you — you do not have to be an owner or an admin of it. Installing the App on an organization is what requires owner rights; connecting it afterwards does not, which is what lets the person who installs Aetherfy and the people who deploy with it be different people. Which repositories Aetherfy can reach is set by whoever installed the App, on the installation screen, not by who connects.

Anyone who can connect an organization can deploy from every repository that organization granted to Aetherfy — including repositories they cannot read on GitHub — and see their contents in build logs. The installation is the unit of access: an installation token reaches everything the installation covers, and Aetherfy does not narrow it per person. Grant the Aetherfy App only the repositories you intend to deploy, choosing Only select repositories on the installation screen rather than All repositories. You can change the selection at any time from GitHub — see changing which repositories Aetherfy can see.

The command then waits for you to finish on GitHub and reports the connection when it lands. The link is valid for a limited time; the command tells you until when, and stops there rather than waiting indefinitely. If it runs out before anything is recorded, run afy github connect again for a fresh link. Pressing Ctrl-C only stops the waiting — the link stays valid, and finishing on GitHub still connects the account.

Running it again is how you add another account. It never replaces what you have: a personal account and an organization can both be connected, and each agent deploys through the one its repository belongs to.

Installing the Aetherfy App from GitHub

You can also install the App from its own page on github.com, without starting from Aetherfy. GitHub sends you back afterwards, but it does not tell us who you are on that path, so what happens next depends on how you sign in to Aetherfy.

If you sign in with GitHub, the installation is attached to your account automatically and there is nothing further to do. The installation event is signed by GitHub and names the account that performed it, and that is the same GitHub account your Aetherfy sign-in already proves you own.

If you sign in with email or Google, we have no way to tell which Aetherfy account the installation belongs to — an installation identifier on its own says nothing about who owns it, and attaching it on that basis would let one customer register webhooks on another customer’s repositories. The dashboard will show not connected even though the App really does have access. Run:

afy github connect

GitHub recognises the existing installation and attaches it — authorizing works on installations that already exist, so you are not installing the App twice and you do not need to uninstall it first.

Checking and removing the Aetherfy GitHub connection

afy github status afy github disconnect

afy github status lists every GitHub account connected to your Aetherfy account, with its installation id and when it was connected. Those accounts are not always the one you sign in with, and there can be more than one: each agent deploys through the account its repository belongs to, so the list is what tells you which account a given agent depends on. The dashboard’s Integrations tab shows the same list, one row per account.

afy github disconnect <account> disconnects one of them. Agents linked to that account’s repositories stop deploying on push; agents deploying through your other accounts are untouched.

afy github disconnect with no argument removes every connected account at once, and is idempotent — running it when nothing is connected is not an error.

Either way, existing deployments on Aetherfy are unaffected and keep running; what stops is automatic deployment on push, whether the repository is public or private.

Uninstalling the App from GitHub does the same thing for that account, by the same route. You do not need to do both.

Your links survive it. Each agent keeps its repository, branch and directory, so reconnecting that account resumes automatic deployment with nothing to set up again. In the agent list, a linked agent is marked AUTO-DEPLOY, and AUTO-DEPLOY OFF while you are disconnected or its branch is deleted. The agent’s GitHub link panel says which, and afy status <agent> says the same in the terminal. These are the only places it is reported, because saying it on the commit would itself need the GitHub access you just withdrew.

Unlinking is the separate, permanent action: use it when you want an agent to forget its repository rather than pause deployment from it.

Linking a repository to an Aetherfy agent

The agent must already exist before you can link it — linking attaches a repository to an agent, it does not create one. The first deploy is what creates the agent (afy deploy <path>, or afy deploy --from-github); link it after that, and every later push deploys it.

Connecting the App is account-level. Linking is per-agent: it tells Aetherfy which repository, branch, and directory belong to a given agent.

afy github link my-bot myorg/my-agent
FlagShortDefaultPurpose
--branch-bmainThe branch Aetherfy tracks for deployments
--root-dir—repository rootThe repo-relative folder holding this agent’s code and aetherfy.yaml

Linking registers the webhook before it records anything, so a link either works completely or changes nothing. If the Aetherfy App has no access to the repository you named, the link fails with GITHUB_REPO_NOT_FOUND and any existing link on that agent is left untouched.

That error cannot tell you which of two things went wrong, and deliberately so: GitHub hides repositories you lack access to rather than revealing that they exist. So “not found” and “not granted to Aetherfy” arrive identically. If you are sure of the name, the answer is almost always the second — grant the repository to the App and link again.

Changing which repositories Aetherfy can see

Repository access belongs to the installation, not to Aetherfy, so you change it on GitHub: Settings → Applications → Installed GitHub Apps → Aetherfy Bot → Configure. Add or remove repositories there and save. afy github status prints a direct link to that page for each connected account.

Adding a repository takes effect immediately and needs nothing on the Aetherfy side. You can link an agent to it straight away.

Removing one stops that repository deploying, and says so. The webhook stays on the repository and GitHub keeps delivering pushes to it, so the next push still creates a deployment — which fails, naming the repository and telling you to either grant it to the App again or reconnect the account that owns it. Any agent still linked keeps its link throughout.

So you are not left with an agent quietly shipping code from a repository you revoked, and you are not left guessing why it stopped either. The same message appears when the account connected to Aetherfy has changed since the link was made: the two causes are indistinguishable from GitHub’s side, which is why it names both remedies.

Linking an Aetherfy agent to the wrong repository

Linking deploys nothing by itself, so a wrong link is harmless until the next push. Relink the agent to the right repository and there is nothing to undo: relinking replaces the webhook, and the old one is removed once the new link is recorded.

If a push landed first, that push built and deployed, and the agent is now running the other repository’s code. Two separate things need doing, in this order.

  1. Relink, or the next push repeats it.
  2. Roll back, to put the previous code back. afy rollback <agent> prints the deployment history and asks which version to return to. See Rollback.

Rolling back without relinking fixes the running agent and leaves the cause in place. Relinking without rolling back stops the bleeding and leaves the wrong code running until the next real push.

Aetherfy will not deploy a repository an agent is not linked to. If a push arrives whose repository does not match the link — which happens when a link moved but its webhook did not — it is ignored rather than built. That protects against a stale webhook, not against linking the wrong repository on purpose, which is a valid instruction Aetherfy has no way to second-guess.

Choosing a branch for an Aetherfy agent

Two forms do the same thing — a flag, or an @branch suffix on the repository argument:

afy github link my-bot myorg/my-agent --branch develop afy github link my-bot myorg/my-agent@develop

If you give both and they disagree, --branch wins.

Aetherfy tracks exactly one branch per agent. A push to any other branch does not deploy.

Keeping several Aetherfy agents in one repository

--root-dir names the repo-relative folder that holds one agent’s code and its aetherfy.yaml:

afy github link my-bot myorg/monorepo --root-dir agents/my-bot

The flag does two things at once on Aetherfy, and both matter:

RoleEffect
Config search rootAetherfy looks for aetherfy.yaml inside that subtree, not at the repository root
Build contextOnly that subtree is uploaded. Sibling folders never enter the build.

Because the build context is scoped, this is how several agents live in one repository without each one dragging in the others’ code:

afy github link api-bot myorg/monorepo --root-dir agents/api-bot afy github link report-task myorg/monorepo --root-dir agents/report-task

Omit --root-dir and the whole repository becomes the build context.

Each agent you link this way gets a webhook of its own on the repository, so one push reaches every linked agent. Aetherfy handles each agent’s delivery separately: a push deploys only the agents whose directory it changed, and every other linked agent reports a skip. Each agent posts its own check on the pushed commit, named after the agent — aetherfy/deploy/api-bot and aetherfy/deploy/report-task for the two above — so one agent’s skip never hides another agent’s deployment.

The webhook secret Aetherfy shows once

The response to afy github link prints a webhook secret exactly once. It is not retrievable later — Aetherfy will not show it again, and there is no command that reveals it.

Copy it when it appears. If you lose it, or you want to rotate it, re-run afy github link on the already-linked agent:

afy github link my-bot myorg/my-agent

Re-linking an already-linked agent is supported and is the intended rotation path. Aetherfy creates the new webhook before removing the old one, so automatic deployment keeps working throughout the rotation with no window where pushes are dropped.

Unlinking a repository from an Aetherfy agent

afy github unlink my-bot

This removes the link and is idempotent. The webhook is deleted on a best-effort basis, so an unlink still succeeds if GitHub cannot be reached at that moment.

What a push to Aetherfy does

A push to the tracked branch that touches the agent’s root_dir triggers a deployment. Aetherfy then:

  1. Clones the repository at the exact pushed commit.
  2. Re-parses the aetherfy.yaml from that commit.
  3. Applies it as an RFC 7396 merge patch.
  4. Builds and deploys.

Step 3 is the one to understand. Because the configuration is a merge patch, fields you omit from the pushed file keep the values you set through the Aetherfy dashboard or API — a push does not reset your agent to the file’s defaults. The full merge-patch table is on /agents/aetherfy-yaml.

Broken YAML fails the deployment loudly. Aetherfy never silently falls back to a previous configuration.

When Aetherfy ignores a push

Aetherfy creates no deployment at all in these cases:

CaseResult
The event is not a pushIgnored
The branch does not match the tracked branchIgnored
The repository does not match the linked repositoryIgnored
The agent is pausedAnnounced on the commit, no deployment created
The GitHub account this agent deploys through is not connectedNo deployment created, and not announced
The tracked branch was deletedNo deployment created; recorded on the agent’s GitHub link

The disconnected-account row is PER AGENT, not per Aetherfy account: each agent deploys through the GitHub account its repository belongs to, so disconnecting one account stops its agents and leaves the rest deploying.

It is also an exception to Aetherfy reporting a skip on the commit, and that is a limit rather than a choice: posting a commit status is itself a GitHub call, and it needs the access that being disconnected removed. A push to a linked repository while that account is disconnected is therefore silent on GitHub. It is reported on the agent’s page in the dashboard, and by afy status <agent>, instead — both of which name the account to reconnect.

None of these are failures, and none of them leave a failed deployment behind. A deliberate non-deploy does not fill your dashboard with red.

The last row is the second Aetherfy cannot tell you about on GitHub, alongside the disconnected account above it, and its reason is the sharper of the two and worth knowing. GitHub reports a deleted branch as a push with no commit in it, so there is no commit for Aetherfy to attach a status to — the place every other skip gets reported simply does not exist. Deleting the branch an agent deploys from also has a consequence the others do not: that agent will not deploy again until the branch is back. So Aetherfy records it on the agent’s GitHub link, and the dashboard and afy status <agent> both say the agent is linked and will not deploy until that branch exists again — naming the branch and when it went. Recreate the branch and push; the link is kept, so deploys resume with nothing to set up. Over the API the same fact is branch_deleted_at on GET /api/v1/agents/{agent}/github.

Path filtering behaves differently, and deliberately so: it fails open. If Aetherfy cannot prove that a push missed your root_dir, it deploys anyway. That happens with force-pushes, branch creations and deletions, and very large commit lists where the changed-file set is not fully available.

The consequence is worth stating plainly: an occasional deployment you did not expect is the designed behaviour. Aetherfy prefers a redundant deploy over a silently skipped one, since a redundant deploy is visible and a missed deploy is not.

A push Aetherfy accepted survives an Aetherfy restart

Aetherfy answers a push webhook the moment the delivery’s signature checks out, before the deploy has started. That acknowledgement now means Aetherfy has this push, not Aetherfy has deployed it: the delivery is written down first, and the deploy runs from that record.

What follows from it is the part worth knowing. If Aetherfy restarts — a deployment of our own, a machine replaced — between accepting your push and finishing it, the push is picked up and completed rather than lost. You do not need to push an empty commit to wake it up.

How long that takes hardly depends on how Aetherfy went away. After an orderly restart, which is the ordinary case, the work is handed back as Aetherfy shuts down and the process that replaces it collects it straight away. After a hard crash, where nothing got the chance to hand anything back, the deploy that was in flight simply stops reporting in, and another process acts on the silence. Neither case leaves a push waiting long.

A deploy that is merely slow keeps reporting in the whole time it runs, however large the repository. Only a deploy that stops reporting in for about a minute is taken back. If one is ever taken back by mistake, the late work of the original is rejected, so the push still deploys once. It does use up one of the push’s three attempts, and a push that runs out of attempts is marked failed; Redeliver gives it a fresh set.

A delivery that never reached Aetherfy at all is a different case, and GitHub shows it: the delivery is red in your repository’s webhook settings. Aetherfy looks for those too and asks GitHub to send them again, so a push made while Aetherfy was unreachable still deploys without you doing anything. If you would rather not wait, Redeliver on that delivery in GitHub’s webhook settings does the same thing immediately.

Redelivering is always safe. GitHub reuses the delivery’s identifier, and Aetherfy keys on it together with the agent the delivery was sent to — GitHub gives one push the same identifier on every agent’s webhook, so each agent keeps its own record. A push an agent has already deployed is recognised and ignored rather than deployed a second time, while a push it accepted and failed to finish is run again. That is the whole reason Redeliver is the right button after a failure — it cannot produce a duplicate deployment.

Aetherfy keeps these delivery records for a few days and no longer. They hold the push payload GitHub sent, including commit messages and committer names and addresses, and their only job is to let a push outlive a restart. Deleting an agent deletes its records with it.

Commit statuses Aetherfy posts back

Aetherfy posts commit statuses on the pushed commit — pending first, then success or failure. Deliberate skips are reported too, so a push that Aetherfy chose not to deploy says so on the commit rather than leaving you to guess from silence.

Each agent posts under a context named after it, aetherfy/deploy/<agent-name>. When several agents link the same repository, the commit carries one Aetherfy check per agent, each with that agent’s own outcome. A check keeps the name the agent had when the push arrived, so renaming an agent in Aetherfy while it is deploying resolves the existing check rather than opening a new one.

This makes the pushed commit the single place to look when you are unsure whether a change deployed.

A failure usually says what went wrong and what to do — the repository Aetherfy cannot reach, the branch that no longer exists, the manifest that would not parse. When something fails for a reason that is ours rather than yours, the check says so plainly and carries a reference like Reference: 11ced866-a5e9-40df-aa78-a0012ea836c1. That is the deployment’s own id, which you can also see in the dashboard — quote it if you contact support, and retry the push, because these failures are not caused by anything in your repository.

Private repositories in github_dependencies on Aetherfy

The github_dependencies field in aetherfy.yaml lists repositories to pull in at build time, each as owner/repo@ref:

name: my-bot runtime: python3.12 github_dependencies: - myorg/[email protected] - myorg/protocols@main

Each entry must fullmatch [A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+@[A-Za-z0-9._/-]+. The @ref is a tag, a branch or a commit SHA.

Private repositories listed here require the Aetherfy GitHub App to be connected and to have access to them. Run afy github connect first, and make sure the dependency repositories are among those you granted on GitHub’s installation screen.

How Aetherfy installs a github dependency

Aetherfy installs the source archive for the ref you named, not a git clone — https://github.com/{owner}/{repo}/archive/{ref}.tar.gz, handed to uv pip install, npm install or bun add depending on your runtime. Private repositories get the same URL with a build-time token that never enters an image layer.

A dependency that builds itself on install is not built. npm runs no prepare script for a tarball, so a JavaScript package whose published form is compiled from its source ships only that source, and importing it fails at runtime. Depend on such a package from a registry instead, or commit its built output to the repository you are depending on. Python packages are unaffected: pip and uv build a source distribution as a matter of course.

This is why the archive is used rather than git+https://: an Aetherfy runtime image has no git binary, so a git install cannot run in one at all.

Last updated on