Skip to content
hushrun

Stop paying CI to test the same code twice

Coding agents push every change to staging and then to production, so CI tests and builds the same files twice. hushrun validates each change once and ships staging's exact artifact to production, by digest.

Free to start, with GitHub or Google. In a pilot, we set it up with you in one session.

Or run this at your repository's root:

npx hushrun init

It finds your checks, signs this terminal in, and shows every change before making it.

acme/apisame files, same digest sha256:bad90344…28f8
stagingdevelop 0e5399f
  1. planfull
  2. lintran
  3. unitran
  4. integrationran
  5. buildran
  6. deployran

imagesha256:3cae5d5c…b157

productionmain 6083e16
  1. lintreused
  2. unitreused
  3. integrationreused
  4. buildcopied

imagesha256:3cae5d5c…b157staging's, by digest

With hushrun: production reuses staging's signed evidence and deploys the same image, by digest.

What's true today

  • Runs in production on Kobranzapp/back, as ci-promote
  • Free CLI, for macOS, Linux and Windows
  • Every event signed and verified by the CLI
  • GitHub Actions today, GitLab next

Your CI bill pays for the same work twice

Agents push every change to staging, then the same change to production. The files are identical, but the production pipeline can't tell: it installs, tests and builds from scratch.

acme/apisame files, same digest sha256:bad90344…28f8
stagingdevelop 0e5399f
  1. lintran
  2. unitran
  3. integrationran
  4. buildran
  5. deployran

imagesha256:3cae5d5c…b157

productionmain 6083e16
  1. lintagain
  2. unitagain
  3. integrationagain
  4. buildagain
  5. deployran

imagerebuilt: a new digest

Today: two commits with the same files, and production runs the whole pipeline again.
  • Every change, two full runs

    With staging and production, one pipeline run in two re-validates files that already passed.

  • Cheaper minutes don't fix it

    Lower runner prices cut the price of a minute, not the number of minutes your agents trigger.

  • More pushes, more waste

    Every agent push, re-push and rebase pays for its duplicate run again.

Build and validate once. Promote the exact artifact.

hushrun is one static binary that runs inside the CI you already have. It adds three things to your pipelines:

  1. A content digest

    It hashes the files of each deployable scope into a source digest, independent of commits, branches and the VCS. A merge commit with the same files has the same digest.

    acme/api

    stagingsha256:bad90344…28f8
    productionsha256:bad90344…28f8

    same files, same digest

  2. Signed evidence in an append-only log

    Each pipeline records what it did (checks run, artifacts built, deploys) as signed events, in an append-only log we host.

    evidence · acme/apisha256:bad90344…28f8

    startedstagingci
    checkstagingci
    checkstagingci
    checkstagingci
    artifactstagingci
    deployedstagingci
    passedstagingci
  3. A plan before any work

    Before running anything, a stage asks the planner what's left for this digest. When staging already validated it, production copies staging's artifact by digest and deploys it.

    production · push to main
    $ hushrun plan --stage production
    default promote: every requirement of `production` is met: deploying image us-docker.pkg.dev/acme-staging/api/server@sha256:3cae5d5c…b157 by digest
      image: us-docker.pkg.dev/acme-staging/api/server@sha256:3cae5d5c…b157
      requirement lint                 satisfied
      requirement unit                 satisfied
      requirement integration          satisfied
    Real hushrun plan output from a demo repository. Digests are shortened; hover for the full value.

In the demo, develop at 0e5399f and main at 6083e16 are different commits with the same files, so both have the source digest sha256:bad90344…28f8.

Six plan modes, and nothing in between

Every plan ends in exactly one mode. Pick one to see what hushrun plan printed for it on the demo repository.

production · hushrun plan
$ hushrun plan --stage production
default promote: every requirement of `production` is met: deploying image us-docker.pkg.dev/acme-staging/api/server@sha256:3cae5d5c…b157 by digest
  image: us-docker.pkg.dev/acme-staging/api/server@sha256:3cae5d5c…b157
  requirement lint                 satisfied
  requirement unit                 satisfied
  requirement integration          satisfied

hushrun plan: production

