Right on the wire
  • Rust 51%
  • QML 10.8%
  • Python 7.7%
  • Svelte 7.3%
  • TypeScript 7.2%
  • Other 16%
Find a file
firebadnofire 6cc2f6286d
Some checks failed
Cords checks / Native Qt desktop (Windows x86_64) (push) Waiting to run
Cords checks / Native Qt desktop (macOS) (push) Failing after 46s
Cords checks / rust-and-frontend (push) Failing after 2m47s
Cords checks / containers (push) Failing after 30s
Cords checks / Native Qt desktop (Linux x86_64) (push) Successful in 6m57s
commit
2026-11-02 16:20:19 -05:00
.forgejo commit 2026-11-02 16:20:19 -05:00
assets/avatar-codec commit 2026-10-16 09:03:51 -04:00
bins commit 2026-10-29 18:14:36 -04:00
build-scripts commit 2026-11-02 16:20:19 -05:00
crates commit 2026-10-29 18:14:36 -04:00
deploy commit 2026-10-16 15:46:25 -04:00
docs commit 2026-10-29 18:14:36 -04:00
migrations commit 2026-10-21 23:06:03 -04:00
packaging commit 2026-08-05 21:11:06 -04:00
scripts commit 2026-11-02 16:20:19 -05:00
test-vectors commit 2026-10-11 15:38:59 -04:00
tests/e2e commit 2026-10-21 11:56:47 -04:00
tools/avatar-codec commit 2026-10-19 10:32:02 -04:00
.dockerignore commit 2026-10-04 21:27:38 -04:00
.gitattributes commit 2026-09-30 13:59:10 -04:00
.gitignore commit 2026-11-02 16:20:19 -05:00
.gitleaks.toml commit 2026-10-04 21:27:38 -04:00
AGENTS.md commit 2026-10-19 22:43:58 -04:00
aqtinstall.log commit 2026-10-16 20:31:58 -04:00
Cargo.lock commit 2026-10-19 10:32:02 -04:00
Cargo.toml commit 2026-10-16 12:45:18 -04:00
CHECKPOINT.md commit 2026-10-10 01:57:48 -04:00
compose.yaml commit 2026-08-05 23:00:19 -04:00
cords-up.sh commit 2026-10-20 18:38:52 -04:00
deny.toml commit 2026-10-11 15:38:59 -04:00
dissection.md commit 2026-10-10 01:57:48 -04:00
KEY-SYSTEM.md commit 2026-10-15 18:31:03 -04:00
LICENSE Initial commit 2026-08-05 19:57:38 -04:00
README.md commit 2026-10-16 15:46:25 -04:00
ROADMAP.md commit 2026-10-10 10:27:39 -04:00
rust-toolchain.toml commit 2026-08-05 21:11:06 -04:00
test-e2e.ps1 commit 2026-10-20 18:38:52 -04:00
test-e2e.sh commit 2026-10-20 18:38:52 -04:00
UI-DESIGN.md commit 2026-10-21 23:06:03 -04:00

Cords

Right on the wire

Cords is a self-hosted communication system designed to keep message and attachment plaintext on authorized client devices. The working tree now implements a development encrypted-channel slice: independent native identities, server pinning, device authentication, MLS, durable HTTP synchronization and WebSocket notifications.

New server operators should start with the Cords server operator guide, which covers OCI deployment with Docker or Podman and direct installation from the unpacked server tarball.

The CLI and native Qt Quick/QML desktop use the same Rust client core. The desktop migration remains in progress; see its acceptance ledger. See the encrypted milestone guide and validation report for reproducible commands, real .54 evidence and remaining gates. Attachments, calls, DMs, full enrollment and recovery remain deferred; this is not a production release claim.

Repository

  • bins/cords-client/qt: native Qt 6 Quick/QML desktop and typed Rust bridge.
  • bins/cords-client/ui and src-tauri: temporary legacy reference pending parity/removal.
  • bins/cords-server: Axum server executable and configuration.
  • crates/cords-protocol: public schemas and deterministic signed encoding.
  • bins/cords-dev: development CLI around the real client core.
  • crates/cords-client-core: protected state, identity, trust, MLS orchestration and synchronization.
  • crates/cords-server-core: persistent server identity and HTTP services.
  • crates/cords-storage: PostgreSQL and SQLite lifecycle adapters.
  • docs/adr: architecture decisions; AGENTS.md is the normative product specification.

Run the server

docker compose up --build --wait
curl -i http://127.0.0.1:4849/health/ready

The base Compose topology exposes internal HTTP on loopback port 4849 for health diagnostics. It is not a client origin. Run the optional Caddy profile for local HTTPS:

docker compose --profile proxy up --build --wait

Caddy uses its internal CA for this local example. Trust that CA explicitly before inspecting https://localhost:4848; Cords never disables normal TLS validation. Production deployments should use a publicly trusted certificate and set CORDS_SERVER__PUBLIC_ORIGIN to the matching HTTPS origin.

