Work with Git repos
Add a repo to a workbench and Git is ready the moment the container starts:
the code is checked out, git push is authenticated, and on GitHub and GitLab
the provider CLI is signed in. Everything around the repo -
branches, pull requests, CI runs - works from inside the workbench, whether
you run the commands yourself or an AI agent does. All it costs is one access
token, set up once.
This guide walks that path end to end: create the token, start a workbench with a repo on board, verify the round trip, add and remove repos in a running workbench, and keep a work and a personal account apart on one machine.
The guide talks GitHub throughout, but GitHub is only the stand-in. GitLab
works exactly the same way - token, clone, push, and the glab CLI in place
of gh. Bitbucket clones and pushes the same way too, and a Bitbucket repo
also brings twg, its command-line layer here, from the
Atlassian feature - that feature is its own topic.
Where the clone lives
Section titled “Where the clone lives”Repos are cloned into projects/ inside the workbench, one folder per repo
(api.git becomes projects/api/). The clone happens inside the container
when it starts, authenticated with your access token, and it is idempotent: a
folder that already exists is left alone. So your branches, uncommitted
changes, and stashes all survive a monoceros apply rebuild. The workspace
sits on your disk under ~/.monoceros/container/acme/, and only
monoceros remove takes it away - with a
backup, by default.
Create an access token
Section titled “Create an access token”Pushing to a repo - and cloning it in the first place, if it is private - needs you to prove who you are. Over HTTPS that proof is a personal access token, the same kind you would create for a provider’s API. You set it up once, and every workbench you build afterwards can reach your repos.
For GitHub:
- Open github.com/settings/tokens.
- Click Generate new token, then choose Generate new token (classic).
- Give it a note and an expiry, then tick these scopes:
repo,read:org,gist,read:user. - Click Generate token and copy the value - GitHub shows it only once.
On GitLab or Bitbucket the moves are the same with different buttons; Git and repositories has the click-by-click steps and scopes for both.
Now store the token where every workbench finds it: monoceros-config.env in
your Monoceros home, the global pool all containers read from.
GITHUB_API_TOKEN=ghp_...That single value does double duty. Monoceros writes it into the container’s
git credential store, so git clone, pull, and push authenticate, and
into the gh CLI, so it is logged in from the start. A GitLab token goes into
the same pool as GITLAB_API_TOKEN; Bitbucket uses an Atlassian token,
ATLASSIAN_BITBUCKET_TOKEN (see the Atlassian feature).
And if you have more than one account on a provider,
several accounts on one machine shows how
the pool keeps them apart. The file lives in your Monoceros home, away from
any project repo - keep it private.
Create the workbench with the repo on board
Section titled “Create the workbench with the repo on board”With the token in place, name the repo when you create the workbench:
monoceros init acme --with-languages=node --with-repos=https://github.com/acme/api.gitNothing is built yet. init writes two files under
~/.monoceros/container-configs/, and they are worth a look (the real files
carry explanatory comments, dropped here for brevity):
schemaVersion: 1name: acmeruntimeVersion: 1.8.0languages: - node:22features: - ref: ghcr.io/getmonoceros/monoceros-features/github-cli:1 options: apiToken: ${GITHUB_API_TOKEN}git: user: name: ${GIT_USER_NAME} email: ${GIT_USER_EMAIL}repos: - url: https://github.com/acme/api.gitGITHUB_API_TOKEN=GIT_USER_NAME=GIT_USER_EMAIL=You asked for Node and one repo, and the yml shows things you did not ask for
by name. The github-cli feature came in with the repo, and that is
deliberate: a repo in a workbench almost always means more than clone and
push - branches, pull requests, CI runs - so Monoceros brings the provider’s
CLI along and signs it in with the same token. A GitLab repo brings glab
the same way; a Bitbucket repo brings twg, Bitbucket’s command-line layer
here, from the Atlassian feature.
The git.user block sets the committer identity for commits made inside the
container; fill the two values in acme.env, or set a machine-wide default
once in monoceros-config.yml. You can also leave everything blank: apply
then uses your host’s global git config, and if that is empty too, it asks
you once for name and email and offers to save the answer, so later applies
and new workbenches don’t ask again.
Git and repositories has the
full resolution order. And the empty GITHUB_API_TOKEN= in acme.env is a
per-workbench override - leave it empty and the global pool value from the
previous step is used.
URLs must be HTTPS. SSH-style URLs (git@github.com:...) are deliberately
rejected: they drag host-specific agent setup into a container that is
supposed to be reproducible anywhere.
Apply, and watch the checkout
Section titled “Apply, and watch the checkout”Now build it. apply validates the yml, materializes the container, and
brings it up - and its output tells the whole story of this guide. Watch the
run, or read its final screen:
$ monoceros apply acme
▸ Configurationℹ Using GITHUB_API_TOKEN for github.com✔ yml validated (~/.monoceros/container-configs/acme.yml)
▸ Scaffoldℹ SSH attach: ssh monoceros-acme (or pick it in your IDE)✔ materialized into ~/.monoceros/container/acme
▸ Container✔ container ready (1m 24s)
Languages node:22 Features github-cli Repositories api
▸ Next stepsℹ monoceros shell acmeThe first line is the credential pick: your token from the global pool,
matched to github.com. While the container starts, the spinner pauses on
cloning api… - that is your checkout happening - and the closing summary
lists the repo right next to the language and the gh feature. The scaffold
also put the repo into acme.code-workspace, so an editor attached to the
workbench shows api as its own root in the Explorer.
The container is up with the repo already checked out. See for yourself:
monoceros shell acmeYou land in a bash session inside the workbench, with the code at
projects/api/. Before you push anything, three quick checks show that the
wiring is right. First, ask the GitHub CLI who you are:
$ gh auth statusgithub.com ✓ Logged in to github.com account jane (GH_TOKEN) - Active account: true - Git operations protocol: https - Token: ghp_************************************ - Token scopes: 'gist', 'read:org', 'read:user', 'repo'The account is yours, and the scopes are the ones from the token step - the
token made it from your env file into the container, and gh is signed in.
Second, step into the clone and look at its remote:
$ cd projects/api$ git remote -vorigin https://github.com/acme/api.git (fetch)origin https://github.com/acme/api.git (push)A plain HTTPS URL, with no token embedded in it - the container’s git credential store answers for the host whenever git needs to authenticate. Third, check who your commits will be made as:
$ git config --get-regexp '^user\.'user.name Jane Doeuser.email jane@example.comThat is the identity apply resolved - from your env values, your defaults,
or the one-time prompt. With all three answers in place, the round trip works
right away: edit, commit, git push.
There is no login prompt and no credential helper to configure. That is the
point of the token step: you did the auth work once, on the host, and every
workbench inherits it. And the signed-in gh reaches further than a status
check: gh pr create opens a pull request right from this shell, gh run watch follows CI after a push, and on a GitLab repo glab does the same
jobs. The login survives rebuilds, so none of this is a first-run-only
convenience.
Add a repo to a running workbench
Section titled “Add a repo to a running workbench”Two weeks in, you need a second repo next to the first. Same idea as every other change, one command against the config:
monoceros add-repo acme https://github.com/acme/web.gitBecause the workbench is running, Monoceros does not make you wait for a
rebuild: the repo is cloned into projects/web/ right away, using the token
from the global pool. The yml is updated either way, so the next apply
would produce the same result from scratch.
Two things to know about the live path. First, the clone authenticates now,
so the token has to be in place before you run add-repo - on a private repo
without a token you get git’s auth error. Second, if the new repo is the
first one for its provider, the CLI feature it brings (gh or glab) lands
in the yml immediately but arrives in the container on the next apply -
features are baked in at build time. The same goes for the folder entry in
acme.code-workspace: it is appended on the next apply, and your editor
picks the new root up from there.
For a self-hosted host, name the provider so Monoceros knows which token family to use:
monoceros add-repo acme https://git.acme.corp/team/web.git --provider=gitlabRemove a repo, keep the work
Section titled “Remove a repo, keep the work”The web experiment is over and you want it out of the config:
monoceros remove-repo acme webThis removes the entry from the yml - and deliberately nothing else. The
clone at projects/web/ stays exactly where it is, with every uncommitted
change in it; delete the folder yourself when you are sure. The gh or
glab feature that came with the repo stays too, since you may well be using
it for other repos - drop it with
monoceros remove-feature if not.
And the folder entry in acme.code-workspace stays as well, since Monoceros
never removes workspace folders you may have kept on purpose - take it out in
VS Code or Codium with Remove Folder from Workspace, or edit the file.
What it changes is future builds: the next fresh build of this yml, on this machine or a teammate’s, will not contain the repo.
Several accounts on one machine
Section titled “Several accounts on one machine”Now the harder case. You have a work account for the acme org and a
personal one, both on github.com, and one GITHUB_API_TOKEN cannot serve
both. Give each account its own token in the global pool, keyed by name:
GIT_TOKEN__GITHUB_ACME=ghp_...GIT_TOKEN__GITHUB_JANE=ghp_...That is the whole setup. Monoceros picks the token per repo from the first
path segment of its URL - the GitHub org or user, uppercased. A repo at
github.com/acme/api picks GIT_TOKEN__GITHUB_ACME; one under
github.com/jane/dotfiles picks GIT_TOKEN__GITHUB_JANE. You configure
nothing per workbench, and a workbench that mixes repos from both accounts
authenticates each one correctly. Swap the provider in the name and the same
scheme covers GitLab groups: GIT_TOKEN__GITLAB_<GROUP>. Bitbucket is the
exception - its Atlassian token is user-scoped, so it isn’t keyed this way.
Under the hood it is a cascade, first match wins:
GITHUB_API_TOKEN- the explicit override, per workbench inacme.envor global.GIT_TOKEN__GITHUB_<SEGMENT>- the account-keyed token above.GIT_TOKEN__GITHUB- a provider-wide catch-all.
To pin a whole workbench to one account regardless of repo URLs, point its
override at the pooled token from acme.env:
GITHUB_API_TOKEN=${GIT_TOKEN__GITHUB_ACME}The same pattern covers the committer side. Commit identity resolves as its
own cascade, from a per-repo git.user down to your host git config, so the
work repo can commit as your work identity while the personal one keeps your
private email. Git and
repositories walks the full
cascade.
See also
Section titled “See also”- Git and repositories - the concept behind this guide: token storage, self-hosted hosts, and commit identity in full.
monoceros add-repo/monoceros remove-repo- the two commands, with all flags.- GitHub CLI / GitLab CLI -
the
ghandglabfeatures and their token options. - Your first workbench - the token step in the context of a full first setup.