ScopeModeReason
defaultpromoteevery requirement of production is met: deploying image us-docker.pkg.dev/acme-staging/api/server@sha256:3cae5d5c…b157 by digest
The same plan as GitHub shows it: the step summary the CLI writes on every run.

Already running in production, on our own CI

hushrun generalizes ci-promote, a bash tool that does the same for one GitHub repository. ci-promote runs in production on Kobranzapp/back, the backend of our own company, Kobranzapp.

Since June, every commit to main on Kobranzapp/back had files that staging had already tested and built. Its production runs skip the tests and the build, and copy staging's exact image.

That's one team, and it's ours. Pilots are how we find out whether yours looks the same.

version: 1
repository: github.com/acme/api

checks:
  lint:        { kind: source, run: pnpm lint }
  unit:        { kind: source, run: pnpm test, timeout: 20m }
  integration: { kind: source, run: pnpm test:integration, timeout: 30m }

artifacts:
  image:
    type: oci
    locations:
      staging: us-docker.pkg.dev/acme-staging/api/server
      production: us-docker.pkg.dev/acme-prod/api/server

stages:
  staging:
    branch: develop
    require: [lint, unit, integration]
  production:
    branch: main
    after: staging
    require: [lint, unit, integration]
hushrun.yaml. The whole hushrun.yaml for a two-stage setup. The CLI validates it.
- id: plan
  run: hushrun plan --stage production --start

# later jobs carry the plan out instead of deciding again
deploy:
  if: contains(fromJSON('["promote","refresh","full"]'),
               needs.plan.outputs.mode)
.github/workflows/deploy-production.yml. The production workflow: one plan step, and jobs that carry the plan out.

Cheaper minutes. Many more runs.

The price of a CI minute went down this year. The number of minutes didn't.

−39%

GitHub cut hosted-runner prices by up to 39% on January 1, 2026.

Source: GitHub, 2026

+130%

Tian Pan describes a CI line item that rose 130% in six weeks once coding agents ran CI on every iteration.

Source: Tian Pan, Jun 2, 2026

Jun 1

Copilot code review has consumed GitHub Actions minutes on private repositories since June 1, 2026.

Source: GitHub changelog, Apr 27, 2026

Agents don't only write more code; they run more CI. hushrun makes each run count once.

Nothing is skipped without signed evidence

hushrun decides from evidence it can verify, and fails closed when it can't.

  • Signed events

    Every check result, artifact and deploy is a signed DSSE envelope. In GitHub Actions, CI signs as the repository's own workflow, with no key to store; a signed-in laptop signs with the key its sign-in registered.

  • Verified on every read

    Membership is the policy: an event counts when a signed-in member's machine, one of your org's agents, or the repository's own CI signed it. Remove someone, and what they sign from then on stops counting. In the dashboard, a stage can take evidence from CI only. An event the CLI can't verify counts as missing.

  • Fails closed

    Missing, expired or failed evidence means the checks run (refresh) or the stage builds (full). Approvals are never waived, and you can force a full run.

  • Append-only, in standard formats

    The log lets CI add events, never rewrite or delete them, and logs every write. Its checkpoints are signed notes, the format of Go's checksum database: Go's note package verifies them. Its proofs follow RFC 6962. The hosted service says who your members are; the deploy decision is always the CLI's, in your CI.

