Documentation
How to install, configure, and use Undertown.
1. Getting Started
First Launch
When you open Undertown for the first time, you’ll be asked to create a session password. This password protects your local encrypted session file. It never leaves your device.
# Create your session (first time) Password: ********** Confirm: ********** [Create Session] # On subsequent launches Password: ********** [Unlock]
Creating a Wallet
After unlocking, you’ll be taken to the wallet manager. Choose Create New Wallet to generate an Ethereum-compatible keypair, or Import to restore one from a private key or mnemonic phrase.
Wallet Manager ├─ Create New Wallet → generates new keypair ├─ Import Private Key → paste hex key └─ Import Mnemonic → BIP39 phrase (12/24 words)
Adding a Network
Go to Settings → Networks. Add a blockchain network by providing:
- Name — display label (e.g. “Anvil Local”)
- Chain ID — numeric chain identifier (e.g.
31337) - RPC URL — JSON-RPC endpoint (e.g.
http://localhost:8545)
Ethereum Mainnet and common testnets ship with default RPC endpoints.
2. Wallet
Undertown uses a non-custodial wallet. Your private key is encrypted with a derived key from your session password and stored locally in SQLite.
View Balance
The Wallet tab shows your current address, ETH balance, and a QR code for receiving funds. Copy your address with the copy button.
Switch Wallets
Go to Settings → Wallets to see all managed wallets. Tap any wallet to set it as the active one. The current wallet determines your identity and which groups you can access.
3. Groups & Contracts
Every group in Undertown is a smart contract deployed on a blockchain network. The contract manages membership, channels, and access control.
Deploy a Group Contract
From the sidebar, click + Add Contract. A wizard will guide you through:
- Select network — which blockchain to deploy on
- Choose privacy — public or private group
- Set name — a human-readable label
- Confirm & sign — your wallet signs the deployment transaction
Deployment requires gas (ETH on the target network). The contract address appears in your sidebar once confirmed.
Join a Group
To join an existing group, the group owner must approve your wallet address. Once approved, the contract will appear in your sidebar automatically via P2P sync.
Manage Members
Open a group and go to Contract Settings → Users:
- Pending — users requesting access. Approve or reject each one.
- Approved — current members. Remove if needed.
Channels
Each group can have multiple channels (topics). Go to Contract Settings → Channels to create, rename, or delete channels. Channels define the encryption scope — all members of the channel share a group key.
Contract Settings
The General tab under Contract Settings lets you rename the contract and view its address on a block explorer.
4. Messaging
Messages are end-to-end encrypted per channel. Encryption keys are derived from the group key and rotated as members join or leave.
Sending a Message
- Select a group from the sidebar
- Pick a channel
- Type your message and press Enter or click Send
Your message is encrypted locally, signed, and relayed through the P2P network. Other members fetch it from relays and decrypt it with the shared group key.
Post Sync
When you come online, Undertown syncs missed posts from peers via the Post Sync Protocol. Sync proceeds newest-to-oldest, filling gaps until your local clock matches the network. This ensures you never miss a message even if you were offline.
5. Contacts & Direct Messages
Direct messages (DMs) are private, encrypted conversations between two wallet addresses. Before you can DM someone, they need to be a contact — cryptographically verified through a handshake protocol.
What Is a Contact?
A Contact is a signed, shareable public identity record. It contains:
- Wallet address — the Ethereum address that signed it
- P2P keys — Ed25519 (signing) and X25519 (encryption) public keys
- Peer ID — libp2p identifier derived from the Ed25519 key
- Multiaddrs — how to reach this peer (direct IP, relay, LAN)
- Name — human-readable display name
- Expiration — contacts expire after 4 months (default) and must be rotated
The entire record is signed by the wallet and tamper-proof. Anyone can run contact.verify() to cryptographically confirm it belongs to the claimed wallet address — no trust required.
Sharing Your Contact
Go to the Contacts tab. Your own contact card appears at the top. You have two ways to share it:
- Copy Contact — copies a base58-encoded string to your clipboard. Paste it anywhere (chat, email, message).
- QR Code — generates a QR code. The other person scans it with their Undertown app.
The contact code looks like a long base58 string:
4jGkqR2...(base58-encoded JSON)
It contains no private keys — it’s safe to share publicly.
Adding Someone’s Contact
If someone sends you their contact code (text or QR), here’s how to add them:
- Go to Contacts from the sidebar
- Click Add Contact
- Paste the contact code into the text field
- Click Send Request
Behind the scenes, this:
- Decodes the base58 string back into the Contact JSON
- Verifies the wallet signature — confirms the contact truly belongs to that address
- Checks the contact hasn’t expired
- Sends a contact request (channel 35) through the P2P network
Accepting a Request
When someone sends you a contact request, it appears under From Others in your Contacts tab. You can accept or deny it.
- Accept — the contact moves to your Connected list. Both sides can now DM each other. An acceptance response (channel 36) is sent back through P2P.
- Deny — the request is rejected and the sender is notified.
Requests you’ve sent appear under Sent by You with a status indicator (pending, accepted, denied).
Sending a DM
Select a connected contact from the DM sidebar. Messages are encrypted for the specific wallet pair using X25519 key exchange and synced through the DM Sync Protocol — same clock-based sync as group posts. If the recipient is offline, your message is relayed and they’ll receive it when they come online.
Transmission Flow
Sender Relay Recipient │ │ │ ├── dm.transmission ──────►│ │ │ ├── notify ───────────────►│ │ │ ├── dm.sync.request │◄────────────────────────┤ │ │ │◄── dm.sync.response ─────┤ │ │ │
6. Identity & P2P
Your Identity
Your identity is a cryptographically signed Contact record containing:
- Wallet address — your on-chain identity
- P2P keys — Ed25519 keypair for libp2p
- Multiaddrs — how peers can reach you (direct, relay, LAN)
- Display name — optional human-readable label
- Expiration — identities expire and must be rotated
The entire contact record is signed by your wallet, so anyone can cryptographically verify it belongs to you.
Peer ID
Your Peer ID is derived from your P2P Ed25519 keypair. It’s stable across wallet switches — all your wallets share the same P2P identity within a session.
Identity Rotation
Go to Settings → Security to rotate your identity. This generates new P2P keys and multiaddrs while keeping the same wallet address. Old contacts remain valid until they expire.
Nearby Peers
If mDNS is enabled, Undertown discovers peers on your local network automatically. These appear under Nearby Peers on the dashboard.
7. Settings
Access settings from the sidebar gear icon or /home/settings.
General
Application version and basic info.
Appearance
Toggle between Dark and Light theme. System auto-detect is available.
Wallets
View all managed wallets, switch active wallet, create new, or import. See Wallet section above.
Networks
Add, edit, or remove blockchain networks. Each network has a name, chain ID, and RPC URL. The active network determines where contracts are deployed and where your wallet balances are fetched.
Security
- Lock session — immediately lock and require password to unlock
- Rotate identity — generate new P2P keys
- Session timeout — auto-lock after inactivity (default: 15 minutes)
Advanced
P2P configuration, debug logging, and data directory location.
8. AI Agent Integration
Undertown ships with an MCP (Model Context Protocol) server, allowing AI agents to interact with your node programmatically.
Starting the MCP Server
# Start in persistent mode (server stays alive) ut mcp start --persistent # Or from the Tauri app npm run tauri mcp start
Unlocking via MCP
# Unlock the session so the agent can sign ut mcp unlock <password>
Available Tools
Once connected, agents can call these tools (subset):
| Command | Description |
|---|---|
get_peer_id |
Return your P2P peer ID |
message_send |
Post a message to a group contract |
dm_send |
Send an encrypted direct message |
contract_deploy |
Deploy a new group contract |
approve_member |
Approve a pending member |
check_session |
Check session lock state |
Claude Desktop Integration
Add this to your Claude Desktop mcpServers config:
{
"mcpServers": {
"undertown": {
"command": "ut",
"args": ["mcp", "start", "--persistent"]
}
}
}
Hermes Agent
Hermes is the built-in AI agent for Undertown. It connects over the same MCP interface and can automate messaging, manage group membership, and monitor contract activity.
See hermes-agent/ in the project repository for setup and configuration.