_               _
 | |__  _   _ ___| |__
 | '_ \| | | / __| '_ \
 | | | | |_| \__ \ | | |
 |_| |_|\__,_|___/_| |_|

Context-efficient command runner for coding agents.

Wraps any shell command and prints a single ✓/✗ summary line. On success, shows only the summary. On failure, shows filtered output. Preserves exit codes.

CI Go Report Card GoDoc
$ go install github.com/alfranz/hush/cmd/hush@latest

# Why hush?

Coding agents burn thousands of context tokens on verbose test output — even when all tests pass. hush reduces that to a single line.

Without hush (~1,028 tokens)
===== test session starts =====
platform linux -- Python 3.12
...
tests/test_auth.py::test_login PASSED  [ 2%]
tests/test_auth.py::test_logout PASSED [ 4%]
  ... (47 more lines)
====== 47 passed in 3.42s ======
With hush (~4 tokens)
 pytest
Test RunnerRaw OutputWith hushSaved
pytest (47 tests)~1,028 tokens~4 tokens99%
Jest (89 tests)~886 tokens~5 tokens99%
go test (14 pkgs)~196 tokens~6 tokens96%
cargo test (51 tests)~683 tokens~5 tokens99%

# Usage

Basic

# Wrap any command
hush "pytest -x"
 pytest

# On failure, shows full output (traceback, assertion details, etc.)
hush "pytest -x"
 pytest
  =================================== FAILURES ===================================
  __________________________________ test_login __________________________________

      def test_login():
          response = client.get("/auth/login")
  >       assert response.status_code == 200
  E       AssertionError: assert 401 == 200

  tests/test_auth.py:10: AssertionError
  =========================== short test summary info ============================
  FAILED tests/test_auth.py::test_login - AssertionError: assert 401 == 200
  ============================== 1 failed in 0.06s ===============================

Custom labels

By default, hush derives the label from the command name. Use --label to override it — especially useful when running the same tool multiple times.

# Default: label is derived from command ("pytest")
hush "pytest tests/unit"
 pytest

hush "pytest tests/integration"
 pytest         # which suite failed?

# With --label: easy to tell apart
hush --label "unit" "pytest tests/unit"
 unit

hush --label "integration" "pytest tests/integration"
 integration    # clear

Filtering output

# Last 30 lines of output
hush --tail 30 "npm test"

# Lines matching a pattern
hush --grep "error|FAIL" "make"

# First 20 lines
hush --head 20 "cargo build"
Caution

--grep and --tail are best suited for linters and build tools that produce high-volume output. For test runners (pytest, Jest, go test), prefer running without filters — the full traceback, assertion diffs, and source context are exactly what an agent needs to debug a failure. A --grep "FAIL" on pytest output, for example, strips away everything except the one-line summary.

# Batch Mode

Run multiple commands in sequence with a combined summary.

hush batch "ruff check ." "ty check src/" "pytest -x"
 ruff
 ty
 pytest
 3/3 checks passed

Use --continue to run all commands even if one fails:

hush batch --continue "ruff check ." "false" "pytest -x"
 ruff
 false
 pytest
 2/3 checks passed

# Config File

Define named checks in .hush.yaml at your project root:

# .hush.yaml
defaults:
  continue: true

checks:
  lint:
    cmd: ruff check .
  types:
    cmd: ty check src/
    grep: "error:"
  test:
    cmd: pytest -x
    tail: 40

Settings in defaults apply to all commands (root, batch, and named checks) unless overridden by per-check config or CLI flags. Precedence: CLI flags > per-check config > defaults.

Then run by name:

hush lint   # run a single check
 ruff

hush all    # run all checks in order
 ruff
 ty
 pytest
 3/3 checks passed

# Best Practices

General Combine filters for builds and linters

Filters stack: use --grep to find error lines, then --tail to limit how many are shown. This works well for builds and linters where each error line is self-contained. For test runners, prefer no filters or just --tail — the full traceback gives agents the context they need to fix failures.

hush --grep "error" --tail 10 "make build"

General Use labels when running the same tool multiple times

When your agent runs the same test suite against different targets, labels make the output scannable.

hush --label "unit" "pytest tests/unit"
hush --label "integration" "pytest tests/integration"

Python Use -x with pytest

Stop on first failure. There's no point burning tokens on 50 cascading failures when the first one is the root cause.

hush "pytest -x --tb=short"
Tip

--tb=short keeps pytest tracebacks concise, reducing the output hush needs to filter on failure.

Python Grep for ruff / ty errors

