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.4.0.tar.gz (304.3 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.4.0-py3-none-any.whl (140.3 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for kirbus-0.4.0.tar.gz
Algorithm Hash digest
SHA256 73f7d80c66916e59add1f06d1bb5a3d75deaea91a5da066d6e4b51ef047b80b2
MD5 2d720513db66f1f6fe91d0936efaa256
BLAKE2b-256 5476c098df715993a713a4b1cb5f1dced85ddb4773ccb9445fe5ed1ec757a4c1

See more details on using hashes here.

Provenance

The following attestation bundles were made for kirbus-0.4.0.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.4.0-py3-none-any.whl.

File metadata

  • Download URL: kirbus-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 140.3 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.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 acca1610a266d93eab9e2d92efe3c4781bafb3b5ef821875db2f13db78d0c434
MD5 158841a2bd19218011e0c1870f34a70d
BLAKE2b-256 037d91cd5c429a666ad3e59d694862e9505c5017b238ab8eb250344c523e0409

See more details on using hashes here.

Provenance

The following attestation bundles were made for kirbus-0.4.0-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