Merge pull request #10 from mhoennig/22-multi-repo

ADR 0009 and step 22 plan: one Werkator instance serves a set of repositories

# Conflicts:
#	docs/plan/22-multi-repo.md
#	docs/prs/2026-09-01-PR#6-werkdock-bootstrap.md
This commit is contained in:
mhoennig
2026-09-02 07:22:59 +02:00
4 changed files with 191 additions and 0 deletions
@@ -0,0 +1,60 @@
# One Werkator Instance Serves a Set of Repositories
**Status:**
- proposed: 2026-09-01
- accepted: 2026-09-01
- rejected: -
- superseded: -
**Decision [accepted]:** The founding tenet "one instance per repository" is revised to "one instance per repository *set*": a Werkator instance aggregates self-contained repositories listed in an instance registry, sharing one service, one port, one UI, one watcher schedule, and one global executor cap.
Implementation is planned as `docs/plan/22-multi-repo.md`; this ADR records the decision and its shape, not the code.
## Context and Problem Statement
"One instance per repository" (docs/Werkator-Konzept.md) does not scale even to two repositories on a Hostsharing Managed Webspace: building Werkbaum next to Werkator on mih34 would need a second service, a second assigned port, a second tunnel or domain, a second UI and metrics page.
Every repository multiplies operations while the instance-level resources could be shared.
### Technical Background
Everything repository-specific already lives inside the repository or is keyed by it: machine config with secrets, build results, auto-build slots, worktrees, and buildenvs under `.git/werkator/`; the artifact store under a per-repo key.
An instance can therefore aggregate repositories without absorbing their state — adding or removing a repository is a registry entry, never a data migration, and single-repo mode stays the degenerate case (a registry of one, implicitly the current working directory).
## Considered Options
* One instance per repository set (registry + aggregation) — chosen
* A federation dashboard proxying several single-repo instances
* Status quo: one instance, one repository
### One Instance per Repository Set
Good:
- One service, port, UI, tunnel/domain, metrics page for any number of repositories.
- Repositories stay self-contained; per-repo secrets, history, and pinning semantics are untouched.
- Global concurrency control across all repositories.
Bad:
- The repo dimension must be threaded through executor pools, watcher cycle, routes, and UI — the largest refactor since the rewrite (mitigated by a behavior-preserving `RepoContext` session first).
- Instance-level and repo-level configuration must be split cleanly (see below).
### Federation Dashboard over Single-Repo Instances
Rejected: less invasive, but it keeps N services, N ports, and N tunnels — it solves only the UI aggregation, not the operations burden that motivated the change.
### Status Quo
Rejected: on a webspace, ports and domains are the scarce, manually assigned resource; per-repository services do not scale there.
## Decision Outcome
One instance per repository set, with the configuration split decided 2026-09-01:
- **Instance config** lives in `~/.werkator.yml` in the home directory of the user running the instance — one instance per OS user, matching the platform model. It carries `server.*` (port, domain/public base URL, nginx), the repository registry, the control token, the global `executor.maxConcurrent`, and the watcher schedule. The file name stays `.werkator.yml` in all three locations; the location carries the meaning.
- **Repo defaults** may live in the home file, but only in an explicit `defaults:` block, merged *below* every repository's own layers (home defaults → committed project config → repo machine config → branch layer); pinning semantics are unchanged. Accepted cost: secrets may then live in two places.
- **Repo config** stays in each repository: the committed `.werkator.yml` and the machine config in its `.git/werkator/`.
- Instance keys found in a repo's machine config are ignored with a warning naming both files once a home config exists — never merged silently.
- When a home config with a registry exists, `werkator server` serves the registry regardless of the current directory; without one it serves the current directory exactly as before.
- Repository names (routes, UI) default to the directory basename, are overridable per registry entry, and duplicates abort the start loudly.
Consequences: `docs/Werkator-Konzept.md` and AGENTS.md change their wording when the implementation lands (plan step 22 sessions BD); until then this ADR documents the target and the existing behavior remains accurate.