Skip to content
| Marketplace
Sign in
Visual Studio Code>SCM Providers>Parallelo SessionNew to Visual Studio Code? Get it now.
Parallelo Session

Parallelo Session

Lilyan ALDIMASHKI

|
6 installs
| (0) | Free
Binds the active terminal to its git worktree. Switch terminals, and the changes and files views follow.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info
Parallelo Session logo

Parallelo Session

⚡ Switch terminals, and the diff follows.

One window. Many agents. Each one's changes, exactly when you look at it.

Marketplace Open VSX MIT

Switching between three worktree sessions: the Changes panel, the file tree, the terminal and the status bar all follow the session you pick

😖 The problem

Run several coding agents at once — each in its own git worktree — and VS Code stacks every worktree together in one Source Control panel. Nothing connects the terminal you are working in to the diff you are looking at. You hunt for the right repository entry every single time you switch.

✨ The fix

Parallelo adds that one missing connection. Focus a terminal, and the Changes and Files views scope themselves to that terminal's worktree.

Three agents, three worktrees, one window. Pick a session and everything follows it — the diff, the file tree, the terminal, the branch in the status bar. The ⚠ marks two sessions that are editing the same file.

It never asks what is running. Claude Code, Codex, aider and a plain shell all behave identically, because the working directory of the process in the terminal is the only contract.

🎁 What you get

🔍 Changes One worktree's staged and unstaged files. Native diffs, per-hunk staging, discard and unstage inline.
📝 Session commits What this session has committed since it branched, one row per commit, files underneath.
⚠️ Conflict radar Two sessions editing the same file get marked before they collide.
🗂️ Sessions Every terminal in a worktree, with branch, drift (↑2 ↓1) and change count. Drag to reorder, drag to pin.
🌲 Files A file tree rooted at the active worktree, and a full-text search scoped to it.
🚀 Every worktree from the start A terminal opens in each one when the window does, so none stays invisible.
● Waiting / done A session marks itself when its agent asks you something or finishes a turn. Clears when you look at it.
🎨 Session appearance Name, colour and icon per worktree, remembered across reloads.
📊 Status bar Active branch and change count. Click to switch session.
➕ Start Session Creates the branch and worktree, copies your ignored files, installs dependencies, launches the agent.
🗑️ Delete Worktree Removes the directory, keeps the branch, always asks first. Says how many sessions share that worktree, and offers to close just one — or to delete the branch too, when nothing would be lost.

📦 Requirements

VS Code 1.93 or newer. No runtime dependencies. Process-tree detection needs macOS or Linux; Windows falls back to shell integration.

🧭 How it behaves

📝 Session commits

The last group in the Changes view: the commits this worktree made, newest first, each with the files it touched.

