DEV Community

Cover image for JetBrains open-sourced an agentic IDE where agents never touch your checkout
Sam LABBE
Sam LABBE

Posted on

JetBrains open-sourced an agentic IDE where agents never touch your checkout

Commenters debating SPEC drift risks

JetBrains just open-sourced an agentic IDE — Apache 2.0, on GitHub as of yesterday — and the name of the repository matters less than the three ideas in it: agents that never touch your checkout, a project's truth that survives the session, and no accounts anywhere. It's called Thinkrail, it wraps the pi coding agent, and after an evening in the repo I think it's the clearest statement yet of what "IDE" means when the coder is a fleet.

This week the agent stack is assembling in public: NVIDIA shipped the runtime layer (OpenShell), and now JetBrains ships the environment layer. Here's what Thinkrail actually does, mechanism by mechanism.

Idea one: isolation by worktree, not by prompt

Every workspace in Thinkrail is a git worktree with its own branch. The README's sentence deserves to be quoted in full: "Agents work in parallel without touching your checkout."

That's the whole design, and it's the correct answer to a question most agent tools answer badly. The common pattern today is: agent edits files in place, you review the diff in the same tree you're building in, and a second agent is a merge conflict generator. Worktrees flip it: N agents, N branches, your checkout untouched, merges become the explicit coordination point. It's the same isolation insight as OpenShell's sandboxes, applied one level up — not "what can the agent touch" but "which tree does the agent live in."

Idea two: SPEC.md as ground truth

The deeper bet: agents are unreliable because their context dies with the chat. Thinkrail's answer is a graph of SPEC.md files sitting beside every module, which the agent itself maintains through dedicated spec_* tools — "so intent survives the session."

Read that again: the documentation is not a byproduct of the work; it's a maintained artifact the IDE treats as ground truth. The agent reads the spec to know what to do, does the work, then updates the spec to record what it learned. JetBrains dogfoods it — the repo is developed spec-first, a SPEC.md sits next to every module. Whether the graph stays honest under agent-driven rewrites is the open question (a spec the agent both follows and edits is one prompt injection away from redefining the project's truth), but as an architecture it's the first serious answer to "how does an agent remember my project" that isn't a vector database.

Idea three: no accounts

"ThinkRail has no accounts of its own" — you bring your own provider credentials, exactly like OpenShell's provider model. The IDE is a host: an HTTP+WS engine (Bun.serve, one in-process agent session per chat), a typed versioned wire protocol (packages/contracts), and a React 19 client. Skills, workflows, MCP servers, subagents, per-chat model selection with token/cost readouts. It's an IDE-shaped shell around an agent protocol, and the shell has no opinion about who pays for inference.

The honest margins

The tagline — "gets better every time you use it" — is marketing for what's actually shipped: living specs today, self-built capabilities tomorrow. It's brand-new (0.x, this week), the wire protocol is versioned but young, and "spec drift under agent edits" is a real attack on its own premise that no README answers yet. The desktop installers exist (macOS Apple Silicon, Windows, Linux), and the CLI is two commands — but nobody has a year of usage to point at.

Run it yourself

curl -fsSL https://raw.githubusercontent.com/JetBrains/thinkrail/main/install.sh | bash
thinkrail ~/code/my-repo
# developers: Bun 1.4.4 + Node >= 22.19, then `bun install && bun run dev`
Enter fullscreen mode Exit fullscreen mode

Repo: github.com/JetBrains/thinkrail · Apache 2.0 · built around the pi coding agent

TL;DR — worktrees for parallel agents, a self-maintaining spec graph for durable intent, your keys and no accounts. The week built the runtime (NVIDIA), the IDE (JetBrains), and left one layer conspicuously unfinished: who proves what the fleet actually did. That's the next post.

Top comments (38)

Collapse
 
alexshev profile image
Alex Shev •

Worktree isolation is a strong default, but it needs a clear promotion step. Having an agent produce a patch plus a short manifest of files changed and tests run makes review and merge the intentional handoff rather than an implicit side effect.

