I kept seeing the same failure in AI-assisted coding: the agent chose the right change, then applied it through an improvised mix of sed, regex replacement, patches, one-off scripts, direct writes, or whole-file rewrites.
The problem is not that those tools are bad. The problem is that each path has different rules for ambiguity, stale state, preservation, failure, and evidence. The agent is left responsible for deciding whether the final write was safe.
So I built Threadmoth, a small Rust CLI for the last mile of repository editing.
The boundary
Threadmoth turns a requested mutation into a narrow pipeline:
OBSERVE → IDENTIFY → GUARD → MUTATE → VERIFY → CERTIFY
It checks the bytes it read, identifies the intended target, refuses ambiguous or stale requests, applies only the authorised effect, reads the result back, and returns machine-readable evidence.
The current implementation includes:
- exact identity and stale-file checks;
- cardinality refusal when a target is ambiguous;
- Tree-sitter structural targeting for code and web formats;
- explicit effect budgets;
- source-preserving byte edits;
- guarded multi-file transactions with recovery; and
- post-write certificates containing hashes, changed ranges, bounded diff evidence, and commit verification.
The important design constraint is that Threadmoth does not try to replace specialist tools. rustfmt, Prettier, Black, gofmt, jq, AST tooling, and similar tools can still decide the desired state. Threadmoth bounds and verifies what lands.
The parser gets to point at the cloth. It doesn’t get to re-weave it.
What I’m testing
Threadmoth 1.5.1 is released for Windows and Linux under the MIT license. Hosted Linux and Windows CI passed. Local correctness-checked runs reported 8/8 tough cases with zero wrong mutations, and torture reported FOOTGUN-100 safe 100/100.
Those are release checks, not proof that the tool is useful in every agent workflow. I’m now running a public field test and looking for people to try one or two real repository mutations with Codex, Claude Code, Gemini CLI, Cline, OpenCode, or another coding agent.
The feedback I want is specific:
- Did the agent discover Threadmoth without being spoon-fed its request schema?
- Did it choose Threadmoth when the task fit?
- Did a valid edit get refused?
- Did an unsafe or stale edit get refused correctly?
- Were unrelated bytes preserved?
- If Threadmoth was unavailable or not selected, what did the agent use instead?
Repo: https://github.com/matthewjameswatkins1978-cyber/Suture
Release: https://github.com/matthewjameswatkins1978-cyber/Suture/releases/tag/v1.5.1
Five-minute field test: https://github.com/matthewjameswatkins1978-cyber/Suture/blob/main/FIELD_TESTING.md
I’m the developer and this is my project. Parts of the implementation and testing were AI-assisted; I’m responsible for the architecture, integration, and release. Specific breakage is more useful than a star.
Top comments (5)
Cardinality refusal is the part I would call the real feature. Almost every bad automated edit I have had to clean up came from a pattern that matched in two places, where the tool cheerfully edited both or picked the first - and the resulting diff looks intentional, so review does not flag it. Making ambiguity an error instead of a silent choice moves that decision back to whoever can actually answer it. Stale-file checking is the other one that pays for itself in agent workflows specifically, because an agent reads a file, thinks for a few turns while something else moves underneath, then writes against a version that no longer exists. The interesting question with effect budgets is what happens on refusal: does the agent get enough structured detail to narrow its request and retry, or does it fall back to the improvised sed path and defeat the boundary?
Thanks, this is exactly the kind of failure mode Threadmoth is aimed at. I agree that cardinality refusal and stale-state checking are only useful if the refusal is actionable. The current release is designed to return structured refusal evidence: what was observed, which guard failed, and what narrower request would be valid—without silently retrying or widening the effect budget. I’m going to make your scenario a field-test case: ambiguous match, then a stale-file change, and see whether the agent narrows and retries or falls back to sed. That fallback question is the important one: a safe boundary that agents route around under pressure is only theatre. Appreciate the sharp read.
The ambiguous-match then stale-file sequence is a useful field test because it exercises recovery, not just refusal. I would give it a second valid path: reread the changed file, narrow the match and complete the edit within the original effect budget.
Then report both the final filesystem state and the sequence of attempted tools. A refusal alone can look successful even if the agent later bypasses it, while a completed narrow edit shows the structured evidence was sufficient to recover without widening the operation.
Your comment about cardinality refusal being the real feature has aged rather well 😄
Since I wrote this post we’ve pushed Threadmoth quite a long way. It’s now at 1.12.0, and the interesting work hasn’t really been “add more editing features”. It’s been making the boundary more useful to agents without weakening it.
We’ve added stronger stale-state and path confinement checks, guarded transactions, better provider-specific suggestions, truthful machine-readable capability reporting, stable refusal exit codes, and a lot more regression testing around Windows junctions, traversal, ambiguity and exact-source preservation.
The biggest thing we’ve learned, though, is about the interface itself. We kept seeing agents make the same procedural mistakes, and initially the temptation was to add more instructions. We’ve gone the other way:
self-teach over rule-teach.
If Threadmoth knows why it refused something, it should tell the agent what happened, what remains allowed, and how to recover. The agent shouldn’t need a giant prompt manual just to use the tool correctly.
We’re now working toward one canonical operation model that drives capabilities, help, MCP schemas, examples, suggest, and recovery, so those surfaces can’t drift apart. We’re also looking at a compact orient/bootstrap surface so a fresh agent can discover how to use Threadmoth from Threadmoth itself.
One useful failure we just found is that the MCP side still doesn’t teach workspace-root recovery well enough in some harnesses. It refuses safely, which is good, but the recovery information still needs work. That’s probably the next thing I want to fix.
I’ve also deliberately resisted turning it into a giant semantic refactoring engine. The idea is still the same as when I wrote the post: let the AI/LSP/AST tooling decide what should change; let Threadmoth decide whether that exact mutation is safe, apply it narrowly, and prove what happened.
Your point about “move the decision back to whoever can actually answer it” is still pretty much the centre of the whole thing.
The canonical operation model sounds like a good way to make recovery guidance agree with actual capabilities. For the workspace-root refusal, I would make the missing decision explicit: whether the agent can discover the already-configured root, or needs the caller to choose one. Suggesting a broader root automatically could undermine the confinement check that correctly refused the operation.
A useful bootstrap test would start with no prior manual in context and require the agent to recover through the advertised discovery surface. It should succeed only after resolving that root choice, rather than learning to work around the refusal.