KKleo

Desktop · macOS, Linux, Windows · MIT

Encrypt to a name,
not to a key.

Kleo brings back the best part of GnuPG's Kleopatra — the Notepad, where you sign, verify, encrypt and decrypt text inline — and builds the rest around it: messages, files, a wallet and channels, all addressed by human-readable BitNames on a Bitcoin sidechain, with every check run against your own node.

No keyringA name is the key
No server to trustVerified on-chain
No accountsA BitName is the barrier
Kleo — Notepad
Sign as alice · key bn-svk1q8x3f0…f3d2
-----BEGIN BITNAMES SIGNED MESSAGE----- The release notes for 0.17.2 are final. -----BEGIN BITNAMES SIGNATURE----- Signer: alice Key: bn-svk1q8x3f0alice7m2kd9w0p5v6r4t3y8u2i1o0p9l8k7j6h5g4f3d2 0x7b41f0c2a98e5d31b6740fe2c18a93db5f0e2a77c4b9016d 83f5a1e6d029b7c4188ae35f90d2c6b71a4e0f83d5629cab -----END BITNAMES SIGNATURE-----
Signed with the key alice publishesThe signature covers exactly the text above — no headers — so any BitNames tool can check it.

The app

What it actually looks like

Nine views, one window. These are real captures of the running interface against a node, not mockups — which is also why the block height differs between them.

Kleo's Notepad view
Notepad. Sign, verify, encrypt and decrypt text addressed by BitName. The armour carries a Signer hint, and Kleo re-checks it against the chain rather than believing it.
Kleo's Chat view
Chat. Messages signed by you and sealed to them, sent straight to their machine. forward secret in the header means the conversation runs a Double Ratchet.
Kleo's Channels view
Channels. Broadcast, private groups and communities. A post from someone the channel does not admit is shown as exactly that, rather than quietly dropped.
Kleo's Your names view
Your names. The BitNames your wallet holds, the keys each one publishes, and a two-block registration that resumes if you close the app.
Kleo's Contacts view
Contacts. Names you have saved, with the keys you pinned. A key that changes since you saved it is flagged, and encrypting is blocked until you look.
Kleo's Files view
Files. The same four operations on disk, plus BLAKE3 checksums. A file signature covers the hash, not the name, so renaming does not break it.
Kleo's Wallet view
Wallet. Receive, pay, deposit and withdraw. Paying a name looks up where that name takes payments, and every payment is quoted back before it is sent.
Kleo's Node view
Node. What your node and the chains are doing: both tips, what is waiting on a block, and a button that asks for one.
Kleo's Settings view
Settings. Which node is yours, which hubs you use, and the lock: a passphrase that takes the vault key out of the keychain.

Download

Unsigned, and saying so

Version 0.1.2, built by CI from the v0.1.2 tag for all three platforms. They carry no code-signing certificate yet, so your system will object — and it is right to. Until they are signed, the honest options are to build from source, which takes two commands, or to open them anyway knowing exactly what that means.

PlatformFileGetting past the warning
macOS
Apple silicon & Intel
Kleo_0.1.2_universal.dmg
26 MB
Right-click the app and choose Open, or run xattr -dr com.apple.quarantine /Applications/Kleo.app. Gatekeeper blocks a double-click because nobody has vouched for it.
Linux
x86-64, glibc 2.35+
Kleo_0.1.2_amd64.deb
16 MB
Kleo_0.1.2_amd64.AppImage
89 MB
Install the .deb, or chmod +x the AppImage and run it. Built on Ubuntu 22.04, so it runs on anything that old or newer. No signature to check either way.
Windows
x86-64
Kleo_0.1.2_x64-setup.exe
8 MB
Kleo_0.1.2_x64_en-US.msi
12 MB
SmartScreen will warn: choose More info, then Run anyway. Either installer works; the .msi suits managed machines.

Checksums are at /downloads/SHA256SUMS. They tell you the file arrived intact, which is worth having and is not the same as knowing who built it — that needs a signature, and there is not one yet.

shasum -a 256 -c SHA256SUMS

Building it yourself is the only way to know what you are running, and the manual covers it. Signed, reproducible builds are the last thing on the roadmap for exactly this reason.

