Skip to main content

P2P end-to-end encrypted terminal chat with AI integration

Project description

kirbus

PyPI CI

kirbus screenshot

A peer-to-peer, end-to-end encrypted terminal chat with built-in AI integration.

  • Private by design — messages are encrypted between peers; no server ever sees content
  • No accounts — identity is an Ed25519 keypair generated on first run
  • Zero-config start — connect to the public registry and pick a server, no URLs needed
  • Works anywhere — direct LAN connections or through a relay server for internet use
  • Local AI/ai command talks to a local Ollama instance; AI context is shared between peers
  • Retro terminal UI — five built-in themes, channel support, scratch pad

Quick start

pip install kirbus
kirbus --handle yourname

That's it. The client connects to the default registry at kirbus.ai, shows you available servers, and you pick one with Tab + Enter.

Requires Python 3.11+. Or run from source with uv:

git clone https://github.com/wehale/kirbus.git
cd kirbus
uv run kirbus --handle yourname

After install, kirbus, kirbus-server, and kirbus-registry are available as commands. If running from the repo with uv instead, prefix with uv run (e.g. uv run kirbus).


LAN mode (no server needed)

# Terminal 1 — listen
kirbus --handle alice --listen 9000

# Terminal 2 — connect
kirbus --handle bob --connect localhost:9000

Registry

The registry is a public directory of kirbus servers. The default registry is https://ezchat.kirbus.ai. When you run kirbus --handle yourname, it fetches the server list and lets you pick one.

To use a different registry:

kirbus --handle yourname --registry https://custom.example.com

To skip the registry and connect directly to a known server:

kirbus --handle yourname --server http://SERVER_IP:8000

Running your own server

One person runs kirbus-server on a machine with a public IP. Everyone else connects through the registry or via --server.

kirbus-server --config server.toml

Open ports 8000 (rendezvous API) and 9001 (TCP relay) in your firewall.

Example server.toml:

[server]
host       = "0.0.0.0"
api_port   = 8000
relay_port = 9001
ttl        = 60
log_level  = "info"

[registry]
url         = "https://ezchat.kirbus.ai"
name        = "my-server"
description = "A public kirbus server"
secret      = "CHANGE_ME"
access      = "open"
public_url  = "http://YOUR_PUBLIC_IP:8000"

[auth]
mode = "open"

Server access modes

Mode Description
open Anyone can join
password Password required on first connect; pubkey saved for future access
allowlist Only pre-approved pubkeys can connect

For password-protected servers, add to server.toml:

[auth]
mode     = "password"
password = "your-server-password"

Superuser (admin)

Connect from the same machine as the server with the --su flag:

kirbus --handle admin --su

Su users get admin commands: /kick, /ban, /unban, /who.


Running your own registry

kirbus-registry --config registry.toml

Example registry.toml:

[registry]
host          = "0.0.0.0"
port          = 8080
heartbeat_ttl = 180
log_level     = "info"

Servers register themselves via heartbeat. The registry is stateless — listings live in memory and rebuild from heartbeats.


Encrypted history

Encrypt chat logs at rest with a passphrase:

kirbus --handle yourname --encrypt-history

First run prompts you to set a passphrase. Subsequent runs prompt for the passphrase to unlock history. The passphrase is never stored — without it, the history files are unreadable.

To decrypt history for export:

kirbus --decrypt-history @alice > alice.log
kirbus --decrypt-history '#general' > general.log

To disable encryption and decrypt everything back to plaintext:

kirbus --handle yourname --no-encrypt-history

Multiple identities

Each --handle gets its own data directory (~/.kirbus-{handle}/) with its own keypair, peers, and history:

kirbus --handle work-me
kirbus --handle personal-me

Override with KIRBUS_HOME:

KIRBUS_HOME=~/.kirbus-custom kirbus --handle custom

Configuration

~/.kirbus-{handle}/config.toml — created automatically on first run.

[ui]
theme  = "ansi_bbs"        # phosphor_green | amber_terminal | c64 | ansi_bbs | paper_white
handle = "you"
encrypt_history = false

[ai]
provider = "openai-compat"
model    = "gemma3:4b"
base_url = "http://localhost:11434/v1"
api_key  = ""

Commands

