ShipSure
Sign in

Docs

Everything below works in the shipped CLI today. Nothing here is planned, aspirational, or coming soon.

Setup, start to finish

Four commands. Two minutes.

$ npm i -g shipsure
$ shipsure login
$ shipsure init
$ shipsure link

login prints a short code and opens your browser. Approve it and the machine is connected — no password is ever typed into a terminal.

init detects your language, package manager and test/build commands, then writes .shipsure/config.json. Commit that file; it is project configuration, and it is meant to be reviewed in a pull request like any CI config.

link attaches the folder to a project you created in the dashboard. The CLI cannot create projects on purpose — an agent token is deliberately not allowed to, so a token lifted off a laptop cannot spin up new ones.

The daily loop

$ shipsure baseline
# … let your agent work …
$ shipsure verify

The order matters. baseline records the state of your tests before the agent touches anything. Run it afterwards and a test the agent just broke looks like it was already failing, so the regression goes undetected. If no usable baseline exists, ShipSure says so in the verdict instead of quietly claiming a clean comparison.

verify runs your project’s own commands, compares against the baseline, checks scope and policy, prints a verdict, and uploads the run so it appears in the dashboard.

Commands

CommandWhat it does
shipsure loginConnect this machine via a device code.
shipsure logoutRevoke this machine server-side, not just locally.
shipsure whoamiAsk the server who this machine is signed in as.
shipsure initDetect the stack and write .shipsure/config.json.
shipsure linkAttach this folder to a cloud project.
shipsure project listList the projects in your organization.
shipsure baselineRecord the "before" state.
shipsure verifyRun verification and print a verdict.
shipsure watchVerify automatically whenever the tree goes quiet.
shipsure cancelStop a run that is still going.
shipsure rollbackRestore the tree to the baseline, stashing first.
shipsure runnerRun this machine as a private runner.
shipsure doctorDiagnose the environment; every failure carries a fix.

Flags

FlagEffect
--jsonMachine-readable output for CI.
--localVerify with no network at all, and do not upload the run.
--no-baselineSkip the comparison. The verdict states regressions were unchecked.
--forceOverwrite config on init, or baseline a dirty tree.
--no-browserOn login, print the URL instead of opening a browser.
--project <id>On link, name the project instead of choosing interactively.
--clear, --showOn baseline, clear or print the stored one.
--quiet-ms <n>On watch, how still the tree must be before verifying.
--yes, --dry-runOn rollback, skip the prompt, or show what would change.
--onceOn runner, take one job and exit.

Exit codes

The CI contract. Separate codes are what let a pipeline treat “needs a human” differently from “the code is broken” — collapsing them into 1 would make ShipSure useless in CI.

CodeMeaning
0Verified
1Failed — a required check failed
2Blocked — a policy or approval gate
3Inconclusive — could not verify reliably
4Cancelled
64Usage error — bad arguments, or not a ShipSure project
77Authentication error
$ - run: npm i -g shipsure
$ - run: shipsure verify --json > shipsure.json

Configuration

.shipsure/config.json holds the project id, the detected adapters, your policy and the default task contract. It is committed. Credentials never go near it — tokens live in ~/.shipsure/credentials.json at mode 0600, per machine.

What runs on your machine

  • Commands run in a child process with an explicit environment allowlist, so stray credentials in your shell are never handed to a test suite.
  • Hard timeouts and output truncation. A runaway process is killed and reported as an error, not a failure — ShipSure does not claim a verdict it cannot support.
  • Secrets are redacted before anything is hashed or uploaded.
  • Source code is never uploaded. File paths and diff statistics are sent as metadata so the dashboard can show what changed; file contents are not.
  • Access tokens are short-lived and rotate on every refresh.

Installing

npm is the primary path and works everywhere Node 20 or newer does.

npm i -g shipsure

On macOS and Linux there is also a Homebrew tap. It depends on node rather than bundling a runtime — anyone verifying a JavaScript project already has one, and embedding it would take a 140 kB download past 100 MB.

brew tap shipsure/shipsure
brew install shipsure

Watching a run happen

A verification opens its run before the checks start, so the dashboard follows along live rather than showing nothing until the end. The run page streams over a WebSocket, falls back to polling where one cannot be opened, and shows each check as it lands.

A run that is still going can be stopped — from the run page, or with shipsure cancel, which with no argument stops whatever is currently in flight. A cancelled run records the verdict cancelled and exit code 4, so a pipeline can tell it apart from a failure. Runs whose machine never reports back are closed out automatically after six hours rather than sitting “running” for ever.

Flaky checks

