End-to-end encrypted messaging for Bittensor.
Install • Getting started • TUI • CLI • SDK • Security
Built on SAMP (Substrate Account Messaging Protocol). Terminal UI, CLI, and embeddable Rust SDK.
brew install mcjkula/tap/taolk
Or with Cargo: cargo install taolk
Or from source: git clone https://github.com/mcjkula/taolk.git && cd taolk && cargo install --path .
Linux requires
libasound2-dev(Debian/Ubuntu),alsa-lib(Arch), oralsa-lib-devel(Fedora).
taolk wallet create --name <name>
The name identifies this wallet on the lock screen. Write down the 12-word recovery phrase before confirming.
taolk prints your address after creation. Each message is an on-chain transaction, so you need a small balance for fees. Transfer τ from an exchange or testnet faucet.
taolk --wallet <name> --mirror https://bittensor-finney.samp.ink
--wallet selects which wallet to unlock. --mirror connects to a SAMP mirror for channel discovery and message history. Both are optional.
Press m, paste your own address, pick public, type something. If it appears in your inbox, the full pipeline works.
Press n to start a thread with someone. Press c to browse public channels.
Press ? for the keybind reference. Press / to open the command palette.
| Context | Keys |
|---|---|
| Timeline | i compose, n thread, m message, c channels, g group, / commands, ? help, q quit |
| Composer | Enter send, Shift+Enter newline, Esc save draft and leave |
| Confirm | Enter submit transaction, Esc back to edit |
| Global | Ctrl+L lock, Ctrl+W switch wallet, Ctrl+C quit |
- Threads: encrypted 1:1 conversations (Ristretto255 ECDH + ChaCha20-Poly1305)
- Channels: public, named, discoverable
- Groups: encrypted multi-party, fixed membership
- One-off messages: public or encrypted, standalone
All messages are signed remarks on-chain with a verifiable sender.
Commands available via /:
| Command | What it does |
|---|---|
thread |
Start a new 1:1 thread |
message |
Send a standalone one-off message |
group |
Create a group conversation |
search |
Search messages in current view |
channels |
Browse the channel directory |
inbox |
Jump to inbox |
outbox |
Jump to sent |
sidebar |
Toggle sidebar |
help |
Show help overlay |
get |
Get remark(s) at block:index positions |
refresh |
Reload and fill message gaps |
copy |
Copy a sender's address |
unlock |
Unlock locked outbound messages |
lock |
Lock the session |
wallet |
Switch wallet |
quit |
Exit |
taolk wallet create --name <name> [--password <pw>]
taolk wallet import --name <name> --mnemonic "word1 word2 ..."
taolk wallet import --name <name> --seed <64-hex-chars>
taolk wallet list
taolk db clear [--wallet <name>]
taolk config get [<key>]
taolk config set <key> <value>
taolk config unset <key>
Use taolk as a library. No terminal dependencies.
[dependencies]
taolk = { path = ".", default-features = false }use taolk::{session::Session, event::Event, wallet};
#[tokio::main]
async fn main() -> taolk::error::Result<()> {
let seed = wallet::open("agent", "password")?;
let (session, mut events) = Session::start(
seed.as_bytes(), "wss://entrypoint-finney.opentensor.ai:443", "agent", true,
).await?;
while let Some(event) = events.recv().await {
match event {
Event::NewMessage { decrypted_body: Some(body), sender, .. } => {
println!("{}: {body}", taolk::util::ss58_short(&sender));
}
_ => {}
}
}
Ok(())
}~/.config/taolk/config.toml (XDG on Linux, ~/Library/Application Support/ on macOS).
| Key | Default | Description |
|---|---|---|
wallet.default |
Wallet to open on launch | |
network.node |
wss://entrypoint-finney.opentensor.ai:443 |
Subtensor node URL |
network.mirrors |
SAMP mirror URLs | |
security.lock_timeout |
300 |
Auto-lock seconds (0 = disabled) |
security.require_password_per_send |
false |
Prompt password for every transaction |
ui.sidebar_width |
28 |
Sidebar width |
ui.mouse |
true |
Mouse support |
ui.timestamp_format |
%H:%M |
Message time format |
ui.date_format |
%Y-%m-%d %H:%M |
Full date format |
Mirrors index SAMP remarks and serve them over HTTP for channel discovery and message history. Mirrors never see decrypted content. taolk verifies all data against the chain.
taolk config set network.mirrors https://bittensor-finney.samp.ink
| Network | URL |
|---|---|
| Mainnet | https://bittensor-finney.samp.ink |
| Testnet | https://bittensor-testnet.samp.ink |
Run your own with mirror-template.
Wallet files: Argon2id (64 MB, 3 iterations) + ChaCha20-Poly1305. Stored with 0600 permissions.
Secret types (Seed, Password, Phrase, SigningKey): no Clone, no Debug, no Display. All wrap Zeroizing and are zeroed on drop. When require_password_per_send is enabled, the signing key is not stored in memory. It exists only between password entry and transaction submission.
On the wire: 1:1 and group messages use ECDH on Ristretto255 with ChaCha20-Poly1305 AEAD. Channels are plaintext by design. The private key never leaves the client.
- Key reuse. sr25519 signing and Ristretto255 ECDH share the same scalar.
- No post-quantum resistance. Ristretto255 is broken by Shor.
- No forward secrecy. Seed compromise decrypts all past 1:1/thread messages.
cargo build --release # TUI + CLI
cargo check --no-default-features --lib # SDK only
cargo test # 374 tests
MIT. See LICENSE.
