Docs
Search docs

Get the repository's GitHub attach and its preview

GET/api/repos/{owner}/{repo}/github-attach

getGithubAttach

The attach in flight, else the most recent one, with its plan: every ref with how its local and GitHub tips compare (`class`) and what the attach does with it (`outcome`, and `preserved_as` where the local tip is kept under `neosource-preserved/`), every ref a confirmed attach would **publish** to GitHub, the open pull requests whose refs move, blockers (each with a `fix` code) and warnings. While the run is still `planning` the lists are empty and `upstream_shape` is `null`. `plan_hash` and `authority_epoch` are what `POST …/github-attach/confirm` must echo (`authority_epoch: null` when the repository has no relationship yet). Requires repository **admin**; `404` when the repository was never attached.

Requires authentication using a bearer token or a session cookie — see tokens and scopes.

curl

curl -X GET 'https://neosource.dev/api/repos/OWNER/REPO/github-attach' \
  -H 'Authorization: Bearer $NEOSOURCE_TOKEN'

fetch

fetch("https://neosource.dev/api/repos/OWNER/REPO/github-attach", {
  method: "GET",
  headers: {
    Authorization: "Bearer $NEOSOURCE_TOKEN",
  },
});

Path parameters

ownerrequired

Repository owner or organization slug.

string

reporequired

Repository name.

string

Responses

200The attach and its preview

application/json

GithubAttachRunResponse

object

An attach run and its preview — `GET …/github-attach` and the confirm's `202`. While the run is still `planning` the lists are empty and `upstream_shape` is `null`.

affected_prsrequired

array

items

GithubAttachAffectedPr

object

An open pull request whose refs the attach moves.

changerequired
AttachPrChange
head_refrequired

string

numberrequired

integerint32

titlerequired

string

authority_epoch

integer | nullint64

The relationship's CURRENT `authority_epoch`, `null` when the repository has no relationship — exactly what a confirm echoes as `expected_authority_epoch`.

blockersrequired

array

items

GithubSyncBlockerRow

One thing that stops GitHub sync: the blocker itself — its `kind` plus whatever detail that kind carries (`outcome`, `health`, `refname`, `missing_events`) — the stable `fix` code the panel renders, and a link to where it is fixed when there is one.

all of
  • GithubSyncBlocker
  • object

    fixrequired
    GithubSyncFix
    fix_url

    string | null

    Where the fix is made: the GitHub App's install page for the App-side fixes, the GitHub repository's settings for an archived repository. `null` otherwise, and when this deployment has no App.

confirmed_at

integer | nullint64

Millis since the Unix epoch; `null` until confirmed.

expires_at

integer | nullint64

Millis since the Unix epoch after which the plan can no longer be confirmed.

last_error

string | null

originrequired

GithubAttachOrigin

string

Who started an attach — `github_attach_runs.origin`.

"import""user"

plan_hash

string | null

64-hex; what a confirm must echo. `null` until planned.

publish_confirmedrequired

boolean

Whether the confirmation acknowledged the publish.

publishesrequired

array

Every ref a confirmed publish sends to GitHub — the `publish` rows of `refs`. Non-empty means a confirm must say `confirm_publish: true`.

items

GithubAttachPublishRow

object

One ref a confirmed publish sends to GitHub under its own name.

kindrequired
AttachPublishKind
oidrequired

string

40-hex git OID.

refnamerequired

string

refsrequired

array

items

GithubAttachRefRow

object

One ref of the preview: how its two tips compare and what the attach does with it.

classrequired
AttachRefClass
local_oid

string | null

40-hex git OID here, `null` when only GitHub has the ref.

outcomerequired
AttachRefOutcome
preserved_as

string | null

Where the local tip is kept, for `preserve` and `preserve_and_reset`.

refnamerequired

string

remote_oid

string | null

40-hex git OID on GitHub, `null` when only this repository has it.

run_idrequired

string

staterequired

GithubAttachRunState

string