ShipSure watches each check across a project’s recent history and flags one whose result keeps changing direction. A check that has simply failed twenty times running is broken, not flaky, and is deliberately not flagged — letting a real breakage hide behind the word is the failure this exists to prevent.

Quarantining a flagged check, under the project’s Flaky tab, records it as flaky rather than failed so it stops blocking every run while staying visible. If the only failing check in a run is a quarantined one, the run passes and says so in its reasons. Any other failure still fails the run.

Watch and rollback

shipsure watch verifies whenever the tree has been still for a few seconds. An agent edits, goes quiet, and the verdict is on screen before you think to ask. It never runs two verifications at once, and edits arriving mid-run queue exactly one more — not one per file.

shipsure watch
shipsure watch --quiet-ms 5000

shipsure rollback puts the tree back to the baseline after a bad run. It stashes your current state first with --include-untracked and prints how to get it back, so nothing is destroyed. It refuses if a commit has landed since the baseline — discarding a commit is a different and worse operation, and git revert is the right tool for that.

shipsure rollback --dry-run
shipsure rollback

Private runners

For code that cannot leave hardware you control. Enrol a machine under Settings → Runners, then run it with the token you are given:

SHIPSURE_RUNNER_TOKEN=ssr_... shipsure runner

The runner polls outward over HTTPS. Nothing connects to it, so there is no firewall exception and no route into your network to arrange. Each job gets a fresh clone that is deleted when the job ends, two runners can never claim the same job, and a runner killed mid-job releases its lease after fifteen minutes so the work requeues rather than vanishing.

It clones two commits deep and captures the baseline from the parent, so a run answers “did this commit break something that worked before it?” rather than just “do the checks pass right now”. On the first commit in a repository there is nothing to compare against and the verdict is inconclusive, which is the honest answer. The result uploads through the same endpoint every other client uses, so the server’s verdict cross-check applies to runner output exactly as it does to a laptop’s.

GitHub and Slack

Connect them under Settings → Integrations. GitHub posts a commit status — a green tick driven by the check results rather than by what the agent claimed — and optionally a pull-request comment. It needs a fine-grained token with Commit statuses: read and write, and nothing else.

Slack takes an incoming webhook URL and posts to that one channel. It defaults to failed and blocked runs only; posting on every green build is how a channel learns to ignore the bot.

Both credentials are checked against the provider before they are stored, and encrypted at rest. Neither is ever returned by the API after you save it.

API keys and webhooks

Create a key under Settings → API keys. Read keys can list projects and runs; write keys can also create them. Neither can touch members, other keys, or the audit trail.

curl https://api.shipsure.space/v1/runs -H "Authorization: Bearer ssk_..."

Webhooks live under Settings → Webhooks. Every delivery carries X-ShipSure-Signature as v1=<hex>, an HMAC-SHA256 over timestamp.rawBody. Compare it in constant time and reject anything older than five minutes — the timestamp is inside the signature precisely so a captured request cannot be replayed later. Failed deliveries retry six times over about two hours, and twenty consecutive failures disables the endpoint rather than hammering a server that is clearly gone.

Your team

Invite people from Settings → Team. They receive a link that works once and expires in seven days, and joining puts them on a seat your plan already covers — an invited teammate does not need their own subscription or card.

A pending invitation holds a seat until it is accepted, revoked or expires, so the count on that page is what you are actually using. Revoking frees the seat immediately and the link stops working.

RoleCan do
OwnerEverything, including billing and deleting the organization.
AdminProjects, integrations, policies and members. Not billing.
DeveloperRun verifications and read everything in the organization.
ViewerRead-only access to runs, evidence and reports.

An organization always has at least one owner: the last one cannot be demoted or removed. Ownership is transferred by promoting somebody else first — it is never handed out by invitation.

Signing in with GitHub

Where the deployment has it configured, the sign-in page offers GitHub. Two rules apply, and both are deliberate:

  • It signs you in, it does not sign you up. There is no free tier, so an account cannot exist without a plan — an unrecognised identity goes to pricing rather than becoming a dead account.
  • It never auto-links on a matching email. If the address already has a password account, you are asked to sign in and link it from Settings. Trusting a provider’s claim about an address is the classic account-takeover route.

Passwords and account recovery

Forgot yours? Use the reset link on the sign-in page. The email arrives in a moment, works once, and expires after an hour. Requesting a new link retires the previous one, so if somebody else triggered a reset on your account, asking for your own immediately kills theirs.

Completing a reset signs the account out on every device, including any CLI session — run shipsure login again on each machine afterwards. To change a password you still know, use Settings instead; that keeps the device you are on signed in and drops the rest.