Syncs public repositories bidirectionally between a GitLab group (git.plan.ai/plan-ai) and a GitHub org (github.com/planailabs).
- creates repos on the side where they're missing (always public; private/internal repos are never touched)
- syncs only the default branch and tags, fast-forward only — diverged heads and mismatched tags are flagged in the web UI, never force-pushed
- tiny web UI showing per-repo sync status at
http://127.0.0.1:8877 - Prometheus metrics at
/metrics:ghglsync_runs_total{result},ghglsync_run_duration_seconds,ghglsync_last_run_timestamp_seconds,ghglsync_repo_status{repo,status}
GITLAB_TOKEN=... GITHUB_TOKEN=... daemon-github-sync # daemon + web ui
GITLAB_TOKEN=... GITHUB_TOKEN=... daemon-github-sync once # single pass, JSON report, exit 1 on errors
daemon-github-sync --config /path/to/config.tomlSee config.toml for all options — including exclude, a
list of repo names to skip entirely. Tokens are read from the
GITLAB_TOKEN / GITHUB_TOKEN environment variables (preferred) or from
gitlab.token / github.token in the config file.
Fine-grained personal access token (preferred), resource owner set to the org:
| Permission | Level | Needed for |
|---|---|---|
| Metadata | read | listing org repos (implicit) |
| Contents | read & write | fetching and pushing branches/tags |
| Administration | read & write | creating missing repos in the org |
Repository access: All repositories (new repos must be covered too).
Classic PAT alternative: public_repo scope is sufficient (only public
repos are synced); repo also works. The token's user must be allowed to
create repositories in the org.
Personal or group access token with the api scope. That single scope
covers listing group projects, creating projects, and git push/fetch over
HTTPS. (read_api + write_repository is not enough — creating missing
projects requires api.)
The token's user needs at least the Maintainer role in the group to create projects and to push to a protected default branch.
nix develop -c cargo build
nix develop -c cargo test
nix build # package{
imports = [ daemon-github-sync.nixosModules.default ];
services.daemon-github-sync = {
enable = true;
settings = {
gitlab = { url = "https://git.plan.ai"; group = "plan-ai"; };
github.org = "planailabs";
};
# file containing GITLAB_TOKEN=... and GITHUB_TOKEN=...
environmentFile = "/run/secrets/daemon-github-sync.env";
};
}Runs under DynamicUser with state (bare mirror cache) in
/var/lib/daemon-github-sync.