Connecting GitHub
How a Kampa project gets access to a repository, how you pick the repository, what Kampa does when that repository is empty, and how the rail you pick decides who merges. Everything here describes what Kampa does today.
How Kampa gets access
Kampa reaches your repository through the Kampa GitHub App, installed on your GitHub account or organisation. It is not an OAuth app acting as you: once connected, every commit and pull request Kampa makes is authored by the app, and GitHub lets it reach only the repositories you grant it.
Connecting sends you to GitHub's own install page for the app. There you choose All repositories or Only select repositories. You can change that choice, or remove the app, at any time from GitHub: your profile or organisation Settings, then Applications, then Installed GitHub Apps.
The app asks for Contents and Pull requests, read and write. It does not
ask for Workflows, so it cannot add or change anything under
.github/workflows/.
Two things are checked when GitHub sends you back:
- The return carries a one-time value Kampa set when you left. If it is missing or doesn't match, Kampa saves nothing and says the link expired.
- The Kampa account that started the connection must be the one that finishes it.
If your organisation requires an owner to approve new apps, GitHub returns without an installation. Kampa shows "Installation requires org-owner approval", and you connect again once an owner has approved it.
If the app is already installed, GitHub shows that installation's settings page instead of a new install. Saving a change there, such as adding a repository, sends you back to Kampa. Not yet: with nothing to change, GitHub keeps Save disabled and doesn't send you back, so return to Kampa yourself.
Two ways in
- From a project. Connect an existing project to a repository, then push to it. Use this when the tokens start in Kampa.
- Connect a repository. Start a new project from the tokens already in a repository. Use this when the tokens start in the repository.
From a project
There are two places to start:
- Push to GitHub on a project that isn't connected yet. Instead of an error, Kampa opens Connect GitHub to push. Click Connect GitHub.
- The project's Settings, then GitHub. The row Connect a GitHub App has a Connect button.
Both go to the same GitHub install page. When GitHub sends you back, pick the repository:
- Repository. A list of the repositories the installation can reach. If you granted the app exactly one repository, Kampa shows that one and skips the list.
- Base branch. The branch your pull requests go into. It starts as
main. Type another name if yours differs.
Click Save connection. Kampa checks, on GitHub, that the installation can reach the repository you picked before it saves it.
If you started from Push to GitHub, the push you were making continues by itself once you save, with the change note you wrote. If you started from Settings, nothing is pushed.
The tokens are written to tokens/ in the repository. The page
Your repository lists every file a push writes and
deletes.
Connect a repository
On Kampa's start screen, choose New project, then Connect. The screen Connect a repository asks for:
- Project name.
- Repository. Every repository the app can reach through the installations your Kampa projects already use, plus one you connect from this screen. If none is listed, use Connect GitHub, which installs the app and brings you back here. Once some are listed, the same button reads Add a repository on GitHub.
- Branch.
mainunless you change it. - Token folder.
tokensunless you change it. This is the folder Kampa reads now and writes on every push. - Rail. Review first is selected. See Rails below.
Then click Read repository. Kampa reads the token folder at the branch's current commit and shows one of two things, before it creates anything:
- What it found: the token count, the modes, the components, and the commit it read, for example "Read at commit 1a2b3c4. The project starts from exactly this commit."
- The one reason it can't use the folder. Nothing is created.
Connect project is enabled only after a successful read. It reads the folder again at the same commit, not at whatever the branch points to by then, and creates the project from it. That commit is the one the project agrees with the repository on, so a change made on the branch after it is noticed, not pushed over.
Changing the repository, branch or token folder after a read makes the read stale; read again.
What Connect a repository reads
Two layouts, and nothing else:
- The layout Kampa pushes. A
manifest.jsonin the token folder, one<mode>.jsonfor each mode it names, and the component documents it lists undercomponents/. The manifest decides the modes and the components, not the folder listing. - A flat DTCG folder, with no
manifest.json. Every.jsonfile directly in the folder is one mode, named after its file:dark.jsonis thedarkmode. Each must be a complete DTCG tree.
When the folder holds a tokens.css Kampa wrote, the mode order is taken from
it, so your next push writes the modes in the same order.
What it refuses
Kampa loads the folder whole or not at all. It refuses, naming the file:
- a branch that doesn't exist, or a token folder that doesn't exist at that commit;
- a Tokens Studio file (
$themes.jsonor$metadata.json) anywhere in the folder: Tokens Studio themes aren't DTCG; - a
manifest.jsonthat isn't valid JSON, has no collections, lists more than one collection, names no modes, maps a mode to a file other than<mode>.json, or lists a file that isn't there; - a manifest component that isn't
components/<name>.jsonwith itscomponents/<name>.resolver.json, one level deep; - with no manifest: a
.jsonfile in a subfolder, no.jsonfiles at all, or a file whose name isn't a valid mode name (letters, digits,-and_); - a token in one mode file and missing from another. Kampa won't copy it in for you;
- token types Kampa doesn't edit yet, shadow tokens included. Kampa won't drop them;
- a dimension Kampa can't read, such as
"medium", in adimensiontoken or a typographyfontSizeorletterSpacing. The message names the token, the mode and the string, and says to write it as{ "value": 16, "unit": "px" }. Kampa never guesses at it; - a folder with too many files for GitHub to list in one request.
What it rewrites, and tells you first
Kampa writes one DTCG shape. When your files spell something another valid way, the read lists what your first push will rewrite, one line each, and the first pull request repeats it:
- a
$typeset on a group: Kampa writes it on each token, which means the same thing (DTCG §6.3); - a dimension written as a string like
"8px", anywhere: Kampa writes a{ value, unit }object, the DTCG 2025.10 shape; - a colour written as a hex string like
"#ffffff": Kampa writes a{ colorSpace, components }object, the DTCG 2025.10 shape; - a colour object not in Kampa's one shape: Kampa rounds the components to 4
decimals, writes
alphaonly below 1, and writeshexfrom the components; - a typography
fontSizeorletterSpacingwritten as a string like"16px": Kampa writes a{ value, unit }object; - a value whose members are in another order: Kampa writes them in the order DTCG 2025.10 gives, which changes no value;
- a value in
em: DTCG has noem, so Kampa converts it to the unit of its font size; - a contrast exemption in Kampa's old per-token form: rewritten as a per-pairing exemption.
A .json file in the folder that is neither a mode nor a listed component is
named on the screen as left in place. Kampa doesn't load it and doesn't delete
it.
An empty repository
A repository with no commits has no branch for a pull request to go into. Kampa treats a repository as empty only when the base branch is missing and GitHub lists no branches at all. A missing branch in a repository that has others is an error that names the branch, never an empty repository.
From a project, the first push to an empty repository stops and asks first. The dialog Empty repository reads:
This repository is empty. Kampa will create its first branch (main) and first commit so your tokens have somewhere to live. Nothing existing is affected. Confirming continues your push and opens a pull request.
with your base branch in place of main. Create first commit and continue
does two things:
- Commits one file,
README.md, directly on the base branch, with the messagechore: initialize repository [kampa]. It holds the repository's name and the line "Design tokens managed by Kampa." Nothing else rides this commit. - Continues the push as normal: a new branch, one commit with the token files, and a pull request into the base branch.
Cancel writes nothing. This is the only commit Kampa ever makes directly on a base branch.
Connect a repository needs a token folder to read, so it refuses an empty repository ("There is no main branch in … or the repository is empty"). Start the project another way and connect it from the project.
Rails
Every project has a rail, set when the project is created. It cannot be changed afterwards: Settings, then Deploy, shows it as Locked. To use the other rail, create a new project.
- Auto-merge (Rail 1). Kampa opens the pull request and merges it straight
away with a squash merge. Nobody reviews it first. If GitHub refuses the
merge, for example because
mainrequires a check that hasn't reported yet, Kampa shows merge blocked and the pull request stays open for a person to merge. - Review first (Rail 2). Kampa opens the pull request and stops. A person, usually your developer, reviews and merges it.
Where you pick it:
- New project, a Template and Generate show both rails, with Auto-merge selected.
- Connect a repository shows both, with Review first selected, because the branch it connects to may be someone else's.
- Import shows no choice. An imported project is Auto-merge.
On both rails Kampa runs its check before it pushes. With Block push on check failure on, the default, a failing check stops the push before any branch or pull request exists. With it off, a failing push is still pushed, and on Auto-merge it is merged. The page The check has the details.
If main is protected, Auto-merge needs the app allowed to bypass that
protection, or every merge is refused and waits for a person. The page
Setting up a repository shows how.
A personal access token instead
The project's Settings, then GitHub, also has Manual token (advanced): an owner, a repository, a base branch and a personal access token. Kampa uses it only while the project has no app connection. A push made this way acts as the token's owner, not as the app, and deletes none of Kampa's older branches. The token is stored with the project and used only on Kampa's server; it is never sent back to your browser.
Disconnecting
- In Kampa: the project's Settings, then GitHub, then Disconnect. The project forgets the installation and the commit it last agreed with. The app stays installed on GitHub, and other projects that use it keep working.
- On GitHub: remove the app under Installed GitHub Apps. Every Kampa project using that installation loses access to its repositories.
What Kampa never does
- Acts as you on GitHub, unless you give it your own token under Manual token (advanced). Otherwise everything it does is done by the app, on the repositories you granted.
- Reads or writes a repository the installation can't reach. Kampa checks the repository against the installation on GitHub before it saves or reads it.
- Writes under
.github/. - Commits directly to your base branch, except the one
README.mdin an empty repository, after you confirm. - Creates a project from a partial read, or from a commit other than the one it showed you.