Phone:

Hidden from the page source until you click: friction against scrapers, not a guarantee.

Email:

[email protected]

Role:

Sole designer & engineer

Stack:

Go, PostgreSQL, XChaCha20-Poly1305, Argon2id, WebAuthn

Status:

Live at contingency.cc, free to start, open registration

Contingency

A dead man's switch you can trust with something that matters. Set a check-in schedule. Nominate the people who should hear from you. Write the messages, attach the files. Then check in when asked, and if one day you don't, after a grace period you chose, Contingency does exactly what you told it to and nothing more.

  • Go
  • PostgreSQL
  • Cryptography
  • Security engineering
  • SaaS
Contingency
The itch

Most dead man's switch services are either a hobby script with a cron job behind it or a page full of skulls and countdown timers. Neither is what you want when the thing being released is the location of your will, the password to a shared account, or a letter to someone you love. I wanted something calm, precise and honest about its limits, built the way a system with real consequences has to be built: so it never fires by accident and never fails to fire when it should.

That second half is the hard part. "Release once, and only once, even if the server crashes halfway through" is a distributed systems problem wearing a very simple user interface.

What I built

A modular monolith: one Go binary, one PostgreSQL database, no queue and no cache tier, about 13,000 lines of Go across 30 internal packages with 38 test files. Every contingency moves through an explicit state machine, from draft through armed, reminder, overdue, grace period and release, and every transition is written to the audit log in the same database transaction that performs it. The scheduler takes a Postgres advisory lock per contingency, so two workers can never act on the same one at the same time, and a crashed worker resumes from what the database says happened rather than what it remembers doing.

The audit log is SHA-256 hash-chained and tamper-evident. The binary doubles as its own admin CLI, which can verify the chain end to end and write a checkpoint outside the database, so a compromised database cannot quietly rewrite history. Message bodies, attachments, SSH private keys and webhook secrets are envelope-encrypted with XChaCha20-Poly1305 under a master key that never touches Postgres. Passwords, cancellation secrets, recovery codes and API tokens are Argon2id hashes.

When a contingency releases it emails each contact only what you explicitly gave them, and can run up to two remote actions exactly once: an HTTP request you define, or a single forced command over SSH to a server you control using an Ed25519 key generated for that contingency alone. There is a versioned JSON API with scoped bearer tokens, so a check-in can live in a crontab with a token that can extend a deadline and do nothing else, and outbound webhooks are HMAC-signed and durably queued with retry and backoff.

Engineering decisions
  • State machine, not booleans: "did the release already fire" is a question you can only answer safely if there is one state column with a transition table, and each transition is idempotent and audited. Scattered flags cannot give you that.
  • Injectable clock: nothing outside one package calls time.Now(). Tests jump the clock forward past a deadline or across a DST boundary without sleeping, which is the only reason the scheduler is testable at all.
  • No admin role in the web app: every account is an ordinary customer account. Operator tasks happen on the host with the CLI, as root, and never through a browser. That boundary removes an entire class of privilege-escalation bugs.
  • High-risk actions demand fresh proof: deleting a contingency, minting a token or changing security settings requires re-authentication within fifteen minutes and is refused during the 24-hour window after account recovery, so a stolen session cannot quietly dismantle an armed plan.
  • A written threat model: 25 numbered scenarios, each with prerequisites, impact, mitigation and the residual risk stated plainly. The landing page repeats the limits in public, because trust comes from precision, not marketing waffle.
  • Two review passes, both documented: the security review lists every real defect found during the build and after it, including an open redirect on the re-authentication page, a 24-hour delay guard that was built and tested but never actually called, and a hash computed at nanosecond precision against a column that stored microseconds. Finding those is the job. Writing them down is the proof.
What it demonstrates

Carrying a product from threat model to production on my own: schema, cryptography, state machine, scheduler, web UI, API, passkeys and MFA, backup and restore drills, hardened deployment, and the discipline to review my own work as an attacker would and record what I found. It is the same care I bring to a client's system, applied to something I had to be willing to trust myself.

Using it

Registration is open and free to start. Create an account, add a passkey or an authenticator app, then create a contingency: pick a schedule that suits how you live, add your contacts, write your messages, attach any files, and arm it. From then on one button confirms you are fine and resets the clock. Miss a check-in and you get a reminder, then your grace period, and only after that does the plan run. A cancellation secret lets you or someone you trust stop a release without signing in.

What it cannot protect against is stated on the front page: compromise of your email account, someone obtaining your cancellation secret, simultaneous compromise of Contingency and your encryption keys, badly configured recipient access, or a remote server that is unreachable when it matters. I would rather say that now than have you assume otherwise.

The source is private for the moment, but the API contract, threat model and security review are the documents I would want to read before trusting a service like this, and I am happy to walk through them.