It is read, not inferred. Every linked worktree keeps its own log of what happened inside it, and Parallelo lists the entries that are commits. So:

  • Merges are never rows. A merge that arrived by git pull is not a commit this session wrote. You see the messages somebody typed, not Merge pull request [#221](https://github.com/lilyanAhmetoglu/parallelo/issues/221).
  • Nothing another branch did can appear. A stale default branch, a branch already merged, an agent that leaves a mirror branch — none of them can add or remove a row, because none of them is in this worktree's log.

Reset Session Baseline to Now hides everything up to this point, for when you have reviewed what an agent did and want to watch what it does next.

The group is for worktree sessions only. A terminal in the main checkout does not get one: its log reaches back to the repository's first commit, which is not a session.

⚠️ Conflict radar

A session that has edited a file another session has also edited since either of them started is marked three ways, so it reads at any sidebar width: the name takes the conflict colour, a ⚠ badge pins to the right edge, and the row leads with ⚠ 2 conflicts. Hover for the files and who else is in them.

Committing does not clear the warning — a session's own commits count, including the old name of a renamed file. This matters, because the agent worth warning about is the one making steady progress.

Three things it leaves out on purpose:

  • Merges — a merge authors nothing, and would drag in every file the merged branch ever touched.
  • The main checkout — a git pull there brings hundreds of commits nobody in the window wrote.
  • Meaning — two sessions in different functions of one file are flagged; two sessions at opposite ends of the same API are not.

Off with parallelo.conflictRadar, or back to uncommitted-only with parallelo.sessionBaseline.

🤖 Agents that make their own worktree

Some agents create a worktree and move into it — claude --worktree is the common case. The shell never moves, so its working directory still points where you launched from.

Parallelo reads the working directory of the terminal's process tree, not just the shell, so those sessions bind correctly anyway. Turn it off with parallelo.followProcessCwd.

Start these as a normal session, not a worktree session — the agent makes the worktree, so there is no point making one first. A normal session opens in the main checkout, on the base branch, whichever session you started it from; it never lands in another session's worktree. When you do want a second terminal in the worktree you are already in — a dev server, a test run — the picker offers This worktree as its own entry. To get the agent its own entry in the picker:

{ "label": "Claude Code (own worktree)", "command": "claude --worktree" }

🧠 Brainstorming rooms

Sometimes the expensive mistake is in the plan, not the code. A room puts two agents in one worktree and makes them argue about it before anyone writes anything.

Click +, choose Brainstorming room, give it a topic, and pick the two agents. Parallelo makes a worktree, opens two terminals in it, and seats one agent as the lead and the other as the peer. They take turns through a transcript on disk until they agree or run out of rounds, and the lead writes a spec file at the end.

Rooms need the server that carries the conversation:

bun add -g roundtable-mcp

The brief travels in the system prompt, not as typed input. --append-system-prompt-file puts each seat's instructions in place before the agent accepts anything, so a startup dialog cannot swallow them. Typed input can be lost; a system prompt cannot. If the opening line is eaten, type anything at all — the agent already knows which seat it is and what the room is for.

No seat can write a file, and that is enforced rather than asked for. An agent holding a file-writing tool will eventually use it: give a lead Write and Bash and it will start implementing the thing it was asked to plan. So the seats get reading and the room's own tools — the spec is produced through the server's write_spec, so no seat needs write access to produce output. Their permissions are settled up front too, because the peer spends most of a room parked inside one tool call, and an agent stopped at a prompt is a conversation that never starts.

Copilot and Codex seats need a POSIX shell. Neither CLI has a system-prompt flag, so their brief is handed over as $(cat …) on the command line, which cmd.exe and PowerShell do not expand the same way. On Windows, seat Claude Code.

Codex seats are read-only, including the lead. Codex fences writes with sandbox_mode=read-only rather than a tool list, and a sandbox cannot make an exception for git — so a Codex lead writes its spec through the room's write_spec and cannot commit it. Seat Claude Code or Copilot as the lead if you want the commit too.

Git is the exception, and only the lead has it. It is the seat that produces something, so it is the one that might commit the spec: it gets Bash(git:*) through leadRoomArgs, while the peer keeps Bash denied outright. Nothing there lets either seat write a file. Both seats share one checkout, so a git checkout . or git reset --hard from the lead discards what the peer is reading, and git stash is shared across every worktree in the repository.

None of that is yours to configure. The flags live on the agent entry in parallelo.agents as roomArgs — plus leadRoomArgs where the lead needs more than the peer — and Claude Code, GitHub Copilot and Codex all ship with working ones, each written in that CLI's own syntax. Claude Code's and Copilot's were checked against the real binary; Codex's come from OpenAI's documentation, because that CLI is not installed here. An agent with no roomArgs is refused a seat rather than opened, because a seat that cannot reach the server produces a terminal that sits there doing nothing and looks exactly like one that is thinking. To seat an agent Parallelo does not know, give it a roomArgs; to force one command line on both seats, set parallelo.roundtable.agentArgs. ${roomDir}, ${room} and ${seat} are substituted per room, and both are used in rooms only, never in a normal session.

Keep worktrees inside the repo. With the default worktreePath of .worktrees, a room's worktree sits under a directory your agent already trusts, and it starts straight into the conversation. Point worktreePath somewhere outside the repo and every seat opens in unfamiliar territory and stops to ask whether you trust it — in both terminals, every room.

You do not type anything into either terminal. The topic you gave the dialog is the whole brief, and it reaches each seat before the seat can be typed at — in the system prompt for Claude Code, and as the opening prompt on the command line for GitHub Copilot and Codex, which have no system-prompt flag. Either way it is an argument to the agent, not text typed at a TUI that is still starting. Parallelo then waits for each seat to appear in the room — an agent registers with the server the moment it has finished starting, which is the only reliable signal that it is ready to be told anything — and sends that seat its opening line. The lead posts first; the peer is already parked inside wait_for_message, so the lead's post wakes it. Nothing needs a person.

If a seat never reaches the room within two minutes, Parallelo says which one and offers its terminal, where the error will be. Parallelo: Send Brainstorming Room Brief re-sends by hand if you restart a seat yourself.

To read the discussion afterwards, not just the conclusion: focus a terminal in the room's worktree and run Parallelo: Show Brainstorming Room Transcript. It opens the whole argument in a preview, rendered outside the worktree.

The spec is the decision, written for someone who was not in the room. The transcript is how they got there — what the peer objected to and what the lead conceded. Deliberately two documents: putting the argument inside the spec makes the decision harder to find, and the spec is the file you push. From a shell:

roundtable transcript --room <name> --cwd <worktree>              # Markdown
roundtable transcript --room <name> --cwd <worktree> --out r.html # a page

You are asked which model each seat runs, so a room can be two of the same agent on different models — Opus 5 leading, Sonnet 5 pushing back. The choice is recorded against every message in the transcript. Add models to any agent in parallelo.agents.

Parallelo does not implement any of the protocol. It starts the worktree and the terminals, and puts a different seat in each terminal's environment — that last part is what lets two instances of the same agent hold a conversation, since neither the extension nor the server can otherwise tell them apart. Claude and Codex, Claude and Claude, Copilot and anything: the room never learns what is sitting in a seat.

Worth knowing before you run one:

  • Both agents share one checkout, because they are arguing about the same code. Rooms are for planning. Give the implementation to one agent afterwards, in a session of its own.
  • The round budget is the termination condition, not a safety rail. Two agents do not get bored and never run out of refinements. The default is 8.
  • It costs double. Two agents reasoning over the same repository. Worth it for a decision you would otherwise get wrong, not for naming a variable.
  • The spec ends with a Dissent section holding whatever the peer still disagrees with, in its own words. Two agents left alone converge into agreement, and what they flattened on the way there is usually the part worth your attention.

What a room leaves behind

One file, and you say where it goes when you create the room. You are offered SPEC-<room>.md in the root of the worktree, an existing docs/specs or docs if the repository has one, a folder browser, and a plain path box — the directories are made when the spec is written, so a folder that does not exist yet is fine. Browsing shows the base checkout, because the worktree does not exist yet and will hold the same directories anyway. That is the room's output and the only thing you need to read — the decision in the first paragraph, then the reasoning, the work broken into steps, and a Dissent section holding whatever the peer still disagrees with, in its own words.

Everything else is working material and is not committed. The prompts, the server config, and the transcript live under .roundtable/, which ignores itself — your repository's own .gitignore is never touched, and git status in a room worktree shows the spec and nothing else.

So the answer to "which file is the final one" is always the same: the one git is showing you.

Choosing the location needs roundtable-mcp 0.2.0 or newer. An older one writes SPEC-<room>.md and Parallelo says so rather than letting the file turn up somewhere you did not expect.

● Which session is waiting for you

Four agents running. Which one asked a question six minutes ago, and which is still working? Today you click all four to find out.

A session row shows a dot when its agent needs you and a tick when it has finished its turn. Both clear the moment you click the row — a mark that stayed after you had read it would be on every row by lunchtime.

The agent says which it is, because nothing outside it can tell. From the process tree, an agent waiting on a question and an agent that finished are identical: both alive, both holding the terminal, both using no CPU. This was built once from CPU sampling and removed, because the dot lit on every idle agent. So the signal comes from the agent itself — from whatever it already runs to tell you it needs you.

The contract is two commands, and any agent can drive it. That is the whole of it, and it is why this is not a Claude Code feature:

# when it needs you
d=$(git rev-parse --absolute-git-dir 2>/dev/null) && printf 'waiting\n' > "$d/parallelo-status"
# when it finishes
d=$(git rev-parse --absolute-git-dir 2>/dev/null) && printf 'done\n' > "$d/parallelo-status"

One line covers every repository, because it finds its own. In a terminal Parallelo opened, $PARALLELO_STATUS names the same file — for an agent whose notification command runs somewhere git is awkward to reach from. Put them wherever your agent takes them: Claude Code's Notification and Stop hooks, Codex's notify, a wrapper script, a Makefile target. Nothing here reads any agent's private session state.

Parallelo: Set Up Status Hooks

That asks which agent you run. For Claude Code it writes the two hooks into ~/.claude/settings.json, shown in full first and merged with whatever is already there. For anything else it hands you the two commands to paste — because writing a config format from memory would put broken settings in your home directory, and only Claude Code's has been checked against a real file.

A mark means something an agent did while Parallelo was watching. Whatever is already in the file when a window opens is treated as read, so yesterday's tick is not on the row this morning — and because a mark is tracked by when it was written rather than by what it says, an agent that finishes twice in a row lights the row twice, even though it wrote the same word both times.

The file lives in the git directory rather than the worktree, so it never appears in git status, the Changes view, or the conflict radar. A linked worktree has its own, so sessions do not collide — though two terminals in one worktree share a directory and so share the mark, which is true: something in there wants you.

Off with parallelo.sessionStatus.

💡 Things worth knowing

⚠️ git stash is shared across all worktrees. refs/stash lives in the common .git directory, so every worktree pushes onto one stack — one agent's stash pop will happily take work another agent stashed. Have agents commit to their session branch instead.

Parallelo warns once per repository per window, the first time the stash is touched while more than one session is live. It is a warning only; the extension deliberately has no stash feature. Off with parallelo.stashGuard.

🗑️ Deleting a worktree discards uncommitted work. The branch is kept, so anything committed is safe. Anything still in the working tree is on no branch and goes with the directory — the confirmation tells you how many files that is. Nothing is ever moved into your main checkout. Use Close Session if you just want the row gone — it closes that one terminal, and leaves any other session in the same checkout running.

When the branch holds nothing your base checkout does not already have, the confirmation offers Remove and Delete Branch as well. That is how a session name becomes free again. It is never offered for a branch with commits of its own, so the button cannot throw away an agent's work.

🌱 A new session always gets a new branch. Because deleting a worktree keeps its branch, a name you have used before is free in .worktrees and still taken in refs/heads. Parallelo will not silently check that old branch out — starting foo again branches session/foo-2 off your base checkout and says so. The old branch is left exactly where it was.

🔍 Search looks inside the session's files, not just at their names. The magnifier on the Files view opens VS Code's own Search panel with files to include already pointed at the active worktree, so a query finds text anywhere under it and nowhere else — switch terminals and the scope follows, like everything else here. It deliberately ignores your .gitignore for that search, because the default worktree location is .worktrees, which most repositories ignore; without that, searching a session would quietly return nothing. The find box on the tree itself is unchanged and still filters the rows you can see.

📦 A new worktree arrives ready to run. git worktree add checks out tracked files and nothing else, so a fresh session has no .env, no node_modules, and no local settings — which usually shows up as the agent's first command failing. Parallelo closes both gaps when it makes the worktree:

  • Ignored files are copied from the base checkout — .env, .dev.vars, .claude/settings.local.json: the machine's half of the project, which .gitignore keeps out of the repository and so out of a new worktree. parallelo.copyExclude skips what is installed or rebuilt rather than carried: node_modules, dist, .next, target, .venv, caches. Names are matched against every part of the path, so a monorepo's packages/ui/dist is skipped too. Files that are simply un-added are left behind — those are your work in progress, not the project's setup. Off with parallelo.copyIgnoredFiles; parallelo.copyFiles still names files to copy whatever else is decided.

  • Dependencies are installed with the command the base checkout implies. Every language keeps its dependencies out of the repository — node_modules, .venv, vendor, target — so no worktree comes with them, whatever the project is written in:

    JavaScript bun.lock · pnpm-lock.yaml · yarn.lock · package-lock.json, or packageManager in package.json, which outranks them all
    Python uv.lock · poetry.lock · pdm.lock · Pipfile.lock · requirements.txt
    Rust · Go Cargo.lock · go.mod
    Ruby · PHP · Elixir Gemfile · composer.json · mix.lock
    Swift · Java · .NET Package.resolved · gradlew or pom.xml · any .csproj
    Dart pubspec.yaml, telling Flutter from plain Dart by what is in it

    A repository with two of these gets both, joined with &&. It is typed into the terminal like any other line, so you can see it and stop it. Nothing runs when nothing says which manager the project uses — guessing wrong writes a lockfile the project does not want. Off with parallelo.installDependencies, and skipped entirely when you have set parallelo.setupCommand.

A new session therefore starts with a clean git status: everything copied is ignored, so the first thing in its diff is the first thing its agent did. The conflict radar is told what a worktree was created holding anyway, because .gitignore is a tracked file and a branch may spell it differently.

Copying is cancellable from the progress notification. An ignored directory can be any size, and a session creation that cannot be stopped would be worse than one that copies nothing.

🔌 Worktrees isolate files, nothing else. Ports, databases, dev servers and .env state are shared. Two agents running the same dev server will fight over the port.

⏱️ Terminals opened before the extension activates are picked up on activation, though one whose shell has not reported a directory yet may take a moment.

⚙️ Settings

Setting Default What it does
parallelo.agents Claude Code, Codex, GitHub Copilot, Shell Agents offered when starting a session or a room, each with its models and its room flags
parallelo.worktreePath .worktrees Where new worktrees go, relative to the repo root
parallelo.branchPrefix session/ Prefix for branches created for new sessions
parallelo.autoOpenRepository true Register a worktree with git when a terminal enters it
parallelo.followProcessCwd true Resolve the worktree from the terminal's processes, not just the shell
parallelo.autoSessionColors true Give each session a distinct colour automatically
parallelo.stashGuard true Warn when the shared stash is used with more than one session live
parallelo.conflictRadar true Mark sessions editing the same file as another session
parallelo.sessionBaseline true List the commits each worktree session has made, and count them in the conflict radar
parallelo.setupCommand — Command run once in a new worktree before the agent starts, instead of the install below
parallelo.installDependencies true Install dependencies in a new worktree, using the package manager the lockfile names
parallelo.roundtable.command roundtable The MCP server executable that brainstorming rooms run
parallelo.roundtable.budget 8 Turns the lead agent gets in a room before it must write the spec
parallelo.copyIgnoredFiles true Copy the files .gitignore covers into each new worktree
parallelo.copyExclude node_modules, dist, caches… Names skipped when copying, matched against every part of the path
parallelo.copyFiles .env, .env.local Files always copied, even when excluded above
parallelo.sessionStatus true Mark a session when its agent asks you something or finishes a turn
parallelo.showStatusBar true Show the active session's branch in the status bar
parallelo.showMainCheckout true List a terminal in the main checkout, not only worktree sessions
parallelo.openWorktreeTerminals true Open a terminal in every worktree when the window starts

🔨 Building it

bun install
bun run compile

Press F5 for an Extension Development Host. Cmd+R reloads it after a rebuild.

📄 Licence

MIT

Made for the window with too many agents in it. 🧵

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
  • Your Privacy Choices
  • Consumer Health Privacy
© 2026 Microsoft