coding-tools
Declarative, agent-friendly command-line tools for working in a codebase, behind
one short ct command. Each tool replaces an ad-hoc shell pattern with a single,
self-describing command, and every tool is framed the same way — so what you learn
from one transfers to the next, and an agent can discover and drive them uniformly.
Tools
ct <command> dispatches to ct-<command> (git-style), or call each tool by its
full name.
| Command | Tool | Purpose |
|---|---|---|
ct search |
ct-search |
Recursively find files by name, type, size, and content (find | xargs grep). |
ct view |
ct-view |
Show a file's lines by range, or the regions around a pattern with context. |
ct tree |
ct-tree |
Report a file tree with per-file line/word/char counts; filter, sort, summarise. |
ct edit |
ct-edit |
Find/replace across files, gated by an --expect verdict and --dry-run. |
ct patch |
ct-patch |
Set/delete nodes by path in JSON/JSONC/JSONL, preserving comments and layout. |
ct test |
ct-test |
Run a command as a framed experiment; classify the result from its output. |
ct each |
ct-each |
Run a command template once per item (no shell); aggregate --expect verdict. |
ct outline |
ct-outline |
Report a file's declarations — kind, name, start:end span — for bounded reads. |
ct rules |
ct-rules |
Record the project's invariants in .ct/rules.jsonc — verified at the moment they're written. |
ct check |
ct-check |
Re-verify every recorded invariant; five lanes, one exit status. Read-only. |
ct deps |
ct-deps |
Assert crate-graph invariants — deny crates, forbid A=>B paths, duplicates — with evidence paths. |
ct await |
ct-await |
Wait, boundedly, for an external outcome via a read-only probe. |
Why
A coding agent's loop is locate → read → change → verify. These tools make each step bounded, deterministic, and self-verifying, which is what lets it run with less supervision:
- Framed verdicts. A search or a command run can pose a
--question, classify into aSUCCESS/ERRORverdict, and--emita templated line; exit status follows the verdict.ct-search --expect nonepasses when nothing is found (a negative assertion);ct-edit --expect =1writes only if exactly one site matched, so a wrong-sized change fails loudly instead of applying silently. - Preview before write.
ct-edit --dry-runshows the diff and verdict without touching disk; edits preserve every untouched byte (indentation, terminators). - Atomic batches.
ct-edit --scriptruns a whole batch of block edits under prepare/confirm/write: every edit is simulated and judged in memory (and every target pre-flighted for writability) before anything is written — one failing anchor means zero writes, never a half-applied batch. - Read-only by default where it matters.
ct-testruns only a fixed, immutable allowlist of read-only commands;ct-eachadds the suite's own gated mutating tools only behind an explicit--mutatingflag. There is no shell mode anywhere — every dispatch is a direct argv launch. - Bounded and observable. Every tool takes
--timeout(self-bounding for the read-only/mutating tools, a child process-group kill folded into the verdict forct-test/ct-each) and--heartbeat, a minimal templated liveness pulse for long runs. - Machine-readable. Every tool takes
--jsonfor structured results, and--explain [md|json]prints its own documentation / tool-use definition. The umbrella'sct --explain jsonis a one-call manifest of the whole suite.
Shared conventions
- Pattern promotion. Any pattern argument is promoted with one rule: no
metacharacters → literal substring; glob metacharacters (
*?[ ]) that are not a valid regex → glob; otherwise → regex.--mode literal|glob|regexpins the interpretation (promotion off) for verbatim code anchors. - Payload schemes. Payload-typed values accept
file:PATH(the file's contents, verbatim — never promoted) andtext:VALUE(the escape for literal values starting with a scheme prefix). A multi-line pattern matches as a line-anchored literal block inct-search/ct-view/ct-edit, with a nearest-miss diagnostic when it matches nothing. - Exit status.
0= success / verdictSUCCESS;1= clean negative / verdictERROR;2= usage or runtime error. The0/1split composes in&&/||pipelines. --explain [md|json]. Every tool is self-describing for humans and agents.
Examples
# Find Rust files mentioning TODO — just yes/no.
# Assert there are no leftover debug prints (passes when nothing matches).
# Read a span, or the neighbourhood of a symbol.
# Preview a one-site rename, then apply it.
# Frame a read-only check as a test.
# Dispatch one check over several items — what used to need a bash for-loop.
# A verbatim block edit with zero quoting — write the payloads as files.
# A batch of structural edits, atomic by construction (.ctb script):
# everything is verified in memory; one failing anchor means zero writes.
The canonical reference for each tool is its --explain md output, mirrored under
docs/explain/; docs/specs/commands.md
is the suite index.
License
Apache-2.0. See LICENSE.