chisel

SKILL.md

Chisel Agent Skill

You have access to a Chisel MCP server. Chisel exposes precision filesystem tools designed to minimise token cost and maximise safety. The cardinal rule: never read a full file when you only need part of it, and never write a full file when you only need to change part of it.


⚠️ shell_exec has no shell interpreter. Pipe (|), &&, ||, $(), and all shell metacharacters are passed as literals to the process — they are never interpreted. Each shell_exec call runs exactly one command. Compose multi-step logic across separate calls.


Tool Selection

Need to find something in a file or directory?
  └─ shell_exec (grep / find / sed / awk / stat / ls)

Need to edit an existing file?
  ├─ Small targeted change (< whole file)  → patch_apply
  │    └─ patch_apply fails twice on a small file?  → write_file (see below)
  └─ Overwrite entirely / file is tiny     → write_file

Need to add content to the end of a file?
  └─ append

Need to create a directory?
  └─ create_directory

Need to rename or relocate a file?
  └─ move_file

Reading — Never Fetch What You Don't Need

Always start with the minimum slice required. Only escalate if the first call does not give enough context.

Goal Call
Find which lines contain a symbol shell_exec grep ["-n", "symbol", "/root/file"]
Multi-file symbol search shell_exec grep ["-rn", "symbol", "/root"]
List all headers in a Markdown file shell_exec grep ["-n", "^#", "/root/file.md"]
Extract one section by header shell_exec sed ["-n", "/^## Section/,/^## /p", "/root/file.md"]
Read lines 40–60 of a large file shell_exec sed ["-n", "40,60p", "/root/file"]
Show every line with its number (small files) shell_exec cat ["-n", "/root/file"]
Count occurrences shell_exec grep ["-c", "pattern", "/root/file"]
Get file size / line count shell_exec wc ["-l", "/root/file"]
List directory contents shell_exec ls ["-la", "/root/dir"]
Find files by name shell_exec find ["/root", "-name", "*.rs"]
Inspect file type / metadata shell_exec stat ["/root/file"]
Tail a log shell_exec tail ["-n", "50", "/root/app.log"]

Avoid calling cat on a file longer than ~50 lines. Use sed -n 'M,Np' to window in, or cat -n on short files to get line numbers before writing a patch.


Editing — Prefer Diffs Over Full Rewrites

patch_apply — primary edit tool

Send only the changed lines. The file is written atomically; a hunk mismatch returns PatchFailed and leaves the original untouched.

--- a/src/main.rs
+++ b/src/main.rs
@@ -12,7 +12,7 @@
 fn main() {
-    let port = 3000;
+    let port = 8080;
     start_server(port);
 }

Rules for a valid patch:

  • Context lines (no prefix) must match the file exactly, including whitespace.
  • @@ -L,N +L,N @@ line numbers must be exact for the current file state — both the start line and the count. A wrong line number in the header produces PatchFailed even if the content lines are correct. Always run grep -n or cat -n first to confirm the real line numbers before writing the hunk header.
  • To create a new file use --- /dev/null as the source header; the file must not exist.
  • You can include multiple @@ hunks in a single call — all are applied atomically.

When PatchFailed is returned:

  1. Re-read the exact lines with grep -n or sed -n 'L-3,L+3p'.
  2. Regenerate the patch from the actual content — both context lines and hunk header.
  3. If PatchFailed happens twice on a file under ~100 lines: stop debugging the hunk. Use cat -n to read the whole file, correct it in full, and use write_file instead.

write_file — full overwrite

Use when:

  • Creating a new file with substantial initial content.
  • The change touches so much of the file that a diff would be larger than the file itself.
  • The file is short (< ~30 lines) and a full rewrite is cleaner.
  • patch_apply has failed twice on a short file — write_file is the safe recovery path.

append

Use for log entries, appending lines to a config, or adding to an incrementally-built file. The file must already exist.


In-place Transformation with shell_exec sed -i

For bulk replacements (rename a symbol, fix a repeated pattern), sed mutates the file directly — no diff needed.

⚠️ sed -i has different signatures on macOS (BSD sed) vs Linux (GNU sed). Use exactly the forms below — do not improvise alternatives.

Platform Argument array
Linux (GNU sed) ["-i", "s/Old/New/g", "/abs/path/file"]
macOS (BSD sed) ["-i", "", "s/Old/New/g", "/abs/path/file"]

On macOS the empty string "" is the backup-suffix argument (meaning: no backup file). Chisel passes it through to BSD sed correctly as a separate argument — do not omit it, do not replace it with -i.bak, and do not combine it with -i into a single arg like "-i''". Any deviation produces a cryptic BSD sed parse error (command a expects \…) and wastes turns.

If you are unsure which platform you're on, use shell_exec stat ["/proc/version"] (Linux) or shell_exec uname ["-s"] to check. Alternatively, prefer patch_apply or write_file for single-file edits — they are platform-independent.

# Linux
shell_exec sed ["-i", "s/OldName/NewName/g", "/root/src/lib.rs"]

