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.

Requirements: minimum 8 characters. Use a strong, memorable password — there is no recovery mechanism.
# 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:

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:

  1. Select network — which blockchain to deploy on
  2. Choose privacy — public or private group
  3. Set name — a human-readable label
  4. 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:

Gas cost: each approval/rejection is an on-chain transaction and costs gas. Batch multiple actions into a single transaction to save fees.

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

  1. Select a group from the sidebar
  2. Pick a channel
  3. 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:

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:

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:

  1. Go to Contacts from the sidebar
  2. Click Add Contact
  3. Paste the contact code into the text field
  4. Click Send Request

Behind the scenes, this:

  1. Decodes the base58 string back into the Contact JSON
  2. Verifies the wallet signature — confirms the contact truly belongs to that address
  3. Checks the contact hasn’t expired
  4. Sends a contact request (channel 35) through the P2P network
Verification is automatic. If the signature doesn’t match the wallet address, the contact is rejected before any request is sent. You can’t accidentally add a fake contact.

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.

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:

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

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.