Files
- .cargo2w ago
- crates2w ago
- nix2w ago
- web2w ago
- .cade11 B2w ago
- .gitignore166 B2w ago
- .mcp.json618 B2w ago
- Cargo.lock136.0 KiB2w ago
- Cargo.toml815 B2w ago
- flake.lock1.6 KiB2w ago
- flake.nix11.8 KiB2w ago
- MACLTOK_IMAGE_PACKS.md2.8 KiB2w ago
- MACLTOK_MEDIA_STREAM.md3.6 KiB2w ago
- MACLTOK_PRESHARE.md4.3 KiB2w ago
- MACLTOK_PROTOCOL_LEAKS.md4.7 KiB2w ago
- MACLTOK_URL_PREVIEW.md2.6 KiB2w ago
- README.md5.0 KiB2w ago
Malice
Malice is a hosted Matrix client with a Rust backend built on macltok and a Svelte frontend. The Nix package serves both the API and the built frontend.
NixOS module
Add this repository to your NixOS flake inputs, then include its module:
# In your flake.nix
inputs.malice.url = "git+file:///absolute/path/to/malice";
# In the modules list for your nixosSystem:
malice.nixosModules.defaultUse a published Git URL instead of the local path if you deploy from another machine. For a local Git flake, add new source files to Git before rebuilding; Nix does not include untracked files.
Enable the service in your NixOS configuration. For access from another machine, put it behind an HTTPS reverse proxy; the service binds to localhost and uses Secure session cookies by default:
{
services.malice.enable = true;
# Optional: services.malice.port = 3000;
services.nginx.enable = true;
networking.firewall.allowedTCPPorts = [ 80 443 ];
services.nginx.virtualHosts."chat.example.org" = {
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://127.0.0.1:3000";
extraConfig = ''
proxy_set_header Host $host;
proxy_buffering off; # Keep event-stream updates timely.
'';
};
};
security.acme.acceptTerms = true;
security.acme.defaults.email = "you@example.org";
}Replace the domain and ACME email, then rebuild your NixOS configuration as
usual. Check systemctl status malice and visit https://chat.example.org/.
The module stores the master key and sessions in /var/lib/malice; back up that
entire directory together. Its listenAddress, port, package, and
openFirewall options can be overridden. Do not expose the HTTP listener
without a trusted TLS proxy.
Client behavior
The home list shows non-space rooms (channels); Matrix spaces have their own navigation and show their advertised child rooms. A Matrix homeserver is the network address used at sign-in, not a space. Sending a message returns a queued command, then the timeline shows whether delivery is queued, sending, confirmed by the server, or failed. Opening a room loads its timeline; scrolling up loads older history. Images and avatars are served through authenticated, bounded media endpoints; SVG content is not rendered. Link previews embedded by the sender always show. Otherwise the homeserver fetches previews in unencrypted rooms, and in encrypted rooms only when the user enables it in the Security panel. Room admins can disable previews per room.
The Security panel accepts incoming device-verification requests and supports emoji/number comparison, confirmation, rejection, and recovery-key entry. Recovery keys and encryption state are per Matrix account; preserve the local session data when migrating an installation.
Development
From the repository root:
nix developThe dev shell links web/node_modules from a nix build of web/package-lock.json,
so there is no install step. After changing dependencies in web/package.json,
refresh the lockfile with npm --prefix web install --package-lock-only and
re-enter the shell.
For live frontend changes, start these in separate terminals inside nix develop:
MALICE_SESSION_COOKIE_SECURE=false cargo run --bin malice
npm --prefix web run devOpen http://127.0.0.1:5173/. Vite proxies /api to the Rust server on port
3000. The cookie override is for local HTTP development only. By default,
Malice accepts HTTPS homeservers; set MALICE_ALLOW_HTTP_HOMESERVER=true only
when testing against a trusted local HTTP homeserver.
To serve the built frontend directly from Rust instead of using Vite:
npm --prefix web run build
MALICE_SESSION_COOKIE_SECURE=false cargo run --bin maliceOpen http://127.0.0.1:3000/. Rust uses web/dist unless MALICE_WEB_DIR
points at another built frontend directory. Local session data defaults to
local-data/; set MALICE_DATA_DIR to use another directory. Keep its
master.key and session files private.
Storybook
Component stories live next to their components as web/src/**/*.stories.ts.
Storybook runs inside nix develop:
cd web
npm run storybook
npm run build-storybookOpen http://localhost:6006/. While it runs, @storybook/addon-mcp serves an
MCP endpoint at http://localhost:6006/mcp, which the repository .mcp.json
registers for Claude Code in this project only.
Testing
In nix develop:
cargo fmt -- --check
cargo clippy --all-targets -- -D warnings
cargo test --all-targets
npm --prefix web run check
npm --prefix web test
npm --prefix web run buildThe Rust integration test uses a mocked Matrix homeserver; it does not require live account credentials. To verify the deployable package and NixOS module:
nix build .#server
nix flake checknix build creates result/bin/malice with the frontend bundled. On a NixOS
host, curl -fsS http://127.0.0.1:3000/api/health checks the local backend;
opening the proxied URL checks the frontend and TLS setup.