Skip to main content

Dark Terminal Chat

Plain English terminal chat. No banner, logo, animation, or forced color. Python 3.10+.

pip install --upgrade dark-chat
dark-chat

iPhone / iSH installation and login.

Temporary chat

dark-chat --new
dark-chat --chat

The creator gets a secret invite code. Share it privately with the other person; they enter it at the prompt. Both commands use the hosted relay automatically. Each room has two slots. Temporary messages are never saved or queued. A disconnected participant has 60 seconds to reconnect. When both participants leave, or the server restarts, the old invite stops working.

Chats and offline messages

Both people start on their own devices:

dark-chat

On the first launch, choose your account password (at least 12 characters) and a username. Usernames have 3-24 letters, numbers, dots, dashes or underscores and start with a letter. Later launches ask only for your account password. Existing accounts keep their keys and conversations.

The app gives you a separate contact password. Share your username and contact password privately with people who should be able to start a chat with you. /profile shows both again. Keep your account password private; it unlocks your identity and is never needed by a friend. If a username is taken, choose another with /profile YOUR_USERNAME.

To start a new conversation:

/chat alice
Contact password for @alice: ************
Hello.

The contact password is hidden while typing. After the first introduction, /chat alice opens the saved conversation without asking again. Your friend must have opened the app at least once but can be offline when you write.

To open an existing conversation, type /chat, then enter its number:

/chat
1. alice (2 new)
2. bob
Number or username: 1

/chat 1 opens it directly. /chat alice also opens a received conversation when its displayed name is unique. If several chats share a name, choose a number. Incoming messages show the short command to open their conversation. Unread counts stay saved until you open the chat. Enter a new username in the same menu to start another chat, or use /cancel to go back. After typing /chat , the arrow keys can select a suggested saved contact.

Long IDs remain available through /id and /chat FULL_ID [local_name] for manual fingerprint verification and older contacts. They are no longer part of the normal chat flow. Names shown on incoming messages are display labels; verify a new contact using their privately shared username/password or full fingerprint. If moving your identity to another device, restore its backup first.

Outgoing messages are saved encrypted on your device before sending. Queued. means the local outbox accepted the message; it is not a read receipt. The outbox retries automatically in order. A full mailbox pauses that contact's queue while other conversations continue. The relay keeps encrypted messages until the recipient has saved and acknowledged them, for at most 30 days. Unconfirmed outgoing messages older than 30 days stop retrying and appear as [unconfirmed: expired] in local history; copy and resend their text if needed. They do not block newer messages. The last 50 locally saved messages appear when opening a conversation. /history shows them again.

The password unlocks this device's identity; it is never sent to the server. Logging in on another computer requires your encrypted identity backup as well as the password. Use one active device per identity; multi-device history synchronization is not provided.

Commands

Type / to display the command menu. Choose with the arrow keys and press Enter. /clean is the first option; / followed by Enter selects it. Typing clean also works.

Command Action
/clean or clean Close the chat and clear the terminal screen and supported scrollback
/exit or Ctrl+C Close the chat
/clear Delete the selected conversation's history for both people and stay in the chat
/help Show commands
/who Show temporary-room participants
/chat ID [name] Open a permanent conversation; optionally name the contact locally
/chat username Open a saved chat, or enter the contact password for a new one
/chat or /chat number Choose a chat or open one by its number
/contacts List chats and unread counts
/profile [username] Show your username/contact password; optionally change the username
/cancel Cancel chat selection or password entry
/id Show your permanent ID
/history Show the selected conversation's recent saved messages
/backup Create an encrypted identity backup and print its path

/clean exits dark-chat and clears the terminal; saved conversations remain. /exit closes without clearing the window. The command menu uses the terminal's normal colors and a simple selection highlight.

In permanent chat, /clear deletes the selected chat's saved history and queued messages on both clients. Contacts stay available, so you can keep chatting. If either person is offline, the signed deletion is saved and applied on reconnection before old messages can be retried. Both clients and the relay need version 3.2.0 or later. Older clients must update after a chat is cleared. Temporary chat has no saved history, so its /clear only clears the window.

Clearing cannot erase separate backups, terminal recordings, screenshots, modified third-party clients or operating-system memory. Scrollback clearing depends on the terminal; it is not secure forensic erasure.

Identity backup and recovery

While logged in, run /backup. Move the resulting encrypted file to a safe location on another device. It contains private keys, encrypted with your existing password. It does not contain conversation history. Anyone with both the backup and password can use your identity and decrypt messages addressed to it.

On a new device:

dark-chat --restore /path/to/identity-backup.json
dark-chat --login

Restore refuses to overwrite an existing identity. There is no server-side password reset or private-key recovery. For a complete local backup, close all clients and copy the whole ~/.dark-chat directory. History is encrypted and tied to the identity. DARK_CHAT_HOME selects a different profile directory.

Security model

