Tools
KHAELOR gives the model exactly seven powerful primitives — not dozens of micro-tools. Every tool call is permission-checked before it runs, rendered as a compact one-liner in the conversation, and journaled in the session's event log.
| Tool | What it does | You see |
|---|---|---|
read | Read a file (paged, line-numbered) | ▸ Read src/kernel/agent.ts · lines 1–2000 of 3417 |
write | Create or fully replace a file | ▸ Write src/context/budget.ts · new file · 114 lines |
edit | Surgical in-place replacement | ▸ Edit src/context/engine.ts · +31 −12 |
grep | Content search (ripgrep) | ▸ Search "ContextEngine" · 14 matches in 5 files |
glob | Find files by name pattern | ▸ Glob src/**/*.ts · 23 files |
bash | Run a short-lived shell command | ▸ Run npm test · exit 0 · 3.2s |
process | Manage background processes | ▸ Process start npm run dev · p3 running |
There is deliberately no git tool — git flows through bash under
the same permission rules, where you can see and gate every command.
read#
Reads files with line numbers, up to 2,000 lines per page; the output always states the total and how to continue, so the agent pages through large files instead of dumping them. Guard rails you benefit from:
- Binary detection — binary files are described (type, size), never dumped as bytes.
- Size guard — files over 10 MB are refused with guidance to search or page instead.
- Near-miss suggestions — a typo'd path gets "Did you mean…?" candidates from the repository index.
- Directories — reading a directory lists its entries instead of erroring.
Every successful read is also recorded in the session's file registry — this is what powers the safety rule that the agent must read before it writes (below).
write#
Writes a complete file, creating parent directories as needed. Two protections guard your work on existing files:
- Read-before-write — the agent cannot overwrite a file it has not read in this session. It is structurally impossible for it to blow away content it never saw.
- External-modification detection — if the file changed on disk after the agent last read it (you edited it, or another process did), the write is refused and the agent must re-read and reapply. Your concurrent edits are never clobbered.
Writes are atomic (temp file + fsync + rename), preserve line endings (CRLF), BOM, and file
mode bits. Every write produces a unified diff you can expand instantly with d or
review in /diff.
edit#
The most important tool: exact string replacement inside a file. The agent supplies the text to find and its replacement; KHAELOR requires the match to be unambiguous. Under the hood, a nine-strategy matching cascade makes edits robust without making them reckless:
- Exact match
- Line-trimmed match (whitespace drift at line edges)
- Whitespace-normalized match
- Indentation-flexible match (block quoted at the wrong indent depth — the file's real indentation is preserved)
- Escape-normalized match (over-escaped
\n,\t, quotes) - Trimmed-boundary match
- Block-anchor fuzzy match (first/last lines as anchors, similarity-scored middle)
- Context-aware fuzzy match (last resort)
- Multi-occurrence replace-all (exact matches only — fuzzy mass-replace is never allowed)
The guards matter as much as the strategies: an ambiguous match (multiple locations) fails
with the line numbers instead of silently picking one; a fuzzy match that would replace a
disproportionately large region is refused. Failed edits return precise repair guidance to the
model — the closest near-miss with the exact line and character difference — so the agent
fixes itself instead of thrashing. Same read-before-edit and external-modification protection
as write; same instant diff.
grep#
Fast regex content search over the repository, powered by ripgrep (bundled — no system
dependency). Results are grouped by file with line numbers, ordered by most recently modified,
and hard-capped at 100 matching lines so the model's context never drowns in output.
Respects .gitignore and .khaelorignore. When results are truncated,
the full result set is spilled to a file the agent can search further.
glob#
Filesystem discovery by name pattern — **/*.ts,
src/**/config.* — returning up to 100 paths ordered newest-first. Respects
ignore files and skips built-in noise (node_modules/, .git/,
dist/) unless the pattern explicitly targets it.
bash#
Runs short-lived shell commands — builds, tests, git, package scripts — and returns interleaved stdout/stderr with the exit code and duration:
$ npm test
> proj@0.3.1 test
> vitest run
✓ src/context/engine.test.ts (14 tests)
[exit code 0 · 3.2s · cwd /Users/x/dev/proj]
- Commands run in their own process group, non-interactively, from the project directory
(or an explicit working directory) — never via hidden
cdside effects. - A failing exit code is a normal observation for the agent, not a crash — it reads the failure and fixes the cause.
- Permission evaluation happens on the parsed command before execution — see Permissions.
The timeout that never kills your command
This is KHAELOR's answer to the classic agent failure of hanging forever on a dev server.
If a bash command is still running when its time budget expires (default 120 s,
max 300 s), it is not killed — it is adopted by the background process
manager, keeps running with its output continuously logged, and the agent immediately gets the
output so far plus a process id:
Command still running after 120s — moved to background as process p4.
Output so far:
...
Use process read p4 for new output, or process stop p4 to stop it.
Nothing blocks forever; nothing is silently killed. (Pressing Esc yourself
does kill a foreground bash command — you asked for that — while
background processes survive.)
process#
A real background process manager the agent can drive: start,
list, read, write (stdin), stop. It is what
lets KHAELOR start a dev server, keep editing, check the server's output, run tests, and check
the server again — the workflow blocking-shell agents simply cannot do.
Started p3 (pid 41232): npm run dev
cwd /Users/x/dev/proj · log ~/.khaelor/process-logs/s_ab12/p3.log
First output (waited up to 2s):
VITE v5.4.1 ready in 431 ms
➞ Local: http://localhost:5173/
- Instant-failure detection —
startwaits up to 2 s for first output, so port-in-use and similar immediate crashes are caught inline without blocking healthy servers. - Nothing is lost — each process keeps an in-memory ring buffer and
a complete log file on disk (
~/.khaelor/process-logs/<session>/<id>.log). Reads return "new output since last read"; older output stays readable by offset or from the log. - Interactive processes —
writesends stdin (REPLs, prompts), then automatically reads the response. - Clean stops —
stopterminates the whole process group (SIGTERM, 3 s grace, SIGKILL), so grandchild processes don't linger. - Lifecycle — processes survive Esc interruptions but end with the session (with notice). Exits are detected and shown even if nobody is reading.
You can watch and control everything yourself in /processes;
the status bar shows a live count of running processes.
Output truncation and spill files#
Every tool that can produce large output truncates it middle-out — head and tail kept, one explicit marker in between — and spills the complete output to disk:
[... 1,842 lines omitted (58 KB). Full output:
~/.khaelor/tool-output/s_ab12/bash-toolu_9.txt — read or grep that file for the rest.]
The agent gets the spill path and can read or grep it; you see a
· truncated badge on the tool row and can expand from the same file. Spill
files are session-scoped, garbage-collected with the session, and capped at 512 MB
globally (oldest sessions pruned first). A 40,000-line test log can never destroy your
conversation layout — what settles into the transcript is bounded.
Inspecting tool calls#
- Live: Ctrl+T toggles a rolling 12-line tail of the currently-running tool.
- After: d prints the most recent edit's diff;
/diffopens the full session diff viewer; each turn's tool calls can be expanded into full detail blocks on demand. - Always: every tool call — inputs, results, approval decisions — is a durable event in the session event log.