What it is

A workbench, not a wallet

Kleo is a desktop client for the plain-bitnames sidechain. It never reimplements the chain: your node holds the keys and does the cryptography, and Kleo is the surface that makes it usable by hand.

Notepad

Sign, verify, encrypt, decrypt

One text pane addressed by name. Verifying checks the signature and that the key is the one that name publishes right now. Decrypt also checks any signature sealed inside.

⌘/Ctrl+Enter runs the suggested action · Undo for every transformation

Your names

Hold an identity

Create or restore a wallet, register a BitName through its two-block commit → reveal, and replace your signing or encryption keys later without losing the name.

12 words to write down, then a three-word check

Contacts

Keys pinned on sight

Save a name and Kleo remembers the keys it published. If they change, the contact is flagged, encrypting to it is blocked until you review, and verified signatures say so.

XChaCha20-Poly1305, key in the OS keychain

Profiles

A phone book that can't lie

Publish a display name, bio, links and ways to be paid. Kleo re-hashes whatever a server returns and compares it with the commitment on-chain. A host can withhold a profile; it can't alter one.

RFC 8785 canonical JSON · BLAKE3 · bitname_commit

Files

Detached signatures and sealed files

Sign a file into a small .bnsig that travels beside it, encrypt one to a name, or write BLAKE3 checksums for a whole folder.

.bnsig · .bnenc · .b3sums · up to 256 MB

Chat

Messages, computer to computer

Write to a name and the message goes straight to their machine over an encrypted peer-to-peer link — signed by you, sealed to them. When they're away, it waits at a hub, still sealed.

iroh QUIC · forward secret · files up to 150 KB · blocking

Channels

A channel is a BitName

Which makes its name unique and costly, and puts its rules — broadcast, private group, or open community — under the same on-chain commitment as everything else. Groups seal a key to each member; a hub holds ciphertext.

published moderators and bans · following is local

Wallet

Coins, and what they were for

Receive, pay a name or an address, and move coins to and from Bitcoin. Every payment is quoted before it is signed, and the history says what each transaction was.

deposits and withdrawals through the BIP300 enforcer

Backup

Your side, on another machine

A recovery phrase brings back the wallet and its names. It brings back nothing Kleo keeps privately — contacts, pinned keys, blocks, invitations, conversations. One file carries those, encrypted to a passphrase rather than to this machine's keychain.

Argon2id · restoring only ever adds, never overwrites

Paid messages

A price to be written to

Publish what a stranger pays to reach you, and their first message arrives as the payment — the message sealed inside its memo. Contacts and anyone you've replied to are never charged.

upstream paymail · on-chain price · allow list

What it checks

Nothing is trusted because it arrived

A message, a profile and a chat line are all judged the same way: re-derive the keys from the chain as your own node reports it, then check the signature. Where something doesn't line up, Kleo says so in words rather than showing a padlock. What it proves, what it only claims, and what it leaks is written down in full — including the gaps — in its threat model.

The four verdicts

OutcomeWhat Kleo saysWhat it means
Verified Good signature from alice The key is the one that name publishes on-chain, and the text hasn't changed since it was signed.
Key mismatch Claims to be from alice, but it isn't signed with alice's key Either they rotated keys after signing, or someone is impersonating them. Never shown as trusted.
Unknown name Claims to be from alice, but no such BitName exists The signature is intact, but nobody has registered that name — so it proves nothing about who wrote it.
Bad signature Bad signature. Do not trust this message. The text was edited after signing, or the armor is damaged. Ask for it again.

What a server can and can't do

WhoCanCan't
A profile host
kleo-hub
Refuse to serve a profile, or serve an old one it kept. Change a field, publish for a name it doesn't hold a signature from, or make Kleo show anything unverified.
Anyone, later
holding a stolen BitName key
Read old messages that were encrypted to that key — the Notepad, files, paid messages. Open a forward-secret conversation: those message keys were used once and thrown away.
A hub
mail, addresses, channels
Withhold, delay or lose mail; see who collects it and when. Read an envelope, forge a sender, invent a channel post, or point you at a machine of its choosing.
A chat relay
iroh
See that two endpoints are talking, and drop packets. Read a message, alter one, or make a message look like it came from someone else.
A node you don't run Lie about the chain, which is why Kleo defaults to loopback. Be silently trusted: point Kleo at your own node and every verdict is yours to check.

