repolane v0.11.0 · open source

Guides

FAQ

The questions a sceptical engineer asks before letting a tool sit between them and every repo they own.

On this page

In brief. Answers to what a sceptical engineer asks before adopting Repolane: when a plain alias is enough, what it changes on your machine, what leaves it, what it costs in context, how to get past a rule, and how you find out the hooks stopped working. The one thing to remember: the rules are a guardrail with stated limits, and lane doctor is how you check they are in force.

Why not just use git worktree and a shell alias?

For one repo, do that. git worktree add plus a function in your .zshrc is genuinely enough, and Repolane would be overhead.

What an alias does not give you is the part that is not about one repo:

  • One name across several repos. A lane is one id, one branch of that name in each repo it touches, and one folder holding all of them. lane start ABC-123 web api does in one command what is otherwise a git worktree add per repo plus the bookkeeping, and lane with adds a repo to work already started.
  • A written-down goal that outlives the terminal. .repolane/registry/lanes/<id>.md holds the goal, the note you left when you parked it, findings, and a log that gets a line when a session ends. An alias has nowhere to put that.
  • Refusing to lose work. lane done checks every repo in the lane before removing any of them, and refuses while anything is dirty or unpushed — including the case where a worktree has gone missing but its branch was never pushed.
  • The rules. Most of the Rules page is enforced by a hook rather than asked for in a prompt, and the page says which rules are only instructions. An alias cannot stop a session reading the repo next door at all; a hook can, within the stated limits.

If none of those four is a problem you have, the alias wins. That is a real answer, not a modest one.

What does this do to my machine, and how do I undo it?

The package, installed by pipx or uv in its own environment with its commands linked into ~/.local/bin; a list of your workspaces under ~/.local/share/lane; some symlinks (each asked about first, and in a few commands deletions) under ~/.claude/projects; and your workspace folder, which holds everything else. Nothing in /usr/local, no shell profile edits, no global Claude Code settings changed.

The full list, file by file, and the removal steps, are on What it changes on your machine. There is no lane uninstall command; the undo is manual and takes a couple of minutes.

Does it work with Cursor, Copilot, or no AI at all?

Yes, with one honest caveat.

Every command works standalone. lane start, lane status, lane brief, lane park, lane done, lane board and the rest are bash and Python over git; they do not call a model and they do not know whether one is running. Claude Code does not even need to be installed: the hooks only matter inside it.

A lane is an ordinary set of git worktrees in an ordinary folder, so any editor can open it — lane workspace (it takes no argument) writes VS Code .code-workspace files: one for the workspace with every active lane, and one per lane.

The caveat: the rules do not travel. The guard is wired through Claude Code’s hook events, so under another assistant you get the structure — one lane, one branch per repo, the lane file, the board — and none of the refusals. Nothing pretends otherwise, and nothing breaks.

Is my code or my prompts leaving my machine?

Repolane itself does not send your code or prompts anywhere. It has no telemetry, no analytics, no update check and no crash reporting. It is not network-silent, though:

  • The hooks read and write files inside the workspace (and, when a session ends, tidy duplicate transcripts under ~/.claude/projects). What they add to a session is text in the session you are already having; it goes wherever that session already goes, which is to Claude.
  • Git talks to your remotes, as git does (lane add <url>, the fetch in lane start, lane rules pull, and lane status / bare lane, which run git fetch -q origin in every base clone each time).
  • lane upgrade and lane upgrade --check ask PyPI for the newest version, and only when you run them; pipx or uv then download it.
  • gh talks to GitHub if you have it installed and signed in: lane gh, lane sync, and, while the board is open, a pull request lookup for each branch every 60 seconds.
  • lane board binds to 127.0.0.1 and nothing else, and rejects any /api request without the per-run token. Its page makes no outbound requests; the fonts ship with it.

See what leaves your machine for the full table.

How much context does the per-prompt injection cost?

Bounded, because memory notes are never injected, only their indexes.

Once per lane per session, on the first prompt, the guard adds a memory brief: .repolane/knowledge/preferences.md (capped at 3,000 characters), each .md file in .repolane/knowledge/shared/ (3,000 each), the cross-repo .repolane/memory/MEMORY.md index (3,000), each lane repo’s .repolane/memory/<repo>/MEMORY.md index (3,000 each), the list of attached references, the four-scope table and a short note on how to save a memory. The individual notes those indexes link to are not injected; Claude opens one only if it turns out to be relevant. A three-repo lane with no shared knowledge has a worst case of about 16,000 characters once (roughly 4,000 tokens, an estimate at about four characters a token), and each shared knowledge file adds up to 3,000. An index shorter than its cap costs only its length.

