Connecting a repository

How a workspace picks the repositories it reads from what the organization connected, what indexing reads and writes, supervised merges, webhooks, and every failure message.

Workspace → Repositories.

Which of the organization's repositories this workspace reads. The rules, the missions and the supervised merges here apply to these and only these. Read-only, always.

The code host — the GitHub organization through the Madebook App, or a person's account through a token — is connected once, for the whole organization, on Organization → Connections. There are no connection forms here. This page answers one question: of the repositories the organization reaches, which does this workspace read? One is the usual answer; several when a workspace spans a front end and its API.

The page opens with a Reading from strip naming the organization's connections — bookbaghq · GitHub organization (App, 42 repositories) — with a Manage on Connections link. When the organization has connected nothing, a callout says so and points there; the bundled sample repository is offered instead, so the pipeline has something to read.

Madebook never clones. Everything is read through the provider's API, so an abandoned run leaves no working copy on disk and no git binary is needed.

What is stored about a repository

Field Notes
Provider github, gitlab, azure_devops or fixture (the bundled sample).
Owner / name / full name
Default branch Read from the host, never from what you typed.
Private flag Also from the host.
Role Free text — frontend, api, shared, infrastructure. The sample is sample.
Indexed commit and time The commit the current intelligence was built from.
Index status See the table below.
Require supervision Whether every mirrored pull request gets a verdict.
Webhook secret Generated the first time somebody asks for the URL — a repository nobody has wired up should not have a live signing key sitting in the database.
Last error

Index status

Status Badge Meaning
never Not indexed Connected, nothing read yet.
queued Queued Waiting for a worker.
ingesting Indexing The deterministic pipeline is running.
ingested Indexed Files, dependencies and rule-based findings are there. The written analysis has not run.
ready Ready The written analysis is available too.
error Failed The last run failed; last_error says why.

Where the connection comes from

