Getting started
Build mxd from source, create a user account, choose between the legacy and Wireframe runtimes, and deploy to production — all in one place.
Five-minute quickstart
Build the SQLite variant
mxd requires the Rust toolchain pinned by rust-toolchain.toml. Clone the repository and build the SQLite variant:
git clone https://github.com/leynos/mxd.git cd mxd make sqlite
The default build keeps legacy-networking enabled, so the classic mxd daemon remains part of the operator surface. Runtime selection is documented behaviour, not a packaging accident.
Create a user account
# The CLI prompts for a password securely (non-echoed). # For scripted/CI use only: --password <value> cargo run --bin mxd -- create-user --username alice
Start the daemon
cargo run --bin mxd -- --bind 0.0.0.0:5500 --database mxd.db
The server prints mxd listening on 0.0.0.0:5500 once the accept loop is running. Login compatibility is currently documented for Hotline 1.8.5, Hotline 1.9, and SynHX with partial status; use the compatibility matrix before assuming broader client parity.
Wireframe server
The mxd-wireframe-server binary runs the new transport runtime. It honours the same configuration surface — flags, env, TOML — and exposes identical admin subcommands.
make APP=mxd-wireframe-server sqlite cargo run --bin mxd-wireframe-server -- --bind 0.0.0.0:6600 --database mxd.db
Wireframe-only build:
disable default features with cargo build --no-default-features --features "sqlite toml"
to omit the legacy mxd
binary entirely while keeping the same CLI flags,
MXD_* overrides,
.mxd.toml defaults,
and admin subcommands.
PostgreSQL
Install the unprivileged embedded helper and switch the database URL:
cargo install --locked pg-embed-setup-unpriv --version 0.5.0 pg_embedded_setup_unpriv export MXD_DATABASE='postgres://postgres:<db-password>@localhost/mxd' cargo run --bin mxd -- --database "$MXD_DATABASE"
Running the test suite
make fmt make lint make test
make test exercises SQLite, PostgreSQL (if the helper has been run), and wireframe-only suites. No manual database setup required.
Installation
mxd builds from source. There is no binary distribution yet.
Prerequisites
The Rust toolchain version is pinned by rust-toolchain.toml in the repository root. cargo and make must be on the PATH. Optionally, install pg-embed-setup-unpriv for PostgreSQL-backed tests without a system-level database install.
Rust toolchain
Version pinned via rust-toolchain.toml
Build tools
cargo and make required
PostgreSQL (optional)
Install pg-embed-setup-unpriv for PostgreSQL tests without system database
Building
For SQLite (the default)
make sqlite
For PostgreSQL
make postgres
For the Wireframe server
make APP=mxd-wireframe-server sqlite
Shared operator surface:
both mxd and
mxd-wireframe-server
reuse the same CLI flags, MXD_*
environment overrides, .mxd.toml
defaults, and admin subcommands such as
create-user.
Runtime selection
The legacy-networking Cargo feature is enabled by default. That keeps the classic mxd binary available. Disabling default features changes the produced binaries and selects the Wireframe runtime as the active listener path:
cargo build --no-default-features --features "sqlite toml"
Feature flags:
This command disables all default features and explicitly
enables only sqlite
and toml. The
legacy mxd
binary is skipped via required-features,
and server::run()
invokes the Wireframe runtime instead.
Treat that runtime choice as user-facing behaviour. The repository documents and tests it explicitly with the Wireframe-first suite, rather than leaving it as an incidental build detail.
Deployment
Production deployment strategies for systemd, containers, and socket activation.
systemd
A recommended service unit:
[Unit] Description=Marrakesh Express Daemon After=network.target [Service] Type=notify ExecStart=/usr/local/bin/mxd --bind 0.0.0.0:5500 --database /var/lib/mxd/mxd.db User=mxd Group=mxd Restart=on-failure WatchdogSec=60s [Install] WantedBy=multi-user.target
Type=notify means mxd signals readiness to systemd after binding the socket and running migrations. WatchdogSec=60s means mxd sends a heartbeat every 20 seconds; if systemd doesn't hear one for 60 seconds, it restarts the process.
Socket activation is supported. Create a companion .socket unit that listens on port 5500; systemd holds incoming connections in queue during restarts so clients experience a pause, not a refusal.
Containers
The default bind address 0.0.0.0:5500 works inside a container without modification. Mount a volume at the database path for persistence:
docker run -v /data/mxd:/var/lib/mxd mxd:latest \ --bind 0.0.0.0:5500 --database /var/lib/mxd/mxd.db
For PostgreSQL, pass the connection string as an environment variable:
# Pass credentials via env file, not inline. docker run --env-file mxd.env mxd:latest
Development note: The fuzz harness ships with its own Dockerfile (fuzz/Dockerfile) that includes AFL++ and sanitizers. It is not intended for production use.
Deployment considerations
User isolation
Run mxd as a dedicated unprivileged user. Never run as root. The service unit example above creates an mxd user and group.
Database backups
For SQLite, back up the .db file while the daemon is stopped. For PostgreSQL, use pg_dump with appropriate scheduling.
Network binding
Bind to 0.0.0.0:5500 for external access or 127.0.0.1:5500 for local-only. Use a reverse proxy for TLS termination if required.
Restart policy
Use Restart=on-failure in systemd or equivalent restart policies in container orchestrators to handle transient failures gracefully.