{"id":50213499,"url":"https://github.com/mrz1836/hush","last_synced_at":"2026-05-26T07:01:47.057Z","repository":{"id":359141649,"uuid":"1221724331","full_name":"mrz1836/hush","owner":"mrz1836","description":"🤫 Discord-gated secrets broker for AI agents — encrypted vault, JWT sessions, Tailscale-only","archived":false,"fork":false,"pushed_at":"2026-05-20T19:44:39.000Z","size":4518,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-05-20T19:47:35.125Z","etag":null,"topics":["bip32","bitcoin","crypto","discord","go","jwt","secrets","security","tailscale"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mrz1836.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":".github/SECURITY.md","support":".github/SUPPORT.md","governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":".github/AGENTS.md","dco":null,"cla":null},"funding":{"github":"mrz1836","custom":"https://mrz1818.com/?tab=tips\u0026utm_source=github\u0026utm_medium=sponsor-link\u0026utm_campaign=hush\u0026utm_term=hush\u0026utm_content=hush","buy_me_a_coffee":"mrz1818"}},"created_at":"2026-04-26T15:47:48.000Z","updated_at":"2026-05-20T19:44:43.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/mrz1836/hush","commit_stats":null,"previous_names":["mrz1836/hush"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/mrz1836/hush","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrz1836%2Fhush","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrz1836%2Fhush/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrz1836%2Fhush/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrz1836%2Fhush/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mrz1836","download_url":"https://codeload.github.com/mrz1836/hush/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrz1836%2Fhush/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33508317,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T03:12:49.672Z","status":"ssl_error","status_checked_at":"2026-05-26T03:12:47.976Z","response_time":63,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bip32","bitcoin","crypto","discord","go","jwt","secrets","security","tailscale"],"created_at":"2026-05-26T07:01:41.907Z","updated_at":"2026-05-26T07:01:47.047Z","avatar_url":"https://github.com/mrz1836.png","language":"Go","funding_links":["https://github.com/sponsors/mrz1836","https://mrz1818.com/?tab=tips\u0026utm_source=github\u0026utm_medium=sponsor-link\u0026utm_campaign=hush\u0026utm_term=hush\u0026utm_content=hush","https://buymeacoffee.com/mrz1818"],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# 🤫\u0026nbsp;\u0026nbsp;hush\n\n**Discord-gated secrets broker for AI agents**\n\nOne passphrase. No key files. No dotfiles on agent disks.\n\n\u003cbr/\u003e\n\n\u003ca href=\"https://github.com/mrz1836/hush/releases\"\u003e\u003cimg src=\"https://img.shields.io/github/release-pre/mrz1836/hush?include_prereleases\u0026style=flat-square\u0026logo=github\u0026color=black\" alt=\"Release\"\u003e\u003c/a\u003e\n\u003ca href=\"https://golang.org/\"\u003e\u003cimg src=\"https://img.shields.io/github/go-mod/go-version/mrz1836/hush?style=flat-square\u0026logo=go\u0026color=00ADD8\" alt=\"Go Version\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/mrz1836/hush/blob/master/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/github/license/mrz1836/hush?style=flat-square\u0026color=blue\u0026v=1\" alt=\"License\"\u003e\u003c/a\u003e\n\n\u003cbr/\u003e\n\n\u003ctable align=\"center\" border=\"0\"\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"right\"\u003e\n       \u003ccode\u003eCI / CD\u003c/code\u003e \u0026nbsp;\u0026nbsp;\n    \u003c/td\u003e\n    \u003ctd align=\"left\"\u003e\n       \u003ca href=\"https://github.com/mrz1836/hush/actions\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/mrz1836/hush/fortress.yml?branch=master\u0026label=build\u0026logo=github\u0026style=flat-square\" alt=\"Build\"\u003e\u003c/a\u003e\n       \u003ca href=\"https://github.com/mrz1836/hush/actions\"\u003e\u003cimg src=\"https://img.shields.io/github/last-commit/mrz1836/hush?style=flat-square\u0026logo=git\u0026logoColor=white\u0026label=last%20update\" alt=\"Last Commit\"\u003e\u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"right\"\u003e\n       \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u003ccode\u003eQuality\u003c/code\u003e \u0026nbsp;\u0026nbsp;\n    \u003c/td\u003e\n    \u003ctd align=\"left\"\u003e\n       \u003ca href=\"https://goreportcard.com/report/github.com/mrz1836/hush\"\u003e\u003cimg src=\"https://goreportcard.com/badge/github.com/mrz1836/hush?style=flat-square\u0026v=2\" alt=\"Go Report\"\u003e\u003c/a\u003e\n       \u003ca href=\"https://codecov.io/gh/mrz1836/hush\"\u003e\u003cimg src=\"https://codecov.io/gh/mrz1836/hush/branch/master/graph/badge.svg?style=flat-square\" alt=\"Coverage\"\u003e\u003c/a\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\n  \u003ctr\u003e\n    \u003ctd align=\"right\"\u003e\n       \u003ccode\u003eSecurity\u003c/code\u003e \u0026nbsp;\u0026nbsp;\n    \u003c/td\u003e\n    \u003ctd align=\"left\"\u003e\n       \u003ca href=\"https://scorecard.dev/viewer/?uri=github.com/mrz1836/hush\"\u003e\u003cimg src=\"https://api.scorecard.dev/projects/github.com/mrz1836/hush/badge?style=flat-square\" alt=\"Scorecard\"\u003e\u003c/a\u003e\n       \u003ca href=\".github/SECURITY.md\"\u003e\u003cimg src=\"https://img.shields.io/badge/policy-active-success?style=flat-square\u0026logo=security\u0026logoColor=white\" alt=\"Security\"\u003e\u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"right\"\u003e\n       \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u003ccode\u003eCommunity\u003c/code\u003e \u0026nbsp;\u0026nbsp;\n    \u003c/td\u003e\n    \u003ctd align=\"left\"\u003e\n       \u003ca href=\"https://github.com/mrz1836/hush/graphs/contributors\"\u003e\u003cimg src=\"https://img.shields.io/github/contributors/mrz1836/hush?style=flat-square\u0026color=orange\" alt=\"Contributors\"\u003e\u003c/a\u003e\n       \u003ca href=\"https://mrz1818.com/\"\u003e\u003cimg src=\"https://img.shields.io/badge/donate-bitcoin-ff9900?style=flat-square\u0026logo=bitcoin\" alt=\"Bitcoin\"\u003e\u003c/a\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003c/div\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n### \u003ccode\u003eProject Navigation\u003c/code\u003e\n\n\u003c/div\u003e\n\n\u003ctable align=\"center\"\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\" width=\"33%\"\u003e\n       🚀\u0026nbsp;\u003ca href=\"#-installation\"\u003e\u003ccode\u003eInstallation\u003c/code\u003e\u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\" width=\"33%\"\u003e\n       ⚡\u0026nbsp;\u003ca href=\"#-quick-start\"\u003e\u003ccode\u003eQuick\u0026nbsp;Start\u003c/code\u003e\u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\" width=\"33%\"\u003e\n       📚\u0026nbsp;\u003ca href=\"#-documentation\"\u003e\u003ccode\u003eDocumentation\u003c/code\u003e\u003c/a\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\n       🔐\u0026nbsp;\u003ca href=\"#-security\"\u003e\u003ccode\u003eSecurity\u003c/code\u003e\u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\n      🛠️\u0026nbsp;\u003ca href=\"#-code-standards\"\u003e\u003ccode\u003eCode\u0026nbsp;Standards\u003c/code\u003e\u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\n      🧪\u0026nbsp;\u003ca href=\"#-examples--tests\"\u003e\u003ccode\u003eExamples\u0026nbsp;\u0026\u0026nbsp;Tests\u003c/code\u003e\u003c/a\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\n      🤖\u0026nbsp;\u003ca href=\"#-ai-usage--assistant-guidelines\"\u003e\u003ccode\u003eAI\u0026nbsp;Usage\u003c/code\u003e\u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\n       ⚖️\u0026nbsp;\u003ca href=\"#-license\"\u003e\u003ccode\u003eLicense\u003c/code\u003e\u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\n       🤝\u0026nbsp;\u003ca href=\"#-contributing\"\u003e\u003ccode\u003eContributing\u003c/code\u003e\u003c/a\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\" colspan=\"3\"\u003e\n       👥\u0026nbsp;\u003ca href=\"#-maintainers\"\u003e\u003ccode\u003eMaintainers\u003c/code\u003e\u003c/a\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003cbr/\u003e\n\n**hush is a single Go binary that keeps every API key, OAuth token, and\nservice credential encrypted on a single trusted host. Agents request\nshort-lived, scoped sessions over Tailscale; the request is approved on\nyour phone via Discord; approved secrets are delivered ECIES-encrypted\nend-to-end and injected into the agent process's environment — never\nwritten to disk on the agent machine.**\n\nIf your dev workflow runs untrusted code (npm/pip packages, LLM-generated\nscripts, AI-agent tools that execute shell commands) and your secrets\ncurrently live in shell rc files or cloud-provider credential files, hush\nis for you. Vault, 1Password CLI, and dotfile-based env vars all leave\nfiles on disk that commodity malware grep for first. hush makes those\nfiles not exist.\n\n\u003cbr/\u003e\n\n```\n                            TAILSCALE MESH\n  ┌─────────────────────────────────────────────────────────────────────┐\n  │                                                                     │\n  │  ┌──────────────────────────┐     ┌───────────────────────────────┐ │\n  │  │  AGENT MACHINE           │     │  VAULT HOST                   │ │\n  │  │  (untrusted, clean disk) │     │  (mlocked memory; offline)    │ │\n  │  │                          │     │                               │ │\n  │  │  interactive client /    │     │  vault server                 │ │\n  │  │  supervisor              │     │                               │ │\n  │  │       │                  │     │       ▲                       │ │\n  │  │       │ ECDSA-signed     │─────┼──────►│ verify signature      │ │\n  │  │       │ claim            │     │       │ check Tailscale IP    │ │\n  │  │       │                  │     │       ▼                       │ │\n  │  │       │                  │     │  Discord DM ─────► phone      │ │\n  │  │       │                  │     │       │  [Approve]            │ │\n  │  │       │ ES256K JWT       │◄────┼───────┤ issue scoped JWT      │ │\n  │  │       │                  │     │       ▼                       │ │\n  │  │       │ secret fetch     │─────┼──────►│ ECIES-encrypt to      │ │\n  │  │       │ (ECIES bytes)    │     │       │ ephemeral pubkey      │ │\n  │  │       ▼                  │     │       │                       │ │\n  │  │  decrypt → env var       │     │       └─────────────────────  │ │\n  │  │  inject into child       │     │  [no key files anywhere]      │ │\n  │  └──────────────────────────┘     └───────────────────────────────┘ │\n  │                                                                     │\n  └─────────────────────────────────────────────────────────────────────┘\n```\n\n\u003cbr/\u003e\n\n## 🚀 Installation\n\n**hush** requires a [supported release of Go](https://golang.org/doc/devel/release.html#policy)\n(Go 1.26+) and is built `CGO_ENABLED=0` — a single static binary.\n\n\u003e **Status:** this is still `ALPHA` and PR's are welcome to improve the project.\n\nPrerequisites: a vault host and an agent host on the same Tailscale\ntailnet, plus a Discord bot you control\n(\u003chttps://discord.com/developers/applications\u003e) for the approval channel.\n\n### Build from source\n\n```bash\ngit clone https://github.com/mrz1836/hush.git \u0026\u0026 cd hush\nmagex build \u0026\u0026 sudo install -m 0755 cmd/hush/hush /usr/local/bin/hush\n```\n\n\u003cbr/\u003e\n\n### Upgrade\n\nOnce `hush` is on your `PATH`, the binary can upgrade itself in place\nfrom the [GitHub releases](https://github.com/mrz1836/hush/releases):\n\n```bash\nhush upgrade          # download the latest release tarball, verify SHA-256, install in place\nhush upgrade --check  # report the latest available version without installing\nhush upgrade --force  # reinstall the latest release even when already current\n```\n\nChannel selection is controlled by the `UPDATE_CHANNEL` environment\nvariable (case-insensitive; default `stable`):\n\n```bash\nUPDATE_CHANNEL=stable hush upgrade   # latest non-prerelease (default)\nUPDATE_CHANNEL=beta   hush upgrade   # latest prerelease, falls back to stable when none\nUPDATE_CHANNEL=edge   hush upgrade   # most recent release of any kind (excludes drafts)\n\n# Or override the env per-invocation with --channel:\nhush upgrade --channel beta\n```\n\nThe install target is the resolved path of the running binary\n(`os.Executable()` with symlinks evaluated — typically `$(which hush)`).\n`hush upgrade` requires write access to that directory; when the\ndirectory is not writable the command exits with a clear error naming\nthe directory rather than silently installing elsewhere. Re-run the\ncommand under `sudo` (or copy the new binary into place manually) when\nthat happens.\n\nAfter a successful upgrade `hush upgrade` prints a `Restart any\nrunning 'hush serve' to pick up the new version` reminder — the\nupgrade does not touch any supervised process.\n\n\u003cbr/\u003e\n\n## 🗺️ Command palette\n\nEvery hush subcommand at a glance — every entry below is real today.\n\n| Command | Purpose |\n|---------|---------|\n| `hush smoke` | Guided end-to-end test with a fake secret — start here |\n| `hush init server` / `hush init client` | Bootstrap a vault host / enroll an agent host |\n| `hush serve` | Run the vault server (Tailscale-only) |\n| `hush secret add` / `list` / `remove` / `rotate` | Manage vault entries (rotate re-encrypts and hot-reloads) |\n| `hush vault rekey` | Change the vault passphrase — rotates the root of trust (TTY-only) |\n| `hush request --exec …` | One-shot interactive fetch + child exec |\n| `hush supervise \u003cconfig.toml\u003e` | Long-running daemon with grace cache + validators |\n| `hush health` / `server-url` / `version` | Daily-driver helpers |\n| `hush revoke --jti …` | Kill an active session token |\n| `hush upgrade` | Self-upgrade from a GitHub release (stable / beta / edge) |\n\nGlobal flags — `--config \u003cpath\u003e`, `--verbose`, `--quiet`, `--no-color` — work on every command.\n\n\u003cbr/\u003e\n\n## ⚡ Quick Start\n\nFour flows, in the order you'll use them.\n\n\u003cbr/\u003e\n\n### Try it in 60 seconds\n\n**One command, fake secret, real Discord approval:**\n\n```bash\nhush smoke --state-dir ~/.hush-smoke --reset\n```\n\n`hush smoke` walks the setup prompts, creates an isolated test vault, adds\n`HUSH_SMOKE_TEST=hello-from-hush`, starts a temporary Tailscale-only server,\nenrolls a client, asks you to approve in Discord, verifies the fake secret,\nand shuts the temporary server down.\n\n\u003e 🧹 **Cleanup:** `hush smoke clean` archives smoke artifacts by default.\n\u003e Add `--destroy --confirm 'destroy smoke'` to permanently delete them.\n\n\u003cbr/\u003e\n\n### Bootstrap the vault host\n\nThree commands, run on the host you trust with your secrets.\n\n```bash\nhush init server                       # interactive preflight + prompts\nhush secret add ANTHROPIC_API_KEY      # then OPENAI_API_KEY, GEMINI_API_KEY, …\nhush serve                             # binds Tailscale, brokers approvals\n```\n\n\u003e 🛰️ **Listen on the vault host's Tailscale IPv4 — not your laptop IP.**\n\u003e When `hush init server` asks for a listen address, run\n\u003e `printf '%s:7743\\n' \"$(tailscale ip -4)\"` on the **server** host and paste\n\u003e the result. Set `discord_approval_channel_id` to route approvals to a\n\u003e channel; leave it empty to DM the owner directly.\n\n\u003e 🔐 **macOS Keychain locked?** Choose the env-token fallback during init\n\u003e and run `hush serve` with `HUSH_DISCORD_BOT_TOKEN` exported in that\n\u003e terminal. Full recovery flow in [`docs/SECURITY.md`](docs/SECURITY.md) §2.4.\n\n\u003cbr/\u003e\n\n### Enroll the agent host\n\nEnroll a per-machine client key, then fetch secrets straight into a child\nprocess. Nothing lands on disk.\n\n```bash\nhush init client --machine-index 1\nHUSH_SERVER=\"$(hush --config ~/.hush/config.toml server-url)\"\n\nhush request \\\n  --server \"$HUSH_SERVER\" \\\n  --machine-index 1 \\\n  --scope ANTHROPIC_API_KEY --scope OPENAI_API_KEY --scope GEMINI_API_KEY \\\n  --max-uses 3 --ttl 10m \\\n  --reason \"claude-code session\" \\\n  --exec zsh\n```\n\nApprove on Discord; the shell you launched inherits all three keys in its\nenvironment — and **only there**. They are zeroed the moment the shell exits.\n\n\u003e ⚙️ **`--scope` is repeatable and comma-separated.** Either\n\u003e `--scope A --scope B` or `--scope A,B` works. `--max-uses` must be ≥ the\n\u003e number of scopes (one fetch per scope per session). `--exec` names a\n\u003e program, not a shell string — pass child arguments after `--`.\n\n\u003cbr/\u003e\n\n### Run a long-running daemon\n\nFor agents that run overnight, swap `hush request` for `hush supervise`.\nOne approval per refresh window keeps a 24/7 child alive across crashes;\nthe grace cache silently restarts a child that dies inside\n`cache_grace_ttl`, so a 3am OOM doesn't page you.\n\nSave the snippet below to `~/.hush/supervisors/hermes.toml` — the full\nschema lives in\n[`deploy/examples/supervisors/example-daemon.toml`](deploy/examples/supervisors/example-daemon.toml):\n\n```toml\nname                      = \"hermes\"\nreason                    = \"Hermes AI gateway\"\nserver_url                = \"http://100.64.0.1:7743/h/example\"\nclient_machine_index      = 1\nsession_type              = \"supervisor\"\nrequested_ttl             = \"20h\"\nrefresh_window            = \"09:00-10:00\"\ncache_secrets_for_restart = true\ncache_grace_ttl           = \"60m\"\nstatus_socket             = \"/tmp/hush/supervise-hermes.sock\"\npid_file                  = \"/tmp/hush/supervise-hermes.pid\"\n\nscope = [\"ANTHROPIC_API_KEY\", \"OPENAI_API_KEY\", \"GEMINI_API_KEY\"]\n\n[child]\ncommand = [\"/usr/local/bin/hermes\", \"gateway\", \"start\"]\n\n[validators]\nANTHROPIC_API_KEY = \"anthropic\"\nOPENAI_API_KEY    = \"openai\"\nGEMINI_API_KEY    = \"google-ai\"\n```\n\nThen:\n\n```bash\nhush supervise ~/.hush/supervisors/hermes.toml --dry-run   # validate the config\nhush supervise ~/.hush/supervisors/hermes.toml             # run for real\n```\n\nBuilt-in validators (`anthropic`, `anthropic-oauth`, `openai`, `google-ai`,\n`github`) hit each provider before the child starts — stale credentials\nfail loudly instead of breaking your daemon at 3am. Full guide in\n[`docs/DAEMONS.md`](docs/DAEMONS.md).\n\n\u003cbr/\u003e\n\n\u003e 📖 **More?** [`docs/OPERATIONS.md`](docs/OPERATIONS.md) covers Keychain\n\u003e ACL recovery, clock-skew overrides, and `--non-interactive` mode for\n\u003e Terraform/Ansible provisioning. [`docs/CONFIG-SCHEMA.md`](docs/CONFIG-SCHEMA.md)\n\u003e has the full server + supervisor TOML schemas, and\n\u003e [`deploy/examples/supervisors/`](deploy/examples/supervisors/) holds\n\u003e production templates ready to copy.\n\n\u003cbr/\u003e\n\n## At a glance\n\n**What hush does:**\n\n- Keeps every secret encrypted in a single AES-256-GCM + Argon2id (256MB) vault file on one trusted host.\n- Requires phone approval (Discord DM with interactive buttons) for every fresh session.\n- Delivers secrets ECIES-encrypted end-to-end into agent process memory only — no disk writes on the agent.\n\n**What hush explicitly does NOT do (v0.1.0):**\n\n- No multi-owner approvals (a single configured operator approves; multi-owner is post-v0.1.0 future scope).\n- No cloud KMS / SaaS dependency. The vault is self-hosted and offline-capable.\n- No public network exposure. The vault server is bound to a Tailscale interface and refuses to start otherwise.\n\n**Daily-driver helpers:**\n\n- `hush health --server \"$(hush server-url)\"` — one-shot reachability + clock-skew check.\n- `hush secret list` — enumerate vault entries (TTY: `NAME — description`; pipe-friendly).\n- `hush secret rotate` — re-encrypt the vault and hot-reload `hush serve` (SIGHUP, no downtime).\n- `hush vault rekey` — change the vault passphrase itself; snapshots the old vault and prints a restart-required reminder. See [`docs/VAULT-REKEY.md`](docs/VAULT-REKEY.md).\n- `hush server-url` — print the canonical server URL from your TOML config, perfect for `$(…)` substitution.\n- `hush revoke --jti \u003cuuid\u003e` — kill an active JWT before its TTL expires.\n\n\u003cbr/\u003e\n\n## 🔀 Operating modes\n\nTwo ways to consume secrets; pick by **how often you can answer your phone**.\n\n| Mode | Best for | Approval cadence |\n|------|----------|------------------|\n| `hush request --exec` | Interactive shells, one-shot scripts, CI jobs | Once per invocation |\n| `hush supervise` | 24/7 daemons, AI gateways, long-running agents | Once per refresh window (e.g. 09:00–10:00 daily) |\n\nPick `request` for ad-hoc work; pick `supervise` when a phone buzz per\nrestart would page you at 3am.\n\n\u003cbr/\u003e\n\n### Why hush exists\n\nWhen untrusted code lands on a developer machine — via npm/pip\nsupply-chain attacks, LLM-generated scripts, or trojans masquerading as\ntools — the very first thing it does is enumerate known credential\npatterns in known files: shell rc files, cloud-provider credential\nfiles, `.env` files, signing keys, and PEM files.\n\n**hush exists to make this enumeration return nothing.** Secrets stay\nencrypted on a single trusted host. Agents fetch them only after a human\napproves the request from a phone. Approved secrets are delivered into\nprocess memory and zeroed when the process exits. Nothing on disk.\n\nFor the full threat model, see [`docs/SECURITY.md`](docs/SECURITY.md).\n\n\u003cbr/\u003e\n\n### Architecture summary\n\nhush is a single Go binary playing three roles:\n\n- **Vault server** — holds the encrypted vault file in mlocked memory;\n  issues ES256K-signed JWTs after Discord approval; ECIES-encrypts\n  secret responses to the client's per-session ephemeral public key;\n  exposes a tiny HTTP API over Tailscale only.\n- **Interactive client** — ECDSA-signs a claim with a per-machine\n  BIP32-derived key; receives a JWT after approval; fetches and\n  decrypts secrets; injects them into a child process's environment.\n- **Supervisor** — long-lived per-daemon process that holds the JWT and\n  ephemeral ECIES key in mlocked memory across child crashes/restarts\n  within the session TTL; runs validators before child start; exposes a\n  Unix status socket for agent-visible freshness queries.\n\n**Seven security layers** stack independently — compromise of any single\nlayer does not enable secret extraction:\n\n1. **BIP32 HD key hierarchy** — all keys derived at runtime from a\n   single passphrase. **Zero key files on disk.**\n2. **ES256K asymmetric JWT signing** — only the server can sign;\n   leaking the public key does not enable forgery.\n3. **ECIES end-to-end secret transport** — secrets are encrypted to a\n   per-session ephemeral pubkey; captured HTTP traffic shows binary\n   blobs.\n4. **ECDSA-signed client requests** — every claim and revocation is\n   signed with a registered per-machine client key.\n5. **mlocked secure memory** — `SecureBytes` containers; secrets never\n   stored as Go `string`; explicit zeroing on shutdown.\n6. **Signed hash-chained audit log** — every event ECDSA-signed; chain\n   breaks on modification.\n7. **Obscurity** — random API path prefix, custom vault file format,\n   non-obvious binary name. Additive only — never load-bearing.\n\nThe network perimeter is **Tailscale-only** (Constitution Principle VI).\nTailscale is the v0.1.0 mesh-VPN choice; the architecture does not depend\non it specifically — the requirement is \"no public reachability\" and\nTailscale satisfies it cleanly. The `Approver` interface is also\npluggable; **Discord is the v0.1.0 reference implementation** and the\nonly one that ships, but future Slack / Telegram / PagerDuty backends can\nbe wired without changing the rest of the system.\n\nFor the full architecture treatment, see [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md).\n\n\u003cbr/\u003e\n\n### Programmatic integration\n\nAI agents that consume hush — Claude Code, Codex, custom Go daemons —\ncan integrate in-process via the\n[`github.com/mrz1836/hush/pkg/client`](pkg/client/) SDK instead of\nexec'ing the CLI. The SDK gives agents typed access to two surfaces:\n\n**1. Supervisor freshness — `SupervisorStatus`** (read what the local\nsupervisor knows; no Discord roundtrip):\n\n```go\nimport \"github.com/mrz1836/hush/pkg/client\"\n\nsup := client.NewSupervisorStatus(os.Getenv(\"HUSH_STATUS_SOCKET\"))\nstatus, err := sup.Snapshot(ctx)\nif len(status.ScopeStale) \u003e 0 {\n    log.Fatal(\"refusing to run — stale scopes:\", status.ScopeStale)\n}\nfmt.Println(\"session expires at:\", status.SessionExpiresAt)\n```\n\n**2. Capability discovery — `Me()`** (ask the vault server *what\nscopes exist* and *what does my current session look like*, signed\nwith the agent's enrolled client key, without burning a Discord\napproval):\n\n```go\nresp, err := client.Me(ctx, client.MeRequest{\n    ServerURL:   \"http://100.64.0.1:7743/h/abcd1234\",\n    ClientKey:   myEnrolledPrivKey,           // *ecdsa.PrivateKey\n    MachineName: \"claude-code-laptop\",\n    BearerJWT:   os.Getenv(\"HUSH_BEARER\"),    // optional\n})\nif err != nil {\n    log.Fatal(err)\n}\nfmt.Println(\"scopes available:\", resp.ScopesAvailable)\nif resp.CurrentSession != nil {\n    fmt.Println(\"current jti:\", resp.CurrentSession.JTI,\n        \"expires:\", resp.CurrentSession.ExpiresAt)\n}\n```\n\nTogether these let an agent plan: \"do I already hold a fresh session\nfor this scope? when does it expire? what *could* I request if I need\nmore?\" — all without touching the operator's phone.\n\nSee [`pkg/client/README.md`](pkg/client/README.md) for the full v1\nsurface. The SDK ships typed errors (`ErrSocketUnavailable`,\n`ErrInvalidResponse`, `ErrRefreshDenied`, `ErrUnauthenticated`) so\ncallers can switch on them with `errors.Is`.\n\n**3. Lifecycle events — `Watch()`** (reactive notification so an\nagent can wind down BEFORE its credentials expire, instead of being\nkilled mid-task):\n\n```go\nevents, _ := sup.Watch(ctx, client.WatchOptions{\n    PollInterval:     30 * time.Second,\n    ExpiryThresholds: []time.Duration{15 * time.Minute, 5 * time.Minute, 1 * time.Minute},\n})\nfor ev := range events {\n    switch ev.Type {\n    case client.EventExpiresSoon:\n        if ev.Threshold \u003c= time.Minute {\n            checkpoint(); shutdownCleanly()\n        }\n    case client.EventStateChange:\n        log.Info(\"supervisor state →\", ev.Status.State)\n    case client.EventSessionRenewed:\n        log.Info(\"fresh JTI\", ev.Status.SessionJTI)\n    }\n}\n```\n\n`Watch()` emits `EventInitial`, `EventStateChange`,\n`EventScopeHealthChange`, `EventSessionRenewed`, `EventExpiresSoon`\n(once per configured threshold per session), and `EventError` for\ntransient poll failures. The channel closes on context cancel.\n\n**Worked example**: a runnable program demonstrating all three SDK\ncalls (Snapshot, Me, Watch) plus the agent-context flags on `/claim`\nlives at [`examples/agent/`](examples/agent/). See\n[`docs/AGENT-INTEGRATION.md`](docs/AGENT-INTEGRATION.md) for the\ncomplete agent integration guide.\n\n\u003cbr/\u003e\n\n### Tech stack\n\n- **[Go 1.26+](https://go.dev/)** — single static binary, `CGO_ENABLED=0`\n  exclusively (Constitution Principle IX).\n- **[decred/dcrd/dcrec/secp256k1/v4](https://github.com/decred/dcrd)** —\n  secp256k1 primitives used for ECDSA signing, ES256K JWTs, and ECIES\n  envelope encryption (Constitution Principle III).\n- **[decred/dcrd/hdkeychain/v3](https://github.com/decred/dcrd)** — BIP32\n  HD key derivation from the operator passphrase (Constitution Principle\n  III); paired with stdlib `golang.org/x/crypto/argon2` for the KDF.\n- **[Tailscale](https://tailscale.com/)** — the only network reachable to\n  the vault server. WireGuard underneath; identity-based ACLs above.\n- **[Discord](https://discord.com/)** + **[discordgo](https://github.com/bwmarrin/discordgo)**\n  — phone-based approval channel; the v0.1.0 reference Approver.\n- **[golang-jwt/jwt v5](https://github.com/golang-jwt/jwt)** — JWT framework;\n  hush registers a custom `ES256K` signing method.\n- **[go-toml v2](https://github.com/pelletier/go-toml)** — strict TOML\n  parsing for server and supervisor configs.\n- **[zalando/go-keyring](https://github.com/zalando/go-keyring)** — OS\n  keychain access with ACL support.\n- **[cobra](https://github.com/spf13/cobra)** + **[pflag](https://github.com/spf13/pflag)** —\n  CLI subcommand routing and flag parsing.\n\nThe `SecureBytes` mlock pattern is custom-implemented in\n`internal/vault/securebytes/`; the design is inspired by\n[sigil](https://github.com/mrz1836/sigil) but takes no dependency on it.\n\n\u003cbr/\u003e\n\n## 📚 Documentation\n\nView the comprehensive documentation for hush:\n\n| Doc | Purpose |\n|-----|---------|\n| [`docs/OPERATIONS.md`](docs/OPERATIONS.md) | Setup, day-to-day modes, `--non-interactive`, Keychain recovery |\n| [`docs/VAULT-REKEY.md`](docs/VAULT-REKEY.md) | Vault passphrase rotation runbook: `secret rotate` vs `vault rekey`, Keychain follow-up, snapshot/rollback |\n| [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) | Component model, trust boundaries, supervisor lifecycle |\n| [`docs/SECURITY.md`](docs/SECURITY.md) | Threat model, 7 security layers, residual risks |\n| [`docs/AGENT-INTEGRATION.md`](docs/AGENT-INTEGRATION.md) | SDK guide for AI agents: `pkg/client` Snapshot / Me / Watch + agent-context flags on `/claim` |\n| [`docs/CONFIG-SCHEMA.md`](docs/CONFIG-SCHEMA.md) | Server + supervisor TOML schemas, defaults, validation |\n| [`docs/DAEMONS.md`](docs/DAEMONS.md) | Supervisor pattern, refresh tuning, validator authoring |\n| [`docs/API.md`](docs/API.md) | HTTP endpoint reference |\n| [`docs/LIFECYCLE-SCENARIOS.md`](docs/LIFECYCLE-SCENARIOS.md) | 17 supervisor lifecycle scenarios — behavioral reference |\n| [`docs/TAILSCALE-ACLS.md`](docs/TAILSCALE-ACLS.md) | Recommended ACL pattern restricting the vault port |\n| [`docs/CLEAN-MACHINE.md`](docs/CLEAN-MACHINE.md) | Agent-machine cleanup checklist |\n| [`.specify/memory/constitution.md`](.specify/memory/constitution.md) | The 11 non-negotiable principles |\n\n\u003cbr/\u003e\n\n## 🔐 Security\n\n### Important Disclaimer\n\n\u003e ⚠️ **Experimental Software — Use at Your Own Risk**\n\u003e\n\u003e hush is experimental, open-source software provided \"AS-IS\" without\n\u003e warranty. By running it, you acknowledge:\n\u003e\n\u003e - **Status:** ALPHA quality; expect bugs, edge cases, and breaking changes.\n\u003e - **No formal audit:** hush has not been professionally audited or\n\u003e   penetration-tested.\n\u003e - **You own the host:** the trusted vault host, your Tailscale config, and\n\u003e   your Discord bot are yours to secure — hush only does its part.\n\u003e - **No liability:** the authors accept no responsibility for compromised\n\u003e   secrets, downtime, or damages.\n\u003e\n\u003e **Don't trust hush with a secret you can't afford to rotate.** If it breaks,\n\u003e you get to keep both pieces.\n\nFor the full threat model and the 7 security layers, see\n[`docs/SECURITY.md`](docs/SECURITY.md). For security issues, see our\n[Security Policy](.github/SECURITY.md) or contact: [hush@mrz1818.com](mailto:hush@mrz1818.com).\n\n\u003cbr/\u003e\n\n### Additional Documentation \u0026 Repository Management\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e\u003ccode\u003eDevelopment Setup (Getting Started)\u003c/code\u003e\u003c/strong\u003e\u003c/summary\u003e\n\u003cbr/\u003e\n\nInstall [MAGE-X](https://github.com/mrz1836/go-mage) build tool for development:\n\n```bash\n# Install MAGE-X for development and building\ngo install github.com/magefile/mage@latest\ngo install github.com/mrz1836/go-mage/magex@latest\nmagex update:install\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e\u003ccode\u003eBuild Commands\u003c/code\u003e\u003c/strong\u003e\u003c/summary\u003e\n\u003cbr/\u003e\n\nView all build commands:\n\n```bash\nmagex help\n```\n\nCommon commands:\n- `magex build` — Build the binary\n- `magex test` — Run test suite\n- `magex lint` — Run all linters\n- `magex deps:update` — Update dependencies\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e\u003ccode\u003eBinary Deployment\u003c/code\u003e\u003c/strong\u003e\u003c/summary\u003e\n\u003cbr/\u003e\n\nThis project uses [goreleaser](https://github.com/goreleaser/goreleaser) for\nstreamlined binary deployment to GitHub. To get started, install it via:\n\n```bash\nbrew install goreleaser\n```\n\nThe release process is defined in the [.goreleaser.yml](.goreleaser.yml)\nconfiguration file. Then create and push a new Git tag using:\n\n```bash\nmagex version:bump bump=patch push=true branch=master\n```\n\nThis process ensures consistent, repeatable releases with properly versioned\nartifacts.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e\u003ccode\u003eGitHub Workflows\u003c/code\u003e\u003c/strong\u003e\u003c/summary\u003e\n\u003cbr/\u003e\n\nhush uses the **Fortress** workflow system for comprehensive CI/CD:\n\n- **fortress-test-suite.yml** — Complete test suite across multiple Go versions\n- **fortress-code-quality.yml** — Code quality checks (gofmt, golangci-lint, staticcheck)\n- **fortress-security-scans.yml** — Security vulnerability scanning\n- **fortress-coverage.yml** — Code coverage reporting to Codecov\n- **fortress-release.yml** — Automated binary releases via GoReleaser\n\nSee all workflows in [`.github/workflows/`](.github/workflows/).\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e\u003ccode\u003eUpdating Dependencies\u003c/code\u003e\u003c/strong\u003e\u003c/summary\u003e\n\u003cbr/\u003e\n\nTo update all dependencies (Go modules, linters, and related tools), run:\n\n```bash\nmagex deps:update\n```\n\nThis command ensures all dependencies are brought up to date in a single step,\nincluding Go modules and any managed tools. It is the recommended way to keep\nyour development environment and CI in sync with the latest versions.\n\n\u003c/details\u003e\n\n\u003cbr/\u003e\n\n## 🧪 Examples \u0026 Tests\n\nAll unit tests run via [GitHub Actions](https://github.com/mrz1836/hush/actions).\nView the [configuration file](.github/workflows/fortress.yml).\n\nRun all tests (fast):\n\n```bash\nmagex test\n```\n\nRun all tests with race detector (slower):\n\n```bash\nmagex test:race\n```\n\n\u003cbr/\u003e\n\n### Test Coverage\n\nView coverage report:\n\n```bash\nmagex test:coverage\n```\n\nCoverage reports are automatically uploaded to [Codecov](https://codecov.io/gh/mrz1836/hush)\non every commit.\n\n\u003cbr/\u003e\n\n### Benchmarks\n\nBaseline performance numbers for the hot crypto paths. Re-measure after any\nrefactor that touches the request path, vault loader, or transport encryption —\nregressions land here before they land in production.\n\nRun the suite:\n\n```bash\nmagex bench:default time=2s\n```\n\nCapture a baseline file for diffs across branches:\n\n```bash\nmagex bench:save time=2s out=bench.txt\n```\n\nCompare two runs:\n\n```bash\nmagex bench:compare old=before.txt new=after.txt\n```\n\n\u003cbr\u003e\n\n**Latest baseline** — Apple M1 Max · darwin/arm64 · Go 1.26 · `benchtime=2s`:\n\n| Benchmark                                        | ns/op   | B/op   | allocs/op | Path covered                                          |\n| ------------------------------------------------ | ------: | -----: | --------: | ----------------------------------------------------- |\n| `BenchmarkValidate` (`internal/token`)           | 192,871 |  5,739 |       105 | JWT parse + ES256K verify + store lookup (supervisor) |\n| `BenchmarkEncrypt` (`internal/transport/ecies`)  | 173,705 |  3,345 |        40 | Ephemeral keygen + ECDH + AES-CBC + HMAC envelope     |\n| `BenchmarkDecrypt` (`internal/transport/ecies`)  | 151,457 |  2,528 |        29 | Pubkey parse + ECDH + KDF + HMAC verify + AES-CBC     |\n| `BenchmarkLoad` (`internal/vault`)               |  51,813 | 16,528 |       113 | Encrypted-vault read (16 secrets, ~64 B each)         |\n\n\u003e Numbers are local-machine baselines, not SLOs. Use them to spot\n\u003e ≥10% regressions on the same hardware after a code change. The CI\n\u003e machine numbers will differ; track relative deltas, not absolutes.\n\u003e\n\u003e Last measured: 2026-05-24\n\n\u003cbr/\u003e\n\n## 🛠️ Code Standards\n\nRead more about this Go project's [code standards](.github/CODE_STANDARDS.md).\n\n\u003cbr/\u003e\n\n## 🤖 AI Usage \u0026 Assistant Guidelines\n\nRead the [AI Usage \u0026 Assistant Guidelines](.github/CLAUDE.md) for details on\nhow AI is used in this project and how to interact with AI assistants.\n\n\u003cbr/\u003e\n\n## 👥 Maintainers\n\n| [\u003cimg src=\"https://github.com/mrz1836.png\" height=\"50\" alt=\"MrZ\" /\u003e](https://github.com/mrz1836) |\n|:------------------------------------------------------------------------------------------------:|\n|                                [MrZ](https://github.com/mrz1836)                                 |\n\n\u003cbr/\u003e\n\n## 🤝 Contributing\n\nView the [contributing guidelines](.github/CONTRIBUTING.md) and please follow\nthe [code of conduct](.github/CODE_OF_CONDUCT.md).\n\n### How can I help?\n\nAll kinds of contributions are welcome :raised_hands:!\nThe most basic way to show your support is to star :star2: the project, or to\nraise issues :speech_balloon:.\nYou can also support this project by [becoming a sponsor on GitHub](https://github.com/sponsors/mrz1836) :clap:\nor by making a [**bitcoin donation**](https://mrz1818.com/?tab=tips\u0026utm_source=github\u0026utm_medium=sponsor-link\u0026utm_campaign=hush\u0026utm_term=hush\u0026utm_content=hush)\nto ensure this journey continues indefinitely! :rocket:\n\n[![Stars](https://img.shields.io/github/stars/mrz1836/hush?label=Please%20like%20us\u0026style=social)](https://github.com/mrz1836/hush/stargazers)\n\n\u003cbr/\u003e\n\n## 📝 License\n\n[![License](https://img.shields.io/github/license/mrz1836/hush.svg?style=flat\u0026v=1)](LICENSE)\n\nThis project is licensed under the terms of the [`LICENSE`](LICENSE) file at\nthe repo root.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrz1836%2Fhush","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmrz1836%2Fhush","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrz1836%2Fhush/lists"}