The example server requires owner approval for new device membership by default. The owner reviews pending requests under Server settings → Members. Set server.join_policy = "public" explicitly for immediate admission. Approved members can discover channel names and stable channel IDs, but cannot read encrypted contents until added to each channel's MLS group. Channel creation is owner-only.

The Compose file uses a conspicuous development-only PostgreSQL password. A deployment must apply deploy/compose.production.example.yaml as an override and provide a matching, URL-encoded CORDS_DATABASE__URL; do not reuse the development credential publicly.

Clients join with the HTTPS URL only. Cords validates the certificate, verifies signed discovery, pins the discovered server identity on first use, and refuses later identity changes for that origin. The pinned fingerprint remains visible for inspection; it is not a join form field.

On a fresh database the server enters UNCLAIMED, generates a 256-bit one-time code, and writes the plaintext once to its operator log. It persists only a server-bound verifier. Read the initial code:

docker compose logs cords-server

Connect the desktop client over its normal certificate-validated HTTPS origin. Signed discovery reports that the server is unclaimed and presents the claim form before ordinary joining. Enter the server-generated code there. The claim proves both the device key and account root key, atomically creates the first membership as owner, and permanently consumes the verifier. Restrict access to bootstrap logs. Before a successful claim, rotate a possibly exposed code with:

docker compose run --rm cords-server --config /opt/cords/server.toml ownership-bootstrap rotate

A populated legacy database without an owner is never assigned one implicitly; its operator must run the same command with initialize instead of rotate. See the operator guide for backup and migration details.

Run the desktop client

Install Rust 1.97.1, Qt 6.10.3, CMake, Python 3 and the native C++ toolchain. The platform build scripts build/test/package the new UI. For example on Linux:

export CORDS_QT_PREFIX="$HOME/Qt/6.10.3/gcc_64"
bash build-scripts/linux-client-tar.sh
# Extract dist/cords-client-linux-<arch>-<version>.tar.gz, then run bin/Cords.

The packaged desktop client also accepts --list-accounts and --account <account-ID> --password-stdin. Listing returns only picker-safe labels and IDs; hidden nicknames stay hidden. Unlocking verifies the existing vault password and retains normal account isolation and auto-lock behavior. With no arguments, startup still opens the account picker. A failed unlock exits nonzero.

Passwords are read from the first UTF-8 line of redirected stdin (maximum 4096 bytes). Do not put passwords in argv, environment variables, shell history or files. For example, a Python parent can prompt without echo and supply the pipe:

import getpass
import subprocess

client = r"C:\path\to\Cords.exe"  # Use the installed executable on other platforms.
accounts = subprocess.run([client, "--list-accounts"], check=True, capture_output=True, text=True)
print(accounts.stdout)
account_id = input("Account ID: ")
password = getpass.getpass("Vault password: ")
process = subprocess.Popen([client, "--account", account_id, "--password-stdin"], stdin=subprocess.PIPE)
process.communicate((password + "\n").encode("utf-8"))
raise SystemExit(process.returncode)

The example waits until the desktop window closes. Python is only an example pipe provider, not a client dependency. A password manager or another parent process can provide the same redirected input. Native password buffers are zeroized after verification; the caller remains responsible for its own memory. Existing CORDS_CLIENT_STATE, CORDS_CLIENT_MIGRATIONS and CORDS_CLIENT_CA overrides select the vault/resources and certificate trust as before. Windows GUI builds expose help/list/errors when stdout/stderr are redirected by the caller.

Checks

cargo fmt --all -- --check
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test --workspace --all-features
cargo deny check
# Desktop builders also run QML lint and CTest with the selected Qt SDK.

Releases and containers

The sole canonical repository is firebadnofire/cords on Forgejo. CI/release definitions, package scripts, public signing pins and policies live in this monorepo. Privileged publication is disabled while execution isolation, protected-tag authorization and authenticated artifact provenance are validated. The current release workflow is an activation stop, not a passing release gate.

The selected release targets remain Linux client/server, native macOS DMG/PKG/server, native Windows builds and multi-architecture OCI images. A Qt/MSVC Linux cross-build is not yet validated. The proposed external executor verifies mandatory tests and exact authorized source identity before GPG .asc file signing, Cosign signing in Forgejo/GHCR, and verified GitHub mirroring. Publication credentials belong outside ordinary Actions secret scope. See the implementation plan, executor contract and validation evidence. Existing release history is preserved.

The public GitHub container is pulled with:

docker pull ghcr.io/firebadnofire/cords

Local native and cross-platform release builders are documented in build-scripts/README.md. They produce client and server file artifacts under dist/, plus a locally loaded server container image, without publishing anything.

Validation boundary

Unit tests and Compose readiness alone do not prove encrypted messaging. The real-server acceptance runner supplies that evidence. A native Qt build does not substitute for native interaction testing, and neither establishes cross-platform signing, a published release, or complete production identity UX.