Collapse
 
slabb profile image
Sam LABBE •

Your manifest is the run receipt missing its seal. Files changed plus tests run is exactly what a receipt binds — the verdict travels with its check — and the seal is what turns "here's what I did" from narration into evidence: the agent authored both, so without a signature the manifest is the worktree's diary entry about itself. With one, the promotion step you describe becomes what it should be — the merge as an intentional handoff between two recorded states, each carrying who ran what and what passed. Cheap addition, and it composes with the spec beside every module: the manifest names what changed, the spec says what it means.

Collapse
 
alexshev profile image
Alex Shev •

A useful next detail is whether the receipt records the base revision as well as the resulting patch. That makes the promotion check reproducible: a reviewer can apply the patch to the declared base, rerun the listed commands, and see whether the same verdict still holds.

Thread Thread
 
slabb profile image
Sam LABBE •

Yes — and the binding you describe is exactly what makes a receipt replayable: base revision, patch digest, the commands, and the evaluator identity all travel with the verdict, so the promotion check becomes what you said: apply the patch to the declared base, rerun, compare. One honest limit to carry alongside: reproducibility proves the verdict was derivable from the recorded inputs, not that the original run happened — a fabricated receipt is perfectly replayable. The authenticity half is the attempt-first seal: the attempt (base, task, inputs digest) sealed before the outcome exists, so a receipt with no run behind it lacks the earlier event and reconciliation names it. Reproducible is the replay's property; witnessed is the run's — a promotion check wants both.

Thread Thread
 
alexshev profile image
Alex Shev •

That distinction is important. The seal also needs a trust boundary: who signs the attempt, where the event is retained, and whether a missing or delayed seal blocks promotion. Replay can validate the recorded computation, while independent evidence of the earlier event supports the narrower claim that an attempt was witnessed.

Thread Thread
 
slabb profile image
Sam LABBE •

All three have shipped answers — the pleasant part of checking instead of designing. Who signs: the writer domain resolves by signature against the sealed known-writers registry, and the signing key loads once into a dedicated daemon the agent's user can't read — so an attempt's signature is attributable to a process, and the custody grade prices that process (unanchored and drift are named states, not vibes). Where retained: retention is the wrong-by-drift half of the grade — receipts authored grade-1 but kept in operator-controlled storage sit grade-3, retention changes are sealed events, and the drift check monitors the tail beyond the newest anchor, because retention is the one grade that fails by silence.

Does a missing or delayed seal block promotion: the journal surfaces rather than gates. outcomes ≤ attempts is the invariant — an outcome with no earlier attempt is a named finding, a late attempt surfaces as an ordering inversion the chain derives — and whether a finding blocks promotion is the deployer's gate. That's the honest division of labor: the journal is domain-blind, the promotion rule is yours. Your last line states the split correctly — replay validates the computation, independent evidence witnesses the event. A promotion check that wants both asks for the replay of one and the anchor or counterparty signature of the other.

Collapse
 
makayis_90942586425f8f6bb profile image
makayis •

The "one prompt injection away" point is the part I'd want ThinkRail to answer before anything else. A worktree protects your checkout, but SPEC.md is the thing the agent trusts most, and the agent can write to it.

The simplest fix I can think of: treat spec_* writes as proposals, not edits. The agent can suggest a change to the spec, but it lands as its own small diff that a human approves, separate from the code diff. Code changes are cheap to review because tests catch a lot. A quiet change to the "truth" file isn't caught by anything.

Did you see any sign that spec edits are logged or diffed separately from normal file changes? That would tell me a lot about how seriously they take that risk.

Collapse
 
slabb profile image
Sam LABBE •

Checked the repo: no. spec_update writes frontmatter straight to disk (its own docstring sends prose to the generic write/edit tools), spec_create scaffolds new files, and neither logs or diffs anything separately: a spec edit lands in git as an ordinary .md change like any other file. The proposal mechanism you describe does not exist.