# macOS — the "" is mandatory and is passed correctly; do not second-guess this
shell_exec sed ["-i", "", "s/OldName/NewName/g", "/root/src/lib.rs"]

A successful in-place edit returns exit_code: 0 with empty stdout. Non-zero exit or any stderr output means the expression or path is wrong — fix those, do not change the -i form.


Workflow Patterns

Locate → Read slice → Patch

The standard low-token edit loop:

  1. grep -n "target_symbol" /root/file — find the line number.
  2. sed -n "L-5,L+10p" /root/file — read a tight window around it.
  3. Verify the @@ -L,N +L,N @@ header matches exactly.
  4. patch_apply — send the diff against that exact content.

Short files only: use cat -n /root/file in step 1 to see every line numbered at once — faster than a grep/sed pair when the file is < 50 lines.

Explore unfamiliar codebase

  1. ls -la /root — top-level layout.
  2. find /root -name "*.rs" -not -path "*/target/*" — enumerate source files.
  3. grep -rn "struct MyStruct" /root/src — locate the definition.
  4. sed -n "L,L+30p" /root/src/file.rs — read the struct body.

Relative paths are auto-anchored to root. . means the root itself, subdir/file means root/subdir/file. Absolute paths also work. Traversal (../escape) is always blocked.

Create a new file with boilerplate

Use write_file. Once it exists, all subsequent edits go through patch_apply.

Rename a symbol across many files

Preferred — one call via find -exec … {} +:

find -exec cmd {} + batches all matched paths into a single command invocation. No shell, no loop, one shell_exec call regardless of how many files match.

# macOS (BSD sed)
shell_exec find ["/root/src", "-name", "*.rs", "-exec", "sed", "-i", "", "s/OldName/NewName/g", "{}", "+"]

# Linux (GNU sed)
shell_exec find ["/root/src", "-name", "*.rs", "-exec", "sed", "-i", "s/OldName/NewName/g", "{}", "+"]

The {} placeholder and + terminator are passed literally to find — they are not shell metacharacters and require no escaping.

Fallback — one call per file (only if find -exec is unavailable or the pattern needs per-file logic):

  1. grep -rl "OldName" /root/src — get the file list.
  2. For each file:
    • Linux: sed ["-i", "s/OldName/NewName/g", "/root/src/file.rs"]
    • macOS: sed ["-i", "", "s/OldName/NewName/g", "/root/src/file.rs"]

Scaffold a directory tree

create_directory /root/src/handlers
write_file /root/src/handlers/mod.rs "..."
write_file /root/src/handlers/auth.rs "..."

Error Handling

Error Meaning Fix
PatchFailed Context lines or hunk header don't match current file Re-read with grep -n / cat -n, fix both header line numbers and context, regenerate patch. If it fails twice on a short file, use write_file.
OutsideRoot Path escapes configured root Use only paths under the root the server was started with
NotFound File doesn't exist Use write_file to create, or check path with find
ReadOnly Server in read-only mode Writes are disabled; only reads and shell_exec work
CommandNotAllowed Command not in whitelist Use only: grep sed awk find cat head tail wc sort uniq cut tr diff file stat ls du

What Not To Do

Anti-pattern Why Do instead
cat /root/large_file.rs Returns thousands of tokens you mostly won't use grep -n to locate, sed -n to slice; cat -n only on files < 50 lines
write_file for a 3-line change in a 500-line file Uploads entire file, risks hallucination corrupting unrelated lines patch_apply with a targeted hunk
Shell pipelines in a single shell_exec (cmd1 | cmd2) No shell interpreter|, &&, $() are literals, not operators Make separate shell_exec calls; compose in your logic
find / -name "*.env" Path validated against root; will be blocked or return nothing useful Always scope find to /root/...
Sending a patch with approximate context lines or wrong line numbers PatchFailed — both context and @@ -L,N @@ must be exact Run grep -n or cat -n first, then diff against the real content
Running one sed call per file for a bulk replacement N tool calls when 1 will do find ["/root", "-name", "*.ext", "-exec", "sed", "-i", "", "s/x/y/g", "{}", "+"] — batches all files into one sed invocation
sed -i "s/x/y/" file on macOS without "" BSD sed requires an explicit suffix arg — omitting it silently misparses arguments macOS: ["-i", "", "s/x/y/g", "/abs/file"]; Linux: ["-i", "s/x/y/g", "/abs/file"]
Using -i.bak or -i'' instead of ["-i", ""] Chisel passes the empty string through correctly — no workaround needed Stick to ["-i", ""] two-arg form; do not invent alternatives
Retrying with a different -i form after a BSD sed parse error The error is the expression or path, not the -i "" form Fix the sed expression or path; keep ["-i", ""] as-is
Continuing to retry patch_apply after two failures on a small file Wastes turns; context drift compounds the problem cat -n the file, use write_file to rewrite it correctly
Weekly Installs
6
GitHub Stars
3
First Seen
14 days ago
Installed on
opencode6
github-copilot6
codex6
kimi-cli6
gemini-cli6
cursor6