Skip to main content

face-recognition-cli

Face recognition and identity management: detect faces, collect embeddings per identity, and manage them by generated id and human name — enroll, match, list, forget one, and forget all at once.

The engine is OpenCV YuNet (detection) + SFace (128-dim embeddings), extracted from reachy-mini-cli so Reachy Mini can depend on this package instead of carrying its own copy. The engine, the store, per-consumer face banks, and all five domain verbs are implemented and covered below.

Install

pip install 'face-recognition-cli[cpu]'

The installed console script is face-recognition. The import package is face_recognition_cli — deliberately not face_recognition, which is the import name of the unrelated dlib-based face-recognition distribution on PyPI.

Compute-class extras — both install the same opencv-python-headless package and load the same two ONNX models, so the choice between them is about where inference runs, never which model runs:

Extra Target What it buys
[cpu] Raspberry-Pi-class boxes, incl. the Reachy Mini robot The default path. Detection and embedding both run on CPU.
[gpu] DGX Spark, Jetson, RTX-class hosts Opportunistic acceleration: if the locally installed OpenCV build carries a CUDA DNN backend, the detector runs through it. The PyPI opencv-python-headless wheel ships no CUDA DNN, so this only activates on a locally built OpenCV (Jetson/DGX images typically carry one) — on a plain pip install, [gpu] behaves identically to [cpu].

The recognizer deliberately stays on CPU on both extras, so the 128-dim embedding it produces is bit-identical no matter which host produced it. This is the hard invariant: both extras run the same ONNX models and produce the same embedding space — a face enrolled on a Jetson matches on a Pi, and vice versa. [gpu] accelerates execution only; it never swaps in a different model, because that would silently fork the embedding space and make stored faces unmatchable across machines.

A bare install (neither extra) stays importable — the introspection verbs (whoami, learn, explain, overview, doctor, cli overview) and the read-only list verb all work with no OpenCV present. The verbs that touch an image (enroll, match) exit 2 with a message naming the extra:

error: the opencv face-recognition engine is not installed
hint: install the cpu extra: pip install 'face-recognition-cli[cpu]'

Quickstart

uv sync                                     # or: pip install 'face-recognition-cli[cpu]'
uv run face-recognition whoami              # identity from culture.yaml
uv run face-recognition learn               # self-teaching prompt (add --json)
uv run face-recognition list --json         # inventory of the default bank

CLI

Face verbs

Every verb below takes --bank <name> (see Banks) and --json. Results go to stdout, errors and diagnostics to stderr (never mixed). Exit codes: 0 success, 1 user error, 2 environment error (missing extra), 3+ reserved.

enroll — detect the largest face in an image, embed it, and file that embedding under a name. Prints the generated 4-char id.

face-recognition enroll --name ada --image face.jpg
face-recognition enroll --name ada --image face.jpg --json
# {"face_id": "a3f9", "name": "ada", "bank": "default", "num_embeddings": 1}

--image also accepts - to read encoded image bytes from stdin, so a capture tool can pipe straight in without this tool ever opening a camera:

some-producer | face-recognition enroll --name ada --image -

match — identify the face in an image against everything enrolled in a bank, by cosine similarity. A no-match is a result, not an error — it exits 0, so match is safe to use in a shell conditional.

face-recognition match --image face.jpg --json
# hit:      {"bank": "default", "match": {"face_id": "a3f9", "name": "ada", "score": 0.87}}
# no match: {"bank": "default", "match": null}

list — inventory of the identities enrolled in a bank. Needs no OpenCV.

face-recognition list
# a3f9  ada  created=2026-07-24  embeddings=1
face-recognition list --json
# {"bank": "default", "faces": [{"id": "a3f9", "name": "ada", "created": ..., "num_embeddings": 1}], "count": 1}

forget <id> — delete one identity (its index record and its .npy embedding file). Takes the id, not the name — names may repeat, ids don't.

face-recognition forget a3f9

forget-all — delete every identity in a bank. Destructive and irreversible, so it is dry-run by default: without --apply nothing is deleted, and the command only reports what would go.

face-recognition forget-all
# would forget 2 face(s) from bank 'default':
#   a3f9  ada
#   b7k2  grace
# nothing deleted — re-run with --apply to commit

face-recognition forget-all --apply
# forgot a3f9  ada
# forgot b7k2  grace
# forgot 2 face(s) from bank 'default'

Introspection verbs

Verb What it does
whoami Report this agent's nick, version, backend, and model from culture.yaml.
learn Print a structured self-teaching prompt.
explain <path> Markdown docs for any noun/verb path (including the banks concept).
overview Read-only descriptive snapshot of the agent.
doctor Check the agent-identity invariants (prompt-file-present, backend-consistency).
cli overview Describe the CLI surface itself.

Banks

Every consumer of this tool — reachy-mini-cli, a mesh colleague agent, an interactive operator — enrolls its own set of faces into its own bank, a self-contained index plus its own embedding files. Identities never leak across banks: an id enrolled for reachy is invisible to list / match / forget run against colleague's bank, and there is no cross-bank search.