Manual

From nothing to a signed message

Fourteen steps, in order. The first three are once per machine; after that you're working, and the rest can be read as you need them. Every command in it is real — the regtest stack in step two builds a complete local chain, so you can practise without touching mainchain coins.

Start

Build it, and point it somewhere

Rust, Node and Tauri's packages; then a chain of your own in one script, or the shared signet in one daemon.

steps 1–3

Use

A name, and the four operations

Register a BitName, then sign, verify, encrypt and decrypt — text in the Notepad, or files on disk.

steps 4–8

Talk

Messages, money and channels

Publish where you are, write to a name, charge a stranger, keep a backup, start a channel.

steps 9–14

Run a node

Three ways to have a chain

Kleo is a client. It needs something to ask — pick whichever suits what you're doing.

Real

A regtest stack

Bitcoin Core 31.1 (checksum-verified), bip300301_enforcer built from source, and plain-bitnames 0.17.2 — all in a gitignored .regtest/.

scripts/regtest.sh install | start | demo-names | automine 10 | status | stop | reset

Fast

kleo-devnode

An in-memory stand-in serving the RPC subset Kleo uses, with the same wire formats, the same cryptography and the same error texts. Four demo names: alice and bob are yours, carol isn't, dave has no encryption key.

cargo run -p kleo-devnode

Yours

A real node

Any plain-bitnames node with its mainchain stack running. Point Kleo at its private RPC address and keep that address on loopback.

http://127.0.0.1:6002 by default

Kleo from a terminal

A window is a poor place to find out why a message did not arrive. kleo-cli drives the same state and the same command functions the window does — the sending and publishing paths were lifted out so both call one implementation, rather than two that can agree with each other while both are wrong.

cargo build -p kleo --bin kleo-cli

kleo-cli --kleo-dir DIR status              # node, names, prekeys, sessions
kleo-cli --kleo-dir DIR sessions            # the ratchet material in detail
kleo-cli --kleo-dir DIR history NAME        # the stored conversation
kleo-cli --kleo-dir DIR reset-session NAME  # drop one that fell out of step
kleo-cli --kleo-dir DIR publish-endpoint NAME
kleo-cli --kleo-dir DIR send --from A --to B --text "..."
kleo-cli --kleo-dir DIR listen              # collect mail, print arrivals

--kleo-dir matches the app's KLEO_DIR. For an instance started without it, pass --config-dir and --data-dir instead. It shares that instance's vault and keychain entry, so run one at a time per directory — the app and this both write, and the last writer wins. The first run raises a keychain prompt, because it is a different binary from the app.

Testing Kleo from the terminal is the whole thing step by step: two people, two wallets, names registered, messages going both ways — on regtest in minutes, or on the signet where it is the real chain.

Running a hub for other people

A hub is the part of Kleo that is awake when you are not: it keeps mail for people who are offline, answers where is this name reachable, stores channel posts, and hands out profiles. Uploads must be signed by the name's current on-chain signing key, which the hub checks against its own node — so only BitName holders can store anything, and it needs no accounts, quotas or moderation.

It is deliberately not something you have to trust. It cannot read your mail, which is sealed to the recipient before it arrives; it cannot forge a profile, which is checked against the chain; it cannot invent an address for you, because endpoint records are signed by the endpoint they name. What it can do is withhold, delay, and see who talks to whom — which is the honest cost of asking someone to hold your mail, and the reason more hubs is a contribution rather than a risk.

One script puts one on a fresh Ubuntu server:

scripts/deploy-hub.sh root@your-server example.com

That installs Bitcoin Core and plain-bitnames, builds the enforcer and the hub, writes the systemd units and configures Caddy for HTTPS. It joins the Kleo signet rather than starting a chain of its own — a second chain would not be a second hub but a second world, where nobody's names resolve but yours. Alongside the JSON-RPC the app uses, it answers a small HTTP API:

