Files
shiro-neko/docs/tools.md
T
Muhammad Zakir Ramadhan 5b8503fcd9 Initial commit: shiro-neko 0.1.0-beta.1
Agentic coding CLI on Bun, Ink, and the AI SDK.

Core: streamText loop with SDK-level tool approval so a denied call provably never executes; endpoint fallback for OpenAI reasoning models; retry with backoff.

Tools: read/write/edit/glob/grep/bash, path-jailed, gitignore-aware, ripgrep with a JS fallback, binary rejection, live bash streaming.

Agents: five variants crossing thinking level with tool restriction; plan and review withhold mutating tools from the model.

Extensibility: frontmatter skills with on-demand bodies, plugin host with blocking hooks, MCP stdio and HTTP, read-only subagents.

State: durable per-project memory, session task lists, session persistence, compaction that repairs provider-item dependencies.

Distribution: five-platform cross-compiled binaries with checksums, install scripts, CI on three operating systems.

404 tests, typecheck clean.
2026-09-02 17:30:18 +07:00

5.2 KiB

Tools

The approval model

Three categories.

Free. Read-only, no prompt: read_file, glob, grep, task.

Session tools. Also free, because they touch the agent's own state rather than your files: todo_write, remember, recall, forget, skill, ask, and anything a plugin marks auto-approved.

Gated. Every call stops for a decision: write_file, edit_file, bash, and every mcp__* tool.

edit_file wants to run
src/users.ts +2 -1
   export function paginate(offset: number, total: number) {
 -   if (offset < total) return next();
 +   if (offset <= total) return next();
   }
y allow once | a always allow edit_file | n deny

a whitelists that tool for the rest of the session. n tells the model it was denied and to ask what to do instead. --yolo skips all prompts.

The guard runs before all of this. It is not an approval — it is a refusal, and --yolo does not reach it. See plugins.

File tools

read_file

path    file path relative to the workspace root
offset  first line, 1-based
limit   max lines, default 2000

Returns contents with 1-based line numbers. Refuses binaries: a NUL byte in the first 8 KB means the file is not text, and a model that reads a 90 MB executable has burned its whole context on nothing.

write_file

path     file path
content  full contents

New files and full rewrites only. Creates parent directories.

edit_file

path        file path
oldString   exact text to find, whitespace and indentation included
newString   replacement
replaceAll  replace every occurrence instead of requiring exactly one

oldString must match byte-for-byte and appear exactly once unless replaceAll is set. An ambiguous match is an error naming the count, which pushes the model to add surrounding context rather than guessing which occurrence it meant.

glob

pattern         e.g. "src/**/*.ts"
limit           max paths, default 200
includeIgnored  also return files git ignores

Walks the tree honouring .gitignore and .shiroignore, skipping .git and node_modules unconditionally. Nested ignore files apply only within their own directory, as git does. Returns posix paths relative to the workspace root.

grep

pattern         regex source
include         glob limiting the search, default "**/*"
ignoreCase      case-insensitive
includeIgnored  also search files git ignores

Shells out to ripgrep when it is on PATH — roughly 15x faster on a real repo — and falls back to a JavaScript walker otherwise. Output is path:line: text either way, so the model sees one format regardless. Skips binaries. Caps at 200 hits.

bash

command  shell command
timeout  ms, default 120000, max 600000

Runs in the workspace root through bash -lc or cmd /c. Output streams live to the panel above the input rather than appearing all at once when the command exits — a two-minute test run is otherwise indistinguishable from a hang. Both pipes are drained concurrently, since a command that fills one while you block on the other deadlocks.

Returns exit code, stdout, stderr, and a note if a signal killed it.

Agent tools

task

description  short label shown to you
prompt       self-contained instructions
kind         "explore" (default) or "review"

Spawns a read-only subagent with read_file, glob, and grep only. It returns one report, so the parent pays for findings rather than the whole search transcript. It sees none of the parent conversation, so its prompt has to stand alone.

explore finds and reports. review critiques code in severity order. Progress streams to the subagent panel.

ask

question  one specific question
options   choices, recommendation first, each with an optional detail
multiple  allow more than one

Stops the turn and puts the question on screen. With options it is a picker; without, free text. esc skips, which tells the model to decide and state its assumption.

Withheld entirely in headless mode — a question with no one to answer it would hang.

todo_write

todos  the complete list: content, status, optional note

Statuses: pending, in_progress, done, blocked. Send the whole list each time; it replaces the previous one. Warns when more than one task is in_progress, when nothing is in_progress while work remains, or when a blocked task has no note.

remember, recall, forget

Durable per-project notes. See memory.

skill

name  skill name from the catalogue

Loads the body of a skill. See skills.

Path safety

Every path a tool receives goes through a jail: resolved against the workspace root, then checked that it did not escape. ../../etc/passwd and absolute paths outside the root are both refused before any filesystem call.

The model's output is a trust boundary. It can emit any string, so the check happens on every call rather than being assumed.

Output caps

Any single tool result is truncated at 30,000 characters with a note saying how much was cut. grep stops at 200 hits, glob at 200 paths, read_file at 2000 lines by default. Without caps one grep for function can end a session.