Bank selection follows this precedence: an explicit --bank <name>, else $FACE_RECOGNITION_BANK, else the bank named default.

On disk, under the state dir:

<state dir>/
    banks/
        default/       # faces.json + embeddings/*.npy
        reachy/        # reachy-mini-cli's identities, fully isolated
        colleague/     # a mesh colleague agent's identities, fully isolated
    models/            # YuNet + SFace ONNX — shared by every bank, downloaded once

<state dir> resolves as $FACE_RECOGNITION_STATE_DIR, else $XDG_STATE_HOME/face-recognition-cli, else ~/.local/state/face-recognition-cli.

The ONNX models are bank-independent — every bank embeds through the same YuNet + SFace pair, so models/ lives once, one level above banks/, rather than being duplicated per bank (SFace alone is ~37 MB).

face-recognition list --bank reachy
FACE_RECOGNITION_BANK=reachy face-recognition list

Library API

face_recognition_cli exposes one function at its root, meant for reachy-mini-cli (and any other in-process consumer) to import directly:

from face_recognition_cli import build_face_recognition

result = build_face_recognition(models_dir=None, store_base_dir=None)
if result is None:
    # opencv (the [cpu]/[gpu] extra) is not installed, or the vision stack
    # is broken — one warning was logged, and the feature stays disabled.
    ...
else:
    engine, store = result

build_face_recognition probes for cv2 with importlib.util.find_spec before importing anything — merely calling it on a bare install never imports cv2 — and returns None (after exactly one process-wide logged warning) rather than raising when the extra is missing or construction fails. models_dir= / store_base_dir= are optional overrides; omit them to use the shared models directory and the default bank.

This tool stores biometric identifiers of real people: a 128-dim face embedding plus a name, per enrolled identity. Treat it accordingly.

  • Enroll people only with their consent. An embedding is derived from someone's face; get their agreement before you run enroll on their image.
  • Everything stays on the machine. Embeddings and the identity index are written under the local state dir only (see Banks). Nothing is ever uploaded, there is no telemetry, and nothing phones home.
  • The only network access anywhere in this package is the one-time download of the two OpenCV model-zoo files — face_detection_yunet_2023mar.onnx and face_recognition_sface_2021dec.onnx — performed by _ensure_model in face_recognition_cli/engine.py the first time an image-consuming verb runs, and cached under <state dir>/models/ afterward. No other module in this package touches the network.
  • Deletion is one verb away. forget <id> removes a single identity and its embedding file; forget-all --apply removes every identity in a bank in one command; deleting the state dir removes everything the tool has ever written.
  • Retention is entirely operator-controlled. Nothing in the permanent tier expires on its own — a record persists until something calls forget or forget-all. The temporary tier (an unused "who are you?" seam, not wired to any CLI verb today) lives only in process memory and holds nothing across process restarts.
  • Per-bank isolation keeps different consumers' data apart. Reachy's identities, a colleague agent's identities, and an operator's identities each live in their own bank on disk, with no cross-bank search or merge.

If you enroll other people, that is their biometric data on your disk. Get their consent, and use forget / forget-all when they ask.

Development

uv sync                                              # create .venv, install (dev deps incl. teken)
uv run face-recognition whoami                       # run the CLI
uv run pytest -n auto                                # full suite (parallel)
uv run pytest --cov=face_recognition_cli --cov-report=term   # coverage (CI gate: fail_under=60)
uv run teken cli doctor . --strict                   # the agent-first rubric gate CI enforces

See CLAUDE.md for the architecture, the naming rules, the conventions (version-bump-every-PR, the cicd PR lane), and the CI/release setup. Skill provenance is tracked in docs/skill-sources.md.

License

Apache 2.0 — see LICENSE.

Metadata

Release files for face-recognition-cli 0.8.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 face-recognition-cli 0.8.0
File Size Uploaded Provenance
face_recognition_cli-0.8.0.tar.gz 254.5 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for face-recognition-cli 0.8.0
File Interpreter ABI Platform
face_recognition_cli-0.8.0-py3-none-any.whl Python 3 none any Details

Total release size: 311.3 kB

Release files / face_recognition_cli-0.8.0.tar.gz

Download URL face_recognition_cli-0.8.0.tar.gz
Size 254.5 kB
Tags Source
SHA-256 checksum
How to use checksums
b433384dcacf27b60e88c15a7a37d2822dbc3b94825c7416b4cc980eae79c250
BLAKE2b-256 checksum
How to use checksums
9fd44d586731ef894a17c138fd87aeafb0aa979cfa92ed06f22e746f59bcd24f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / face_recognition_cli-0.8.0-py3-none-any.whl

Download URL face_recognition_cli-0.8.0-py3-none-any.whl
Size 56.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bef5f82c8838b608ca36810c2c204ae8a51d9926184402035a5ab60dfd59782e
BLAKE2b-256 checksum
How to use checksums
8e997d45fba28dcfda6bfc52ffe0aa5c08998087c4e419ed63c952df6b07d9ca
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for face-recognition-cli 0.8.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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

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