Facelock is a Linux face authentication PAM module written in Rust. Single unified binary (facelock) handles CLI, daemon, one-shot auth, and benchmarks. The PAM module (pam_facelock.so) is a thin client that either connects to the daemon or spawns facelock auth. IPC uses the D-Bus system bus (org.facelock.Daemon), not Unix sockets.
Cargo workspace, 11 crates. What each is for — the manifests carry no description, so this is the only map.
facelock-core— config, types, errors, D-Bus interface, traitsfacelock-camera— V4L2 capture, auto-detection, preprocessingfacelock-face— ONNX inference (SCRFD + ArcFace)facelock-store— SQLite face embedding storagefacelock-daemon— auth/enroll logic, rate limiting, liveness, audit, D-Bus serverfacelock-cli— thefacelockbinary, plus a library target so the domain layer is testablefacelock-bench— standalone benchmark and calibration utilitypam-facelock— the PAM module, a thin client to the daemonfacelock-tpm— TPM-sealed key encryption, software AES-256-GCMfacelock-polkit— polkit authentication agentfacelock-test-support— mocks and fixtures
Dependencies are whatever the manifests say; there is no separate allowed-list to keep in sync. The one enforced boundary is the PAM ceiling below.
cargo build --workspace
cargo test --workspace
cargo clippy --workspace -- -D warnings
cargo run --bin facelock -- --helpGPU acceleration is a runtime option — no special build flags needed. Install a
GPU-enabled ONNX Runtime package and set execution_provider in config:
sudo pacman -S onnxruntime-opt-cuda # NVIDIA
# Then edit /etc/facelock/config.toml: execution_provider = "cuda"Supported providers: cpu (default), cuda (NVIDIA), rocm (AMD), openvino (Intel).
- Do not change binary names, paths, config keys, database schema, or auth semantics without updating
docs/contracts.md. - Keep the PAM module free of heavy dependencies (no ort, no v4l, no facelock-core).
pam_facelock.soloads into every PAM-using process,sshdandloginincluded. Full ceiling in.claude/rules/pam-boundary.md. - Keep all inference local. No cloud services, no runtime model downloads in the auth path.
- Prefer minimal dependencies and clear crate boundaries.
See .claude/rules/security.md, which loads when you open daemon, PAM, TPM, or auth-path sources.
thiserrorfor library error types,anyhowin binaries.- Return
Result<T>over panicking. Neverunwrap()in library code. tracingfor structured logging. Control verbosity viaRUST_LOGenv filter.#[cfg(test)]modules in each source file for tests.
See .claude/rules/testing.md, which loads when you open the justfile, test/, crate integration tests, or CI workflows.
- Version declared once in root
Cargo.toml, inherited viaversion.workspace = true. - Inter-crate deps use relative paths (
path = "../facelock-core"). - Release profile: LTO + single codegen unit + strip.
just release X.Y.Zbumps version in Cargo.toml, PKGBUILD, spec, debian/changelog.- Tag
vX.Y.Ztriggers CI to build binaries, .deb, and .rpm. - Update
CHANGELOG.mdbefore committing the release. - See
docs/releasing.mdfor full process and versioning contract.
Applies to anything an agent authors in this repository, including runs
triggered from GitHub (@claude in a comment or issue).
- Titles:
<type>(<scope>): <subject>. Types:featfixrefactorpolishdocstestcichoreperfbuildstylerevert. - No AI attribution anywhere: no "Generated with Claude Code" footer, no
Co-Authored-Bytrailer, no mention of Claude, AI, agents, or assistants in a title, body, commit message, or changelog entry. - Open PRs as drafts. The maintainer marks them ready.
- PR and issue bodies are bullets: verb-first fragments, lowercase, no terminal period. Prose only for the
Why, capped at four sentences. A small PR is two or three bullets with no headings. - Never paste command output, CI logs, or pass/fail tables into a PR. Naming a check under
Validationis fine; reporting its result is not. - Every PR says why the change exists. If it cannot be derived, ask; never invent one.
- Docs are part of the deliverable. A change to paths, config keys, CLI flags, D-Bus interface, or behavior updates
docs/(anddocs/contracts.mdwhere it applies) in the same PR.