.repoman.jsonEvery key here has a documented default; an empty {} is a fully valid
opt-in (see repoman-030-getting-started.md). You only add a key when you
want to diverge from its default. This document lists every key once, in
one place — the individual tool documents describe how each tool behaves,
not what every configuration key means, specifically so a key's meaning
doesn't have to be looked up in more than one document or risk drifting
between descriptions.
| Key | Default | Read by |
|---|---|---|
id_prefix |
"T" |
register |
id_separator |
"-" |
register |
legacy_id_prefix |
"" |
register |
legacy_id_separator |
"-" |
register |
id_namespaces |
[] |
register, waveprogress |
tracking |
"docs/TRACKING.md" |
register |
resolved |
"docs/RESOLVED.md" |
register |
known_issues |
"docs/KNOWN_ISSUES.md" |
guards |
guard_id_prefix |
"G-" |
guards |
changelog |
"CHANGELOG.md" |
guards (previous-release date), relcore |
version_file |
"VERSION" |
syncver, relcore |
version_targets |
[] |
syncver |
wave_tracking |
"docs/WAVE_TRACKING.md" |
waveprogress, addwave |
wave_plan |
"docs/WAVE_PLAN.md" |
waveprogress, addwave |
wave_short_names |
{} |
waveprogress, addwave |
wave_themes |
{} |
waveprogress |
wave_visibility |
{} |
waveprogress |
wave_html_title |
"wave progress" |
waveprogress |
wave_complete_word |
"" (means "done") |
waveprogress |
release |
{"steps": [], "archive": {}} |
relcore |
workspaces |
[] |
workspace |
id_prefix (default "T") and id_separator (default "-") —
the prefix and separator register.py next_id() uses for every new id it
generates. The default reproduces this project's own original,
only-ever-tested shape (T-1, T-2, ...) exactly for any consumer that
doesn't set these.
legacy_id_prefix (default "", meaning disabled) and
legacy_id_separator (default "-") — for a project that migrated id
shape mid-project and needs both forms recognized: ids already issued in
the old shape stay frozen in that shape permanently, while next_id()
issues only the new shape going forward. This isn't hypothetical scope —
the documented real case is a project whose ids T-1 through T-163 are
permanently frozen in T-NNN shape, with T-164 onward forward-only in a
new XOTNNN shape. Leaving legacy_id_prefix empty (the default) means
single-format behavior, byte-identical to before these two keys existed —
they're additive and change nothing for a consumer that never sets them.
id_namespaces (default []) — additional id prefixes recognized
alongside the primary id_prefix/id_separator, each with its own
independent next_id() counter. This is for a project running two (or
more) id shapes permanently side by side — e.g. T-nn for general debt
and BF-nn for bugfixes, both live indefinitely — as distinct from
legacy_id_prefix above, which is for a one-time migration where the old
shape is retired in favor of the new one and the two share a single
counter. Each entry is {"prefix": ..., "separator": ...}:
"id_namespaces": [
{"prefix": "BF", "separator": "-"}
]
register add --id-prefix BF ... allocates from that namespace (refused
if --id-prefix names anything not listed here); a plain register add
with no --id-prefix always uses the primary namespace. register
check/list recognize ids from every configured namespace — before this
key existed, a second live namespace like BF-nn was silently invisible
to both, undercounting open items with no warning at all.
tracking (default "docs/TRACKING.md") and resolved (default
"docs/RESOLVED.md") — where register reads and writes the live register
and the closed-item record. known_issues (default
"docs/KNOWN_ISSUES.md") — where guards reads and writes the
dormant-guard table. All three are plain paths, relative to the repository
root.
guard_id_prefix (default "G-") — the full prefix, including
separator, for dormant-guard ids ("G-" → G-13). A single string is
enough generality here — guards don't have the mid-project id-migration
need legacy_id_prefix exists for.
changelog (default "CHANGELOG.md") — read by guards stale to
derive the previous release's date when --since isn't given explicitly,
and by relcore for its own bookkeeping.
version_file (default "VERSION") — the single file syncver
treats as the source of truth for the current version.
version_targets (default []) — every other file that has to
agree with version_file. Each entry:
{"file": "app.py", "match": "VERSION = \"([0-9.]+)\""}
match is a regex with exactly one capture group — the group is what gets
replaced on set/bump-*, and what gets compared on check.
All optional — every key here defaults to empty or generic, specifically so a consumer that never touches waves sees no behavior change at all.
wave_tracking (default "docs/WAVE_TRACKING.md") and wave_plan
(default "docs/WAVE_PLAN.md") — the two documents addwave writes to and
waveprogress reads from.
wave_short_names (default {}) — wave_id -> short name,
auto-maintained by addwave. Never hand-edited.
wave_themes (default {}) — wave_id -> [themes], hand-curated when
used at all. Which open register debt genuinely belongs to a given wave's
subject matter is a judgment call, not something mechanically derivable
from the data alone — the empty default (no debt cross-referencing) is the
correct starting behavior until those calls have actually been made.
wave_visibility (default {}) — wave_id -> bool. Absent means
visible, matching the same additive-default rule as everything else here —
a consumer who's never touched this sees every wave, exactly as before the
key existed. This is persisted data, not a per-renderer setting: both the
ASCII and HTML renderers read this same dict, so visibility can't drift
between the two display forms the way it would if each tracked its own
separate notion of what's shown.
wave_html_title (default "wave progress") — the heading text for
waveprogress --html output. Cosmetic; the generic default is deliberate.
wave_complete_word (default "", meaning "done") — the word
waveprogress writes into a wave's own summary line
(**Wave N: k/n, <word>.**) once that wave reaches 100%. Hardcoded to
"done" before this key existed, with no override — a project whose own
established convention uses a different word had every existing summary
line silently rewritten the first time it ran waveprogress on an
upgraded binary, a one-time, unavoidable terminology migration bundled
into the upgrade. Set this to whatever word your project already uses
(for example "complete") to keep existing prose consistent across an
upgrade; leaving it unset is byte-identical to behavior before this key
existed.
release (default {"steps": [], "archive": {}}) — the manifest
relcore executes. Full schema:
{
"release": {
"steps": [
{"name": "build", "run": "make build", "resumable": true},
{"name": "test", "run": "make test", "resumable": true, "timeout": 900},
{"name": "gate", "run": "python3 scripts/my_gate.py", "always": true},
{"name": "sync", "builtin": "syncver", "always": true},
{"name": "archive", "builtin": "archive", "always": true}
],
"archive": {
"name": "{repo}-v{version}-checkpoint.zip",
"sources": ["README.md", "CHANGELOG.md", "VERSION", "src"],
"exclude": ["*.tmp", "*.log"],
"size_warn_mb": 3
}
}
}
Each step in steps is either a shell command (run) or a builtin
(syncver, archive — currently the only two). always: true re-runs the
step every time, resumed or not; resumable: true means the step is
journaled and skipped on --resume if it already succeeded — a step marked
neither runs once, and isn't specially skipped on resume the way a
resumable one is. timeout (seconds, default 600) bounds how long a
run step is allowed to take.
archive.sources lists what the archive builtin packages;
archive.exclude adds glob patterns on top of the builtin's own
always-excluded self-generated output (MANIFEST.sha256,
.release-state.json, release-*.log) — see
repoman-020-failure-modes.md #7 for why that exclusion exists.
archive.name supports {repo} and {version} placeholders;
size_warn_mb (default 3) flags an archive larger than that many
megabytes rather than silently producing an unexpectedly large one.
workspaces (default []) — every cross-project workspace this
project has joined, written and maintained entirely by repoman
workspace join/leave (see repoman-086-workspace.md); never
hand-edited. Each entry:
{
"name": "acme-platform",
"remote": "git@github.com:acme/workspace.git",
"credential_env": "ACME_WORKSPACE_TOKEN",
"project_name": "acme-web"
}
name identifies the workspace locally (what every workspace
subcommand takes as its first argument). remote is the git remote
join cloned from and every subsequent workspace operation clones
again. credential_env only ever names an environment variable
that holds the credential for pushing to remote — the secret itself
is never written here, provisioned separately per machine, the same
principle badcode's own config follows. project_name is the name
this project registered under on the workspace side at join time;
workspace newissue defaults its filer identity to this rather than
re-deriving it from the current directory, so a project can't
register as one name and file issues under a different one by
accident.