Tools
kli ships the tools the agent calls during a turn. Two run code: bash runs a shell command, eval runs Common Lisp in the live image. The rest are the file surface: read, find, and search look at files; write and edit change them.
Every tool carries a capability gate. A gate is a capability name the tool requires before it runs. By default kli grants every capability, so every tool runs. The capabilities array in settings.json overrides that: an empty array denies all gated tools, and an array of capability names grants exactly those (see Capabilities). Each tool below lists its gate. A call whose gate is not granted returns an error and runs nothing.
bash
Run a shell command in a child process. The command runs through sh -c, with stdout and stderr captured separately.
Capability gate: process/exec.
| Parameter | Type | Required | Effect |
|---|---|---|---|
command | string | yes | The shell command to run. |
directory | string | no | Working directory for the command. Defaults to the process working directory. |
input | string | no | Text fed to the command's stdin. Defaults to empty. |
shell | string | no |
Shell binary invoked with -c. Defaults to sh. |
timeout | integer | no | Wall-clock limit in seconds. Defaults to 30, clamped to a maximum of 300. |
Output limits and behavior:
- A command that runs past its timeout is killed (its whole process group when possible) and the call returns an error naming the timeout.
- stdout and stderr are each capped at 1 MiB (1048576 characters). Output past the cap is dropped and the result notes the truncation.
- The exit code rides in the result details. A non-zero exit returns an error result.
- Interactive programs are rejected before the command runs. kli inspects the first effective command word (skipping
env,command,exec,time,sudo,doas, leading assignments, and their options) and refuses these names:vi,vim,nvim,nano,emacs,less,more,man,top,htop,watch,ssh,mosh,tmux,screen. The rejection returns an error and runs nothing.
eval
Read and evaluate Common Lisp forms in the running kli image. The forms run on a dedicated thread under the requested package. The value of each form, and anything the forms print, comes back in the result.
Capability gate: image/eval.
| Parameter | Type | Required | Effect |
|---|---|---|---|
form | string | yes | Common Lisp source. All forms in the string are read and evaluated in order. |
package | string | no |
Package the forms read and run in. Defaults to CL-USER. An unknown package name is an error. |
Output limits and behavior:
- Evaluation has the same time budget as
bash: 30 seconds by default, 300 maximum. A form running past the deadline is interrupted, and the result notes that the interrupted form may have left image state partially modified. - Captured output is capped at 1 MiB (1048576 characters), counted and dropped at the stream so a printing loop cannot exhaust the heap.
- Printed values are bounded:
*print-length*is 100,*print-level*is 20, and*print-circle*is on, so a large or circular value prints to a finite string.
read
Read a file and return its lines with anchors. Each line comes back as LINE:HH|content, where LINE is the 1-based line number and HH is a two-hex-digit hash of the line's content. These anchors are what edit references.
Capability gate: file/read.
| Parameter | Type | Required | Effect |
|---|---|---|---|
path | string | yes | File to read. |
start | integer | no | First line of an inclusive 1-based range. A start past end-of-file is an error. |
end | integer | no | Last line of the range. An end past end-of-file clamps to the last line. |
raw | boolean | no |
When true, return line content with no LINE:HH| prefix. Defaults to false. |
A read over a file larger than 2 MiB is an error, and the error names search as the way to inspect a file that large. An empty file reads as (empty file). Reading a file records its current line hashes for the session, which is the read-before-edit state edit requires.
find
List file paths matching a glob pattern. Returns paths only, no file content.
Capability gate: file/read.
| Parameter | Type | Required | Effect |
|---|---|---|---|
pattern | string | yes |
Glob pattern, for example src/**/*.lisp. * spans a run of characters within one path segment; a bare ** segment spans any depth, including zero. |
Symlinks to files match; symlinked directories are not descended. At most 1000 paths are reported, sorted, with any overflow counted in the output. The walk stops and returns a partial result if it visits 100000 entries or runs longer than 10 seconds; the stop is surfaced in the text.
search
Search file contents with a regular expression across one file or a glob. Match lines come back as *LINE:HH|content, surrounding context lines as LINE:HH|content (space-prefixed). Each matching file is read whole, so its anchors are recorded and ready for edit with no separate read.
Capability gate: file/read.
| Parameter | Type | Required | Effect |
|---|---|---|---|
pattern | string | yes | Regular expression matched against each line. |
path | string | yes |
A single file or a glob, for example src/**/*.lisp. |
context | integer | no | Number of surrounding lines to show around each match. Defaults to 0. |
Files that fail to read as text are skipped. Files over 2 MiB are skipped, with the count surfaced in the result. The result is capped at 100 matching files and 1000 rendered match lines; the same 100000-entry and 10-second walk bounds as find apply.
write
Write content to a file, replacing it whole. Missing parent directories are created. The file's prior content rides in the result details so the change can render as a diff.
Capability gate: file/write.
| Parameter | Type | Required | Effect |
|---|---|---|---|
path | string | yes | File to write. |
content | string | yes | Full new content of the file. |
edit
Apply a hashline patch to one or more files, or accept a pending Common Lisp repair preview. A patch is whole-or-nothing: every anchor is validated against current disk content before any file is written, and a single stale or unread anchor rejects the entire patch. No file is partially modified.
Capability gate: file/edit.
| Parameter | Type | Required | Effect |
|---|---|---|---|
input | string | mode-specific | A hashline patch (grammar below). Required unless accepting a repair preview. |
repair | string | no |
Common Lisp repair policy for unbalanced patch output: safe (default), preview, or reject. |
accept_repair | string | mode-specific | Candidate id returned by a repair preview. Required only when accepting a preview. |
path | string |
with accept_repair | Target path for the candidate; used for authority gating and stale-content checks. |
A patch is one or more sections, each opened by a @@ PATH header and followed by ops:
| Line | Effect |
|---|---|
@@ PATH | Section header. One or more sections per patch. |
+ LINE:HH | Insert the following payload after the anchored line. |
+ |
Insert payload at end of file (bare +). |
< LINE:HH | Insert the following payload before the anchored line. |
< |
Insert payload at beginning of file (bare <). |
- A:HH..B:HH | Delete the inclusive line range. |
= A:HH..B:HH | Replace the range with the payload; no payload deletes the range. |
~content |
A payload line. Everything after ~ is verbatim. |
Anchor validation:
- The target file must have been read this session (by
reador by asearchthat matched it). An unread file rejects the patch with a prompt to read it first. - Each
LINE:HHanchor is re-hashed against current disk content at edit time. A hash that no longer matches is stale and rejects the whole patch instead of overwriting changed content; the error names the file and line to re-read. - Overlapping range ops, and an insert that falls inside a range op, are rejected, and the error names both spans.
On success the result reports each file as Edited PATH (+added -removed) and prints fresh LINE:HH|content anchors for the changed regions. Those anchors are valid for a follow-up edit with no intervening read. Edited files end with a trailing newline.
For Common Lisp source, edit checks the patched file for balanced delimiters before writing. Balanced output writes normally. Unbalanced output is repaired in memory according to repair: reject errors without writing, preview returns a candidate without writing, and safe writes only repairs classified as local to the edited range with a stable top-level form count. Unsafe repairs return a preview and must be accepted with accept_repair plus path; acceptance rechecks that the file has not changed since the preview.