Which makes your framing the design argument. The truth file is the one artifact every other artifact defers to, and it is the only one the agent can write with no detector at all: the mechanical check covers surfaces only (check:spec-surface compares declared exports against barrels), so a quiet narrative rewrite passes every gate until a human reads it.

Spec writes as proposals is pre-registration applied to the truth file: the diff exists before the code that depends on it, and reviewing the two separately is right because they fail differently.

Collapse
 
makayis_90942586425f8f6bb profile image
makayis •

Thanks for actually checking. That's the answer I was afraid of. The surface check makes it worse in a way, because it gives a green signal that sounds like the spec was verified when only the exports were. The cheapest version of the fix wouldn't even need a new mechanism: make SPEC.md a protected path, so an agent edit to it goes into its own commit that a human has to approve. Same idea as the proposal, built from what's already there.

Thread Thread
 
slabb profile image
Sam LABBE •

Your green-signal point is the sharpest thing in this thread: a check that verifies exports and reports green reads as the spec verified. The fix at that layer costs one word: the check's output should say what it checked, spec surface checked, never spec verified. A green light that names its scope cannot impersonate a bigger green light. An earlier thread on this blog landed the same law for the word verified itself, and it applies unchanged here.

And your protected path is the mechanism version of the same honesty: the proposal exists because the signal was carrying weight it did not earn. Branch protection plus a path-scoped owner on **/SPEC.md is exactly what the neighboring thread on this post converged on for the prose. Cheap, built from what is already there, and it turns an agent's spec edit into a first-class event instead of a rider.

Thread Thread
 
makayis_90942586425f8f6bb profile image
makayis •

"Spec surface checked" is a good rule for any check, not just this one. Half the trust problems with agent tooling come from a green light that's vaguer than what it actually tested. Naming the scope costs nothing and stops the over-reading.

Collapse
 
kevinhall profile image
Kevin Hall •

Worktrees answer "which tree does the agent live in". For research agents an even blunter version works for me: give the agent no tree at all. My Claude Code sessions that pull job and company data run with --allowedTools set to the MCP tools only, no file or shell tools. In one recorded session the agent still tried a shell command, to check whether an API token was set, and the call was simply refused; it carried on with the tools it had. The isolation came from the tool list, not the prompt, which is your point one level further down.

The SPEC.md idea is the part I'd want for those sessions. Right now the only memory between runs is what I paste back in.

Collapse
 
slabb profile image
Sam LABBE •

The no-tree mode is the schema argument taken past its own endpoint: heyvaldemar's "never hand the agent an HTTP API" minus the API — the tool list is the boundary, and the refused shell call you recorded is the negative control doing its job in public. Worth more than the refusal itself: an attempted-and-denied call is a denominator event — the agent probed the fence, the fence held, and the attempt was observable. That's the difference between isolation and the appearance of it; a prompt-only fence produces no refused calls to count, because the persuasion happens instead.

On inter-run memory: the SPEC.md pattern transfers directly — the durable home for what survives a session is a maintained artifact the next run reads first, which is exactly this post's bet. The piece to add from this thread's discipline: a memory the agent writes is a diary, and diaries don't bind the next session to anything; sealed per run (what it read, what it concluded, which corpus state it saw), the handoff becomes a receipt the next run can cite — your pasted-in context becomes "the state as of this digest." Research agents are where that pays double, because the corpus moves under them: last week's summary of a dataset is exactly the kind of belief that needs a consumed-head, not a paste.

Collapse
 
alexshev profile image
Alex Shev •

Keeping agents out of the checkout is a strong default because it makes the diff the handoff artifact. The next useful question is how the system proves the patch was produced and tested in an equivalent environment—base commit, commands run, dependency lockfile, and test evidence should travel with the proposal.

Collapse
 
slabb profile image
Sam LABBE •