Command Description
/help Show all commands
/ai <prompt> Ask the AI; response shown in conversation
/ai-peer Forward the last peer message to your local AI
/theme <name> Switch theme
/themes List available themes
/accept [peer] Accept a new or key-changed peer
/block [peer] Mark a peer as blocked
/unblock [peer] Remove blocked mark
/servers Refresh server list from registry
/connect <name> Connect to a server by name
/disconnect Leave current server, return to server list
/channel create <name> Create a channel
/channel join <name> Join a channel
/channel invite <peer> [channel] Invite a peer to a channel
/channel leave <name> Leave a channel
/clear Clear chat history
/quit Exit

Su commands (admin only):

Command Description
/kick <handle> Disconnect a peer
/ban <handle> Kick and revoke access
/unban <handle> Restore access
/who List connected peers with details

Keyboard shortcuts:

Key Action
Tab Focus peer list
/ Navigate peers or command history
Enter Select peer / send message
Esc Return focus to input
PgUp / PgDn Scroll chat
Mouse wheel Scroll chat

AI integration

kirbus uses Ollama for local AI.

# Install Ollama, then pull a model
ollama pull gemma3:4b

# Ask the AI in any conversation
/ai what's the capital of France?

AI context is shared between peers — if alice asks a question and bob follows up, the AI sees the full conversation history.

/ai-peer grabs the last message from your peer and forwards it to your AI automatically.

Each person's /ai runs against their own local model. For cloud AI, point base_url at any OpenAI-compatible endpoint and set api_key.

WSL2 note: if Ollama is running on Windows, set OLLAMA_HOST=0.0.0.0 before starting it and point base_url at the Windows host IP (find it with ip route | grep default | awk '{print $3}').


Verify message signatures

Every message is signed with the sender's Ed25519 key and stored in ~/.kirbus-{handle}/history/.

kirbus --verify-log @alice
kirbus --verify-log '#general'
kirbus --verify-log scratch

Test mode

Try the UI without any network setup:

kirbus --test

Simulated peers come online, join channels, and respond to messages.


Deploy to AWS

A CDK stack is included in deploy/ to provision an EC2 instance with the registry and a lobby server:

cd deploy
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cdk deploy -c key_name=your-ssh-key

The stack creates an EC2 instance, Elastic IP, security group, nginx reverse proxy, and Let's Encrypt TLS. See deploy/kirbus_stack.py for details.


Security model

  • Identity — Ed25519 keypair, generated locally, never leaves your machine
  • Key exchange — X25519 ECDH ephemeral keys per session
  • Encryption — AES-256-GCM with HKDF-derived keys
  • Message signing — every message signed by sender's Ed25519 key
  • History encryption — optional AES-256-GCM at rest with scrypt-derived key
  • Server auth — password gate + pubkey allowlist for access control
  • Relay — the relay server pipes opaque ciphertext; it cannot read messages
  • Rendezvous — registrations are signed; the server stores handle → IP:port for 60 seconds then discards
  • Registry — stateless directory; never touches chat traffic

Self-host the server and registry for full sovereignty.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

kirbus-0.3.1.tar.gz (295.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

kirbus-0.3.1-py3-none-any.whl (133.1 kB view details)

Uploaded Python 3

File details

Details for the file kirbus-0.3.1.tar.gz.

File metadata

  • Download URL: kirbus-0.3.1.tar.gz
  • Upload date:
  • Size: 295.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for kirbus-0.3.1.tar.gz
Algorithm Hash digest
SHA256 32cef6f7cef563caf4d32105ea59293670d4601ce301bd048bbf891b31ae6ce7
MD5 72ca77fc02f52e97141c78ef3efa9458
BLAKE2b-256 94b50356c955056cfe9ed31d6a95f2d456304b2ba650c2eae7b91510fdbad2a9

See more details on using hashes here.

Provenance

The following attestation bundles were made for kirbus-0.3.1.tar.gz:

Publisher: publish.yml on wehale/kirbus

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file kirbus-0.3.1-py3-none-any.whl.

File metadata

  • Download URL: kirbus-0.3.1-py3-none-any.whl
  • Upload date:
  • Size: 133.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for kirbus-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 084f3d12aceb42709d8925e0eff64e9e55d895fa286de88a78d1dcab151c9ca9
MD5 ce4fdd2d477a75860ba665ad8ced2d23
BLAKE2b-256 8ee9b4dc9a41b5ec12165bfd95c0c59bc90945754e693069c207805e3c764b44

See more details on using hashes here.

Provenance

The following attestation bundles were made for kirbus-0.3.1-py3-none-any.whl:

Publisher: publish.yml on wehale/kirbus

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page