Skip to content

Day to day with hushrun

Updated

This page is for you if you work in a repository that already uses hushrun. You run checks as before, and hushrun skips what this exact code already passed.

Before you begin

Sign in once on your machine, so that your passes count for teammates and CI, and theirs for you:

npx hushrun login

Until you do, checks run as usual, and nothing is shared.

Run checks as usual

Run your checks the way the repository always has, such as npm test or pnpm lint. Each script starts hushrun run, which skips the check when this exact code already passed it on your machine, in CI or in an agent's sandbox, and runs it otherwise.

  • A skip exits 0, like a pass.
  • A failure keeps the check's own exit code and output.
  • hushrun's own lines go to stderr and start with hushrun: . Everything else is the check's.
  • Change a file and the checks run again. Go back to files that passed and they skip.

Note: With Bun, run bun run test, not bun test. bun test is Bun's own runner, which never reads package.json, so hushrun never sees it.

A partial run, such as npm test -- src/cart.test.ts, is a separate check, and never stands in for the full run.

Read the lines

The lines you'll see most:

LineWhat it means
test running: no pass yet for this exact codeNothing passed on these files yet, so the check runs
test passed in 41s; it won't run again on this codeIt passed, and the pass is recorded
test skipped: this exact code passed in CI 3 min ago (saves 41s)A pass was found. The command didn't run, and hushrun exited 0
test failed in 2s (exit 1)It failed. The failure is recorded, and the exit code kept

Every other line, and what to do about it, is in Lines hushrun prints.

Name a check

A check's name labels its history and is part of what hushrun compares. You rarely set one:

  • Run through a package.json script, a check takes the script's name. test:unit becomes test-unit.
  • Anywhere else, it takes the program's name. hushrun run -- vitest run is vitest.

Give a variant its own name when a check depends on something outside the files, such as an environment variable or the Node.js version. hushrun doesn't compare those, so a pass under Node.js 22 would skip a run under 24. Put the name before --:

npx hushrun run unit-node22 -- vitest run

Name the Node.js 24 run unit-node24, and each skips only on its own pass. Where a check counts is another guard, and Commands has the naming rules.

Run a check again

--force runs a check even after a pass, and records the new result. Use it to see a skipped check's output, such as a coverage report:

npx hushrun run --force test -- vitest run

Give the check's name and exact command, from the same directory, so the result counts for the same check.

Before you push

Commit, then ask what CI would still run on this exact code:

$ npx hushrun ready
a0b1c2d isn't ready: CI would run 2 checks again.
  missing test   no pass yet for this exact code
  missing lint   it failed on this exact code last time
  passed  types
Run these here, then push:
  npm run test
  npm run lint

Run the commands it prints. Once it says a0b1c2d is ready to push., push, and CI skips what passed. A check marked ci is one nothing on this machine can settle, such as one needing a secret, so CI runs it.

The pre-push hook asks the same question when you push. For your push, it warns and goes on:

hushrun: CI will run test on a0b1c2d. To skip that, run these before you push:
  npm run test

It refuses a coding agent's push instead, until those checks pass (For coding agents). It tells an agent from a person by what the agent sets in its environment: Who is an agent.

Flaky checks

A failure is recorded too, and the newest result decides the next run. So a check that last failed always runs again.

A check that passed and failed on the same code is flaky, and the dashboard marks it flaky. If you doubt a skip, run the check again.

Keep generated files ignored

hushrun looks at the files again when the command ends. If they changed, the result belongs to neither version of the code, so it isn't recorded:

hushrun: test passed in 12s, but files changed while it ran, so it wasn't recorded. If test writes files, list them in .gitignore

List what your checks write, such as coverage/ or build output, in .gitignore.

When a check keeps running

Most often a file changes on every run, or the command differs: npm test -- --coverage is not npm test. Troubleshooting has every cause and its fix.

Next

Markdown