Discord-gated secrets broker for AI agents
One passphrase. No key files. No dotfiles on agent disks.
CI / CD Β Β
|
|
Β Β Β Β Quality Β Β
|
|
Security Β Β
|
|
Β Β Β Β Community Β Β
|
|
πΒ Installation
|
β‘Β QuickΒ Start
|
πΒ Documentation
|
πΒ Security
|
π οΈΒ CodeΒ Standards
|
π§ͺΒ ExamplesΒ &Β Tests
|
π€Β AIΒ Usage
|
βοΈΒ License
|
π€Β Contributing
|
π₯Β Maintainers
|
||
hush is a single Go binary that keeps every API key, OAuth token, and service credential encrypted on a single trusted host. Agents request short-lived, scoped sessions over Tailscale; the request is approved on your phone via Discord; approved secrets are delivered ECIES-encrypted end-to-end and injected into the agent process's environment β never written to disk on the agent machine.
If your dev workflow runs untrusted code (npm/pip packages, LLM-generated scripts, AI-agent tools that execute shell commands) and your secrets currently live in shell rc files or cloud-provider credential files, hush is for you. Vault, 1Password CLI, and dotfile-based env vars all leave files on disk that commodity malware grep for first. hush makes those files not exist.
TAILSCALE MESH
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β ββββββββββββββββββββββββββββ βββββββββββββββββββββββββββββββββ β
β β AGENT MACHINE β β VAULT HOST β β
β β (untrusted, clean disk) β β (mlocked memory; offline) β β
β β β β β β
β β interactive client / β β vault server β β
β β supervisor β β β β
β β β β β β² β β
β β β ECDSA-signed βββββββΌβββββββΊβ verify signature β β
β β β claim β β β check Tailscale IP β β
β β β β β βΌ β β
β β β β β Discord DM ββββββΊ phone β β
β β β β β β [Approve] β β
β β β ES256K JWT βββββββΌββββββββ€ issue scoped JWT β β
β β β β β βΌ β β
β β β secret fetch βββββββΌβββββββΊβ ECIES-encrypt to β β
β β β (ECIES bytes) β β β ephemeral pubkey β β
β β βΌ β β β β β
β β decrypt β env var β β ββββββββββββββββββββββ β β
β β inject into child β β [no key files anywhere] β β
β ββββββββββββββββββββββββββββ βββββββββββββββββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
hush requires a supported release of Go
(Go 1.26+) and is built CGO_ENABLED=0 β a single static binary.
Status: v0.1.0 is a private MVP. Treat the steps below as the documented happy path, not a guarantee.
Prerequisites: a vault host and an agent host on the same Tailscale tailnet, plus a Discord bot you control (https://discord.com/developers/applications) for the approval channel.
git clone https://github.com/mrz1836/hush.git && cd hush
magex build && sudo install -m 0755 cmd/hush/hush /usr/local/bin/hushGet up and running with these essential commands:
One command, fake secret, real Discord approval:
hush smoke --state-dir ~/.hush-smoke --resethush smoke walks the setup prompts, creates an isolated test vault, adds
HUSH_SMOKE_TEST=hello-from-hush, starts a temporary Tailscale-only server,
enrolls a client, asks you to approve in Discord, verifies the fake secret,
and then shuts the temporary server down. Clean smoke artifacts safely with
hush smoke clean (archives by default).
hush init server # guided / interactive; preflight + prompts
hush secret add OPENAI_API_KEY
hush serve # binds Tailscale interface, brokers approvalshush init server is the canonical first-run entry point. It runs a
diagnostic-first preflight, prompts for the inputs it actually needs,
classifies pre-existing state per-artifact, and never silently overwrites.
When it asks for a listen address, use the vault host's Tailscale IPv4
plus a free port (for example, run printf '%s:7743\n' "$(tailscale ip -4)"
on the server host). Do not use the laptop/client IP.
During hush init server, set discord_approval_channel_id if you want
approvals in a Discord channel instead of owner DMs. On macOS, if the login
Keychain is locked or unavailable, choose the env-token fallback and run
hush serve with HUSH_DISCORD_BOT_TOKEN exported in that terminal.
hush init client --machine-index 1
HUSH_SERVER="$(hush --config ~/.hush/config.toml server-url)"
hush request \
--server "$HUSH_SERVER" \
--machine-index 1 --scope OPENAI_API_KEY \
--max-uses 1 --ttl 5m --reason "smoke test" \
--exec printenv -- OPENAI_API_KEYApprove on Discord; the child process you named in --exec runs with
OPENAI_API_KEY in its environment β and only there. --exec names a
program, not a shell string; pass child arguments after --. Nothing is
written to disk on the agent host.
π For the full walkthrough β Keychain ACL recovery, clock-skew override,
--non-interactivemode β seedocs/OPERATIONS.md. For Keychain vsHUSH_DISCORD_BOT_TOKENpositioning and the threat model, seedocs/SECURITY.mdΒ§2.4. For long-running daemons, seedocs/DAEMONS.mdanddeploy/examples/supervisors/. For server + supervisor TOML schemas, seedocs/CONFIG-SCHEMA.md.
What hush does:
- Keeps every secret encrypted in a single AES-256-GCM + Argon2id (256MB) vault file on one trusted host.
- Requires phone approval (Discord DM with interactive buttons) for every fresh session.
- Delivers secrets ECIES-encrypted end-to-end into agent process memory only β no disk writes on the agent.
What hush explicitly does NOT do (v0.1.0):
- No multi-owner approvals (a single configured operator approves; multi-owner is post-v0.1.0 future scope).
- No cloud KMS / SaaS dependency. The vault is self-hosted and offline-capable.
- No public network exposure. The vault server is bound to a Tailscale interface and refuses to start otherwise.
When untrusted code lands on a developer machine β via npm/pip
supply-chain attacks, LLM-generated scripts, or trojans masquerading as
tools β the very first thing it does is enumerate known credential
patterns in known files: shell rc files, cloud-provider credential
files, .env files, signing keys, and PEM files.
hush exists to make this enumeration return nothing. Secrets stay encrypted on a single trusted host. Agents fetch them only after a human approves the request from a phone. Approved secrets are delivered into process memory and zeroed when the process exits. Nothing on disk.
For the full threat model, see docs/SECURITY.md.
hush is a single Go binary playing three roles:
- Vault server β holds the encrypted vault file in mlocked memory; issues ES256K-signed JWTs after Discord approval; ECIES-encrypts secret responses to the client's per-session ephemeral public key; exposes a tiny HTTP API over Tailscale only.
- Interactive client β ECDSA-signs a claim with a per-machine BIP32-derived key; receives a JWT after approval; fetches and decrypts secrets; injects them into a child process's environment.
- Supervisor β long-lived per-daemon process that holds the JWT and ephemeral ECIES key in mlocked memory across child crashes/restarts within the session TTL; runs validators before child start; exposes a Unix status socket for agent-visible freshness queries.
Seven security layers stack independently β compromise of any single layer does not enable secret extraction:
- BIP32 HD key hierarchy β all keys derived at runtime from a single passphrase. Zero key files on disk.
- ES256K asymmetric JWT signing β only the server can sign; leaking the public key does not enable forgery.
- ECIES end-to-end secret transport β secrets are encrypted to a per-session ephemeral pubkey; captured HTTP traffic shows binary blobs.
- ECDSA-signed client requests β every claim and revocation is signed with a registered per-machine client key.
- mlocked secure memory β
SecureBytescontainers; secrets never stored as Gostring; explicit zeroing on shutdown. - Signed hash-chained audit log β every event ECDSA-signed; chain breaks on modification.
- Obscurity β random API path prefix, custom vault file format, non-obvious binary name. Additive only β never load-bearing.
The network perimeter is Tailscale-only (Constitution Principle VI).
Tailscale is the v0.1.0 mesh-VPN choice; the architecture does not depend
on it specifically β the requirement is "no public reachability" and
Tailscale satisfies it cleanly. The Approver interface is also
pluggable; Discord is the v0.1.0 reference implementation and the
only one that ships, but future Slack / Telegram / PagerDuty backends can
be wired without changing the rest of the system.
For the full architecture treatment, see docs/ARCHITECTURE.md.
- Go 1.26+ β single static binary,
CGO_ENABLED=0exclusively (Constitution Principle IX). - decred/dcrd/dcrec/secp256k1/v4 β secp256k1 primitives used for ECDSA signing, ES256K JWTs, and ECIES envelope encryption (Constitution Principle III).
- decred/dcrd/hdkeychain/v3 β BIP32
HD key derivation from the operator passphrase (Constitution Principle
III); paired with stdlib
golang.org/x/crypto/argon2for the KDF. - Tailscale β the only network reachable to the vault server. WireGuard underneath; identity-based ACLs above.
- Discord + discordgo β phone-based approval channel; the v0.1.0 reference Approver.
- golang-jwt/jwt v5 β JWT framework;
hush registers a custom
ES256Ksigning method. - go-toml v2 β strict TOML parsing for server and supervisor configs.
- zalando/go-keyring β OS keychain access with ACL support.
- cobra + pflag β CLI subcommand routing and flag parsing.
The SecureBytes mlock pattern is custom-implemented in
internal/vault/securebytes/; the design is inspired by
sigil but takes no dependency on it.
View the comprehensive documentation for hush:
| Doc | Purpose |
|---|---|
docs/OPERATIONS.md |
Setup, day-to-day modes, --non-interactive, Keychain recovery |
docs/ARCHITECTURE.md |
Component model, trust boundaries, supervisor lifecycle |
docs/SECURITY.md |
Threat model, 7 security layers, residual risks |
docs/CONFIG-SCHEMA.md |
Server + supervisor TOML schemas, defaults, validation |
docs/DAEMONS.md |
Supervisor pattern, refresh tuning, validator authoring |
docs/API.md |
HTTP endpoint reference |
docs/LIFECYCLE-SCENARIOS.md |
17 supervisor lifecycle scenarios β behavioral reference |
docs/TAILSCALE-ACLS.md |
Recommended ACL pattern restricting the vault port |
docs/CLEAN-MACHINE.md |
Agent-machine cleanup checklist |
.specify/memory/constitution.md |
The 11 non-negotiable principles |
The v0.1.0 goal is a working private MVP that proves the threat model in practice: an agent machine with a clean disk, a vault host on a phone-gated Tailscale mesh, and a daily dev workflow that no longer requires plaintext credentials anywhere on the agent.
Post-v0.1.0 / future scope (any of these may become a future release; none is on the v0.1.0 critical path):
- Multi-owner approvals
- Slack / Telegram / PagerDuty Approver backends (the interface is already pluggable)
- Shamir passphrase splitting (sigil's SSS) for vault recovery
- Web dashboard
- Proxy mode (vault proxying provider API calls instead of injecting tokens)
- Agent-side credential proxy (per-provider HTTP proxy on the agent host)
- TLS within Tailscale (defence-in-depth on top of WireGuard)
- TOTP second factor on Discord approval
- Custom validator authoring SDK
β οΈ Experimental Software β Use at Your Own Riskhush is experimental, open-source software provided "AS-IS" without warranty. By running it, you acknowledge:
- Private MVP: v0.1.0 is an unproven private MVP β not production-grade, and the end-to-end round-trip has not been independently verified.
- No formal audit: hush has not been professionally audited or penetration-tested.
- You own the host: the trusted vault host, your Tailscale config, and your Discord bot are yours to secure β hush only does its part.
- No liability: the authors accept no responsibility for compromised secrets, downtime, or damages.
Don't trust hush with a secret you can't afford to rotate. If it breaks, you get to keep both pieces.
For the full threat model and the 7 security layers, see
docs/SECURITY.md. For security issues, see our
Security Policy or contact: hush@mrz1818.com.
Development Setup (Getting Started)
Install MAGE-X build tool for development:
# Install MAGE-X for development and building
go install github.com/magefile/mage@latest
go install github.com/mrz1836/go-mage/magex@latest
magex update:installBuild Commands
View all build commands:
magex helpCommon commands:
magex buildβ Build the binarymagex testβ Run test suitemagex lintβ Run all lintersmagex deps:updateβ Update dependencies
Binary Deployment
This project uses goreleaser for streamlined binary deployment to GitHub. To get started, install it via:
brew install goreleaserThe release process is defined in the .goreleaser.yml configuration file. Then create and push a new Git tag using:
magex version:bump bump=patch push=true branch=masterThis process ensures consistent, repeatable releases with properly versioned artifacts.
GitHub Workflows
hush uses the Fortress workflow system for comprehensive CI/CD:
- fortress-test-suite.yml β Complete test suite across multiple Go versions
- fortress-code-quality.yml β Code quality checks (gofmt, golangci-lint, staticcheck)
- fortress-security-scans.yml β Security vulnerability scanning
- fortress-coverage.yml β Code coverage reporting to Codecov
- fortress-release.yml β Automated binary releases via GoReleaser
See all workflows in .github/workflows/.
Updating Dependencies
To update all dependencies (Go modules, linters, and related tools), run:
magex deps:updateThis command ensures all dependencies are brought up to date in a single step, including Go modules and any managed tools. It is the recommended way to keep your development environment and CI in sync with the latest versions.
All unit tests run via GitHub Actions. View the configuration file.
Run all tests (fast):
magex testRun all tests with race detector (slower):
magex test:raceView coverage report:
magex test:coverageCoverage reports are automatically uploaded to Codecov on every commit.
Read more about this Go project's code standards.
Read the AI Usage & Assistant Guidelines for details on how AI is used in this project and how to interact with AI assistants.
![]() |
|---|
| MrZ |
View the contributing guidelines and please follow the code of conduct.
All kinds of contributions are welcome π! The most basic way to show your support is to star π the project, or to raise issues π¬. You can also support this project by becoming a sponsor on GitHub π or by making a bitcoin donation to ensure this journey continues indefinitely! π
This project is licensed under the terms of the LICENSE file at
the repo root.