Permanent messages use libsodium sealed boxes through PyNaCl and Ed25519 signatures. Clients verify the sender's key fingerprint and signature and the intended recipient. Authentication signs a fresh server challenge; old responses cannot log in again. Message IDs and durable acknowledgments suppress retries and replay. The server never receives private keys, account passwords, contact passwords, local contact aliases, or decrypted message text.

Each generated contact password has 72 random bits. The username and password derive an AES-256-GCM key that protects the public contact card; the relay stores the encrypted card and a one-way lookup token. Clients decrypt and authenticate the card before saving the keys. Share the contact password through a trusted channel. Anyone who has it can resolve that contact's keys; changing a username removes its old directory entry but does not revoke saved conversations. The relay sees usernames and directory lookups. Your own contact credentials are encrypted in the local history database; copy the entire profile directory to preserve them alongside history.

The identity file uses AES-256-GCM with a random salt/nonce and scrypt (N=131072, r=8, p=1) to protect against offline password guessing. Local message bodies and contact names use AES-256-GCM under an independent random storage key kept inside the encrypted identity. Files are owner-only on Unix; Windows uses the profile directory's inherited access permissions, plus encryption. Names/text received from peers are stripped of terminal control characters.

Temporary rooms continue to use AES-256-GCM with keys derived from their random 32-byte invite codes. A shared invite grants room access; it is not a permanent identity. Version 3 supports version 2 temporary clients. Permanent accounts require a version 3 server. Username introductions require both client and relay version 3.2.0 or later. Saved conversations and manual ID lookup continue to work with older version 3 relays.

Public Internet connections require verified WSS/TLS. Account mode refuses insecure remote/LAN connections even if --allow-insecure is supplied. Local loopback WS is available for development.

The relay sees IP addresses, public IDs/keys, sender/recipient relationships, timing, sizes, and delivery metadata. The local database exposes contact IDs and message metadata, although bodies and names are encrypted. There is no anonymity guarantee, forward secrecy against later compromise of a recipient's long-term private key, independent security audit, or protection from malware on an unlocked device. Sealed messages are signed, so they are not deniable. Terminal clearing does not change these limits.

Hosting

The default relay is wss://zubayr.alwaysdata.net/dark-chat/ws. Advanced options remain available but are hidden from the short help: --server, --name, --ca, --allow-insecure, --password-file, and --restore. DARK_CHAT_SERVER overrides the relay; DARK_CHAT_CODE provides a temporary invite for automation. --password-file reads a protected local file for automation; do not put passwords directly on a command line.

dark-chat-server --database /persistent/private/path/mailbox.db
dark-chat --server ws://127.0.0.1:8080/ws --new

Run one relay process. Its default database is ~/.dark-chat-server/mailbox.db, outside release directories; DARK_CHAT_DATABASE overrides it. Never put it in .deploy/releases. The server keeps ciphertext only and bounds storage to 1,000 identities, 1,000 pending messages overall, 100 pending messages per recipient, and 10,000 pending-message/delivery-receipt rows. A full mailbox returns an error while the encrypted outbox stays on the sender's device. Delivered ciphertext is deleted after acknowledgment; replay receipts expire after 30 days. Pending mail and public identities survive normal restarts and upgrades. Availability and backups of the server database remain the operator's responsibility.

AlwaysData setup and automatic updates. Package distribution.

Development

python -m venv .venv
python -m pip install -e . build twine
python -m unittest discover -s tests -v
python -m build
python -m twine check dist/*

Activate the virtual environment before installing. GitHub Actions tests installed wheels on Linux (Python 3.10 and 3.12) and Windows (Python 3.12). Only passing commits advance the deployment branch; AlwaysData tests the candidate again before activation. Tests cover offline delivery, database persistence, signatures, challenge replay, recipient isolation, key substitution, local encryption, CLI flows, and slash completion. A local test run does not establish live production behavior.

The earlier Node.js experiment is reference source only. The Python package is the application.

Metadata

Release files for dark-chat 3.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for dark-chat 3.2.0
File Size Uploaded Provenance
dark_chat-3.2.0.tar.gz 65.4 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for dark-chat 3.2.0
File Interpreter ABI Platform
dark_chat-3.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 102.2 kB

Release files / dark_chat-3.2.0.tar.gz

Download URL dark_chat-3.2.0.tar.gz
Size 65.4 kB
Tags Source
SHA-256 checksum
How to use checksums
998e7d0fee7ce346df38ae1cd2f670f813ff98735a47c19072d2533989807922
BLAKE2b-256 checksum
How to use checksums
4aea6fb434c51f60668eb61a0219f6a7589fc82292e2fdd62bd217422d06591b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Release files / dark_chat-3.2.0-py3-none-any.whl

Download URL dark_chat-3.2.0-py3-none-any.whl
Size 36.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a6136e66c37c239719b65ced7242e55643174364da9c95a47d9578b65af6d77d
BLAKE2b-256 checksum
How to use checksums
2a0fee79751c6e653ba4529a26c14a07866f663a98bc5e158596607d375bea0a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Security for dark-chat 3.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for dark_chat-3.2.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page