Connecting repositories
How to register and manage a git repository in your workspace.
A repository is a git repo connected to your workspace. When an agent picks up a task, CodeHerder cuts a fresh branch from the repo (or repos — see Tasks that span several repositories) it’s building in, and gives the agent an isolated checkout to work in. See Core concepts for where repositories fit in the full object model.
Registering a repository
You need CH_WORKSPACE_ID set before running any ch repo command.
Register a repo with its display name and clone URL:
ch repo create --name my-app --url https://github.com/acme/my-app
With no --branch given, CodeHerder starts agents from whichever branch your remote’s own HEAD points at. If your repo’s default branch has a different name, set it explicitly instead of relying on that fallback:
ch repo create --name my-app --url https://github.com/acme/my-app --branch develop
Pass the name of your actual default branch (develop, master, trunk, or whatever it is). You don’t have to get this right at registration time — see Editing a connected repository, below, for how to change it later, including from the web app.
Which clone URLs work
CodeHerder accepts a Git URL in one of two forms, and clones it over HTTPS either way:
- An HTTPS URL,
.gitsuffix optional:https://github.com/acme/my-app.gitorhttps://github.com/acme/my-app. This works for any git host reachable over HTTPS — GitHub, GitLab, Bitbucket, or a self-hosted server. - GitHub’s or GitLab’s SSH-style address, written exactly in lower case:
git@github.com:acme/my-app.gitorgit@gitlab.com:acme/my-app.git. CodeHerder rewrites this to an HTTPS clone before it ever reaches git — see Git access to clone the repository, below.
Everything else is rejected when you try to save it:
ssh://orgit://addresses, includingssh://git@github.com/acme/my-app.git- plain
http://(unencrypted) - an SSH-style address for any host other than github.com or gitlab.com — for example
git@bitbucket.org:acme/app.git - a bare file-system path
- a URL with a password in it, e.g.
https://user:token@github.com/acme/app.git
If you have an SSH-style address for a host other than GitHub or GitLab, convert it to HTTPS instead: git@bitbucket.org:acme/app.git becomes https://bitbucket.org/acme/app.git.
The host also needs to be reachable over HTTPS from the public internet; CodeHerder Cloud can’t register a repo on an internal-only git host. A self-managed deployment can lift that restriction, and re-admit http:// and the SSH/ssh:///git:// forms above, with the CH_ALLOW_INTERNAL_GIT_HOSTS setting — applied on the server and on every device that clones.
Even a form CodeHerder does accept — a plain https://<token>@github.com/acme/app.git, with no password — isn’t a safe place for a token: a repo’s Git URL is visible to every workspace member. Keep the credential on the device instead — see Git access to clone the repository, below.
This rule applies wherever you set a repo’s Git URL — the CLI or the web app — and to an edit exactly as it does to a new registration.
You can also register a repo from the web app instead of the CLI: open Set up → Repositories in the sidebar and click Register repo. The form has an optional Default branch field alongside name and Git URL — leave it blank to use the fallback described above. Either way, once it’s registered the repo appears under Set up → Repositories.
Listing and inspecting repositories
List all active repos in your workspace:
ch repo list
Include archived repos too:
ch repo list --all
Or see only the archived ones:
ch repo list --archived
See Listing archived records for how this flag works across CodeHerder. In the web app, Set up → Repositories carries the same three states as a Live / Archived / All picker in place of --all/--archived.
Show the full details for one repo:
ch repo show <name|id>
You can refer to a repo by its name or its full UUID — see Referring to things on the command line for how name matching works.
Editing a connected repository
You can update a repo’s name, Git URL and default branch from the CLI or the web app. Two more settings, the access level and the commit identity, are covered in their own sections below.
ch repo edit <name|id> --name my-app-renamed
ch repo edit <name|id> --url https://github.com/acme/my-app-moved
ch repo edit <name|id> --branch develop
Pass whichever flags you’re changing — --name, --url, --branch, or several together in the same call. Renaming a repo is open to any workspace member. So is archiving one. Registering a repo and restoring an archived one need a person’s account: an agent is refused. Changing the Git URL needs workspace owner or admin, and it has to be a person’s account doing it — an agent can’t repoint a repo, even one that holds admin. Your own account works either way: from the web app, or with ch repo edit --url using your own CLI credentials. A member without owner or admin sees the URL as plain text instead of an editable field in the web app (see Why a control is missing), and ch repo edit --url from an account without that role is refused.
In the web app, open Set up → Repositories in the sidebar, click the repo, then click-to-edit the name, Git URL or default branch: click the value, type the new one, and click Save (or press Enter) to commit it. Press Escape or click Cancel to discard your change and keep the current value.
Editing the Git URL is how you repoint a repo whose remote has moved — an org rename, a move to a different git host, or a URL that was mistyped when you registered it — without archiving and re-registering the repo (which would detach its task history). The same accepted forms described in Which clone URLs work, above, apply to an edit: a URL outside that list is rejected and the current value is left in place. CodeHerder uses the new URL the next time an agent clones the repo, so confirm the device still has git access to it — see What the device needs, below.
A couple of guardrails apply: the name can’t be empty, and you can’t rename a repo to a name already used by another repo in your workspace, or point two repos at the same Git URL — CodeHerder rejects the change and leaves the existing value in place. Re-saving a repo’s current URL is a no-op.
Changing the default branch
ch repo edit <name|id> --branch develop
ch repo edit <name|id> --branch ""
The second form clears the default branch back to unset. Changing the default branch is open to any workspace member — it doesn’t need owner or admin the way the Git URL does — but an agent can’t change it from inside a session, even one with member access; only your own account, from the web app or with your own CLI credentials, can.
Give it a plain branch name. A value that isn’t one — anything starting with -, containing .., whitespace, or one of : * ? [ \ ^ ~, or @{ — is rejected and the current value stays as it was.
Clearing it (or never setting one) doesn’t leave the repo without a starting point: CodeHerder falls back to whichever branch the remote’s own HEAD points at — the same fallback described in Registering a repository, above. ch repo show and ch repo edit display an unset default branch as (server HEAD) to make that fallback visible; ch repo list shows a plain - in the same case. In the web app, clearing the field in place of a value shows the (server HEAD) label.
A change takes effect for the next session provisioned for the workspace — a session already running keeps working from the ref it started with. Every change, including who made it, is recorded in the repo’s activity feed as default branch changed.
A repo’s default branch is the starting point for every task, but an individual task can override it — see Choosing a task’s base branch.
Read-only reference repos
Every repo has an access level. A new repo is always read and write: the Register form and ch repo create have no option to set it. To mark a repo as a reference that agents can read but not change, set it to read only:
ch repo edit <name|id> --access-level read_only
ch repo edit <name|id> --access-level read_write
On the web app, open the repo’s page and use the Access select, which offers Read and write and Read only (reference). Only a workspace owner or admin sees the select; other members see the level as plain text. As with the Git URL, it has to be a person’s account — an agent can’t change it. ch repo show prints the level in an access row.
For a read-only repo:
- Agents can still clone and fetch it, so they can read the code.
- CodeHerder refuses to record a merge request for it on a task.
- CodeHerder refuses an agent’s push to it through the git access it provides to agent sessions. On a device where agents use the device’s own git sign-in instead, that sign-in may still allow a push. For a hard guarantee, also use branch protection or a read-only token on the git host. See Isolating agent runs on a device.
CodeHerder doesn’t tell an agent in advance that a repo is read only. The agent finds out when its push or its merge-request record is refused. Nothing stops you attaching a read-only repo to a task, but a task needs a read-and-write repo to land changes.
A change applies to the next session; a running session keeps the level it started with. Every change, including who made it, is recorded in the repo’s activity feed as access level changed.
Setting a commit identity for a repo
By default, commits made by an agent carry the names described in Whose name is on a commit. If one repo needs a single fixed name on its commits — a release bot, say — set a commit identity on it:
ch repo edit <name|id> --publication-identity "Release Bot <release-bot@example.com>"
ch repo edit <name|id> --clear-publication-identity
The two flags can’t be used in the same call. This is a CLI setting only; the web app has no control for it. It needs workspace owner or admin, and a person’s account, not an agent.
With an identity set, an agent’s commits in that repo carry that name and email as both author and committer. This covers commits, amends, cherry-picks and rebases the agent makes. Other repos in the same session keep the usual names, and the task and session records still name the real agent. ch repo show prints the setting as publication identity: Name <email>, or (none: per-actor identity) when there isn’t one.
The name can be up to 128 characters and can’t contain < or >. The email needs exactly one @ and no spaces. A value that fails these checks is rejected and the current setting stays.
A change applies to the next session. A repo attached to a session that’s already running keeps the identity it started with.
Know the limits:
- A merge or rebase done on the git host records the owner of the token that did it, not this identity.
- A rebase keeps the authors of commits that already exist.
- The identity isn’t a signature. An agent in the session can override it.
Archiving and restoring
ch repo archive soft-archives the repo — it is not deleted and all history is preserved. Archiving removes the repo from the active list so it is not considered for new task assignments, but the record and any associated history remain intact and can be restored at any time.
ch repo archive my-app
To bring an archived repo back into service:
ch repo restore my-app
ch repo unarchive is an alias for ch repo restore.
Seeing what’s happened in a repo
For the commit ledger, the merge-request list, and the CodeHerder-versus-external activity split, see What CodeHerder built in this repo. For production and test line counts over time, see Tracking codebase size.
What the device needs
Registering a repository tells CodeHerder where your code lives. For that registration to translate into running tasks, the device that executes agent sessions also needs to be set up correctly — CodeHerder does not provision or manage the credentials described below, and the default workflow does not route work around a device that is missing them.
Git access to clone the repository
When a task starts, the device clones the repository over HTTPS — even one registered with a git@github.com: or git@gitlab.com: address (see Which clone URLs work, above). What the device needs is an HTTPS git credential, not an SSH key; an SSH key on the device is never used to clone, whichever form the Git URL takes.
The simplest way to set this up doubles as something you’ll want anyway — signing in with the host CLI:
- GitHub repositories: run
gh auth loginon the device (orgh auth setup-git, ifghis already signed in but git itself isn’t). See Host CLI for opening and landing pull requests, below — this same sign-in also covers opening pull requests, so it’s one setup step, not two. - GitLab repositories:
glab auth logincovers the same ground forglab.
Any HTTPS git credential helper that supplies a valid token for the host also works, if you’d rather manage it that way. If one device needs to work in repositories under different accounts or hosts, a single sign-in can’t express that — see Git tokens on a device for a pool of scoped tokens instead.
Public repositories need no credentials; git clone succeeds without authentication.
If the clone fails — for example, because the HTTPS credential is missing or has expired — the sandbox fails to provision and the task stays at its current stage. The failure is visible under the task’s Sessions view, where the abandoned sandbox shows the clone error, and under the device’s Git credentials check in its health snapshot — see Readiness checks. Fix the credential on the device and the task picks up on the next automatic retry.
Host CLI for opening and landing pull requests
Agents open pull requests and land them through the host’s own command-line tool. This CLI must be installed on the device and signed in with an account that has write access to the repository:
- GitHub repositories: install
ghand rungh auth loginon the device. - GitLab repositories: install
glaband runglab auth loginon the device.
If the CLI is absent or not authenticated, the code-stage agent cannot open the pull request, or the merge-stage agent cannot land it — whichever stage runs first reports the problem as a task comment. Install and authenticate the CLI on the device to resolve it. Here too, a device that needs write access under more than one account can add a scoped token instead of relying on a single sign-in — see Git tokens on a device.
CodeHerder does not manage or inject these credentials. Work simply fails on a device that is missing them, and the fix is always to configure the device — not to change the repository registration.
Checking host-CLI authentication
ch githost auth-check lets you verify that the correct CLI is installed and authenticated for a given repository before you start work. Run it from inside the repository:
ch githost auth-check
CodeHerder detects the host from the repository’s origin remote and checks the matching CLI — gh for github.com, glab for gitlab.com. It prints a clear result and exits 0 on success or 1 on failure:
✓ github.com (gh) authenticated
✗ gitlab.com (glab) not authenticated
auth-check only reads credentials — it never modifies them. If the check fails, follow the remediation the command prints: gh auth login for GitHub, glab auth login for GitLab.
To check a specific remote URL without being inside a git repository, supply it with --remote:
ch githost auth-check --remote git@github.com:acme/my-app.git
ch githost auth-check --remote https://gitlab.com/acme/my-app
For scripting or machine-readable output, add --json:
ch githost auth-check --json
# → {"data":{"host":"github.com","cli":"gh","authenticated":true}}
auth-check supports github.com and gitlab.com only. Bitbucket, self-hosted GitHub Enterprise, and self-hosted GitLab instances are not recognised — the command exits 1 with an “unrecognised host” message for any other remote URL.
Which repositories a task builds in
A task can work in more than one repository at once — see Tasks that span several repositories for the full model. CodeHerder resolves what a task builds in, in order:
- The repo set attached to the task itself, if it has one — this always wins, whether that’s one repo or several.
- The workspace’s default repo, if you’ve set one (see below).
- The one active repository across the workspace and its parent groups — the common case: connect one repo, and CodeHerder chooses it with nothing else to configure. A repo inherited from a parent group counts here.
If none of those resolve while at least one repository is in play somewhere — there is more than one active repo across the workspace and its parent groups, and no default — CodeHerder doesn’t leave the task guessing. It parks the task blocked right away, with a note naming every repo it found in play and telling you how to fix it: attach a repo set on the task, or set a workspace default. Check ch task blockers <taskId> to see it, or read the full symptom-to-fix walkthrough in Why isn’t my task moving?.
CodeHerder makes this choice when the task is created and attaches the result to the task. Changing the workspace default later only affects new tasks; existing ones keep the repos they have. A task a schedule spawns makes the choice when it starts. See Tasks that span several repositories for the details, including --no-repo for a task that needs no checkout.
If there’s no repository in play anywhere at all, that’s not a failure: CodeHerder runs the task in a sandbox with no repository attached. See Tasks with no repository at all in Tasks that span several repositories.
Setting a default repo
If a workspace has, or might ever have, more than one repository connected to it, set a default so CodeHerder always knows which one to build in:
ch workspace edit <workspace> --default-repo <name|id>
<name|id> can name a repository registered directly on the workspace, or one connected to a parent group and inherited into it — pointing a workspace’s default at an inherited repo is a supported way to build against a shared codebase without registering a second copy directly on the workspace. The repo must be active; naming an archived one is rejected. Setting or clearing a default requires workspace owner or admin access.
Only a leaf workspace can have a default repo — a group can’t, and a group’s default doesn’t carry down to the workspaces beneath it, so each one sets its own.
Read the current setting back with:
ch workspace show <workspace>
which prints a default repo row when one is set.
To clear a default and fall back to the sole-repo rule below:
ch workspace edit <workspace> --clear-default-repo
--default-repo and --clear-default-repo are mutually exclusive on the same call. This is a CLI and API setting today — there’s no matching control in the web app yet.
One thing to watch for: archiving a repository does not clear a workspace default that names it. A default pointing at an archived repo blocks that workspace’s tasks the next time CodeHerder starts a session for them, with a note naming the repo. When you archive a repo, repoint or clear the default on any workspace that names it in the same step.
Relying on the sole-repo rule instead
With no default repo set, a workspace with exactly one active repository just works — no configuration needed, and most single-repo workspaces never touch any of this. The count includes repositories inherited from parent groups, which show an inherited badge under Set up → Repositories. A workspace with one repo of its own plus one from its group has two candidates, so it needs a default.
If a workspace has more than one active repository, counting those inherited from parent groups, and you’d rather not set a default, archive the extras and keep exactly one — see Archiving and restoring, above. Archiving a parent group’s repo removes it from every workspace under that group, so prefer a default when the extra repo is inherited. If you regularly work across several codebases, you have two options: give each one its own workspace (see Managing workspaces) and set each workspace’s default repo to the codebase it should build, or — if a single task genuinely needs to change more than one of them together — attach the whole set to that task instead, as described in Tasks that span several repositories.
For the full symptom-to-fix walkthrough, see No repository resolves to build in in Why isn’t my task moving?.
Last updated