Linters can produce huge output. Filter to just the actionable lines.

# Only show lines with "error" for ty
hush --grep "error:" "ty check src/"

# Ruff is usually concise, but cap it anyway
hush --tail 20 "ruff check ."

JavaScript Tame Jest and Vitest output

Jest and Vitest are notoriously verbose. For test failures, prefer --tail over --grep — it preserves the traceback and assertion context that agents need to debug. Use --grep for linters like ESLint where each line is self-contained.

# Tail keeps the traceback + summary intact
hush --tail 30 "npx jest --no-coverage"

# ESLint: just errors (each line is self-contained, grep is fine)
hush --grep "error" "npx eslint src/"
Tip

Pass --no-coverage to Jest when running via hush. Coverage tables add hundreds of tokens with zero debugging value.

JavaScript TypeScript type-checking

hush --grep "error TS" "npx tsc --noEmit"

Go Use go test with targeted packages

Go test output is already fairly lean, but hush still saves tokens on pass. Target specific packages when possible.

hush "go test ./internal/runner/..."
hush "go test -race ./..."

Go Go vet and staticcheck

hush "go vet ./..."
hush --grep "error" "staticcheck ./..."

Rust Tame cargo output

Cargo is extremely verbose during compilation. Use --head or --grep to surface just the errors.

# First 20 lines catches the first compiler error
hush --head 20 "cargo build 2>&1"

# Just errors from cargo test
hush --grep "FAILED|error\\[" "cargo test"

Rust Clippy lints

hush --grep "warning:|error:" "cargo clippy -- -W clippy::all"

# Recommended Workflows

These patterns work well with coding agents (Claude Code, Cursor, Aider, etc.).

1. Define project checks in .hush.yaml

Define your project's checks once, then the agent can run them all with a single command. This is not a git hook — the agent runs it explicitly.

# .hush.yaml
defaults:
  continue: true

checks:
  lint:
    cmd: ruff check .
  types:
    cmd: ty check src/
    grep: "error:"
  test:
    cmd: pytest -x --tb=short
    tail: 40

# Agent runs:
hush all

2. Full pipeline check before commit

Run lint, type-check, and tests in one batch. The agent sees a clean summary or exactly which step failed.

hush batch --continue \
  "ruff check ." \
  "ty check src/" \
  "pytest -x --tb=short"
 ruff
 ty
 pytest
 3/3 checks passed

3. Build verification

Catch build errors early. Use --head to show the first error without the full cascade.

hush --head 15 "cargo build 2>&1"
hush --head 15 "go build ./..."
hush --head 15 "npm run build"

4. Targeted test runs after edits

When the agent edits a specific file, run only the related tests. Faster feedback, fewer tokens.

# Python: run the test file that matches
hush "pytest tests/test_auth.py -x"

# Go: run the specific package
hush "go test ./internal/runner/"

# JS: use Jest's path filter
hush "npx jest auth.test.ts"

5. Agent instructions integration

Add the snippet below to your CLAUDE.md or AGENTS.md. The key point: agents will naturally reach for bare commands like pytest tests/test_foo.py::test_name — the rule needs to cover individual test runs, not just full suites.

## Running shell commands

Always wrap test, lint, and build commands in `hush` — including
targeted runs against a single file or test function:

# Tests — full suite or individual file / function
hush "pytest -x --tb=short"
hush "pytest tests/test_auth.py -x"
hush "pytest tests/test_auth.py::test_login -x"
hush "go test ./..."
hush "go test ./internal/runner/ -run TestRun"
hush "npx jest auth.test.ts --no-coverage"

# Linters and type checkers
hush "ruff check ."
hush "ty check src/"

# If .hush.yaml is present
hush all

Never run these bare — hush keeps output concise on success and
surfaces only the relevant lines on failure.
Avoid

Don't use hush for commands where you need the full output (e.g., hush "cat file.txt" or hush "git diff"). hush is for commands where success = silence.

# Flags Reference

FlagDescription
--labelCustom label for the summary line
--tail NShow only last N lines on failure
--head NShow only first N lines on failure
--grep PATTERNFilter output to lines matching pattern
--continueContinue running after a failure (batch/all)

# Install

go install github.com/alfranz/hush/cmd/hush@latest

This places the binary in $GOPATH/bin (usually ~/go/bin). Make sure it's in your $PATH:

# Check if it's already there
which hush

# If not, add to your shell profile (~/.zshrc, ~/.bashrc, etc.)
export PATH="$HOME/go/bin:$PATH"