Appearance
Polyrepo, monorepo feel
Starting state
A constellation of repos under ~/code, each in daft's worktree layout:
~/code/
├── api/
├── web/
├── worker/
└── infra/The ritual: navigation is cd ~/code/wor<Tab> muscle memory, and staying current is a shell loop —
bash
for d in ~/code/*/main; do (cd "$d" && git pull); done— that you run when you remember to. The pain has already happened: the loop silently skipped worker (its default worktree is master, not main), so a security bump everyone "pulled" never landed there, and the stale checkout burned an afternoon. Meanwhile "do we have a repo for the billing prototype, and where is it?" is a question you answer by reading ls ~/code and guessing.
The reach for daft: it already touches every one of these repos — let its catalog be the fleet's index, and run navigation and maintenance against the catalog instead of against a hand-rolled loop.
What changes
Nothing to configure. Every repo daft clones (or runs inside) registers itself in a machine-local catalog — identity, name, path, remote, default branch. On top of that index:
daft go <repo>jumps to any repo's default-branch worktree, from anywhere on the filesystem.daft list --all-repos,daft update --all-repos, anddaft exec --all-repossweep the whole fleet.daft doctoraudits the catalog itself and reconciles it with--fix.
Recipe
Clone the fleet — each clone registers itself:
bash
cd ~/code
daft clone git@github.com:acme/api.git
daft clone git@github.com:acme/web.git
daft clone git@github.com:acme/worker.git
daft clone git@github.com:acme/infra.gitFor a repo daft has never touched (an old plain clone), register it explicitly from inside:
bash
daft repo add --name legacy-billingThen the daily surface:
bash
# The fleet's index — names, default branches, locations.
daft repo list
# Jump anywhere, from anywhere. Lands on the repo's default-branch worktree.
daft go worker
# Monday morning, one command instead of the shell loop. Each repo's
# default branch is what updates — master, main, whatever it actually is.
daft update --all-repos
# Fleet-wide maintenance, run in each repo's default-branch worktree.
daft exec --all-repos -- npm audit fix
# Every worktree of every repo, one listing.
daft list --all-repos
# Audit the index itself: stale paths, identity drift, name collisions.
daft doctor --all-reposPiece by piece:
daft repo listshows what the catalog knows:NAME, defaultBRANCH,PATH.daft repo info <name>shows one entry in full, including any declared relations.daft go workerworks from~/, from insideapi, from anywhere — the catalog supplies the path, and daft lands you in the default-branch worktree.daft go worker feat/retryopens a specific branch's worktree there, creating it if the branch exists.daft update --all-reposreplaces the pull loop, and it can't make themaster-vs-mainmistake: each repo's recorded default branch is the target.daft doctorowns catalog hygiene. Deleted a repo with plainrm -rf? Doctor flags the entry pointing at a missing path, anddaft doctor --fixmarks it removed.
Removed repos stay addressable on purpose — their entry (and their hook-run history) survives, so restoring one is:
bash
daft clone worker # re-clones from the recorded remote URLVariants
By how repos join the catalog.
All up front
The Recipe's shape: a one-time clone script (or docs page) that daft clones the whole fleet. Best when the set is small and everyone should have all of it. The catalog mirrors the org list from day one.
Lazily, as touched
Clone nothing in advance. Repos enter the catalog the first time daft operates in them — a clone for a bug fix, a daft list inside an old checkout, an explicit daft repo add for the odd pre-daft clone. Best for large orgs where nobody holds the whole fleet: your catalog converges on exactly the repos you actually work in, and --all-repos means your fleet, not the org chart.
Idempotency & safety
The catalog is machine-local state (under daft's data directory), never committed, and self-healing: entries refresh whenever daft runs inside a repo, so moves and re-clones converge without ceremony. Re-cloning over a removed entry revives the name; the old identity is retired, not lost.
Names come from the repo's directory or remote and must be unique among live entries — a second clone of api elsewhere registers as api-2, with a notice. Rename anytime from inside the repo with daft repo add --name <name>.
Branch names shadow repo names
daft go api opens the branch api if one exists in the current repo — anything resolvable locally wins over the catalog. When a repo name is shadowed, address it explicitly: daft go --repo api.
Where to next
- Coordinating a service and its client — the relations manifest: teaching repos in the fleet that they move together.
- daft repo list — the catalog's CLI reference, including structured
--formatoutput for scripting. - Run daft from anywhere — the
-Cflag,daft go's single-repo ancestor.