title: Home layout: home nav_order: 1 permalink: /
Software lives in multiple repos. Even a monorepo has upstream dependencies, vendored libraries, etc., where the source of truth is elsewhere. The code you work with almost always spans repos you own, repos you depend on (or forked), and maybe even repos you just want around as a reference.
The value of a monorepo is the workspace — all your code in one directory tree, so every tool that touches the filesystem works across all of it. Reporoot gives you the workspace without merging repos. A project reporoot.yaml file declares which repos belong together; reporoot workspace creates an isolated working copy with git worktrees and ecosystem wiring so cross-repo imports resolve locally. Repos stay sovereign: normal git, normal branches, normal push/pull.
reporoot/
├── github/ # Bare repos (shared store)
│ ├── myorg/
│ │ ├── server.git/
│ │ ├── web.git/
│ │ └── protocol.git/
│ └── socketio/
│ └── engine.io.git/
│
├── projects/
│ └── web-app/
│ ├── reporoot.yaml # which repos, what roles
│ ├── reporoot.lock # pinned SHAs
│ └── workspaces/ # gitignored
│ ├── default/ # primary workspace
│ │ ├── github/myorg/server/ # worktree
│ │ ├── github/myorg/web/ # worktree
│ │ ├── github/myorg/protocol/ # worktree
│ │ ├── package.json # generated: npm workspaces
│ │ ├── go.work # generated: Go workspace
│ │ └── node_modules/ # isolated
│ └── agent-task-42/ # parallel workspace
│ ├── github/myorg/server/
│ ├── github/myorg/protocol/
│ └── package.json
│
└── .gitignore
Bare repos at github/owner/repo.git/ hold the shared git object store. Workspaces at projects/{name}/workspaces/{ws}/ are isolated working copies with their own branches, worktrees, ecosystem files, and tool state. One fetch benefits all workspaces; cd switches between them instantly.
Why not just...
...use a monorepo? You'd need everyone to buy in, and you still have external deps, forks, and reference code outside the repo. The coordination problem exists either way.
...use git submodules? Submodules take ownership: detached HEAD by default, can't adopt existing clones, the parent controls the relationship. For repos you don't control, this is backwards.
...clone repos into a flat directory? Works for one person who set it up. Fails for: reproducing on a new machine, onboarding someone, remembering why a repo was cloned six months later.
Reporoot is the layer in between — structure and reproducibility without giving up repo independence.
Install
pipx install reporoot
Quickstart
Starting fresh:
mkdir ~/reporoot && cd ~/reporoot
reporoot fetch myorg/web-app
# Clones project + all its repos as bare clones
# Creates a default workspace with worktrees and ecosystem wiring
Creating additional workspaces:
reporoot workspace web-app review-pr-42
# New isolated workspace — own branches, own node_modules, own everything
cd projects/web-app/workspaces/review-pr-42
Inside a workspace, ecosystem commands just work — npm test --workspaces, go test ./..., uv run pytest. Git operations work normally in each worktree.
Three layers
1. The directory tree
Bare repos live under one root at {registry}/{owner}/{repo}.git/. This is just a directory convention — no tooling required. Workspaces mirror this layout (without the .git suffix) so relative paths in generated files work unchanged.
2. Ecosystem wiring
Each workspace gets its own generated ecosystem files:
| Ecosystem | Generated file | What it enables |
|---|---|---|
| Node (npm) | package.json with workspaces |
import { x } from '@myorg/shared' resolves locally |
| Go | go.work |
import "myorg/shared" resolves locally |
| Python (uv) | pyproject.toml with [tool.uv.workspace] |
editable installs across repos |
| gita | .gita/ config |
gita ll, gita super pull, role-based groups |
| VS Code | {project}.code-workspace |
single-root workspace with git repo detection |
Each integration auto-detects relevant repos (has package.json? include in npm workspaces) and skips gracefully if the tool isn't installed.
3. Reproducibility
A reporoot.yaml file declares which repos belong to a project. reporoot lock snapshots every repo's HEAD into a reporoot.lock file — the multi-repo equivalent of a monorepo commit hash.
# On a new machine — one command to reproduce the full workspace
reporoot fetch myorg/web-app
sha256sum reporoot.lock gives a single fingerprint for the entire project state.
Projects
Projects are named views over subsets of repos, with roles that signal how freely code should be changed:
# projects/web-app/reporoot.yaml
repositories:
github/myorg/server:
type: git
url: https://github.com/myorg/server.git
version: main
role: primary # your code — change freely
github/myorg/protocol:
type: git
url: https://github.com/myorg/protocol.git
version: main
role: primary
github/socketio/engine.io:
type: git
url: https://github.com/myorg/engine.io.git
version: main
role: fork # your fork — changes ideally go upstream
Repos can appear in multiple projects with different roles. Each workspace is an isolated instance of a project — own branches, own tool state, own everything. Create as many as you need:
reporoot workspace web-app # default workspace
reporoot workspace web-app hotfix # parallel workspace for a hotfix
reporoot workspace web-app agent-42 # isolated workspace for an agent
Commands
| Command | What it does |
|---|---|
reporoot |
Show current context (root, project, workspace, repos) |
reporoot workspace {project} [name] |
Create a workspace (default name: default) |
reporoot workspace {project} [name] --delete |
Delete a workspace |
reporoot workspace {project} [name] --sync |
Sync workspace worktrees with manifest |
reporoot workspace {project} --list |
List workspaces for a project |
reporoot fetch {source} |
Clone a project and all its repos, create default workspace |
reporoot add {url|path} |
Clone a repo and register it in the current project |
reporoot remove {path} |
Remove a repo from the current project |
reporoot lock |
Snapshot repo versions from the current workspace |
reporoot lock-all |
Snapshot repo versions for all projects |
reporoot check |
Run convention enforcement checks |
reporoot resolve |
Print the root or workspace path |
Docs
- Conventions — full design: directory layout, projects, roles, workflows, adjacent tools
- Integrations — how each integration works, generated file formats, configuration
License
MIT
Metadata
Release files for reporoot 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| reporoot-0.5.0.tar.gz | 53.1 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| reporoot-0.5.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 97.2 kB
Release files / reporoot-0.5.0.tar.gz
| Download URL | reporoot-0.5.0.tar.gz |
|---|---|
| Size | 53.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5c374e9fa8d400999e357e79c1d8b520adcdfeeaa9a61c45a6730977f9ff713f
|
|
BLAKE2b-256 checksum How to use checksums |
0d53a7c8f3d84714774e2d95b220f3403796550f13572ea7978889c06a8af18e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 3, 2026.
Transparency logRelease files / reporoot-0.5.0-py3-none-any.whl
| Download URL | reporoot-0.5.0-py3-none-any.whl |
|---|---|
| Size | 44.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9db22424ea75c4c4539fc3a7c9d3aa736357ef0ab792211192a37decfb0aacac
|
|
BLAKE2b-256 checksum How to use checksums |
545c3d4362ceb8edc8bae7fa2d7dd585c62c191ac6c385dca0316d708cb71531
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 3, 2026.
Transparency logSecurity for reporoot 0.5.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for reporoot-0.5.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 3, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.