Expand description
Redirection steering: recognise the ad-hoc shell idioms a ct tool serves
better, and (as a Claude Code PreToolUse hook) steer the agent to the
ct equivalent instead.
Agents reach for raw shell — find | xargs grep, sed -i, cat | head,
for/while loops, sleep-polling waits, wc -l counts, and python -c/
jq file reads — even when a suite tool would do the job bounded,
deterministic, and self-verifying. analyze is the pure heart: it
classifies a shell
command string into an optional Steer naming the ct tool that serves
it and a best-effort equivalent command. The hook submodule wraps that
in the Claude Code PreToolUse JSON protocol (deny / ask / warn); the
install submodule wires the hook into a project’s .claude/settings.json.
The matcher is deliberately conservative: it only fires on a fixed set
of high-confidence 1:1 idioms, never re-steers a command that already
invokes ct, and returns None (allow) whenever it is unsure. The hook
is fail-open — any malformed input or unrecognised command is allowed —
because it runs ahead of every shell call.
Modules§
- hook
- The Claude Code
PreToolUsehook protocol: turn a stdin envelope into a steering decision. - install
- Merging the steering hook into a Claude Code settings file. The merge runs
through the comment- and layout-preserving
ct-patchengine (crate::patch): the existing file is parsed only to decide which edits to make, and those edits are byte-range splices against the original text, so the user’s comments and formatting survive.
Structs§
- Steer
- A steering match: a
cttool serves the inspected command.
Enums§
- Mode
- What the hook does when a command matches a steering rule.
Constants§
- LOG_
IGNORE_ RULE - The gitignore rule that hides the tool-call log directory. Placed in
.ct/.gitignore, the pattern*logmatches thetclogdirectory (and any other…logentry under.ct), keeping the logs out of version control while the.gitignoreitself stays tracked.
Functions§
- analyze
- Classify a shell command or multi-line scriptlet.
Nonemeans “allow” — nocttool clearly serves it. A single command runs the high-confidence idiom matcher ([analyze_one]); a multi-line scriptlet is classified line by line ([analyze_script]) so a hand-sequenced series of ct-serviceable steps is steered toward one shell-lessct andchain. Never re-steers a command that already invokesct. - date_
stem - The UTC calendar date
yyyy-mm-ddforepoch_secsseconds since the Unix epoch — the daily tool-call-log filename stem. Pure (it reads no clock), via Howard Hinnant’s civil-from-days algorithm, so it is deterministic and testable; the caller supplies the current time. - gitignore_
with_ log_ rule - Given a
.ct/.gitignore’s current contents (orNonewhen it is absent), return the contents to write so it carriesLOG_IGNORE_RULE, orNonewhen the rule is already present (no write needed). Existing lines are preserved; the rule is appended. - glob_
steer - Steer a harness
Globcall toct search(name filter from a root). - grep_
steer - Steer a harness
Grepcall toct search(the suite’s content search). - pipeline_
nudge - A generic nudge against any shell pipeline that we could not map to a
specific
cttool: prompt the agent to try harder to express it withct, without a concrete rewrite.Noneunless the command contains a pipe, is not already actcall, andanalyzefound no specific steer (so the two never both fire). Meant to be shown warn-only — it never denies. - read_
steer - Steer a harness
Readcall toct view— unless the path is somethingct view(a line reader) cannot render (an image, PDF, or notebook), whereReadis the right tool and the call is left alone (None).