#file editing/grepping/etc
1 messages · Page 1 of 1 (latest)
🧵 since there are a couple ongoing discussions
nice!
fwiw I vibe coded an edit implementation that seems to work - instead of sed it does the replacements in Go, by looking for matches for the 'search' and erroring if there are multiple matches, with the error including IDs so the agent can try again with the specific edit ID
I’m still testing it and want to write some tests
Oh interesting. I was heavily inspired by Claude’s tools
same - I was using Claude Code a lot over the weekend and noticed it's defensive against multiple matches, so tried to approximate that
wait so claude code really has the agent edit files with s/old/new/g instead of by line number?
yep afaict. i'm not sure how it actually narrows it down if there's ambiguity
this explains why claude sonnet 4 uses sed on it's own sometimes
this is actually how most editors work: https://aider.chat/docs/more/edit-formats.html
i bet you they trained it specifically for this
none of these have line numbers
i don't think it LITERALLY uses sed under the hood
but could be wrong if @tawdry cypress saw that
I thought of doing line number edits in addition to sed. But maybe it gets confused. I’m just hoping that if Claude knows then it must be good
it's definitely find-and-replace though
No it doesn’t use sed. I’m using sed because dagger doesn’t have it
my worry with sed would be like...fitting arbitrary code into the replacement pattern
i'll push up my edit version so we can compare notes
And I didn’t want to take all the contents and do it myself but now that I think about it I’m stupid I should just do that
yeah of course not, im talking about the model more than the agent: without an edit tool, claude (not claude code) will run crazy seds via shell commands
Or maybe not. Wdyt? For a big file. Is it better to contents and then replace in go ? GC might not like it
Btw, I'll update the PR description, but Claude's tools doesn't use sed syntax per-se, it's just that since I was using sed, and didnt feel comfortable with the / escaping, i figured i'd let the LLM specify the sed syntax.
hmm yeah not sure. in either case you'll end up with a layer that has the whole modified file, but it does kinda suck to still have the giant WithNewFile calls stacking up in the DAG.
maybe we could do the replace logic in go, but then generate a precise .patch file that we apply?
WithNewFile sucks in that case, but what i'm saying is it saves a call to Contents too
yes 🙂
but the question is the API facing the LLM
claude does list of search replace rules
we don't have good control over the tools available in THE container but we can do whatever we want with additional containers
subject to caching weirdness potentially though so be thoughtful
we could add an isRegex bool, and call strings.Replace or regexp.Regexp.Replace in our own binary
oh fun, does claude code do regex replacements too? (i see it grepping all the time but havent seen it edit like that i don't think)
i do see MultiEdit too yeah, wonder if it's been using that and i haven't noticed
yeah i wasn't sure whether both were needed
i implemented MultiEdit and called it FileEdit
i feel like it just does a bunch of edits one at a time pretty often
i dont want to depend on the golang image though. But that means need to set up pipelines to push a new replace image
there's always the option of improving the Dagger API
if we're hesitant to read a whole file into memory, other clients might be too
that being said, maybe it's fine? these are just text files, and i think folks know to not have absurdly large code files with vibecoding
cc @civic basin - vaguely remember us considering making the file operation APIs more fluent so people don't have to keep implementing filesystem Workspaces
lol i kinda like having huge files while vibe coding
how huge is huge 😛
Agreed on improving dagger api
idk bigger than i like as a human, i like that i can load a phat amount of context in with a single file
our longest file in dagger/dagger is module_test.go at 6153 (next is ~5k and then a drop off to ~2k)
which is 156k
i hit a hard limit in Claude Code at one point, tool calls started erroring and I had to split a file up
i would heavily vote in favor of this because it will be 1000x easier to debug / get visibility into the agents work compared to a bunch of WithNewFiles
It’s not entirely clear to me what the patch logic would be
For having reverse engineered Claude its full of reading all the files into memory and keeping them there forever
What program would be doing the patch?
does busybox have patch?
Ah you mean not do search replace and do patch instead?
i mean do the search and replace logic in Go, but then generate a .patch file from that and apply that in the environment, since that'd be more minimal than WithNewFile with the whole content
ahhh right
https://github.com/sourcegraph/go-diff-patch this seems handy
is it cheating too much to just use the patch executable from in the environment? it feels about the same as depending on sh. patch is used as part of a bunch of clunky linux distro packaging systems so I'd expect this core functionality to be pretty universal
here's how it looks (trace)
(sorry if I'm stepping on your toes here @tawdry cypress - I'm still toying with my own impl so I can dogfood container-use more for side stuff)
No worries at all! It's a great idea! I'll blatantly steal your commit. I just prefer to rely on busybox patch instead of the user's environment.
I'd be really happy if we get to a point where it's usable for you @noble scroll, pretty sure we'll see telemetry improvements and other goodies shortly after 😛
hoping you and @tawdry cypress can collaborate on this one
Same!
I'm upgrading my PR to use a custom efficient binary that does search replace, no Contents()
I'll be using it from now on with this change 
funny story: I told Claude to trim trailing whitespace the other day, and it happily ran a find . -type f -exec sed -i -e 's/ $//g' {} \; and corrupted my git repo
so...plenty motivated
btw - has anyone asked Claude to dump its tool schemas yet? seems like it's willing to. or is there a public repo with all that?
here's Edit:
{
"description": "Performs exact string replacements in files. \n\nUsage:\n- You must use your `Read` tool at least once in the conversation before editing. This tool will error if you attempt an edit without reading the file. \n- When editing text from Read tool output, ensure you preserve the exact
indentation (tabs/spaces) as it appears AFTER the line number prefix. The line number prefix format is: spaces + line number + tab. Everything after that tab is the actual file content to match. Never include any part of the line number prefix in the old_string or new_string.\n- ALWAYS prefer editing existing
files in the codebase. NEVER write new files unless explicitly required.\n- Only use emojis if the user explicitly requests it. Avoid adding emojis to files unless asked.\n- The edit will FAIL if `old_string` is not unique in the file. Either provide a larger string with more surrounding context to make it
unique or use `replace_all` to change every instance of `old_string`. \n- Use `replace_all` for replacing and renaming strings across the file. This parameter is useful if you want to rename a variable for instance.",
"name": "Edit",
"parameters": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"file_path": {
"description": "The absolute path to the file to modify",
"type": "string"
},
"new_string": {
"description": "The text to replace it with (must be different from old_string)",
"type": "string"
},
"old_string": {
"description": "The text to replace",
"type": "string"
},
"replace_all": {
"default": false,
"description": "Replace all occurences of old_string (default false)",
"type": "boolean"
}
},
"required": ["file_path", "old_string", "new_string"],
"type": "object"
}
}
yeah i have it all
nice
i'm working on a proxy so i know EVERYTHING 😄
The descriptions are quite long and detailed
yeah
those are different from Claude Code, i think, but strong parallels for sure
i updated my PR @noble scroll not sure if you're still testing it
sweet, i'll give it a try
something's not working i'm debugging
or is it the usual claude issue with:
tool_use ids were found without tool_result blocks immediately after: toolu_0116Ls3UTdr89LEm6rNhXnHV. Each tool_use block must have a corresponding tool_result block in the next message.
Strange to see that in Claude code, I haven't when using it directly
Proxy could help, in the past that's been a sign that the client is doing something wrong (eg dropping error responses)
So maybe goose bug
i'll figure it out eventually 🙂 but right now i wanna make sure the fstools pr works
i dont trust the code i changed it too many times
I didn't do Claude but I did Cursor ...
Also created https://github.com/aluzzardi/fakemcp to load the json dump to provide a fake, log-only mcp server to see how it actually calls them
But I think that's the right track -- they (coding agent makers) probably spent tons of time fine tuning the little descriptions, argument names, etc. Would be shame not to steal that work
i'm having it rename my entire project lol. so far so good
$3.08 and 13 minutes later, seems like success. wonder how much it would have cost without the patch tool. time to find out
oh, oops, that was with MY branch 
hit a couple issues with the real pr, left comments
btw looks like Claude just revised the Grep tool, started it just now and saw:
• Redesigned Search (Grep) tool with new tool input parameters and features