silence
Strips comments in an agent post-write hook. Preserves doc comments and directives by default (e.g. JSDoc, eslint-disable-next-line, @ts-check, noqa:, TODO, FIXME, HACK).
Works with Claude Code, Codex, Opencode, and Pi.
Supports TypeScript/JavaScript, Python, Rust, Go, C/C++, Java, Kotlin, C#, Swift, CSS, JSON, YAML.
Grammars are downloaded lazily to avoid a huge binary.
install
yolo curl to shell
|
install with cargo
&&
or grab a binary from Releases.
tldr
usage
commands
silence strip — remove or check for comments
<path>…— file or directory (omit when using a git scope flag)-r, --recursive— recurse into subdirectories--check— print what would be removed; exit 1 if any--inline— remove only line comments (//,#)--block— remove only block comments (/* … */)--preserve-lines— leave blank lines where comments were--backup— write a<file>.baknext to each modified file--no-default-preserve— drop the built-in preserve list and directive detection--threads N— parallelism (default: CPU count)--verbose— verbose output--staged— only comments inside staged hunks--unstaged— only comments inside unstaged + untracked changes--changes— strip comments inside all uncommitted changes
silence hook — agent post-edit hook
[path]…— optional paths; reads the agent's stdin event when omitted- strips comments inside the uncommitted change; always exits 0
- feeds the model a short note so it learns the comments were stripped and
stops re-adding them: Claude Code and Codex read the
additionalContextstdout JSON natively; the Opencode and Pi plugins splice it into the tool result --no-default-preserve— same as onstrip
silence hooks — install into agent configs
install— wiresilence hookinto~/.claude/,~/.codex/,~/.config/opencode/plugins/,~/.pi/agent/extensions/install --to codex --to claude— selected agents onlyinstall --project— project-local paths under the current diruninstall— remove installed hooksstatus— per-agent install state
silence config
show— print active configuration and where it came fromshow --no-default-preserve— preview preserve rules with defaults offinit— write an example.silence.tomlto the current dir
silence llm — usage guide for agents
preserve rules
A comment is kept when it matches a preserve pattern or looks like a
directive: i.e. body starting with @, shaped namespace:value, or an XML-ish
<tag … /> (so @ts-ignore, //go:embed, /// <reference /> survive
without a rule each). A #! shebang on line 1 is never removed.
.silence.toml (searched cwd → git root → ~/.config/.silence.toml):
= ["TODO", "FIXME", "*IMPORTANT*"] # extra patterns; globs allowed
# use_default_preserve = false # drop built-ins (default: true)
--no-default-preserve drops the built-ins and directive detection but keeps
your preserve list. .silenceignore (same format as .gitignore, optionally
at ~/.config/.silenceignore) excludes files from walks.
example usage
rant
Yes, machine, you have obeyed. Yes, the code is blazing fast, just like I asked. Yes it's "no-slop and production-grade". Neither the code reviewer, nor future me, nor future you spending tokens reading this code needs to know that I asked.
contributing
design
Tree-sitter parses each file to a CST; a tiny (comment) @comment query
returns exact byte spans; spans matching preserve patterns are dropped (and,
in git mode, spans outside changed line ranges); the file is reassembled.
The engine (silence-core) is I/O-free so the logic is
unit-tested in isolation and u can build on top of it.
build
Needs a Rust toolchain (1.82+). git2 links libgit2 (vendored by default
via the crate; system cmake/C toolchain may be required on first build).
cargo build --release
cargo test
./target/release/silence --help
hook benchmark
Measures end-to-end silence hook latency (process spawn + git scan + parse).
Build release first, then:
./scripts/bench-hook.sh
Env: RUNS (default 50), WARMUP (default 5), SILENCE_BIN (path to binary).
adding a language
Built-in: TypeScript/JavaScript, Python. Everything else (Rust, Go, C/C++, TOML, …)
downloads on first use into ~/.config/silence/grammars/ from GitHub release assets.
- add optional pack metadata in
silence-langs(grammar_pack_id, extensions) - add the pack to
silence-grammar-packs/build.rsand release assets in.github/workflows/release.yml - wire
silence-grammarsensure();every_grammar_loads_and_query_compilesinsilence-strip-grammarsverifies query/ABI