For GitHub there are two, both made on the organization's Connections page: the Madebook GitHub App (Option A — the organization's own connection, nothing that expires with a person, and the identity the supervised-merge check run is posted under) or a personal access token (Option B — a person's account). The picker here shows which one each repository would read through.

On Connections, the App panel shows one of three states:

  • Installed — the target, whether it covers all repositories or only selected ones, when it was last verified, and a note that webhooks and the check run arrive through the App. Links to change the selection on GitHub, and a Reinstall button.
  • Registered but not installed here — "Install the Madebook App on your GitHub organization and choose which repositories it may read. Nothing to paste, nothing that expires with a person, and the supervised-merge check run posts as Madebook."
  • Not registered — "The GitHub App is not registered on this Madebook yet. A platform admin does that once under Admin › Integrations; until then, connect with a personal access token."

Tokens for GitLab and Azure DevOps

GitLab and Azure DevOps are connected with a token on Connections too, under Not on GitHub?. What each token needs:

A token is tied to the person who made it and expires when they set it to. It is verified against GitHub, encrypted before it is stored, and never sent back to the browser.

Host What the token needs Looks like
GitHub A fine-grained token with Contents: read and Pull requests: read on the repositories this workspace needs. A classic token with repo also works. github_pat_…
GitLab read_api and read_repository. Add api only if the supervised-merge status should be posted — that is the one write, and it is a status, not code. glpat-…
Azure DevOps Code: Read, and Code: Status to post the supervised-merge verdict. The API base is the organization URL and is required. a 52-character token

For GitHub Enterprise Server or self-managed GitLab, open Self-hosted? and give the API base alongside the token — both must be entered together.

The token is verified against the host before anything is stored, then encrypted with AES-256-GCM. If no encryption key is configured on the server, nothing is stored and the error says so. Only a hint — the first and last few characters — is ever shown again.

Replacing a token (Rotate) verifies the new one first, then swaps it in place. Repositories and indexes are untouched: "Token replaced — every repository on this connection uses it now."

Disconnecting the account (Revoke) marks the connection revoked: "Disconnected — repositories and their indexes are kept, they just stop syncing until a new token arrives."

Adding the repository

Add a repository is one searchable picker across every connection the organization has — no choosing a connection first. It lists what the organization offers (everything its connections reach, or only the repositories chosen on Connections) minus what is already here, and shows beside each entry whether it is private and which connection it comes through: "{n} available to add". When repositories are being withheld, the line under the picker says how many and links to change it. There is also a by-hand field taking owner/repository; Madebook works out which connection can reach it — the account that owns it, else the App's — so nobody picks a connection by hand.

When nothing is connected at all, the empty state offers the alternative:

Connect GitHub on the left, or try the bundled sample: no credentials, and the whole pipeline has something real to find.

The bundled sample is acme-insurance/acme-claims-portal — a small C# web-and-API claims portal. Everything derived from it is labelled as sample data.

What happens on connect: Madebook fetches the repository from the host, which both proves it is reachable and supplies the default branch and the private flag. Then the row is written, an audit event recorded, and indexing is queued immediately.

{full_name} added — indexing has started

What indexing does

Five stages. Stages one to four are entirely deterministic — no model is involved.

Progress Message What it does
5% Reading the repository tree The branch head, then the full recursive tree — paths and sizes.
20% Classifying files Language, role, module and entry-point status per file.
45% Reading manifests and scanning for risks Dependency manifests and their packages.
70% Checking configuration for exposed credentials Secret patterns over config files.
95% Finishing

The fifth stage is a separate job — the written analysis — which reports Reading the repository digest, Deriving an architecture draft, and Analysis complete.

The reading budget

Cap Value
Files read in full during an index 60
Largest manifest read 400,000 bytes
Config files scanned The first 25, each under 100,000 bytes
Manifest excerpt kept 4,000 characters

What it writes

One row per file — path, directory, extension, size, language, role, module and whether it is an entry point. Never file content. Plus manifests, dependencies, and rule-based findings.

An index is a snapshot of one commit: every set is replaced rather than appended to, so a deleted file does not sit in the index forever.

Your verdicts on findings survive. A finding you dismissed does not come back as new after a re-index.

File classification

Vendor directories are excluded by whole path segment, never by substring: node_modules, bower_components, vendor, packages, third_party, bin, obj, dist, build, out, target, .next, .nuxt, .output, __pycache__, .venv, venv, env, .tox, .gradle, .terraform, coverage, .nyc_output, site-packages.

Manifests are recognised by filename: package.json and its lockfiles (npm), requirements.txt / pyproject.toml / Pipfile (pypi), go.mod, Cargo.toml, Gemfile, pom.xml / build.gradle (maven), composer.json, and *.csproj / *.fsproj / *.vbproj / packages.config (nuget).

A file's module is its first path segment — except that src/, app/, lib/ and packages/ are treated as containers and the second segment is used instead.

Re-indexing

Re-index on the repository, needing repository.analyse (member and up). It is disabled while a run is active.

Indexing also happens automatically on a push to the default branch, when a webhook is wired up.

There is no scheduled re-index. It is manual, or push-driven.

Asking for one while a run is in flight is not an error:

An index of this repository is already in progress.

While a run is live, both the repositories list and the repository page poll every 2.5 seconds and show the progress message and a bar.

Supervised merges

On the repository, a toggle:

Off — "What it does. Right now anyone can merge a pull request here, and nothing records whether the code was written under supervision. Turn this on and Madebook posts a pass/fail check on every pull request: green when the work went through a supervised session and no critical rule was broken, red when it went around Madebook. Make that check required under Branch protection on GitHub and nothing merges without it." Then: "Why you want it. Madebook exists so AI-written code only ships when a person supervised it. Until this is on, that is a habit; with it on, it is a rule the code host enforces."

On — "Every pull request on this repository gets a check called madebook/supervised: green when the code was written in a supervised session and no critical rule was broken, red when it went around Madebook. Make that check required under Branch protection on GitHub and a red one cannot be merged. A thin evidence trail never turns it red — that is judged in the review, not here."

Turning it on re-checks every open pull request immediately: "Supervised merges on — {n} open pull request(s) re-checked."

The panel counts what it knows: open pull requests, how many are supervised, how many went around Madebook, how many are not judged yet, and how many are not on the host — the last meaning the verdict exists here but the host does not have it.

See The pull request check for the branch-protection step that makes it binding.

This toggle is madebook/supervised only. Whether the exact commit meets the organization's rules is a second check, madebook/compliance, switched on per repository from the workspace's Compliance page — see The compliance check. A repository connected with a personal token can be monitored but never enforced, because a status posted by a person cannot be pinned to the App.

Webhooks

With a token connection, the webhook is pasted per repository. The panel explains why it is worth doing:

{provider} calls this URL the moment something happens — a push, a pull request, a CI check finishing, a review approval — so Madebook hears about it in seconds instead of on its polling schedule. It is what turns test results and approvals into observed evidence rather than an agent's own account of its work, and it keeps the repository index fresh after every push. Without it everything still works, just minutes later.

Paste the payload URL and the secret under the repository's Settings → Webhooks, content type application/json, and send check_run, check_suite, pull_request and pull_request_review. Add push too if you want automatic re-indexing.

Each provider verifies differently: GitHub signs with X-Hub-Signature-256 over the raw bytes, GitLab sends the secret in X-Gitlab-Token, Azure DevOps uses basic auth with the secret as the password. A delivery that does not verify gets a 404, never a 401 — an attacker probing for live webhook URLs should not learn which ids exist.

Rotating the secret: "The current secret stops working the moment the new one exists." Until you paste the new one into the host, events arrive on the slower path instead — nothing is lost. Do it whenever the secret may have been seen: a screenshot, a log line, a screen share. The audit log records that it changed, never what it became.

If Madebook does not know its own public API address, the panel cannot tell you the full URL:

Madebook does not know its own public API address: Bookbag SSO has no API base registered for it, and MADEBOOK_PUBLIC_URL is not set. Register the URL GitHub can reach, then paste the URL shown here into the repository's webhook settings.

The address comes from Bookbag's app registry (the API base registered for Madebook under Platform admin → Apps at Bookbag); MADEBOOK_PUBLIC_URL on the host overrides it for local development. Until one of them is set, the panel shows only the path, to prefix with your Madebook API URL.

Disconnecting

Disconnect {full_name}? Everything derived from it goes too.

The file index, the dependency map, the analysis, the architecture map and the findings are all removed. Keeping an orphaned index of a repository nobody can read any more would be a copy of the customer's structure with no owner.

Plans and reviews already produced are kept — they are a record of what happened.

What can go wrong

Message What it means
"GitHub rejected this token — it may be invalid, expired, or missing access to this repository. A fine-grained token needs Contents: read and Pull requests: read on the repositories this workspace uses." The credential.
"Not found on GitHub. Check the repository name, and that the token can see private repositories." The name, or the token's visibility.
"GitHub rate limit reached. The next run resumes where this one stopped." Wait. Nothing was lost.
"This connection's token could not be read. Re-enter it in the workspace's repository settings — the encryption key may have changed since it was saved." The server's encryption key changed.
"This repository has no source-control connection. Reconnect it in the workspace's settings." The connection was deleted.
"The GitHub App installation no longer includes this repository. Add it back on GitHub, or disconnect it here." Somebody narrowed the installation.
"{full_name} is already connected to this workspace." It is already there.
"Give the repository as owner/name." The by-hand field wants both halves.
"This connection is read-only. Madebook proposes changes for an engineer to make; it does not write to customer repositories." Something tried a write. Nothing in the product should.
The last run failed The repository card shows this with the stored error.

When the tree came back truncated, the index records it and the repository page says so, rather than pretending the whole tree was read.