I'm setting up my new blog right now. I'm thinkin of having a toggle to "hide" ai generated content from my main list of writing, and labeling (and a disclaimer at the toop of each ai-generated post a message).
Not trying to self-promote, but honsetly trying to leverage AI when appropriate, and to also not take away from my hand-written articles that are typically my thoughts and opinions....
I wonder if it's primarily that developers are too lazy to design anything? I remember low-quality developers relying on Bootstrap and not making a modicum of effort to design a website.
Of course, if you're that lazy, you're going to surround yourself and industry with AI-generated websites and UI, and you're going to recognize it, so...
Git worktrees are a great isolation boundary for _changes_ (especially making changes in parallel on a single machine), but not behavior. If you are trying to actually run autonomous agents securely you need something that lives outside the harness that actually blocks actions in a way that can't be prompted around.
We use nono [1] for this internally, essentially blocking any actions we don't want agents to be able to do without human approval. Our developers can just run `task claude` or whatever their harness is) and it pre-wraps it with our profile that enforces:
- Filesystem: read/write only the worktree plus dev-tooling dirs (Go, Doppler, Graphite caches, git common dir); explicitly no Docker socket and it can't edit its own Claude settings files (so it can't loosen its own permissions).
- Network: outbound only to an allowlist - Anthropic, Doppler, Go module proxies, our dev environments while still allowing binding local dev-server ports.
- GitHub: read anything in the org, and create/edit PRs and push branches - but it cannot merge, close, review, or comment on PRs, delete branches, touch repo settings/secrets, manage auth, or use raw gh api. Those are all "human-only". GitHub tokens are never exposed to the agent; they're injected by a proxy so it can't read or exfiltrate them.
This is great because it is harness agnostic - any developer can use whatever harness they want as long as they port the nono profile to it, as it will enforce all of the above in a way that is not tied to a specific harness implementation
"read/write only the worktree", but git requires .git dir writable for common commands to work in a worktree. And that's where .git/hooks live. So agent inside that profile can still write a pre-commit hook that runs on your machine whenever you commit outside the sandbox. Or am I missing something?
All git config and hooks are not writable inside the sandbox. This can be somewhat frustrating as you have to run git config commands outside, but the tradeoff is worth it imo. Nono allows for directory level permissioning, so the entire `.git/hooks` directory and `.git/config` / `.git/worktrees/*/config.worktree` are write blocked.
Worth calling out that this doesn't close all of these types of attacks, just the ones that are invisible (claude could very well write ./hack.sh and tie that in to your main.go, but at least it would be a diffable change, instead of invisible like a git hook)
It would be interesting to have a general fix for this in git. Something that more carefully splits the metadata from the working copy, a bit like we used to routinely do with "shadow build trees" with autoconf+make etc.
The parallel trees could have different ownership and access privileges, so that the editable working copy does not require the same filesystem access rights as the metadata tree. The git CLI actions would be performed with the more privileged filesystem role, and it would also have to be audited to make sure it treats all the working copy content as untrusted payload.
The big advantage of using worktrees is the shared git state, it makes it so much easier to cherry-pick and move commits around those worktrees. Complaining that they aren’t isolated goes against the spirit of worktrees in the first place.
This is quite useful. The title and first paragraph anyway; the rest is fluff. I've actually been trying to solve a problem where I have agents running other agents in worktrees, with the delegated agents contained by jai[0], and the delegating agent would always have to check and reconcile the commits since they get jailed (by design for security). Working on clones instead should resolve that cleanly, as I can relax the .git limitation. I do wish I'd thought it this before.
For me the most pragmatic way to solve this is in the agent harness layer simply prohibiting commands like git force and others in the settings configuration of your harness of choice with pre tool hooks, its quite easy to setup, obvious ones are prohibiting pushes to main, among others.
Unless someone is building their harness from scratch like you this is a 30sec configuration and you could just save your list of blocked commands with wildcards in a file, and copy paste from one harness to the other.
Agreed. I had to solve this at the harness layer myself. It just makes more sense to me this way. We basically created hooks around these operations and you can configure what happens at these calls.
Disclosure: I'm building AQ (aq.dev) a multiplayer coding harness.
Why a clone over a worktree? The obvious disadvantage I can see is you dont share your git objects with a clone and for really large repos that becomes an issue
I haven’t hit these issues when using worktrees. But what’s a pain is having to compile from scratch every time, and not carrying over gitignored files.
I set up a custom hook in Claude which runs my own worktree creation/cleanup script, which takes care of copying my node_modules into the worktree, my .env (plus doing some edits to the .env to isolate it so it can run in parallel), and stuff like that. Each worktree gets its own docker compose project name so they can run docker stacks in parallel. Works pretty seamlessly.
Worktrees are the obvious pick, and I get why. One command, cheap, and if you're the only one driving, then sharing .git is the point rather than a compromise. I started there too.
An agent in a worktree can reach your hooks, your config, another worktree's stash. Probably not a common problem. But when it does happen you're not debugging your code, you're debugging git, and it's not obvious where to even start looking.
The one that actually bothers me is prompt injection. The agent reads an issue, or a dependency's README, or a web page, and what it's told to do is drop a file in the .git it can already write to. Next time you commit, that runs on your machine as you.
Separate thing - worktrees just get annoying to manage. Can't check out the same branch twice, so you're making up branch names to keep git happy. Every one is another directory to keep track of. Then something goes stale and you're back in git worktree prune.
So has any of it got to you? Or do you hit the annoying parts, shrug, and carry on?
Please stop writing straw man arguments to sell your product. Worktrees do work as intended for most people. And they work better than your broken homepage.
Do people not know how to write blogs without AI anymore? I enjoy hearing a human's unique voice and miss hearing it when it's abscent.
I would bet the guy asked ChatGPT a question and then went "turn your answer into a blog post"
I'm setting up my new blog right now. I'm thinkin of having a toggle to "hide" ai generated content from my main list of writing, and labeling (and a disclaimer at the toop of each ai-generated post a message).
Example home page: https://taude.xyz/ Example AI Slop post: https://taude.xyz/posts/the-tool-stack-behind-this-blog/
Not trying to self-promote, but honsetly trying to leverage AI when appropriate, and to also not take away from my hand-written articles that are typically my thoughts and opinions....
You can literally tell from the box styling that it's AI now. Awful.
I wonder if it's primarily that developers are too lazy to design anything? I remember low-quality developers relying on Bootstrap and not making a modicum of effort to design a website.
Of course, if you're that lazy, you're going to surround yourself and industry with AI-generated websites and UI, and you're going to recognize it, so...
Git worktrees are a great isolation boundary for _changes_ (especially making changes in parallel on a single machine), but not behavior. If you are trying to actually run autonomous agents securely you need something that lives outside the harness that actually blocks actions in a way that can't be prompted around.
We use nono [1] for this internally, essentially blocking any actions we don't want agents to be able to do without human approval. Our developers can just run `task claude` or whatever their harness is) and it pre-wraps it with our profile that enforces:
- Filesystem: read/write only the worktree plus dev-tooling dirs (Go, Doppler, Graphite caches, git common dir); explicitly no Docker socket and it can't edit its own Claude settings files (so it can't loosen its own permissions).
- Network: outbound only to an allowlist - Anthropic, Doppler, Go module proxies, our dev environments while still allowing binding local dev-server ports.
- GitHub: read anything in the org, and create/edit PRs and push branches - but it cannot merge, close, review, or comment on PRs, delete branches, touch repo settings/secrets, manage auth, or use raw gh api. Those are all "human-only". GitHub tokens are never exposed to the agent; they're injected by a proxy so it can't read or exfiltrate them.
This is great because it is harness agnostic - any developer can use whatever harness they want as long as they port the nono profile to it, as it will enforce all of the above in a way that is not tied to a specific harness implementation
[1] https://github.com/nolabs-ai/nono
"read/write only the worktree", but git requires .git dir writable for common commands to work in a worktree. And that's where .git/hooks live. So agent inside that profile can still write a pre-commit hook that runs on your machine whenever you commit outside the sandbox. Or am I missing something?
All git config and hooks are not writable inside the sandbox. This can be somewhat frustrating as you have to run git config commands outside, but the tradeoff is worth it imo. Nono allows for directory level permissioning, so the entire `.git/hooks` directory and `.git/config` / `.git/worktrees/*/config.worktree` are write blocked.
Worth calling out that this doesn't close all of these types of attacks, just the ones that are invisible (claude could very well write ./hack.sh and tie that in to your main.go, but at least it would be a diffable change, instead of invisible like a git hook)
I don't think people use it for isolation, but for what the feature enables in the first place: parallel workstreams
It would be interesting to have a general fix for this in git. Something that more carefully splits the metadata from the working copy, a bit like we used to routinely do with "shadow build trees" with autoconf+make etc.
The parallel trees could have different ownership and access privileges, so that the editable working copy does not require the same filesystem access rights as the metadata tree. The git CLI actions would be performed with the more privileged filesystem role, and it would also have to be audited to make sure it treats all the working copy content as untrusted payload.
The big advantage of using worktrees is the shared git state, it makes it so much easier to cherry-pick and move commits around those worktrees. Complaining that they aren’t isolated goes against the spirit of worktrees in the first place.
This is quite useful. The title and first paragraph anyway; the rest is fluff. I've actually been trying to solve a problem where I have agents running other agents in worktrees, with the delegated agents contained by jai[0], and the delegating agent would always have to check and reconcile the commits since they get jailed (by design for security). Working on clones instead should resolve that cleanly, as I can relax the .git limitation. I do wish I'd thought it this before.
[0] jai.scs.stanford.edu/
I think the first question is what exactly are we trying to preserve by using either worktrees or multiple clones? The answer is: non-pushed changes
So if all you want is to work on index.ts in a separate dir from api.ts then worktrees might work well
If you want to be able to rm -rf one of the dirs without wondering about dependencies then yeah multiple clones makes sense
Either way is a way to avoid using more fragile/finicky workflows like stash and stash pop
For me the most pragmatic way to solve this is in the agent harness layer simply prohibiting commands like git force and others in the settings configuration of your harness of choice with pre tool hooks, its quite easy to setup, obvious ones are prohibiting pushes to main, among others.
Unless someone is building their harness from scratch like you this is a 30sec configuration and you could just save your list of blocked commands with wildcards in a file, and copy paste from one harness to the other.
Agreed. I had to solve this at the harness layer myself. It just makes more sense to me this way. We basically created hooks around these operations and you can configure what happens at these calls.
Disclosure: I'm building AQ (aq.dev) a multiplayer coding harness.
Checked it out, it doesn't particular talk to me but for sure other people, looks like a cool project! Wish you best of luck and success!
Why a clone over a worktree? The obvious disadvantage I can see is you dont share your git objects with a clone and for really large repos that becomes an issue
Well, actually `git clone --shared` writes an alternates file pointing at your object store and copies zero objects.
I haven’t hit these issues when using worktrees. But what’s a pain is having to compile from scratch every time, and not carrying over gitignored files.
I set up a custom hook in Claude which runs my own worktree creation/cleanup script, which takes care of copying my node_modules into the worktree, my .env (plus doing some edits to the .env to isolate it so it can run in parallel), and stuff like that. Each worktree gets its own docker compose project name so they can run docker stacks in parallel. Works pretty seamlessly.
Same here, over hundreds of worktrees in months of work.
The only problem I ran into was when Codex or Claude Code were configured to create the worktrees nested into the parent repository.
Then grep would yield results from a worktree and the agent would happily start to work in the wrong worktree.
.worktreeinclude is probably part of the solution.
https://code.claude.com/docs/en/worktrees#copy-gitignored-fi...
look into .worktreeinclude
Worktrees are the obvious pick, and I get why. One command, cheap, and if you're the only one driving, then sharing .git is the point rather than a compromise. I started there too.
An agent in a worktree can reach your hooks, your config, another worktree's stash. Probably not a common problem. But when it does happen you're not debugging your code, you're debugging git, and it's not obvious where to even start looking.
The one that actually bothers me is prompt injection. The agent reads an issue, or a dependency's README, or a web page, and what it's told to do is drop a file in the .git it can already write to. Next time you commit, that runs on your machine as you.
Separate thing - worktrees just get annoying to manage. Can't check out the same branch twice, so you're making up branch names to keep git happy. Every one is another directory to keep track of. Then something goes stale and you're back in git worktree prune.
So has any of it got to you? Or do you hit the annoying parts, shrug, and carry on?
Is this an LLM response? If not, take a break, you've assimilated.
If you want to properly isolate things, use containers. That's not what worktrees are for.
Please stop writing straw man arguments to sell your product. Worktrees do work as intended for most people. And they work better than your broken homepage.
If you can't be fucked to write your blog, nobody will be fucked to read it.
tl;dr an agent can still run commands that affects other worktrees
Local agents use worktrees. If you do not trust those (or your own input), then what are you doing?