Skip to main content

Module steer

Module steer 

Source
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 PreToolUse hook 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-patch engine (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 ct tool 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 *log matches the tclog directory (and any other …log entry under .ct), keeping the logs out of version control while the .gitignore itself stays tracked.

Functions§

analyze
Classify a shell command or multi-line scriptlet. None means “allow” — no ct tool 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-less ct and chain. Never re-steers a command that already invokes ct.
date_stem
The UTC calendar date yyyy-mm-dd for epoch_secs seconds 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 (or None when it is absent), return the contents to write so it carries LOG_IGNORE_RULE, or None when the rule is already present (no write needed). Existing lines are preserved; the rule is appended.
glob_steer
Steer a harness Glob call to ct search (name filter from a root).
grep_steer
Steer a harness Grep call to ct search (the suite’s content search).
pipeline_nudge
A generic nudge against any shell pipeline that we could not map to a specific ct tool: prompt the agent to try harder to express it with ct, without a concrete rewrite. None unless the command contains a pipe, is not already a ct call, and analyze found no specific steer (so the two never both fire). Meant to be shown warn-only — it never denies.
read_steer
Steer a harness Read call to ct view — unless the path is something ct view (a line reader) cannot render (an image, PDF, or notebook), where Read is the right tool and the call is left alone (None).