Lifecycle of one attach attempt — `github_attach_runs.state`. ```text planning ─► planned ─(confirm)─► frozen ─► publishing ─► applying ─► applied ▲ │ │ │ └── needs_reconfirm ◄──(undo)───┴───────────┘ (+ failed, cancelled, expired) ``` The six nonterminal states are exactly the partial unique index `github_attach_runs_one_nonterminal_per_repo`, so a repository has at most one attach in flight.

"planning""planned""frozen""publishing""applying""applied""needs_reconfirm""failed""cancelled""expired"

targetrequired

GithubAttachTarget

object

The GitHub repository an attach targets.

full_namerequired

string

github_repository_idrequired

integerint64

upstream_shape
one of
  • AttachUpstreamShape

    string

    What GitHub holds relative to this repository, decided once per plan before any ref is classified (D11).

    "empty""unrelated""related"

  • null

warningsrequired

array

items

AttachPlanWarning

Something the preview should say that does not stop the attach. Serialized internally tagged by `kind`, which is also [`Self::kind`].

one of
  • object

    The repository's default branch and GitHub's differ; GitHub's wins.

    githubrequired

    string

    kindrequired

    string

    "default_branch_differs"

    localrequired

    string

  • object

    GitHub's default branch could not be read.

    kindrequired

    string

    "default_branch_unobserved"

Standard errors

Bodies documented once for the whole API — see standard errors.

  • 400Bad Request — one of: invalid_input
  • 401Authentication required
  • 403Forbidden — one of: forbidden
  • 404Not Found — one of: not_found
  • 423Locked — one of: busy
  • 429Rate limited — retry after the `Retry-After` header
  • 500Internal server error
  • 503Service temporarily unavailable / at capacity — retry after the `Retry-After` header
  • 504Gateway timeout — the request exceeded the server's handling budget

Schemas

Referenced above. Listed here rather than expanded inline, so the same definition is not repeated at every level.

AttachPrChange

string

What an attach does to an open pull request's refs.

"head_follows""head_preserved""base_moves"

GithubSyncBlocker

Everything that stops GitHub sync, enabling or ongoing: closed and typed, so the GitHub panel can name a fix for each. Each variant mirrors an existing core outcome rather than restating it: the binding ones are [`GithubAppBindingHealth`] values, `RulesetAudit` / `ProtectionEventsNotSubscribed` / `AdministrationReadMissing` are [`RulesetAuditOutcome`] refusals, `WritesRefused` is [`GithubWriteHealth::refuses_managed_writes`], the LFS ones are [`LfsVerificationResult`] verdicts. An empty or unrelated upstream is not a blocker (D11), nor is a tombstone (D7). Serialized internally tagged by `kind`, which is also [`Self::kind`].

