lab: run multiple concurrent instances per project #50
Labels
No labels
bug
enhancement
in-progress
needs-info
needs-triage
p0
ready-for-agent
ready-for-human
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Cloonar/nixos#50
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem Statement
On the lab server I can only run one Claude session per project at a time — the tmux session name is the project name, so Start is capped at exactly one
claude --remote-controlper project. When one instance is busy with a long-running task, I'm blocked: I can't spin up a second session to investigate something else in the same project until the first is free.Solution
lab lets me run several concurrent
claude --remote-controlinstances of the same project. The index page groups instances under their project. I start an extra instance with one click (optionally giving it a label so I can tell which is which), open each instance in claude.ai independently, and stop them one at a time or all at once — up to a global safety cap. My primary work and my side-investigation run side by side against the same code.User Stories
tmux lsandtmux attachare self-describing when I drop to a shell.foovsfoobar) is never killed by mistake.Implementation Decisions
--permission-mode autoand can edit the same files. (The maintainer explicitly declined an ADR; the rationale is recorded here instead.)(project, number, label) → name; parsename → (project, number, label); allocate the lowest free slot (≥1 for an unlabeled instance, ≥2 when a label is given, where slot 1 is the bare project name); andbelongsTo(name, project)using exact-or-~-prefix matching. This is the riskiest logic, isolated behind a small interface.project~Norproject~N~label. The separator is~because the project-name sanitizer only ever emits[A-Za-z0-9._-](so~can never collide with a real project's derived name — instance detection is unambiguous even against a project literally namedfoo-2), and because~is the one separator with no special meaning in tmux's target-pane parser, on which the existing bare-name capture/send path depends (@ % $ : . =are all reserved by tmux).-max-instancesflag defaulting to 6.Testing Decisions
Good tests assert on externally observable behavior, not private fields: the session name produced, which pane actually receives keystrokes, what the store returns across operations, and the page rows/flags the handlers render. All four modules below are in scope for tests.
belongsToprefix-safety (foovsfoobar,foo~2vsfoobar~2). Prior art: the existingsessionNamesanitization unit tests.fooandfoo~2alive at once, capture / send / stop each hit the correct pane via tmux's exact-match preference, and stopping one leaves the other running. Prior art: the existing tmux-backed sessions tests (a real tmux is provided during the check phase).Note: lab's Go tests do not run in the repo's pre-commit hook (it is nix-eval-only). Run
go test ./...,go vet, and a build locally before opening the PR.Out of Scope
Further Notes
~-separator rationale and the shared-directory decision are captured in this PRD instead.SeedTrustrace stays at its accepted single-user level (same-directory starts write the same idempotent trust value).-max-instancesif needed.fw); per the lab vendoring ADR, onlyfwdry-builds when lab changes.