That bundle has a name in this series: the run receipt. Base commit, commands, evaluator identity, sealed before the verdict exists. The journal side already binds it (attempt-first, spec_hash on the spec it loaded), and the two halves stay distinct: replay validates the recorded computation, the seal witnesses the run.

What Thinkrail lacks is not the idea but the seal: its archaeology receipt is a markdown file the same session writes, so the equivalent-environment claim rests on trust in the process rather than on an anchored record.

Collapse
 
alexshev profile image
Alex Shev •

A clean checkout boundary is strong, but I would still treat patches as untrusted inputs. The handoff should carry the diff, command log, and declared files touched, then require a human or policy gate before any merge into the real workspace.

Collapse
 
suirindo profile image
asagiman •

The worktree boundary raises a useful distinction: is “never touch your checkout” enforced by the host's filesystem permissions, or by routing the agent to a separate working directory? A worktree alone doesn't remove the process's access to sibling paths or shared credentials.

A small acceptance test could put a harmless sentinel outside the assigned worktree, ask the agent to modify it, and record both the tool denial and the unchanged sentinel. That would make the enforcement claim independently checkable alongside the spec/merge checks. I haven't run Thinkrail; does its current host enforce that boundary?

Collapse
 
slabb profile image
Sam LABBE •

Checked the repo, since it's open: enforcement is routing, not confinement. The worktree comes from git worktree add (workspaces.ts), which is a separate directory under the same user — sibling paths and shared credentials stay reachable by the process. The only sandbox-exec in the tree is in the test harness, denying the desktop host read of the repo root for e2e isolation — so macOS Seatbelt is already in the building, just not applied to agent sessions. Your sentinel test is the right acceptance check, and run today it fails on the deny half: the tool call would succeed and the sentinel would change.

One distinction your test already contains, worth naming: record both the refusal and the unchanged sentinel. The refusal is a step — a tool can be told to deny; the unchanged sentinel is the sensor — the world has to actually hold still. Anything the agent's report can attest alone, the agent can forge; the sentinel is what makes the claim checkable without trusting the reporter. That's the same law the geometry thread ran: enforcement by permission is the declared vantage, the sentinel is the effective one, and the gap between them is the finding.

Collapse
 
suirindo profile image
asagiman •

Thanks for checking the source and clarifying routing versus confinement. I would treat the predicted sentinel outcome as a source-reading conclusion, not a recorded test result; I haven't run Thinkrail either. For the acceptance check, both the tool denial and an independently verified unchanged sentinel matter.

Thread Thread
 
slabb profile image
Sam LABBE •

Correct, and the correction lands on me: "run today it fails" was a derivation wearing a measurement's clothes. The verified half is the source reading — git worktree add, same user, no confinement in the session path. The failing half is a prediction and gets its label: predicted from source, not executed. Your acceptance formulation is the tight one — tool denial and independently verified unchanged sentinel, both recorded, either both passing or the finding named. The protocol is three lines (sentinel outside the worktree, prompt the agent to modify it, record the denial and the bytes) and it's pre-registered here: whichever way the run lands, the result replaces this prediction.

Thread Thread
 
suirindo profile image
asagiman •

Thanks for making that correction explicit, Sam. Recording both the tool decision and the independently observed sentinel state gives the eventual result a clear basis. The source-derived prediction remains labeled as such until that run supplies the evidence.

Collapse
 
salparvez profile image
Sal Parvez | ML Systems RI •

A SPEC.md beside every module reminds me of as-built drawings. The plans say what was intended, the as-builts say what actually got built, and trouble starts when the same person updates both and nobody checks. A separate sign-off on spec changes seems like the cheap fix. It's how we're thinking about house records at ML Systems.

Collapse
 
slabb profile image
Sam LABBE •

As-builts is the exact analogy, down to the failure you name — the same hand updating both is the second-speaker problem wearing a hard hat. Construction solved it institutionally: the contractor doesn't stamp his own as-builts; a different licensed speaker does, because the two documents serve opposite parties — intent for the designer, reality for whoever maintains the building after. The repo version of the stamp is the path-scoped sign-off: any PR touching both code and spec needs both reviewers, so the as-built can't be amended inside the same approval that changed the building. Cheap fence, and it's the one that doesn't trust anybody's diligence — which, per your house-records point, is the only kind that survives the person who updates both leaving.