one of
  • object

    The GitHub-sync offering is not enabled for this repository.

    kindrequired

    string

    "feature_not_offered"

  • object

    No App installation is bound to the repository.

    kindrequired

    string

    "no_app_binding"

  • object

    [`GithubAppBindingHealth::Unverified`], or `RulesetUnverified` with no refusing audit outcome recorded (awaiting a (re-)audit).

    kindrequired

    string

    "binding_unverified"

  • object

    [`GithubAppBindingHealth::Error`]: the binding probe failed.

    kindrequired

    string

    "binding_error"

  • object

    [`GithubAppBindingHealth::Revoked`].

    kindrequired

    string

    "binding_revoked"

  • object

    [`GithubAppBindingHealth::InsufficientScope`].

    kindrequired

    string

    "binding_insufficient_scope"

  • object

    The ruleset audit refused the binding for `outcome` ([`RulesetAuditOutcome::remedy`] is the fix). A struct variant because an internally tagged enum cannot carry a bare string newtype.

    kindrequired

    string

    "ruleset_audit"

    outcomerequired

    RulesetAuditOutcome

    string

    What the last ruleset audit of a binding found (`github_app_bindings.ruleset_audit_outcome`, migration `20260928120000_github_binding_ruleset_audit.sql`). [`Self::Clear`] is the one outcome that makes a binding `Healthy`; every other value records WHY it is `ruleset_unverified`. The audit fails closed: anything it cannot prove — a field GitHub did not report, a list it may not read, a rule whose ruleset it cannot see — is a refusal, never an assumed "the App cannot bypass" (`plans/github-managed-repositories-2026-09.md` Phase 2; evidence `docs/evidence/github-managed/provider-contract-2026-09-27-175844.md`).

    "clear""app_can_bypass""bypass_unknown""rulesets_unreadable""ruleset_hidden""too_many_rulesets""classic_protection_unreadable""app_in_classic_allowance""app_holds_administration_write""protection_events_not_subscribed"

  • object

    [`RulesetAuditOutcome::ProtectionEventsNotSubscribed`], with the webhook events the installation has not accepted (from the audit's detail; display only).

    kindrequired

    string

    "protection_events_not_subscribed"

    missing_eventsrequired

    array

    items

    string

  • object

    [`RulesetAuditOutcome::ClassicProtectionUnreadable`] on an installation without `administration: read`.

    kindrequired

    string

    "administration_read_missing"

  • object

    The write health refuses managed writes on its own ([`GithubWriteHealth::refuses_managed_writes`]).

    healthrequired

    GithubWriteHealth

    string

    Whether a GitHub-authoritative repository is currently safe to write through — the `github_repo_sync.write_health` column. Closed vocabulary; the tokens are the CHECK list at `migrations/20260901120000_github_relationship_expand.sql`. The default for a fresh relationship is [`Self::LfsUnverified`], not `Healthy`: a repo whose LFS posture nobody has looked at yet is not known-good, and the fail-closed direction is the one that does not push objects at an upstream that will reject or mangle them.

    "healthy""lfs_unverified""lfs_blocked""paused""error"

    kindrequired

    string

    "writes_refused"

  • object

    [`LfsVerificationResult::PointersDetected`] over the post-attach ref set, published refs included.

    kindrequired

    string

    "lfs_pointers_detected"

  • object

    [`LfsVerificationResult::Unverified`], or no verification at all.

    kindrequired

    string

    "lfs_unverified"

  • object

    The GitHub repository is archived.

    kindrequired

    string

    "github_archived"

  • object

    GitHub advertises `refname` inside the preserved namespace.

    kindrequired

    string

    "github_advertises_preserved_prefix"

    refnamerequired

    string

  • object

    This repository already holds `refname` inside the preserved namespace.

    kindrequired

    string

    "local_ref_under_preserved_prefix"

    refnamerequired

    string

  • object

    No preserved name within [`MAX_REFNAME_BYTES`] can be formed for `refname`.

    kindrequired

    string

    "preserved_name_too_long"

    refnamerequired

    string

  • object

    A GitHub ref intent is not terminal (an `ambiguous` one included).

    kindrequired

    string

    "unsettled_ref_intent"

  • object

    Another attach run for this repository is not settled.

    kindrequired

    string

    "unsettled_attach"

GithubSyncFix

string

The stable code the GitHub panel renders as the remedy for a [`GithubSyncBlocker`]. Closed, so the SPA's copy table is exhaustive; one code may answer several blockers ([`GithubSyncBlocker::fix`] is the map).

"contact_operator""install_github_app""wait_for_binding_audit""recheck_github_app""reinstall_github_app""grant_github_app_permissions""fix_github_rulesets""accept_github_app_events""resume_sync""check_write_health""remove_lfs_pointers""recheck_lfs""unarchive_github_repository""remove_preserved_refs_on_github""rename_local_ref""resolve_ref_intent""settle_attach"

AttachPublishKind

string

What a publish sends to GitHub: a branch or a tag, read off the refname.

"branch""tag"

AttachRefClass

string

How one ref's local and GitHub tips compare — the left column of D4.

"equal""local_behind""local_ahead""diverged""only_github""only_neosource"

AttachRefOutcome

string

What the attach does with one ref — the middle column of D4.

"keep""fast_forward""create""preserve_and_reset""preserve""drop""publish"