Problem
The Lab (RFC 0035) keeps a team's RFCs, studies and diagrams in the platform first: a
labs service stores every version, the console edits them, and an export gives the
files back. That suits a team starting from nothing. It does not suit the teams RFC 0035
was written for, whose decisions already live in Git next to the code, reviewed in pull
requests like the code. For them a second copy in the platform is a copy that drifts,
and an editor that writes around their review process is one they will not use.
RFC 0035 decided the direction: the repository stays the source of truth, and an edit in
the console becomes a pull request. It left the mechanism open. The platform now has the
pieces it needs: connections (RFC 0018) hold outside credentials and run actions under
grants, the agent (RFC 0029) reaches systems inside a company's network, and the labs
service records versions with their author and message.
Proposal
A GitHub connection kind
A new connection kind, github, authenticated as a GitHub App that the platform
registers once and a team installs on the repositories it chooses. GitHub issues an
installation access token that "will expire after 1 hour" and can be limited to named
repositories and permissions when it is made
(GitHub docs).
The connections service mints one per action, for the one repository and the
permissions that action needs, and never keeps it.
The App asks for the least that the sync needs (permissions):
| Permission | Level | For |
|---|---|---|
| Metadata | read | required by GitHub for every App |
| Contents | read | reading trees and files |
| Contents | write | a branch and a commit for a proposed change |
| Pull requests | write | opening the pull request |
The kind's actions, each with its class (RFC 0018):
| Action | Class | Does |
|---|---|---|
read_tree |
read | lists the files under the lab's paths at a ref |
read_file |
read | one file's text at a ref, with its blob id |
propose |
write_reversible | a branch from the lab's branch, one commit with the changed files, a pull request; closing the pull request undoes it |
status |
read | the installation, the repository and the last delivery |
Push and pull request events arrive through the App's webhook, verified with its signing
secret like any incoming hook (webhook-in), and are routed to the lab bound to that
repository. A team that runs GitHub Enterprise or GitLab inside its network uses the
agent as the executor later; the actions stay the same.
A lab bound to a repository
A lab's settings gain a source: the connection, the repository, the branch it follows
(the default branch unless named) and the paths it reads, by default the layout
iohr lab check already reads (docs/rfcs/, docs/studies/, the lab's
redaction.json) plus docs/lab/diagrams/ for diagrams as JSON.
- Binding reads the tree and imports every document and diagram as version 1, with the commit it came from. The redaction config in the repository replaces the one in the platform; from then on it is edited in the repository.
- A push to the followed branch records a new version of each changed file: the commit's id, its subject as the version's message and its author. An author is shown as the account member whose verified e-mail matches, and otherwise by name as Git recorded it. A file deleted in the repository is archived in the lab, never erased.
- An edit in the console on a bound lab is a proposal, not a version: saving opens (or updates) a pull request with that one document on a branch named after it. The document shows the open proposal and its review state on GitHub. The version is recorded when the merge arrives as a push, so the lab and the branch never disagree.
- A conflict (the file changed on the branch since the proposal's base) is shown in the console with the diff; the person rebases the proposal on the newest version or keeps it as it is for GitHub to resolve.
- Comments and reviews in the console stay in the platform and are linked from the pull request's description; the pull request's own review stays on GitHub. A lab can require both.
A diagram is drawn here in the RFCs product; this page does not show diagrams yet.
Safe by construction
- The App reaches only the repositories a team installs it on, and each token only the one repository and permissions of the action that asked for it.
- Every read, proposal and received event is in the audit log as who, what and outcome, with repository and commit ids, never file contents.
- Document text is customer data: it is never logged, never put in an error or a URL, and no model reads it in this phase.
- Unbinding stops the sync and keeps the lab's history; uninstalling the App on GitHub does the same from the other side, within one delivery.
- Actions cost units (
computeper action) and are rate limited per installation, below GitHub's own limits.
Alternatives considered
A personal access token. The quickest to build and the wrong default: it acts as a person, usually across every repository that person can reach, and lives until someone revokes it. An App installation is scoped to the repositories chosen and its tokens last an hour.
Deploy keys. Scoped to one repository, but they speak Git over SSH and cannot open a pull request, so every proposal would need a second credential.
Polling the repository. No webhook to verify, and minutes of lag and wasted calls on
every quiet repository. Events with a periodic reconcile (a daily read_tree to catch a
missed delivery) give both freshness and correctness.
The platform as the source of truth, with export. What the Lab does today. It stays the answer for teams without a repository; for teams with one it is the drift this RFC removes.
Decision
Open. Proposed: a github connection kind as a GitHub App with the four permissions
above and short-lived per-action tokens; a lab bound to one repository, branch and set
of paths; merges recorded as versions; console edits as pull requests; the platform's
own comments and reviews kept and linked. Order: the kind and binding with import, then
push events, then proposals, then GitLab and the agent executor.
Publication
The console's lab settings gain Source (connect GitHub, choose the repository, branch and paths); a bound lab's documents show their commit and any open proposal. The developer docs gain the App's permissions, what the sync reads and writes, and how to unbind.
Status log
- 2026-10-03: opened, after the connections service landed, as the mechanism RFC 0035 left open for keeping a lab in the team's own repository.
- 2026-10-04: the
githubkind is built once, as the GitHub App connector of RFC 0044 (its phase 3), and Lab uses it as the product consumerproduct:labthrough a person's grant:read_tree,read_file,proposeandstatus, withpushandpull_requestevents, installation tokens minted per call and never stored. - 2026-10-07: Checked: a
githubconnector exists in the connections catalogue, but no PR builds the sync (#162, #187 and #235 are text and diagrams), and no lab reads a repository. Open.