Umbrella mode
Umbrella mode lets one rota setup span several independent git repositories that sit side by side under one parent folder. Knowledge, decisions, vision, and the backlog live once at the umbrella; each sub-repo keeps its own history, branches, and remotes.
In single-repo mode, skip this page.
When to use it
Turn on umbrella mode when you maintain a handful of related repositories (say ~/projects/myorg/ with web/, api/, and shared/) and want one shared KNOWLEDGE.md, DECISIONS.md, MILESTONES.md, and backlog instead of forking them into N copies. The typical signal: “I keep cross-pasting the same gotcha into three repos’ notes.”
When NOT to use it
- Single-repo project. The single-repo path is simpler and faster.
- Monorepo. A monorepo is one git repo; umbrella mode is for multiple repos under a parent.
- Casually-grouped unrelated repos. If the repos under your folder don’t share knowledge, decisions, or planning concerns, umbrella mode just adds bookkeeping.
How it differs from single-repo
| Aspect | Single-repo | Umbrella |
|---|---|---|
.rota/ location |
Repo root | Umbrella root (one level up from sub-repos) |
Where rota runs git ops |
The repo | The sub-repo for the current item (resolved via Repos: tag or --repo flag) |
| Worktree path | <repo>/.claude/worktrees/<branch> |
<umbrella>/.claude/worktrees/<repo>/<branch> (Layout B) |
BACKLOG.md, ARCHIVE.md, DECISIONS.md, MILESTONES.md |
Per-repo | Shared at the umbrella. With issues.source set to github or gitlab there is no BACKLOG.md: each sub-repo’s items live on that sub-repo’s own tracker (issue backend). When the sub-repos sit on different forges (some on GitHub, some on GitLab), set issues.source: forge: each sub-repo’s issues then live on its own forge. rota migrate source picks it for such an umbrella |
KNOWLEDGE.md (+ Glossary, tier sidecar) |
Per-repo | Hybrid: umbrella .rota/KNOWLEDGE.md for cross-repo learnings/terms plus per-sub-repo .rota/knowledge/<name>/KNOWLEDGE.md for repo-local ones |
status.json entries |
Keyed by branch |
Keyed by (branch, repo) |
.rota/handoff/<branch>.md |
One per branch | .rota/handoff/<branch>@<repo>.md (one per branch+repo) |
| Sub-repo git histories | n/a | Independent, with no submodules or version pinning |
Umbrella mode is in effect when .rota/repos.json registers at least one sub-repo; umbrella.enabled in .rota/config.json is informational. Without registered sub-repos, every skill behaves exactly as before.
Enabling it
cdto the umbrella folder, the parent that contains your sub-repos as immediate children.- Run
rota init umbrella --listto see the immediate git children it would register. - Run
rota init umbrella --repos web,api,shared(or--allfor every child). It seeds.rota/likerota init, writes.rota/repos.jsonwith the repos you chose and setsumbrella.enabled: truein.rota/config.json. - If the umbrella is itself a git repo,
.gitignoregains a# ── rota umbrella ──block listing.claude/,.rota/, and each registered sub-repo.
The result looks like:
myorg/ # umbrella root
├── .rota/ # shared coordinator state
│ ├── repos.json
│ ├── KNOWLEDGE.md
│ ├── DECISIONS.md
│ └── …
├── .claude/ # worktrees land here (Layout B)
├── web/ # registered sub-repo (independent git)
├── api/ # registered sub-repo (independent git)
└── shared/ # registered sub-repo (independent git)
To opt back out, run rota config set umbrella.enabled false (see configuration). The registry file stays intact: entries in .rota/repos.json remain on disk, and rota stops consulting them until you toggle umbrella mode back on.
The registry: .rota/repos.json
The registry is one JSON file at the umbrella’s .rota/repos.json:
{
"repos": [
{ "name": "api", "path": "./api" },
{ "name": "web", "path": "./web" }
]
}
nameis the sub-repo’s basename and the value/rota-captureaccepts in theRepos:field on items.pathis relative to the umbrella root.rotacanonicalizes each entry viarealpathat lookup time, so symlinked sub-repo paths resolve correctly.- Entries are sorted alphabetically for stable diffs.
- The registry holds no SHAs or version pins: sub-repos are independent git repositories. See
.rota/DECISIONS.md(Architecture, “Umbrella mode does not use git submodules”) for the rationale.
Edit the registry with rota repo add and rota repo rm (see below), or re-run rota init umbrella to rescan. rota init umbrella is idempotent: a second run with the same selection is a no-op; a run with new names adds them; names you omit but were previously registered are kept (with a warning).
Editing the registry: rota repo add and rota repo rm
rota repo add services/billing # registers "billing" at ./services/billing
rota repo add ./api --name backend # registers "backend" at ./api
rota repo rm backend # unregisters it; ./api is left alone
rota repo add <path> registers one git repo below the umbrella root. The name defaults to the directory’s name; --name overrides it. Repeating it with the same name and directory changes nothing and exits 0. A name already taken by another directory, or a directory already registered under another name, exits 4. A path that is missing, not a git repo or outside the umbrella exits 3. A new entry gets the same .rota/knowledge/<name>/ directory and .gitignore line rota init umbrella writes.
rota repo rm <name> drops the entry and nothing else: the repo, its knowledge directory and its .gitignore line stay. An unregistered name exits 3. It warns when open items still carry the repo in Repos: or an active stream in status.json is in it; the warning does not block, and --json lists both as openItems and activeStreams.
Both take --json.
KNOWLEDGE.md and Glossary in umbrella mode
KNOWLEDGE.md is hybrid in umbrella projects:
.rota/KNOWLEDGE.md: umbrella file. Cross-repo learnings and umbrella Glossary terms..rota/knowledge/<name>/KNOWLEDGE.md: per-sub-repo file. Repo-local learnings and per-sub-repo Glossary terms. Created on first write (and pre-seeded byrota initumbrella setup).
The Glossary topic follows the same hybrid scoping. Scope resolves in this order: an explicit --repo umbrella|<name> flag wins; otherwise the cwd auto-resolves (inside a registered sub-repo it resolves to that repo, at the umbrella root to the umbrella). Single-repo projects always resolve to umbrella and behave byte-identically to before. The knowledge verbs (rota knowledge add, query, tier, amend) and the glossary verbs (rota glossary write, read, import) all take --repo; readers (rota knowledge query, rota glossary read) merge umbrella + sub-repo content with a > from: <path> provenance line per source when scope is a sub-repo. Tier sidecars split per file (.rota/knowledge-tier.json umbrella, .rota/knowledge/<name>/knowledge-tier.json per sub-repo).
DECISIONS.md stays umbrella-only. Hard boundaries are inherently cross-repo. A repo-local “decision” is really a learning; capture it with /rota-learn. Full model and rationale: references/persistence-skills.md, governed by the .rota/DECISIONS.md “Persistence-trio scoping under umbrella mode” boundary.
Resolvers: rota repo umbrella and rota repo which
Two verbs answer the questions every umbrella-aware skill asks: “is this an umbrella?” and “which sub-repo am I in?”
rota repo umbrella reports whether the project is an umbrella: it is when .rota/repos.json holds at least one registered sub-repo. --json returns {"umbrella": true|false}.
| Exit | Meaning |
|---|---|
0 |
Umbrella. |
1 |
Not an umbrella: no .rota/, no .rota/repos.json, or an empty registry. |
rota repo which answers the second question. From any cwd inside a registered sub-repo (including a Layout B worktree), it prints the registered name, and --json adds the sub-repo’s absolute path. It uses git rev-parse --git-common-dir to find the sub-repo root from inside a worktree, then matches against canonicalized entries in .rota/repos.json. To go from a name to a path, use rota repo resolve <name>.
| Exit | Meaning |
|---|---|
0 |
Inside a registered sub-repo. |
3 |
Not inside a registered sub-repo, not in a git repo, no umbrella, or a stray .rota/ inside a registered sub-repo masks the umbrella (the message says which). |
Both are read-only.
Worktree layout
Umbrella worktrees use Layout B:
<umbrella>/.claude/worktrees/<repo>/<branch>
One discovery point at the umbrella, <umbrella>/.claude/worktrees/, holds every active worktree across every sub-repo, grouped by repo. Sub-repos need no .gitignore edits. Single-repo mode keeps <repo>/.claude/worktrees/<branch> and is unaffected. To resolve the canonical Layout B path for a (repo, branch) pair without hand-encoding it, call rota git worktree-path --repo <name> <branch>.
Per-skill behavior
Most skills delegate umbrella resolution to the underlying verbs and stay umbrella-flat at the prose level. The user-visible surface:
/rota-captureasks forRepos:when umbrella mode is on, accepting one or more registered names. Items can also be untagged (umbrella-flat, appropriate for cross-cutting tasks)./rota-workreadsRepos:from the item and runs the orchestrator plus workers against the resolved sub-repo’s.git/. The atomic commits land in that sub-repo’s history;status.jsonrecords the entry as(branch, repo)./rota-pausewrites its handoff to.rota/handoff/<branch>@<repo>.md(instead of<branch>.md) so two sub-repos sharing a branch name don’t clobber each other’s notes. The body gains aRepo: <name>line./rota-work(no argument) reads the umbrella-keyed path first and falls back to the legacy<branch>.mdform for older streams./rota-planrecords the target sub-repo in plan frontmatter (repo: <name>) when invoked with--repoor when the item carriesRepos:. Slice and milestone plans stay umbrella-flat./rota-spikeruns the spike branch in the resolved sub-repo (spike/<name>lives in that repo’s.git/); the spike file stays at<umbrella>/.rota/spikes/<name>.mdwith arepo: <name>frontmatter line./rota-work --previewdisplays the resolved sub-repo for items withRepos:in its peek output./rota-debugroutes its single fix-commit to the sub-repo resolved from the bug’sRepos:tag./rota-reviewscopes its branch inspection to the sub-repo viarota review scope --repo <name>.BACKLOG.mdandARCHIVE.mdlookups stay at the umbrella./rota-shipthreads--repothroughrota ship merge/rota ship prso the merge or PR runs in the correct sub-repo. Each run ships one sub-repo’s branch (at the umbrella root--repois required, exit 2 without it). For an item that spans several repos on the file backend, nothing opens linked PRs across repos or links them to each other: ship each repo’s branch separately, one PR (or merge) per repo./rota-refactorruns once per sub-repo with--repo <name>(rota refactor targets --jsonlists them), so each finding is filed on the tracker that owns the code./rota-learnroutes the learning (and--termGlossary entries) to the scope resolved from cwd or--repo: repo-local learnings land in.rota/knowledge/<name>/KNOWLEDGE.md, cross-repo ones in the umbrella file. At the umbrella root it asks once whether a learning is umbrella-shared or sub-repo-scoped. The per-sub-repo CLAUDE.md knowledge block lists umbrella ∪ that sub-repo’s topics. DECISIONS via/rota-decidestays umbrella-only.
The --repo <name> flag is also exposed on the underlying verbs when you call them directly: rota status add, rota status rm, rota review scope, rota ship merge, rota ship pr, rota plan add, rota spike add, rota git worktree-path, plus the knowledge/glossary surface (rota knowledge add, rota knowledge query, rota knowledge tier, rota knowledge amend, rota glossary write, rota glossary read, rota glossary import) where scope auto-resolves from cwd when the flag is omitted. Without the flag, verbs operate on the cwd’s git tree / umbrella scope as in single-repo mode.
What’s not yet in umbrella mode
- Multi-repo items on the issue backend. An item lives on one sub-repo’s tracker, so
rota item createrefuses several repos: capture one item per repo and link them withRelated:. On the file backendRepos:takes a comma-separated list and/rota-workbranches in each repo.
Footguns
- Don’t create
.rota/inside a registered sub-repo. It masks the umbrella.rota repo whichdetects this and exits 3 with a message naming the stray.rota/. - Never add a sub-repo as a git submodule of the umbrella. Sub-repos must remain independent. See
.rota/DECISIONS.md(Architecture).
See also
.rota/DECISIONS.md(Architecture, “Umbrella mode does not use git submodules”)- The
.rota/folder: whatrota initwrites - Vision and plans: milestones and plans
- Parallel rounds: the
rota roundverbs are not repo-scoped (no--repo)