Fettler
The conversation that commissioned Fettler. The author’s messages, verbatim
This document is the record of the conversation in which Fettler was commissioned, shaped, and named. It took place in a single session between its author (Stephen Vincent Foster) and Claude, on 16 August 2026, inside the Shoddy repository, the project whose development pains produced the need. Its outcome was the enhancement request specifying Fettler: a C# file, search and edit tool with an MCP front end and a CLI front end. The tool this site documents is that request, built.
Fidelity note. Every message from the author below is reproduced verbatim, typos included, deliberately, as part of the record. Claude’s replies are condensed in substance, with the tables, examples and conclusions intact. Summarized tool activity is set in italics. The working transcript this page presents is kept in the repository as fettler-design-transcript.md, written at the author’s request in the conversation’s final turn.
throughout our work, we've consantly been hit by bash and windows issues when using tools to develop shoddy.
please prepare for me a list of the essential commands/tools/etc you use to search for files and their contents, to read file contents, to create files or change existing files. when i say files, i mean source files of any type or language, not binary. and anything else you use frequently to help me write code.
Claude ran two verification searches against the standard library to confirm how the files are matched, then answered. The headline: every file operation has a dedicated tool that never touches a shell. The bash and Windows pain comes entirely from reaching for a shell to do something a dedicated tool already does.
| Purpose | Tool | Notes |
|---|---|---|
| Find files by path | Glob | results sorted by modified time |
| Which files contain a pattern | Grep (files only) | cheapest way to narrow before reading |
| Matching lines | Grep (content) | line numbers, context |
| Read | Read | absolute path; offset and limit for large files |
| Targeted change | Edit | must have read first; the anchor must be byte-exact and unique |
| New file / full replacement | Write | overwriting an unread file is refused |
Alongside the table came the PowerShell 5.1 traps. There is no &&. And 2>&1 on a native program wraps its error stream as NativeCommandError and reports failure even on exit 0. Then the rule that would have saved most of the trouble: if the operation is find, read, or change a text file, no shell, ever. The shell is for verbs that produce output: build, test, run.
i also have this desire that anyone using shoddy -- including with claude, not need anything else. no python. no wsl. no bash. nothing else required.
please consider all of the actions you perform on source code files...which you listed above....and design a single, cohesive, comprehensive tool, or suite of tools that would be written in shoddy. be holestic. don't be afraid to suggest shoddy enhancements, such as file operations. don't just recreate what's there....this is your chance to tell me how you'd like to work with files.
Claude read the language’s file library in full, launched two exploration agents over the builtin file and text surfaces, and read the capability manifests and the path-boundary source. The research surfaced what mattered. The file library was eight whole-file builtins with no directories, no rename, no copy, no atomic write. The capability manifest already gated file access by pattern. A root boundary already held for every file word. And Sparky was the precedent: a program whose user is a model, hand-rolled JSON-RPC over stdio, self-contained single-file publish per OS. The turn was interrupted before the design was delivered.
ok...that's enough. i'm asking a purely functionaly language to do a lot of side-effect stuff. that's not a good fit for the language.
Our goal of a single install can be met with c#. same requirements, different target. what's that plan?
Agreed. The design was pushing effects into a language built to keep them at the edges. Claude verified the MCP host’s project layout and confirmed the existing path boundary was pure System.IO with no language dependencies, and was interrupted again before the plan was delivered.
let's keep this 100% csharp. no shoddy. but part of the repo. to keep our single-install goal.
The shape: one more MCP server, 100% C#, with read/write/edit/find/search/run over stdio. Five design calls worth making deliberately:
On the shell: run passes its command as an argument list, never a command string. No quoting layer, no dialect.
would this be both mcp and scripted (from ps or sh)?
Yes, and the CLI mode pays for itself fastest. Every line of logic out of the script twins is a line that cannot drift, and driving a stdio JSON-RPC session to check a glob is miserable where a command line is not. The shape: one core knowing nothing of protocol or console, an MCP front end, a CLI front end. The split must exist from the first phase or it is a retrofit. What the CLI needs that MCP does not: distinct exit codes, a --json mode, and the complete result including failures on standard output, because PowerShell 5.1 turns redirected native error output into an error of its own. If a script ever needs 2>&1, the bug is rebuilt.
no dependencies on shoddy... including its runtime. i don't want these two things coupled together.
the implementation can use whatever fileio mechanims work best.
also, what about file-level operations? move, copy, delete, rename, create
also, must work on windows and mac.
please write an enhancement request, save in github\shoddy-planning\requirmenents (see folders for pattern). you have permission to write there. not a lot of design, focus on requirements.
Claude read the planning tree’s existing requests to match the house pattern, then wrote the document. Three clauses set the frame:
Flagged at the close of the turn: the planning tree sat on its main branch, the write was authorised in that message, and nothing was committed.
for naming, consider the tools use and the source of the shoddy name. think maintenance in a 1875 shoddy mill.
Claude read the naming tradition’s sources and confirmed the candidate unclaimed in both repositories. Fettler. In a West Riding woollen mill the fettler kept the carding engines in order: stripping matted fibre and dirt out of the card clothing, cleaning, setting, repairing. He produced no cloth. His whole job was keeping the machines that produced cloth in a state where they could.
Sub-choice: project and server Fettler, executable fettle, so that commands read as imperatives. Runners-up and why they lost: Millwright (maintains machinery, not material), Mender (exact for editing, undersells the rest), Overlooker (supervision, not repair), Tuner (overloaded in software), Mungo (already taken by a sibling project). The full account is on the heritage page.
agreed. include that in the requirements.
Six targeted edits folded the name through the document. They set the title and the lane it would live in. They added the ruling that no project in it carries the parent’s prefix, because the prefix would claim the kinship the independence clause exists to deny. They settled the two spellings, and recorded the naming decision with the five candidates that lost.
looking good. add examples for each command.
Twelve verbs, one example each. Writing them exposed a hole: there was no requirements section for find or search at all. The opening prose promised both and the acceptance criteria assumed them, but nothing in between said what they must do. Added, with three clauses that earn their place:
remove all the referencs to shoddy...just the requirements for this thing. simply say 'all c#', or whatever.
A full rewrite of the document. Every reference to the other project removed. The only surviving mill mentions explain where the name comes from. The independence clause became “written entirely in C#, no reference to any other project here; shares the repository and the release and nothing else”, the sentence that still governs this repository. Ground truth was rewritten from facts about another codebase into nine verifiable platform behaviours. Among them: the PowerShell 5.1 error-stream trap, case-insensitive filesystems, macOS filename normalization, Windows reserved names and path limits, open-file locking, and a file move having two different atomicity guarantees depending on the volume.
your forgot to add examples for every command
Correct. The worked forms covered six of twelve. Replaced with one worked example per verb, each captioned with what it pins and which clause it comes from, headed by a note that the examples pin the information each answer must carry, not its layout. Several show the refusal path rather than the happy one, which is where the requirements have teeth:
$ fettle delete "artifacts/*.tmp"
refused: delete does not accept a pattern; name one path
$ fettle edit src/Fettler/Glob.cs --script edits.json
refused: edit 2 matched 4 places in src/Fettler/Glob.cs; nothing written
$ fettle move src/glob.cs src/Glob.cs
moved src/glob.cs -> src/Glob.cs atomic: yes case-only rename
is a file-watcher useful in the mcp? to notify you of changes you may not otherwise know about...
Yes, but almost certainly not as a watcher, and the reasoning inverts the obvious answer. The problem is real. Refusing an edit against a file that changed since it was read catches staleness at the moment of writing. It misses the worse case. Read a file, reason about it for several turns, never write, and the answer is built on content that stopped being true. The recommendation: stat what was read, not watch the tree. The set of files with stale beliefs attached is exactly the set that has been read.
| Stat what was read | Recursive watcher | |
|---|---|---|
| Cross-platform reliability | A stat is a stat | Overflows under bursts on Windows; a long history of trouble on macOS |
| Noise from own writes | None. It knows what it wrote | Every edit reports itself unless carefully attributed |
| Noise from a build | None. Nobody read the build output | Thousands of events without a scoping rule |
| What it misses | Files never read. No beliefs held about them | Whatever the OS dropped, silently |
Three clauses if it goes in: advisory never authoritative; modified time and size together; Fettler’s own writes are not news. A real watcher would earn its place driving something reactive, which is a different product, so it goes in Out of scope with the reasoning recorded.
provide a transcript of this conversation, as an md file please
The transcript was written. It is the document this page presents. Its closing inventory recorded the state of the world at the end of the conversation. The enhancement request was written and uncommitted. The file-watcher clauses were recommended but not yet written in. The requirements file was not yet renamed for its subject. And nothing was committed in either repository at any point in the conversation. Every one of those decisions, what to keep, what to rename, what to make permanent, remained the author’s.
What the conversation produced is the tool this site documents: what fettle is, the rules it holds to, and the account of who made it.