Collapse
 
vishisht_choudhary_a12d08 profile image
Vishisht Choudhary •

The worktree-per-agent part makes total sense, but I think the SPEC.md graph is the bigger bet, and you named the catch well: if the agent both follows the spec and edits it, the spec can drift without anyone noticing. Did you see anything in the repo that makes spec edits go through review on their own, kept apart from code changes? Without that, I'd expect someone's SPEC.md to slowly turn into whatever the agent did last Tuesday.

Collapse
 
slabb profile image
Sam LABBE •

Checked the repo, since it's open. The review separation you're asking about doesn't exist — one CODEOWNERS gate for everything (*, five owners, require_code_owner_review on the main ruleset), so a spec edit rides the same review as the code it changed. What does exist is a mechanical drift check one layer down: check:spec-surface compares every enrolled SPEC.md's declared public surface against the module's TypeScript barrel and fails on "Spec surface drift" — which fences the cheap layer in both directions: code that changes the barrel without the spec update fails, and a spec declaring exports that aren't there fails too. What the agent can still do is update both to match whatever it did — the names check out because they were made to.

Your "last Tuesday" drift lives in the layer the check can't see: the spec's narrative — invariants, trade-offs, decisions. That layer has exactly one fence today (the owner gate), and in a mixed PR one review does both jobs at once. The two fences that would actually separate them, cheapest first: a path-scoped CODEOWNERS row (**/SPEC.md owned by a different or additional set — any PR touching spec and code then needs both sign-offs, and a spec-only change gets the spec review alone), and past that, the treatment this series runs on documents the agent follows and writes: the spec sealed at provision, edits arriving as named diffs against the sealed baseline. A spec the agent maintains is a governance file with a compiler attached — the compiler keeps the surface honest, and the seal is what keeps the story honest.

Collapse
 
paullovelace profile image
Paul Lovelace •

For me the worktree idea is almost too obvious in hindsight — I've lost more time to an agent quietly editing the tree I was building in than to any single bad suggestion. Making merges the explicit coordination point feels right, but it also moves the pain somewhere else: what happens when two agents' worktrees touch the same module and both look reasonable? That's the part I'd want to see in practice before I trust a fleet of them, even with SPEC.md sitting beside every module.

Collapse
 
slabb profile image
Sam LABBE •

The honest answer is that the merge stays hard — the isolation just changes what kind of hard. Two worktrees that each pass their own tests and both "look reasonable" produce the nastiest conflict class there is: not textual (git resolves that) but compositional — each diff fine alone, the combination breaking an invariant neither touched. The referee for that can't be either diff; it has to be a third document that states what the module is allowed to mean, which is exactly the seat SPEC.md occupies in this design — the owning spec's invariants are what "both look reasonable" gets checked against, mechanically where the surface is concerned (check:spec-surface) and by the owning review where it isn't.

The deeper half is the record-keeping: in journal terms, a merge is a fan-in — an event binding both consumed heads, so each side's assumptions (which spec version it read, which head it built on) are on the chain, not in the agent's chat history. That's what makes a later "these two changes were each fine and together wrong" derivable instead of archaeological: the conflict propagates to both parents as a precise path set. It won't make two reasonable agents agree — nothing does — but it makes their disagreement derivable: who assumed what, at which head, visible at the merge instead of discovered in production. That's the part I'd want to see in practice too, and it's checkable without trusting anyone's judgment of "reasonable."

Collapse
 
mudassirworks profile image
Mudassir Khan •

the worktree per agent part is the piece i would copy first, merges as the only coordination point beats five agents editing one tree. on the spec drift worry, we let agents propose spec edits but only a human merges them, with CODEOWNERS on the spec files so a bad edit cannot ride along inside a feature branch. do the spec tools in Thinkrail support marking some SPEC.md files read only for agents, or is everything writable?