GET /health                 # ok
GET /v1/names/{name}        # keys and verified profile
GET /v1/names/{name}/pay    # payment methods
GET /v1/commitments/{hex}   # a document by its hash

The whole procedure, the ports — note that BitNames peers over UDP, so a TCP check on 4002 will always look closed — and what to do when it goes wrong are in Running a Kleo hub.

Roadmap

What's done, what's next

Each phase ended in a runnable, tested build, checked against a real plain-bitnames regtest. All twelve are in, plus vault backup, forward secrecy and a lock for the app itself. What remains needs a certificate or a decision, not a design.

Shipped

Twelve phases

Node and Notepad, identity and profiles, files, direct messages, hubs, everyday chat, the wallet, paid messages, channels, release engineering.

Since

Backup, secrecy, a lock

One encrypted file for everything Kleo keeps privately; a Double Ratchet between names that publish a prekey; a passphrase that takes the vault key out of the keychain.

Next

A certificate, mostly

Signing and notarization, an update channel, reproducible builds — and fees to post in busy channels, plus rotating prekeys on a schedule.

Questions

Reasonable doubts

Is this PGP with extra steps?

No — there is no OpenPGP anywhere in Kleo. The hard part of PGP was never the algebra, it was the keyring: finding a key, believing it, noticing when it changed. A BitName answers all three, because the key is published by the name on a chain anyone can read.

Do I have to run my own node?

You should. The node holds your wallet and does the cryptography, and its answers are what every verdict rests on. Kleo can point at a remote node behind an HTTPS proxy with auth, but then you are trusting whoever runs it to tell the truth about the chain.

What happens if someone steals a name's keys?

The owner publishes new ones. Everyone who has that name saved sees the contact flagged, encrypting to it is blocked until they review, and old signatures start reading “isn't signed with the key they publish now” — which is the warning you want, rather than silence.

Can the people hosting profiles read them?

Profiles are public documents, so yes — that's their job. What a host can't do is change one: Kleo hashes what it receives and compares with the on-chain commitment, and shows nothing that doesn't match. Messages and files are a different matter; those are encrypted end to end and no host ever sees them.

Does chat work when my friend is asleep?

Yes, if either of you has a hub configured. The message waits there — signed by you, sealed to them — until they collect it. A hub sees that someone sent them something, when, and how big; never what it said, and it cannot forge one. With no hub, both of you have to be online at once.

What stops strangers flooding me?

Writing to you at all costs a BitName, which has to be registered on a chain. On top of that you can publish a price for people you've never spoken to: their first message arrives as a payment carrying the message, and anyone you reply to writes free from then on. Blocking is separate, local, and never announced.

Can I run the infrastructure myself?

All of it. kleo-hub is one binary that hosts profiles, holds mail, answers where machines are, and keeps channel posts; point Kleo at yours and it never touches anyone else's. The defaults exist so a new install works, not because they are required.

If my key is stolen, can someone read old messages?

In a conversation where both names publish a prekey, no: each message has its own key, derived, used once and dropped, so the BitName key opens none of it — before or after. Everywhere else — the Notepad, files, paid messages, channel posts — a message is encrypted to a long-lived key, and someone who obtains that key and kept the ciphertext can read it. Kleo says which kind of conversation you are in. The ratchet is Kleo's own implementation of a well-known design, not an audited library, and the threat model says so.

What happens when I get a new laptop?

The recovery phrase brings back the wallet and its names. Everything else Kleo holds — contacts, the keys you pinned, blocks, invitations, followed channels, conversations — comes from a backup file you made, encrypted to a passphrase. Without one, the names come back and the history does not.

Which cryptography is actually used?

For anything addressed to a BitName, whatever plain-bitnames uses, done by your node: Ed25519 signatures with the arbitrary domain separator, ECIES over X25519 with AES-256-GCM, and BLAKE3 for hashing. Kleo adds three things its node cannot do for it: XChaCha20-Poly1305 for the local vault, Argon2id for a backup's passphrase, and the message ratchet — X25519, HKDF-SHA256 and XChaCha20-Poly1305 — which exists precisely so that the node's long-lived keys stop being able to open old messages.