/snip
You are an expert at writing declarative YAML filters for **snip**, a CLI proxy that reduces LLM token consumption by filtering shell output.
$ npx -y skills add edouard-claude/snip --skill snip --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/snip
Context preview
The summary Claude sees to decide when to auto-load this skill.
You are an expert at writing declarative YAML filters for **snip**, a CLI proxy that reduces LLM token consumption by filtering shell output.
SKILL.md
snip.SKILL.mdCreating snip Filters
You are an expert at writing declarative YAML filters for **snip**, a CLI proxy that reduces LLM token consumption by filtering shell output.
Filter File Location
- **Built-in filters**: `filters/*.yaml` (embedded in the binary at build time)
- **User filters**: `~/.config/snip/filters/*.yaml` (override built-in filters by name)
- **Per-project filters**: configure additional directories via `filters.dir` array in `~/.config/snip/config.toml` (e.g. `dir = ["~/.config/snip/filters", "${env.PWD}/.snip"]`). Later directories take priority.
**Trust store**: filters in any directory outside `~/.config/snip/` are ignored (with a stderr warning) until approved once with `snip trust <dir>`, which pins each file's SHA-256. Re-run `snip trust` after editing a trusted file.
Filter Structure
Every filter is a YAML file with this structure:
name: "tool-subcommand" # Required. Unique identifier, used for registry lookup.
version: 1 # Informational revision number of the filter (bump on behavior change).
description: "What this filter does" # Human-readable purpose.
match: # Required. When to apply this filter.
command: "tool" # Required. The CLI tool name (e.g., "git", "go", "npm").
subcommand: "sub" # Optional. First non-flag argument (e.g., "test", "log").
# Also accepts a list: ["install", "add", "i"]; include ""
# in the list to match the bare command invocation too.
exclude_flags: ["-v", "--json"] # Optional. Skip filter if user passes any of these.
require_flags: ["--all"] # Optional. Only apply if user passes ALL of these.
inject: # Optional. Modify command args before execution.
args: ["--json"] # Arguments to append to the command.
defaults: # Flag defaults, only added if flag not already present.
"-n": "10"
skip_if_present: ["--json"] # Don't inject anything if any of these flags are present.
streams: ["stdout", "stderr"] # Optional. Which streams to filter. Default: ["stdout"].
# Use ["stderr"] for tools that output to stderr (e.g., bun test).
# Use ["stdout", "stderr"] to filter both streams merged together.
pipeline: # Required. Ordered list of transformation actions.
- action: "keep_lines"
pattern: "\\S"
- action: "head"
n: 20
on_error: "passthrough" # Descriptive convention: the engine ALWAYS falls back to raw
# output when a pipeline fails; no other value is implemented.Match Rules
- `command` is matched exactly against the first token of the shell command.
- `subcommand` is matched against the first non-flag argument.
- Flag matching uses **prefix matching**: `"-v"` matches both `-v` and `-verbose`.
- Registry lookup is O(1) by key `"command"` or `"command:subcommand"`.
Inject Behavior
- Injected `args` are inserted before any `--` separator, otherwise appended.
- `defaults` only apply if their flag key is not already present in the user's args.
- If any flag in `skip_if_present` is found, the entire inject block is skipped.
The 20 Pipeline Actions
Line Filtering
| Action | Params | Description | |--------|--------|-------------| | `keep_lines` | `pattern` (regex) | Keep only lines matching the pattern | | `remove_lines` | `pattern` (regex) | Remove lines matching the pattern | | `head` | `n` (int, default 10), `overflow_msg` (string, default "+{remaining} more lines") | Keep first N lines | | `tail` | `n` (int, default 10), `overflow_msg` (string, default "+{dropped} earlier lines") | Keep last N lines | | `dedup` | `normalize` ([]string of regexes to strip before comparing), `top` (int, 0=all) | Deduplicate lines, output "text (xN)" for repeats |
Line Transformation
| Action | Params | Description | |--------|--------|-------------| | `truncate_lines` | `max` (int, default 80), `ellipsis` (string, default "...") | Truncate long lines | | `replace` | `pattern` (regex), `replacement` (string, supports $1, $2...) | Regex find and replace on each line | | `truncate_bytes` | `max` (int, 0=disabled), `overflow_msg` (string, default "... truncated at {max} bytes") | Cap the whole output at `max` bytes, cutting on a UTF-8 rune boundary. The marker is paid for out of `max`, and is dropped when it alone would not fit | | `strip_ansi` | (none) | Remove ANSI escape codes | | `compact_path` | (none) | Strips a leading `src/`/`lib/`/`internal/`/`pkg/`/`vendor/` segment. The result may not resolve from the cwd, and carries no marker saying so — no bundled filter uses it. Display-only paths only. |
Extraction & Grouping
| Action | Params | Description | |--------|--------|-------------| | `regex_extract` | `pattern` (regex with capture groups), `format` (string using $0, $1, $2...) | Extract data via regex capture groups | | `group_by` | `pattern` (regex with capture group), `format` (template, default "{{.Key}}: {{.Count}}"), `top` (int) | Group lines by capture group, count occurrences | | `aggregate` | `patterns` (map of name->regex), `format` (Go template), `append` (bool) | Count lines matching named patterns. **Replaces** the input lines with the summary unless `append: true` (forgetting it caused bugs #134/#136: a correct count and no content) | | `state_machine` | `states` (map of state definitions with `keep`, `until`, `next`) | Stateful line filtering with transitions |
JSON Processing
| Action | Params | Description | |--------|--------|-------------| | `json_extract` | `fields` ([]string), `format` (template, optional) | Extract fields from JSON input | | `json_schema` | `max_depth` (int, default 3) | Output JSON type schema | | `ndjson_stream` | `group_by` (string field name), `format` (template with .Key, .Count, .Events)
Read more
Creating snip Filters
You are an expert at writing declarative YAML filters for **snip**, a CLI proxy that reduces LLM token consumption by filtering shell output.
Filter File Location
- **Built-in filters**: `filters/*.yaml` (embedded in the binary at build time)
- **User filters**: `~/.config/snip/filters/*.yaml` (override built-in filters by name)
- **Per-project filters**: configure additional directories via `filters.dir` array in `~/.config/snip/config.toml` (e.g. `dir = ["~/.config/snip/filters", "${env.PWD}/.snip"]`). Later directories take priority.
**Trust store**: filters in any directory outside `~/.config/snip/` are ignored (with a stderr warning) until approved once with `snip trust <dir>`, which pins each file's SHA-256. Re-run `snip trust` after editing a trusted file.
Filter Structure
Every filter is a YAML file with this structure:
name: "tool-subcommand" # Required. Unique identifier, used for registry lookup.
version: 1 # Informational revision number of the filter (bump on behavior change).
description: "What this filter does" # Human-readable purpose.
match: # Required. When to apply this filter.
command: "tool" # Required. The CLI tool name (e.g., "git", "go", "npm").
subcommand: "sub" # Optional. First non-flag argument (e.g., "test", "log").
# Also accepts a list: ["install", "add", "i"]; include ""
# in the list to match the bare command invocation too.
exclude_flags: ["-v", "--json"] # Optional. Skip filter if user passes any of these.
require_flags: ["--all"] # Optional. Only apply if user passes ALL of these.
inject: # Optional. Modify command args before execution.
args: ["--json"] # Arguments to append to the command.
defaults: # Flag defaults, only added if flag not already present.
"-n": "10"
skip_if_present: ["--json"] # Don't inject anything if any of these flags are present.
streams: ["stdout", "stderr"] # Optional. Which streams to filter. Default: ["stdout"].
# Use ["stderr"] for tools that output to stderr (e.g., bun test).
# Use ["stdout", "stderr"] to filter both streams merged together.
pipeline: # Required. Ordered list of transformation actions.
- action: "keep_lines"
pattern: "\\S"
- action: "head"
n: 20
on_error: "passthrough" # Descriptive convention: the engine ALWAYS falls back to raw
# output when a pipeline fails; no other value is implemented.Match Rules
- `command` is matched exactly against the first token of the shell command.
- `subcommand` is matched against the first non-flag argument.
- Flag matching uses **prefix matching**: `"-v"` matches both `-v` and `-verbose`.
- Registry lookup is O(1) by key `"command"` or `"command:subcommand"`.
Inject Behavior
- Injected `args` are inserted before any `--` separator, otherwise appended.
- `defaults` only apply if their flag key is not already present in the user's args.
- If any flag in `skip_if_present` is found, the entire inject block is skipped.
The 20 Pipeline Actions
Line Filtering
| Action | Params | Description | |--------|--------|-------------| | `keep_lines` | `pattern` (regex) | Keep only lines matching the pattern | | `remove_lines` | `pattern` (regex) | Remove lines matching the pattern | | `head` | `n` (int, default 10), `overflow_msg` (string, default "+{remaining} more lines") | Keep first N lines | | `tail` | `n` (int, default 10), `overflow_msg` (string, default "+{dropped} earlier lines") | Keep last N lines | | `dedup` | `normalize` ([]string of regexes to strip before comparing), `top` (int, 0=all) | Deduplicate lines, output "text (xN)" for repeats |
Line Transformation
| Action | Params | Description | |--------|--------|-------------| | `truncate_lines` | `max` (int, default 80), `ellipsis` (string, default "...") | Truncate long lines | | `replace` | `pattern` (regex), `replacement` (string, supports $1, $2...) | Regex find and replace on each line | | `truncate_bytes` | `max` (int, 0=disabled), `overflow_msg` (string, default "... truncated at {max} bytes") | Cap the whole output at `max` bytes, cutting on a UTF-8 rune boundary. The marker is paid for out of `max`, and is dropped when it alone would not fit | | `strip_ansi` | (none) | Remove ANSI escape codes | | `compact_path` | (none) | Strips a leading `src/`/`lib/`/`internal/`/`pkg/`/`vendor/` segment. The result may not resolve from the cwd, and carries no marker saying so — no bundled filter uses it. Display-only paths only. |
Extraction & Grouping
| Action | Params | Description | |--------|--------|-------------| | `regex_extract` | `pattern` (regex with capture groups), `format` (string using $0, $1, $2...) | Extract data via regex capture groups | | `group_by` | `pattern` (regex with capture group), `format` (template, default "{{.Key}}: {{.Count}}"), `top` (int) | Group lines by capture group, count occurrences | | `aggregate` | `patterns` (map of name->regex), `format` (Go template), `append` (bool) | Count lines matching named patterns. **Replaces** the input lines with the summary unless `append: true` (forgetting it caused bugs #134/#136: a correct count and no content) | | `state_machine` | `states` (map of state definitions with `keep`, `until`, `next`) | Stateful line filtering with transitions |
JSON Processing
| Action | Params | Description | |--------|--------|-------------| | `json_extract` | `fields` ([]string), `format` (template, optional) | Extract fields from JSON input | | `json_schema` | `max_depth` (int, default 3) | Output JSON type schema | | `ndjson_stream` | `group_by` (string field name), `format` (template with .Key, .Count, .Events)
CLI proxy that filters shell output before it reaches your AI coding assistant's context window.

