---
url: /reference/tools.md
---
# Tools & permissions

Kuru's runtime executes tool proposals after applying permissions and bounds. A provider supplies inference; it does not take over the tool host.

## Discover and invoke

```sh
kuru -C /path/to/project tools
kuru -C /path/to/project tool file_read --args '{"path":"README.md"}'
```

`tools` and the terminal UI's `/tools` command return one shared catalog with
built-ins, filtered MCP metadata, and a `disabled`, `live`, `stale`, or
`degraded` state for every configured alias. Use the returned identifier for a
tool on a live MCP alias; names are generated to stay distinct across servers.
Stale cached metadata is inspectable but cannot be routed or treated as a grant.

## Tool cards

In the terminal conversation, F6 selects the next observed tool call
and F7 expands or collapses its card. Permission prompts, pickers and
prompt search keep their own key handling. Page Up and
Page Down scroll expanded details without changing your draft.
Calls keep their admitted order even when parallel results arrive out of order.
The header distinguishes pending, complete, failed, denied, cancelled and
interrupted calls. An interrupted call with no exact settlement says its
outcome is unavailable; a partial preview does not prove success or no effects.

External arguments and results pass through Kuru's credential projection and
display bounds. Shell stdout and stderr have separate partial previews;
truncation or omitted updates is marked, and the settled result remains
authoritative. Private cognitive and peer-message arguments and results are
withheld. Expanding a card never invokes or retries a tool.

File-write, edit and delete cards read the exact checked checkpoint's retained
before/after snapshots. They do not compare the current workspace. Missing,
pruned, uncertain, binary, oversized or corrupt snapshots show an unavailable
label. Explicit checkpoint pruning can therefore remove a card's diff without
changing the conversation or current file. The diff marks a missing final
newline and displays bounded text after credential projection.

Detailed cards are temporary in the current harness and session, bounded to
64 calls and a 1 MiB presentation window. Older evicted detail is marked
unavailable. Resume, historical replay and completed-turn retries cannot
recreate missing tool bodies or admission order; they do not rerun tools to
populate cards. The saved public conversation and private actor memories are
unchanged by these display limits.

## Built-in tools

