From cheese-flow
Hash-anchored file editing using tilth MCP. Replace specific functions or blocks using hash anchors from tilth_read, not entire file rewrites. Use when: editing code, replacing functions, deleting blocks, or making precise surgical changes. Always read first to get hash anchors. Do NOT use for reading files — use cheez-read. Do NOT use for searching — use cheez-search. Examples: "replace the validateToken function with this new implementation", "delete lines 44-89", "update the authenticate method".
npx claudepluginhub paulnsorensen/cheese-flowThis skill is limited to using the following tools:
> **Hard dependency**: If `mcp__tilth__tilth_edit` is unavailable, stop immediately and report
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Checks Next.js compilation errors using a running Turbopack dev server after code edits. Fixes actionable issues before reporting complete. Replaces `next build`.
Guides code writing, review, and refactoring with Karpathy-inspired rules to avoid overcomplication, ensure simplicity, surgical changes, and verifiable success criteria.
Share bugs, ideas, or general feedback.
Hard dependency: If
mcp__tilth__tilth_editis unavailable, stop immediately and report "tilth MCP server is not loaded — cannot proceed." Do NOT fall back toEdit,Write, or any host tool.
Hash-anchored file editing via tilth MCP (tilth_edit).
Never rewrite whole files. Use hash anchors from tilth_read to make precise, surgical edits.
Traditional AI editing rewrites entire files, wasting tokens and risking data loss. tilth_edit uses hash anchors — unique identifiers for each line — to:
The protocol:
tilth_read → get hash anchorstilth_edit with those anchors and new contentWhen you read a file with tilth_read, lines have anchors:
42:a3f│ let x = compute();
43:f1b│ return x;
Format: <line>:<hash>│ <content>
The hash is a short content fingerprint. If someone else edits the file, hashes change, and your edit is safely rejected.
Single line edit:
tilth_edit({
"path": "src/auth.ts",
"edits": [
{ "start": "42:a3f", "content": " let x = recompute();" }
]
})
Multi-line range replacement:
tilth_edit({
"path": "src/auth.ts",
"edits": [
{
"start": "44:b2c",
"end": "89:e1d",
"content": "export function handleAuth(req, res, next) {\n // new implementation\n const token = extractToken(req);\n if (!token) return res.status(401).end();\n next();\n}"
}
]
})
Delete a block:
tilth_edit({
"path": "src/auth.ts",
"edits": [
{ "start": "44:b2c", "end": "89:e1d", "content": "" }
]
})
Multiple edits in one call:
tilth_edit({
"path": "src/auth.ts",
"edits": [
{ "start": "12:a1b", "content": "import { newHelper } from './helpers';" },
{ "start": "44:b2c", "end": "89:e1d", "content": "// replaced function\n..." }
]
})
Show diff in response:
tilth_edit({
"path": "src/auth.ts",
"diff": true,
"edits": [...]
})
tilth_read(path: "src/auth.ts", section: "44-89")
Output:
44:b2c│ export function handleAuth(req, res, next) {
45:c3d│ const token = req.headers.authorization?.split(' ')[1];
...
88:d4e│ next();
89:e1d│ }
44:b2c (first line of function)89:e1d (closing brace)tilth_edit({
"path": "src/auth.ts",
"edits": [{
"start": "44:b2c",
"end": "89:e1d",
"content": "export function handleAuth(req, res, next) {\n const token = extractToken(req);\n if (!validateToken(token)) {\n return res.status(401).json({ error: 'Invalid token' });\n }\n req.user = decodeToken(token);\n next();\n}"
}]
})
This is the most common use case. The pattern:
Read the function (outline first if file is large):
tilth_read(path: "src/auth.ts")
# See: [44-89] export fn handleAuth(req, res, next)
tilth_read(path: "src/auth.ts", section: "44-89")
# Get hash anchors
Note start/end anchors from the hashlined output
Replace the entire function body:
tilth_edit({
"path": "src/auth.ts",
"edits": [{
"start": "44:b2c",
"end": "89:e1d",
"content": "<your new function implementation>"
}]
})
If the file changed since you read it:
Error: Hash mismatch at line 44
Expected: b2c
Found: f9a
Current content:
44:f9a│ export async function handleAuth(req, res, next) {
...
Recovery:
This is a safety feature, not a bug.
When you edit a function signature, tilth_edit shows callers that may need updating:
Edit applied to src/auth.ts
── callers that may need updates ──
src/routes/api.ts:34 router.use('/api/*', handleAuth)
src/routes/admin.ts:12 app.use(handleAuth)
src/middleware.ts:8 const wrapped = handleAuth(...)
Check these locations and update if needed.
Use the start anchor of the line AFTER where you want to insert:
tilth_edit({
"path": "src/auth.ts",
"edits": [{
"start": "13:abc",
"content": "import { newHelper } from './helpers';\nimport { oldImport } from './old';"
}]
})
This replaces line 13. To truly "insert", include the original line 13 content in your new content.
tilth_edit({
"path": "src/auth.ts",
"edits": [
{ "start": "44:b2c", "end": "89:e1d", "content": "" },
{ "start": "120:f4g", "end": "180:h5i", "content": "" }
]
})
Make separate tilth_edit calls per file (cannot batch across files):
tilth_edit({ path: "src/auth.ts", edits: [...] })
tilth_edit({ path: "src/routes.ts", edits: [...] })
For large files, tilth_read shows an outline, not hashlined content:
# src/giant.ts (2400 lines, ~32k tokens) [outline]
[1-20] imports
[22-89] interface Config
[91-450] class GiantHandler
[100-180] fn process
[182-340] fn validate
To edit, drill into the specific section:
tilth_read(path: "src/giant.ts", section: "100-180")
# Now you get hashlined content for fn process
Then edit with those anchors.