production · hushrun verify
$ hushrun verify --scope default --digest sha256:bad90344…28f8
ok        v1/events/default/bad90344f9e5f7d8a3f4a46a99b40eede644f97d1dc93de3ce59c7cbb9ee28f8/01M63WSKM1RC1PA3Y6HHBTFNFC.started.staging.json: started at staging signed by ci (custody ci) for sha256:bad90344…28f8, with identity https://github.com/acme/api/.github/workflows/deploy-staging.yml@refs/heads/develop, timestamped at 2026-10-29T13:15:08.802Z
ok        v1/events/default/bad90344f9e5f7d8a3f4a46a99b40eede644f97d1dc93de3ce59c7cbb9ee28f8/01M63WSKS5VZAK8574WJTKDWS8.check.staging.json: check at staging signed by ci (custody ci) for sha256:bad90344…28f8, with identity https://github.com/acme/api/.github/workflows/deploy-staging.yml@refs/heads/develop, timestamped at 2026-10-29T13:15:08.966Z
ok        v1/events/default/bad90344f9e5f7d8a3f4a46a99b40eede644f97d1dc93de3ce59c7cbb9ee28f8/01M63WSKX146X9HF9E43DHN0WK.check.staging.json: check at staging signed by ci (custody ci) for sha256:bad90344…28f8, with identity https://github.com/acme/api/.github/workflows/deploy-staging.yml@refs/heads/develop, timestamped at 2026-10-29T13:15:09.089Z
ok        v1/events/default/bad90344f9e5f7d8a3f4a46a99b40eede644f97d1dc93de3ce59c7cbb9ee28f8/01M63WSM0PNGDC8NSK7J079SWY.check.staging.json: check at staging signed by ci (custody ci) for sha256:bad90344…28f8, with identity https://github.com/acme/api/.github/workflows/deploy-staging.yml@refs/heads/develop, timestamped at 2026-10-29T13:15:09.206Z
ok        v1/events/default/bad90344f9e5f7d8a3f4a46a99b40eede644f97d1dc93de3ce59c7cbb9ee28f8/01M63WSM60NR3SEF83MRHGNN0H.artifact.staging.json: artifact at staging signed by ci (custody ci) for sha256:bad90344…28f8, with identity https://github.com/acme/api/.github/workflows/deploy-staging.yml@refs/heads/develop, timestamped at 2026-10-29T13:15:09.377Z
ok        v1/events/default/bad90344f9e5f7d8a3f4a46a99b40eede644f97d1dc93de3ce59c7cbb9ee28f8/01M63WSMB5412BRQPQC8HX8GR3.deployed.staging.json: deployed at staging signed by ci (custody ci) for sha256:bad90344…28f8, with identity https://github.com/acme/api/.github/workflows/deploy-staging.yml@refs/heads/develop, timestamped at 2026-10-29T13:15:09.542Z
ok        v1/events/default/bad90344f9e5f7d8a3f4a46a99b40eede644f97d1dc93de3ce59c7cbb9ee28f8/01M63WSMMMD5NS6JX3DZJMT0AJ.passed.staging.json: passed at staging signed by ci (custody ci) for sha256:bad90344…28f8, with identity https://github.com/acme/api/.github/workflows/deploy-staging.yml@refs/heads/develop, timestamped at 2026-10-29T13:15:09.845Z
hushrun verify on the demo's production run: who signed what, for which digest.

Fits the CI you already run

  • CI
  • GitHub Actions
  • A setup action
  • Ready-made workflows
  • Step summaries and annotations
  • GitLab CI, next
  • Evidence
  • Hosted, over HTTPS
  • GitHub OIDC for CI
  • Tokens for any other CI
  • A transparency log of every write
  • Artifacts
  • OCI images, by digest
  • Multi-platform indexes
  • Plain files
  • Code
  • Any language
  • Any VCS
  • Any directory
  • One static binary

One requirement: a build that can run in every environment, with environment values supplied at deploy time instead of baked in.

A free CLI. A paid plan for teams.

CLI

Free

Everything that decides a deploy, in your CI.

  • Source digests for any language and any VCS
  • Signed events, verified on every read
  • The planner and its six modes
  • OCI images promoted by digest
  • Decisions made in your CI, never by our servers

Team plan

Free to start

What a team shares around the CLI. It never makes a deploy decision.

  • A hosted log, with tokens and GitHub OIDC for CI
  • A dashboard of every stage, digest and deploy
  • An audit trail of who signed what, verified by the same code as the CLI

Prices are on the pricing page: free for 2,000 recorded checks a month. Pilot teams get a founding price, and the CLI stays free.

Questions teams ask first

  • hushrun skips a check only when it has valid evidence for exactly the same files: a pass, signed by a member's machine or your repository's CI (or only CI, for a stage set that way in the dashboard), younger than the check's max_age. A repository can also have CI reuse only CI's results. Deployment checks, such as smoke tests against production, still run after the deploy. Approvals are never waived, and you can force a full run.

Try it on one repository

Sign up with GitHub or Google, then run one command at your repository's root.

Or set it up with us

We also work with a few pilot teams, on one repository each.

Setup together, in one session. Free during a four-week pilot. A founding price afterwards.

We'll use your email only to write to you about hushrun.