Separately, the first time a session touches a repo, that repo’s own CLAUDE.md is injected, cut at 8,000 characters, with its .claude/rules/ files listed by name and description rather than by content.

On every prompt, the first included, what is added is one line per repo — branch, ahead, behind, uncommitted — plus a pointer to the lane’s spec, and for a multi-repo lane a short reminder of the four ways to reach each repo. For the three-repo example on Working with Claude that is about 1,000 characters (roughly 250 tokens, an estimate); it grows with the number of repos in the lane, not with the size of anything else.

I already have twelve repos checked out with in-flight branches. What happens to them?

Nothing happens to them. lane add <path-to-a-checkout> takes the checkout’s origin as the remote and copies its git database into .repolane/repos/<name>; it never writes to the original. Your branches, your stashes and your uncommitted work stay exactly where they are.

Two things happen that you should know about (precisely, on Install): the copy’s default branch is reset to origin/<default>, so unpushed commits on it are not on that branch in the copy (push them first), and any ignored .env* files are copied into the base clone.

It also records where the repo came from, in the repo’s old_paths and in .repolane/registry/old-checkouts.json. That has two effects worth knowing: lane status will tell you when work is happening out in the old checkout rather than in a lane, and the guard will refuse to let a session read the old path — because a frozen copy of a file from before you adopted Repolane is exactly the sort of thing that gets quietly edited in the wrong place.

The practical migration is unexciting: add the repo, finish or push the in-flight branches in the old checkout at your own pace, then delete it when you stop using it.

What do I do when a rule blocks something I actually need?

Every rule has a way through it, and the refusal message names the one that applies.

BlockedThe way through
reading something outside the workspacelane ref <id> add <path> "why" — it appears under lanes/<id>/refs/<name>. Read-only by default; add --rw to allow edits
pushing to a default branchprefix the command with the marker you can see: ALLOW_DEFAULT_BRANCH_PUSH=1 git push …
reading a .env or a key filelane keys <path> from your own terminal lists the variable names and never the values. Inside a session that spelling is refused; the bare lane-env-keys passes, or point the session at .env.example (readable as normal). lane env <repo> checks the file is wired
a recursive grep -r or Grep-tool search refused because a repo has a .envleave the secret out: --exclude='.env*', rg -g '!.env*', or a Grep glob of "!.env*"; the denial names the option
a read-only reference you need to editlane ref <id> add <path> --rw, or lane ref <id> rm <name> to detach it

If what you need is not on that list, there is no switch that turns a built-in rule off. The built-in refusals live in the guard inside the installed package (scripts/hooks/guard.py), and an upgrade replaces it. The events the guard runs on are the lane hook … entries in .claude/settings.json at the workspace root. Deleting one there turns that event off for sessions started at the root, but per-lane sessions get their own .claude/settings.local.json, rewritten by lane start and lane resume, and lane upgrade and lane doctor --fix put Repolane’s hooks back. Make any such edit from your own terminal or a session at the workspace root (a lane session is refused). Rules specific to your project go in .repolane/registry/rules.yaml instead, and those can only add refusals (see Extending).

What happens when the hooks break and I don’t notice?

A guard that silently stops guarding is worse than no guard at all, and the bad case is real: if guard.py stops compiling, every rule is off at once and a session looks entirely normal. The check for it is lane doctor, and it makes more than one check. First, that guard.py compiles and still refuses: it feeds the guard eleven named probes (ten that must be denied, one ordinary command that must not be), so a file that compiles but does not enforce is caught too, and it checks that each of your own project rules still refuses its example. Second, that the guard is actually wired in everywhere: it walks every lane and worktree looking for the hook entries in each .claude/settings.local.json, and for a PreToolUse matcher that includes Glob and Grep, because a session whose local settings lost its hooks is unguarded even while guard.py is perfectly healthy. If a lane’s wiring is missing, the fix it prints is lane resume <id>, which rewrites it.

lane status runs the one-line form of the same check at the top of its output, so it is in front of you in the command you already type. lane doctor also checks, before anything else, that lane is on the PATH the hooks use: every hook is a lane hook … command, and one that cannot start leaves Claude Code running tools unguarded. lane doctor -v also runs the fuller guard test suite (over 1,800 cases), which exercises the individual refusals. It builds its own throwaway setup and never skips: if the fixture cannot be built, the run fails. A green doctor means the rules are in force, not that nothing can get past them; the security model lists how the guard fails.

Next steps

  • InstallRequirements, setup commands, how to check it worked, and how to remove it.
  • Security modelThe threat model, what the guard checks, how it fails, and where it stops.
  • RulesEvery refusal and which rules a hook enforces.
  • TroubleshootingHow Repolane breaks and what to type.