Collapse
 
slabb profile image
Sam LABBE •

Checked the repo: everything is writable today. spec_update edits frontmatter only (its own docstring says prose goes through the generic write/edit tools), spec_create scaffolds new files, and neither carries a protection flag or deny list. So the read-only marking you're asking about doesn't exist in the tooling; the fence lives where you put yours, at the repo boundary: agents propose, humans merge, CODEOWNERS on the spec paths. Your setup is the load-bearing layer, and per this thread's law it's the only kind that holds: an in-session read-only flag would be advisory unless the harness enforces it, and a fence the session can weigh is a suggestion.

Where a tool-level flag would still earn its keep is earlier in the lifecycle: a bad spec edit caught at write time is cheaper than one caught at review, and protecting, say, the dependency-edge fields (the graph's load-bearing lines) from spec_update would kill the quiet-rewiring class while leaving prose to the merge gate. That's a design suggestion for upstream, not a capability that exists today.

Collapse
 
mudassirworks profile image
Mudassir Khan •

fair, so the fence really is the merge gate and not the tool. the dependency edge fields idea is the one i would push upstream, since a quiet rewire of the graph slips through review easily when the diff looks like a one line frontmatter change.

do you split CODEOWNERS between the spec prose and the edge fields, or is it one owner for the whole spec path?

Thread Thread
 
slabb profile image
Sam LABBE •

One owner for the whole spec path today, and the reason is mechanical: CODEOWNERS works at file granularity, so it cannot split inside a SPEC.md between the prose and the four edge fields. That is worth knowing before designing around it.

Two ways to get the split you want, cheapest first. The CI one: a diff-lint that parses the frontmatter and fails when any edge field (depends-on, references, implements, covers) changed without a matching graph-change label or a second approval. Same repo layout, the rewire stops looking like a one-line prose tweak because a gate says so.

The structural one: hoist the edges out of SPEC.md into their own file, say SPEC.graph.yaml. Now CODEOWNERS can do its job: the prose file gets the team owners, the graph file gets a different set, or a tool-only writer with humans proposing. That is also the version worth pushing upstream alongside your idea, because it matches how Thinkrail already treats structure: the surface check validates barrels mechanically, and the graph is even more machine-shaped than the surface. Edges as data in their own artifact is the same move as the destructive verbs getting their own tools.

One caution from the ossification thread: whichever fence wins, the graph file inherits the staleness problem, so the pair travels with a validator that re-derives it from the code on a schedule.

Collapse
 
sofiicaste01 profile image
sofia castellanos •

The checkout lock is the interesting part. Reviews of agent output fail mostly because they are optional; making the workspace the boundary removes the choice. The open question is how it copes with work that spans several sessions on the same branch.

Collapse
 
slabb profile image
Sam LABBE •

"Reviews fail because they are optional" is the whole argument for structural boundaries in one line — the checkout lock doesn't make reviewers better, it deletes the choice, which is the same reason prompt-level defenses lose: a defense the agent can weigh is a suggestion.

On multi-session work on one branch: the answer that survives this thread's vocabulary is that the branch is a sequence of promoted states, never a shared scratchpad. Each session is a run — it starts from the last promoted (committed) state, and its only path onto the branch is the merge as intentional handoff, binding what it built on. Same-branch-sequential is safe exactly while every session begins committed; the failure mode is sessions sharing uncommitted state, which is chat-RAM with worse observability — the worktree-per-agent design quietly contains it, because a session that dies mid-work leaves a disposable dirty tree, not a poisoned branch. In receipt terms: the branch becomes the chain of run receipts, each one citing the base digest it started from — which is also what makes "which session broke it" derivable instead of argued. (Design answer, labeled as such — the repo's multi-session UX is one of the parts I haven't exercised.)

Some comments have been hidden by the post's author - find out more