Microcode ships seven tools. Each is implemented in ~50–100 lines under src/tools/.
| Tool | Side effect | Permission gated | Description |
|---|---|---|---|
read |
read | no | Read a UTF-8 text file with line numbers |
ls |
read | no | List a single directory level |
glob |
read | no | Find files by glob pattern |
grep |
read | no | Search file contents with a regex |
write |
mutating | yes | Create or overwrite a file |
edit |
mutating | yes | Replace exact strings in a file |
bash |
mutating | yes | Run a shell command |
Read tools are never gated. Mutating tools always go through the permission policy.
{
"name": "read",
"input": {
"path": "src/main.rs",
"offset": 1,
"limit": 200
}
}path— relative to cwd or absolute.offset— 1-indexed line to start at. Default 1.limit— max lines to return. Default 2000.
Output is <line-number>\t<line> so the model can reference exact locations. Files larger than 1.5 MB return an error suggesting offset/limit.
{ "name": "ls", "input": { "path": "src" } }Single-level directory listing. Honors .gitignore. Returns up to 500 entries, prefixed d (directory) or f (file).
{
"name": "glob",
"input": { "pattern": "src/**/*.rs" }
}pattern— gitignore-style glob.path— search root, relative to cwd. Defaults to cwd.
Returns up to 200 matches, sorted by mtime (newest first).
{
"name": "grep",
"input": {
"pattern": "TODO|FIXME",
"include": "*.rs",
"case_insensitive": false
}
}pattern— Rust regex syntax.path— search root.include— glob filter, e.g.*.rsorsrc/**/*.toml.case_insensitive— defaults to false.
Returns up to 200 matches as path:line:content. Skips files that look binary (NUL byte in first 8 KB) and files outside the gitignore set.
{
"name": "write",
"input": {
"path": "src/lib.rs",
"content": "pub fn hello() {}\n"
}
}Overwrites unconditionally. Creates parent directories as needed. Triggers the cargo verifier if the path ends in .rs.
{
"name": "edit",
"input": {
"path": "src/main.rs",
"old_string": "fn main() {}",
"new_string": "fn main() { println!(\"hi\"); }",
"replace_all": false
}
}old_stringmust match exactly (whitespace included). It must be unique in the file unlessreplace_allis true.- The match must exist; missing matches return a tool error.
- Triggers the cargo verifier if the path ends in
.rs.
This is the right tool for surgical edits. If the model wants to rewrite a whole file, it should use write.
{
"name": "bash",
"input": {
"command": "cargo test --quiet",
"timeout_ms": 60000
}
}command— shell pipeline. Run viash -c.timeout_ms— max ms. Defaults to 120000, capped at 600000.
Returns combined stdout+stderr (separated by --- stderr ---), truncated to 200 KB, with the exit code on the last line. Non-zero exit codes mark is_error = true.
Bash is the only tool that can do arbitrary side effects, so it's also the tool whose permission rules deserve the most thought. The default microcode init config allows bash:cargo * and bash:rg * and denies bash:sudo * and bash:rm -rf /*. Tune to taste.
See DEVELOPMENT.md. Six steps:
- New file
src/tools/foo.rsimplementingTool. - Register it in
ToolRegistry::defaults(). - If it modifies Rust files, extend
CargoVerifier::should_run_for. - Add a unit test in
tests/tools_test.rs. - Document in
docs/tools.md. - If it adds a config knob, document in
USAGE.md.
Resist the urge to add a tool unless you've personally wanted it on three separate occasions. The seven existing tools cover the long tail.