EngineeringWhy Janus Stopped Giving Agents a Separate Worktree
· Janus
- #git
- #worktree
- #agent
- #tradeoff
At first, Janus created a separate git worktree for every Task (a unit of work handed to the agent). A worktree checks out the same repository into another folder. The agent edited files only on a janus/ branch in that copy and never touched the user's own checkout. To bring the result over, you ran a cherry-pick command (a git command that copies commits from another branch onto the current one) that Janus gave you.
Janus doesn't do this anymore. The agent works directly on the current branch of the repository you pick. This post covers how that changed and how the risks that came with it were handled.
Finding out late that isolation was gone
While preparing v1.0.28 I was checking the docs against actual behavior and found that isolation was already broken. An earlier commit that cleaned up the code that managed agent runs (the orchestration engine) had removed the Task isolation wiring and the janus/ branch guard along with it. From then on, the agent had been working in the user's real repository on the real branch.
The app, meanwhile, kept saying "creates a Task worktree without modifying your main checkout." The behavior and the description were opposites.
Restoring it, then removing it again
I restored isolation first. But thinking it over, what I actually wanted when using Janus was to see the agent's changes right away in my own editor and dev server. With a separate copy, I had to go to that folder or cherry-pick the changes over, and that distance was more of a hassle than I expected.
So I removed isolation again and settled on working directly in the original checkout, with git as the one way to undo.
Worktree isolation
Your checkout stays safe. To see the result, you go to the copy or cherry-pick it over.
Work in the original checkout
You see changes right away in your editor and dev server. Some things can no longer be undone with git.
The risks taken on
The revert commit message lists exactly what git history can't undo.
- Unsaved changes: if the agent edits a file you also changed, your version isn't in history. Reverting throws away both the agent's edits and yours.
- Untracked files: files that were created or overwritten aren't in history.
- Shell commands: file tools are confined to the repository, but the shell only starts there and can leave with
cd. - Two Tasks in the same project: they share one working tree, so they can overwrite each other's unsaved changes, and since neither has committed, git can't separate them.
How the risks were exposed and contained
The behavior stayed with working in the original checkout, and the descriptions and safeguards were brought in line with that.
Say what actually happens
"Creates a worktree without modifying your main checkout" became "works directly on this repository's current branch." When isolation was reverted, this wording was not.
Document the boundaries that don't exist
The README got a section on where the agent writes, with a table for each way of running the agent (Janus's local model, or a subscription CLI such as an already signed-in Claude Code or Codex) covering path confinement, approval before writes and whether the shell can leave. SECURITY.md lists boundaries that are missing, such as Tasks not being isolated from each other.
Test docs against code
So the docs can't drift again, CI runs a test that checks key claims in the docs against the code.
Block concurrent runs in one project
A warning on screen couldn't prevent conflicts, so at the moment a run starts, Janus checks whether another Task in the same project is running and refuses to start if it is. It names the blocking Task and clears as soon as that Task stops.
Limit the subscription CLIs
Working in the original checkout makes this more important, so Claude Code runs with the
--restrictedoption, which keeps file tools inside the working folder, and its allowed tools come from the agent profile (the setting that lists which tools each agent may use).
Summary
Isolation protects your checkout, but in a tool used by one person it added distance between the agent's work and checking it. Working in the original checkout brought risks git can't cover; those are written down in the docs and on screen, and the ones that could be blocked in code (concurrent runs in one project, subscription CLI scope) were.
One more rule came out of this: when behavior changes, the screen text and docs change with it, and a test checks that instead of someone having to remember.