A [`[[permissions]]` rule](./configuration#tool-permissions) can `allow`, `ask`, or `deny` any of these by exact name, and can additionally pattern-match file mutations — `file_write`, `file_edit` (sharing `file_write`'s selector), and `file_delete` — by anchored, project-relative path. Absent a matching rule, reads and listing stay allowed; `file_write`/`file_edit`/`file_delete` fall back to `allow_write`, while `shell` and `web_fetch` ask for approval. Add an explicit `deny` rule to refuse a tool outright.

| Tool          | Arguments                                                       | Permission fallback                       |
| ------------- | --------------------------------------------------------------- | ----------------------------------------- |
| `file_read`   | `path`, optional `offset`, `limit`                              | Always allowed (project read)             |
| `file_list`   | `path`                                                          | Always allowed (project listing)          |
| `grep`        | `pattern`, optional `path`, `include_hidden`, `include_ignored` | Per-candidate project read                |
| `glob`        | `pattern`, optional `path`, `include_hidden`, `include_ignored` | Per-candidate project discovery           |
| `file_write`  | `path`, `content`                                               | `allow_write` → ask                       |
| `file_edit`   | `path`, `hunks`                                                 | `allow_write` → ask (shares `file_write`) |
| `file_delete` | `path`                                                          | `allow_write` → ask                       |
| `shell`       | `command`, optional `timeout_ms`                                | `allow_shell` → ask                       |
| `web_fetch`   | `url`                                                           | Ask                                       |

`file_read` returns its plain text response when called with only `path`. Supplying `offset` or `limit` selects a page of one-based logical UTF-8 text lines: the JSON page carries `text`, `offset`, `limit`, `line_count`, `next_offset` when more lines remain, and `omitted_lines`; pass `next_offset` back as the next call's `offset` to continue. `offset`/`limit` must be positive integers; offset zero, a limit outside 1–10,000, an out-of-range page, binary content, more than 100,000 lines, or a file over 2 MiB fails without returning partial page metadata.

`grep` and `glob` search only regular UTF-8 project files and exclude hidden and repository-ignored paths by default; set `include_hidden` or `include_ignored` independently to include them. Search never follows links and caps candidate files at 10,000, individual file snapshots at 2 MiB, matched lines at 8 KiB, and returned matches at 2,000. A binary, unreadable, protected, linked, denied, oversized, or over-limit candidate is omitted without exposing its path or content, and the result's `omitted` object counts each applicable category, including oversized matched lines. Each discovered candidate receives its own exact permission evaluation, and the search directory itself is never granted as a whole subtree, so an allow rule cannot override a more specific deny.

For an explicit write:

```sh
kuru --allow-write tool file_write \
  --args '{"path":"notes.txt","content":"A working note."}'
```

## Web fetch authority

`web_fetch` retrieves a UTF-8 document from a public HTTP(S) address only after the normal permission decision. It rejects URLs with credentials and rechecks every connection and redirect target, refusing loopback, private, link-local, multicast, unspecified, IPv4-mapped IPv6, carrier-grade NAT, and other special-purpose destinations. It follows at most five redirects, uses a 20-second operation deadline, accepts at most 2 MiB of response bytes, and returns at most 64 KiB. Its result records total `body_bytes`, retained `content_bytes`, `truncated`, and `untrusted: true`. Proxy, provider, and MCP credentials or headers are never forwarded.

Fetched text is untrusted tool data. It can inform the current response but cannot add instructions, change workspace trust, widen permissions, or authorize later tool calls. Kuru currently refuses compressed content rather than accepting an unbounded decompressor.

## Concurrent independent reads

If a provider proposes several independent reads that are already authorized,
Kuru can run `file_read`, `file_list`, `grep`, `glob`, and `web_fetch` calls
concurrently up to `max_parallel`. Permission and nested-instruction admission
still happen for each call in provider order. Progress can finish in a different
order, while the provider receives the final tool results in its original call
order and with the original call IDs.

A fresh approval or newly discovered instruction boundary stays on the normal
foreground path before later calls continue. File mutations, shell, MCP, skill
activation, cognition, and unknown tools remain serial. Kuru rechecks the
workspace, exact target, permission, and instruction scope before each read; a
change refuses that call instead of exposing data under stale authority.

## File boundaries

Paths are relative to the opened project. Absolute paths, parent traversal, and symlinks are rejected. Sensitive directories and configuration or credential files are protected; instruction files can be read but not mutated.

In an actor turn, an authorized file path can reveal nested project instructions. Kuru reviews their complete workspace manifest separately from file permission before returning a read/search result or applying a write. Grep and glob review only individually allowed candidate files. A newly instructed write/delete first returns a replan result without changing the file; the actor's next request receives the updated instructions. Direct `kuru tool` commands keep their explicit tool behavior without actor instruction activation.

The actor-only `skill_load` tool selects a name from the effective [skill catalog](./configuration#skills-and-custom-prompts) and optionally one direct Markdown reference. Kuru captures and, for project sources, reviews the selected prompt bytes before adding them to the next actor request. It does not execute skill scripts or grant the tools mentioned by a skill. Direct `kuru tool` calls cannot activate skills.

The built-in file tools enforce containment through capability-relative filesystem operations. UTF-8 file reads retain a marked 2 MiB head-and-tail excerpt after credential projection. The private state directory must remain outside the tool root.

## Shell authority

Shell execution goes through the permission engine. An explicit `deny` rule refuses it outright and can never be prompted around; an explicit `allow` rule runs it immediately. Absent a matching rule, `--allow-shell` or `allow_shell = true` allows it, and `allow_shell = false` (the default) asks for approval rather than blocking — a direct CLI command or other headless caller that hits that ask with no prompt to answer gets a structured permission-required refusal instead of executing or hanging. Once approved, it runs with your process permissions, including possible network access and access beyond the project. It is not a sandbox.

The built-in shell receives a finite compatibility subset of inherited variables
for command discovery, home/profile, temporary paths, locale, time, and standard
XDG locations. Provider/authentication variables, proxy configuration, agent
sockets, arbitrary `KURU_*` variables, and shell-startup controls are omitted.
Windows derives its stock system-shell paths and omits inherited `PSModulePath`,
allowing stock PowerShell to reconstruct its standard module paths. This
reduces accidental environment disclosure; it does not restrict filesystem,
process, or network authority. Before running your command, the Windows shell
loads the shipped `Microsoft.PowerShell.Management` and
`Microsoft.PowerShell.Utility` modules from `$PSHOME`. Other modules can still
load automatically. Configured stdio MCP servers retain their own inherited
environment and configured overrides.

Commands use `sh` on macOS/Linux and stock Windows PowerShell on Windows. The default timeout is 30 seconds. `timeout_ms` accepts 1–120000 milliseconds. Standard output and standard error each retain an independent marked 2 MiB head-and-tail excerpt after credential projection. On Unix, a registered owner retains the standard shell root, both pipes, and its fresh process group through cleanup; it signals that original group before reaping the root. Cleanup can inspect membership and repeat a freshly authorized signal while the root remains unreaped, under the same allowance. After reap, observation is read-only; group absence and pipe completion are still required for normal completion. If bounded confirmation is unavailable, Kuru reports it while retaining the owner for later observation. A selected execution/startup deadline may use one additional five-second cleanup-confirmation allowance; delayed startup returns at the deadline plus that allowance, and host shutdown shares one five-second window across registered shells. This does not control processes that leave the original group. Windows retains its existing Job cleanup. MCP protocol framing stays hard-bounded at 2 MiB.

Before Kuru returns a built-in file or shell result, or an MCP success or
application error, it replaces recognized credential spans with
`[REDACTED:recognized-secret]`. The finite rules cover Basic/Bearer
Authorization and Proxy-Authorization values; OpenAI `sk-svcacct-`, `sk-proj-`,
then `sk-` prefixes, longest first, with at least 16 token bytes after that
prefix; GitHub `ghp_`, `github_pat_`, `gho_`, `ghu_`, `ghs_`, and `ghr_` forms
with at least 8 following token bytes; AWS `AKIA`/`ASIA` followed by exactly
16 uppercase-alphanumeric bytes; supported PEM private-key blocks; and exact
sensitive field names including `api_key`, `password`, and `refresh_token`.
Outward tool-failure details, including error formatting and source chains,
receive the same projection.
OpenAI and GitHub minimum lengths are local false-positive controls, not proof
that a value is valid. In JSON, an exact sensitive or Authorization key replaces
its whole value; otherwise Kuru replaces only recognized text spans.
AWS matching uses its uppercase-alphanumeric token alphabet for the trailing
boundary, so a following lowercase byte is outside that token shape.

The projection changes only the returned value. Tool arguments, writes, source
files, prior history, configured MCP environments, credential stores, and each
producer's own size limit stay unchanged. It does not discover arbitrary,
encoded, split, transformed, or future secret formats, so an unrecognized value
may remain visible; a matching ordinary string may be projected. Tool output is
therefore not a byte-exact backup. Stdio MCP stderr is scanned before a bounded,
terminal-escaped tail is retained for direct human diagnostics. The finite
scanner does not remove every ordinary URL, path, or configuration-like value.
Captured stderr is not placed in runtime events, model input, or memory.

## Third-party tools

Configured MCP servers bring their own authority. Kuru's built-in write and shell switches do not restrict what those services can do. Select services and credentials accordingly; [MCP configuration](./mcp) covers transport and lifecycle behavior.

MCP discovery publishes complete catalogs per configured alias. One unavailable
server does not hide built-in or healthy-server tools; its prior routes dispatch
nothing until a later explicit discovery succeeds. Transport failures and
ambiguous cancellation do not automatically retry mutating calls. MCP
application errors remain useful results and do not disable a healthy server.
Original-name allow/deny filters run before publication, with deny precedence.
Private discovery cache metadata is bound to the reviewed workspace and exact
server/authentication context; it contains no resolved static-header values.
