labelsync

command module
v0.1.0-rc.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 11, 2026 License: MIT Imports: 5 Imported by: 0

README

specsnl/labelsync

Synchronise GitHub issue/PR labels across a set of repositories from a local YAML file.

labelsync is a reconciler, not a script: for each target repository it reads the current labels, resolves the desired set, computes an ordered plan, and then applies it — or prints it, under --dry-run. One labels.yml describes the labels you want; groups describe which repositories should have them. Running it twice changes nothing the second time.

# labels.yml
version: 1

groups:
  ours:
    org: yourorg
    exclude: ["*-archive"]

defaults:
  groups: [ours]

renames:
  - from: "bug"
    to: "type: bug"

labels:
  - name: "type: bug"
    color: "d73a4a"
    description: "Something isn't working"
  - name: "type: feature"
    color: "0e8a16"
    description: "New functionality"
labelsync groups            # which repositories that selects, and why the rest were filtered out
labelsync sync --dry-run    # the plan; writes nothing; exits 2 if anything has drifted
labelsync sync              # apply it

What it does, in one list:

  • Creates, updates, and converges names, colours, descriptions, and casing across every selected repository. Nothing is deleted unless you ask for --mode=prune, which reports first and then asks which labels to remove.
  • Renames without losing anything. A renames: entry becomes a PATCH, so every issue and pull request that carried the old label still carries it under the new name.
  • Never touches a repository no group selects. That is the safety property the rest is built on.
  • Runs in CI. --dry-run exits 2 on drift, so a pull-request check fails when the committed config and the live labels disagree; --output=json emits NDJSON with a stable error_kind.

Install

brew install specsnl/tap/labelsync

Or go install github.com/specsnl/labelsync@latest, or download a tar.gz for your platform from the releases page — Linux and macOS, amd64 and arm64.

Building from a checkout needs nothing but Docker and Task:

task build

Getting started

Export before you write a config. Descriptions in the config file are authoritative, so a config written from scratch clears every description your repositories already have:

labelsync export yourorg/yourrepo --out labels.yml

The rest — describing the repositories, the dry run, the first apply — is in Getting started.

Documentation

Page Covers
Getting started From install to a first apply, in six steps
Configuration file version, groups, defaults, renames, labels, and what is rejected
Commands Every command and flag, with the rename and prune recipes
Running in CI Exit codes, NDJSON, the workflow recipe, and the token CI needs
Architecture How it is built: packages, planner, palette, rate limiting, output
Design plan The design record — goals, prior art, the algorithm, milestones

The architecture section describes what has been built; docs/design.md is the forward-looking plan, kept as the design record and linked from the pages that grew out of it.

Contributing

Every command runs through Task, which wraps the Docker Compose services that pin the Go, golangci-lint, and Node versions — so a check runs the same way locally as it does in CI. Run task --list for the full set.

task checkall   # tidy:check, lint, test, md:check — run this before opening a pull request

Conventions, workflow, and the house rules that reviews are held to: AGENTS.md.

Documentation

Overview

Command labelsync synchronises GitHub issue/PR labels across a configured set of repositories, using a local YAML file as the source of truth.

Directories

Path Synopsis
internal
apply
Package apply executes a plan.Plan.
Package apply executes a plan.Plan.
cmd
Package cmd is the labelsync command tree.
Package cmd is the labelsync command tree.
config
Package config finds the labelsync config file, parses it, normalises what it parsed, and validates the result.
Package config finds the labelsync config file, parses it, normalises what it parsed, and validates the result.
github
Package github is labelsync's GitHub boundary.
Package github is labelsync's GitHub boundary.
github/ratelimit
Package ratelimit keeps a run inside GitHub's limits, proactively and reactively.
Package ratelimit keeps a run inside GitHub's limits, proactively and reactively.
labelsync
Package labelsync holds the values every other labelsync package depends on: the sentinel errors that describe how a run can fail, and the XDG paths and file names that describe where its files live.
Package labelsync holds the values every other labelsync package depends on: the sentinel errors that describe how a run can fail, and the XDG paths and file names that describe where its files live.
palette
Package palette owns colour allocation: the fixed grid of candidate colours a displaced label may be moved to, and the rule that picks one of them.
Package palette owns colour allocation: the fixed grid of candidate colours a displaced label may be moved to, and the rule that picks one of them.
plan
Package plan turns "these labels are configured" and "these labels exist" into an ordered list of changes.
Package plan turns "these labels are configured" and "these labels exist" into an ordered list of changes.
util/exit
Package exit holds the process exit codes labelsync returns, and the error type that carries one out of a command.
Package exit holds the process exit codes labelsync returns, and the error type that carries one out of a command.
util/output
Package output is the single channel for user-facing output.
Package output is the single channel for user-facing output.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL