Your trading agent shouldn't hold your private keys .
openKMS is a deny-by-default signing API for Solana and Cosmos, backed by a YubiHSM2 you actually own. Autonomous strategies request signatures over HTTP. Per-key policy stops the bad trades before the hardware ever touches them.
- Chains
- Solana · Cosmos
- Hardware
- YubiHSM2
- License
- Apache-2.0
curl -sS \
-H "Authorization: Bearer $(cat signer.token)" \
http://pi.local:9443/policy/solana-hot-0 {
"label": "solana-hot-0",
"chain": "solana",
"effective_enabled": true,
"policy": {
"enabled": true,
"max_signs_per_minute": 30,
"max_signs_per_day": 5000,
"per_tx_cap_lamports": "5000000000",
"allowed_programs": [
{ "id": "11111111111111111111111111111111" }
]
},
"runtime": {
"sign_counts": {
"per_minute": { "limit": 30, "used": 0 }
}
}
} The problem
Hot wallets are a liability.
Every drained validator, every rug pull, every "compromised hot wallet" post-mortem traces back to the same mistake: keys lived next to the code that uses them.
Threat #1
Mnemonics in .env
Anyone who reads the host reads the seed. One leaked file, one stolen backup, one curious sysadmin — and the treasury is gone.
Threat #2
Unsupervised strategies
A buggy or compromised agent can drain an account in seconds. Spend caps and allowlists shouldn't live inside the same process that builds the trade.
Threat #3
Custody you don't own
Cloud custody and cloud KMS put your keys behind someone else's policy, someone else's audit log, and someone else's outage page.
How it works
Five gates between the strategy and your keys.
Every signing request crosses authentication, chain decoding, policy evaluation, replay protection, and only then reaches the YubiHSM2. Each layer is fail-closed and emits to the audit log.
HTTP, policy, replay cache, audit log, metrics. Runs as a
hardened systemd service on a dedicated user with
NoNewPrivileges,
PrivateTmp, and
SystemCallFilter.
Signing keys live only inside the YubiHSM2. The runtime auth key can sign but cannot export or mutate keys. Backups are wrap-encrypted under a key that never leaves the device.
Every accepted and denied signature lands in the JSONL audit log with optional HMAC chaining. Prometheus exports counters for sign attempts, denials, and policy reasons.
ChainSigner trait —
policy, audit, and metrics are chain-agnostic.
Full architecture
Sign over HTTP
One bearer token. Two chains. Zero key egress.
openKMS speaks plain HTTP on loopback or behind your proxy. Your agent posts a chain-native message; it gets back a signature, never a key.
curl -sS -X POST \
-H "Authorization: Bearer $(cat signer.token)" \
-H "Content-Type: application/json" \
http://pi.local:9443/sign/solana \
-d @sign-request.json {
"label": "solana-hot-0",
"expected_chain_id": "mainnet-beta",
"message_b64": "<base64 VersionedMessage>",
"address_lookup_tables": [
{ "key": "<ALT pubkey>", "addresses": ["<base58>", "..."] }
]
} {
"signature_b64": "<base64 64-byte ed25519>"
} {
"error": "policy: per_tx_cap_lamports exceeded (cap=5000000000, attempted=12000000000)"
} Policy inspection
GET /policy/{label} returns the effective policy plus runtime counters so agents self-throttle.
Read the routeAdmin overlays
PATCH a partial overlay onto a key without rewriting config. Persisted, restart-safe, fully audited.
See the schemaOpenAPI v1
Generated from the Rust source at build time. CI fails on drift so the spec is always live.
View the specWhat ships in the box
Everything an autonomous strategy needs to never touch a key.
HSM-only signing
Ed25519 (Solana) and secp256k1 (Cosmos) live inside the YubiHSM2. The runtime auth key can sign but cannot export.
Learn moreDeterministic ceremony
One BIP-39 mnemonic seeds ceremony, provisioner, signer, and the AES-256-CCM wrap key. Lose hardware, restore in minutes.
Learn morePer-key policy
Rate limits per minute / hour / day, per-tx and rolling daily caps, plus program / message-type / recipient allowlists.
Learn moreKill switch + overlays
Disable a key without deleting it. Persist partial overlays through the admin API; baseline config stays untouched.
Learn moreAudit + metrics
Append-only JSONL audit with optional HMAC chain. Prometheus exposes accept / deny counters with policy reasons.
Learn moreChain-agnostic
Add a chain by implementing the Rust ChainSigner trait. Policy, audit, replay, and metrics layers stay shared.
Learn moreHow we compare
Same threat model. Different blast radius.
Cloud custody and cloud KMS solve part of the problem. They still leave you trusting someone else's policy, audit log, and uptime.
| Property | Hot wallet Mnemonic in .env | Cloud custody Fireblocks · Turnkey · Privy · Anchorage | Cloud KMS AWS KMS · GCP Cloud KMS | openKMS Self-hosted YubiHSM2 signer |
|---|---|---|---|---|
| Where keys live | Strategy host (plaintext) | Vendor cloud HSM | Vendor cloud HSM | Your YubiHSM2 |
| Who writes the policy | Nobody | You, in their UI | Generic IAM only | You, in TOML + admin API |
| Chain-aware allowlists | None | Partial, vendor-defined | Not supported | Programs · message types · recipients |
| Audit log ownership | App logs (if any) | Vendor dashboard | CloudTrail / Cloud Audit Logs | Local JSONL + HMAC chain |
| Open source | — | Closed | Closed | Apache-2.0 |
| Runs on a Raspberry Pi | Yes (and that's the problem) | No — vendor cloud only | No — vendor cloud only | Yes — homelab is the design target |
| Pricing | Free until you're drained | Per signature / seat | Per key / per request | One-time hardware |
Vendor names are trademarks of their respective owners. Listed for comparison only.
Built for autonomous agents
How an Openclaw strategy uses openKMS.
openKMS is the signing boundary, not the strategy. Agents construct transactions, ask for a signature, and broadcast — the policy engine keeps a buggy or compromised agent from draining an account.
- 01 Strategy GET /policy/{label}
Inspect effective limits and live counters before constructing a trade. If a daily cap is nearly exhausted, wait or escalate.
- 02 Strategy Build the transaction
Construct a chain-native message (VersionedMessage for Solana, SignDoc for Cosmos). openKMS never sees the strategy logic.
- 03 openKMS POST /sign/{chain}
Decode → policy → replay cache → HSM. A denial is a 403 / 429 with a precise reason. An accept records to the audit log.
- 04 Strategy Broadcast through chain RPC
openKMS never broadcasts. The strategy assembles signature + message and submits to the chain. The signing boundary stays narrow.
Self-throttling agents
Agents read policy before they sign. Runtime counters tell them when a window is full so they back off instead of probing for a denial.
Bounded blast radius
Per-tx caps limit a single bad trade. Daily caps limit sustained bad behavior. The admin kill switch stops a key without deleting it.
AgentSkills-compatible manual
An operator manual ships at .agents/skills/openkms/SKILL.md so any AgentSkills-aware agent can correctly call openKMS without bespoke onboarding.
Open the skillRead the full integration guide
Trust boundaries · token scopes · admin overlays · operator hand-off.
Run it on a Pi today.
One BIP-39 mnemonic, a YubiHSM2, and a Raspberry Pi. Your strategy signs through a deny-by-default boundary and your keys never leave the device.