All notable changes to this project will be documented in this file.
Format follows Keep a Changelog. This project adheres to Semantic Versioning.
- FaceEngine (engine.py): the YuNet+SFace engine extracted from reachy-mini-cli — lazy cv2 import, model-zoo download with .part-then-rename and size sanity floors, synchronous largest-face detect(); byte-identical model URLs/filenames preserve the embedding space, plus an opportunistic (fully guarded) cv2 CUDA DNN backend on the detector only
- FaceStore (store.py): the ported two-tier embedding store — cosine matching, faces.json + one .npy per embedding (byte-compatible with reachy-written stores, proven by a reachy-authored fixture), secrets-generated 4-char ids, write-then-replace saves, corrupt-index degrade, base_dir=/clock=/now= determinism seams
- Per-consumer face banks (state.py): $FACE_RECOGNITION_STATE_DIR → $XDG_STATE_HOME/face-recognition-cli → ~/.local/state/face-recognition-cli, with
banks/<name>/per consumer, $FACE_RECOGNITION_BANK / --bank selection, and a bank-independent shared models/ directory - CLI verbs: enroll, match, list, forget, and forget-all (dry-run by default, --apply commits, per-bank scoped) — every verb takes --json and --bank; enroll/match take
--image <path>or-for stdin bytes - build_face_recognition(*, models_dir=None, store_base_dir=None) public API (api.py, re-exported at the package root): probe-first, lazy-import, returns (engine, store) or None with one process-wide warning — the call shape reachy-mini-cli already uses
- [cpu] and [gpu] extras (both opencv-python-headless over the same ONNX models — same embedding space) and numpy as the single base dependency
- explain catalog entries for the five verbs plus a banks concept entry; a skippable end-to-end enroll→match roundtrip test; a reachy-store compatibility fixture
- README rewritten to the shipped surface, including a Privacy & consent section (local-only storage, sole network path = one-time model download, one-verb deletion)
- CLAUDE.md realigned: domain work moved from planned to landed, the five open questions recorded as decisions
- CLI parser/learn/overview self-descriptions updated from the template wording to face identity
CLAUDE.mdis now a real runtime prompt — the/initpass replaced the bootstrap seed. Grounded in the build brief (#1) and the siblingreachy-mini-clicheckout, it documents: the agent-first CLI contract (verb registration, theparser_class=type(p)rule for noun groups, theCliError/hint:/ exit-code policy, the stdout-vs-stderr split, theexplaincatalog gotcha); the deliberate naming split (console scriptface-recognition, import packageface_recognition_cli— neverface_recognition, which would shadow the unrelated dlib distribution on PyPI); the planned domain work (the YuNet+SFaceFaceEngineandFaceStoreto extract, their contracts and test seams, the dry-run-by-defaultforget-all, thebuild_face_recognitionAPIreachy-mini-cliconsumes); the[cpu]/[gpu]compute-class split and its non-negotiable same-embedding-space invariant; the five open design questions from the brief; the migration protocol forreachy-mini-cli(open an issue, publish first, never push into that repo); and CI/release, skills, and workflow conventions. Planned work is marked as planned throughout — no face-recognition code is checked in yet.- Worktree, memory, and
ask-colleagueconventions restored intoCLAUDE.md.CHANGELOG.md0.6.1 documented a worktree-location convention that lived in the template'sCLAUDE.mdand was lost when the scaffold replaced that file with the seed; it is back, repo-named as../.worktrees.face-recognition-cli/<name>/. The memory-discipline note is written against the vendored scripts' actual behaviour (default--visibility public→ the in-repo<repo-root>/.eidetic/memory), which differs from the description text in the skills' own frontmatter. - A Privacy section in
README.md— the build brief asks for the biometric stance to be written down, since this repo is public and the tool stores identifiers of real people. States the design commitments: everything stays on the machine, the only network access is the one-time OpenCV model-zoo download, deletion is a first-class verb (forget/forget-all), and what is stored is a 128-dim embedding rather than a photograph. - A Roadmap section in
README.mdlisting the plannedenroll/match/list/forget/forget-allverbs (withforget-alldocumented as dry-run-by-default,--applyto commit) and the[cpu]/[gpu]extras with their same-embedding-space guarantee — kept separate from the verb table of what actually runs today.
README.mdrewritten from theculture-agent-templateboilerplate into an agent-specific readme. The template's "Make it your own" cloning instructions are gone (this repo has already been cloned and renamed), replaced by a status banner that marks the repo as scaffold-only, the install/extras table, the current CLI surface, and the roadmap.
- Recorded the
culture.yamlbackend mismatch rather than leaving it to be rediscovered. The build brief lists the backend asclaude"as scaffolded" and the old seedCLAUDE.mdrepeated that, but the checked-in reality isbackend: colleaguewithAGENTS.colleague.mdon disk, inherited verbatim from the template. The reconciliation the brief asks for is still open;CLAUDE.mdnow names the three things that move together, including thatdoctorwould still pass (_PROMPT_FILEmapsclaude→CLAUDE.md, which exists) whiletest_whoami_text/test_whoami_jsonwould fail on theirbackend == "colleague"assertions. Records the mesh evidence gathered fromdevex pr delta:devague'sCLAUDE.mdcallsclaude"the mesh standard", and of the siblings in this workspace onlysteward(and this repo, via the template) declarescolleague. Also records that the mismatch is already breaking a tool —devex pr replyrejectsbackend: colleagueoutright (unknown backend, expecting one ofclaude/codex/copilot/acp), so thecicdskill's reply lane needs an explicit--agent claude-codeoverride until the declaration is reconciled.
- Worktree location convention in
CLAUDE.md— every worktree you create by hand (workforce fan-out lanes, scratch checkouts) lives in../.worktrees.face-recognition-cli/<name>/, one repo-named directory beside the checkout, replacing a shared../worktrees/folder. This workspace holds many sibling projects, so a generic shared folder accumulates orphaned trees from several repos at once with nothing indicating ownership — a stale-tree sweep can't tell a live lane from junk. Matches the convention already documented in sibling reporeachy-mini-cli. Adds branch-prefix guidance (scope the prefix to the work; plainagent/*collides with leftovers from earlier fan-outs and failsgit worktree add -b), and notes that the vendoredassign-to-workforceskill uses both the shared path andagent/<task-id>branches in its fan-out example — it is cited verbatim and must not be edited, so both are overridden when following it. Teardown guidance namesgit worktree remove <path>as the verb that actually deletes a worktree;git worktree pruneonly clears metadata for directories that are already gone. Tool-managed throwaways are explicitly out of scope:ask-colleague's read-only verbs create a detached worktree under${TMPDIR:-/tmp}and reap it on an EXIT trap, so they never persist to need an owner.
-
Four devague-origin skills re-vendored into
.claude/skills/(cite-don't-import), synced to the fixed devague source (devague#74/#75/#76):challenge— a risk-scaled blind-spot discovery pass that runs between/thinkand/spec-to-plan, routing findings back through the existing deterministic moves as human-adjudicated proposals.scope— the idea→scope leg that surveys the surfaces an idea touches before framing, seeding the Announcement Frame with provenance-backed boundary/non-goal/assumption claims.deviate— stops an in-flightassign-to-workforcerun when execution must diverge from the confirmed plan and records the divergence as a first-class, append-only deviation record.summarize-delivery— closes the loop after anassign-to-workforcerun with a planned-vs-actual accountability artifact.
These four originate in
devagueand are re-broadcast via guildmaster; seedocs/skill-sources.mdfor provenance.
- Memory-discipline "Conventions and workflow" section in
CLAUDE.md— a per-task recall-before / remember-after convention (scope localized to this repo's nick) so the vendoredremember/recallskills are actually used, not just present:/recallbefore non-trivial work to build on prior decisions instead of re-deriving them, and/rememberwhen a non-obvious decision, constraint, fix-and-why, or hard-won gotcha surfaces. The section documents this repo's memory as in-repo and public — records resolve to<repo-root>/.eidetic/memory(committed, team- and mesh-shared). Inserted idempotently (skipped if already present), slotted under an existing "Conventions and workflow" heading when one exists, else appended.
- Refreshed the
remember+recallwrappers from eidetic-cli 0.10.0 (cite-don't-import) — picks up eidetic's project-local store default: the files backend now resolves per record by visibility — PUBLIC records inside a git repo go to<repo-root>/.eidetic/memory(committed, team-shared), PRIVATE records (or any record outside a repo) go to$HOME/.eidetic/memory(never committed), an explicitEIDETIC_DATA_DIRstill wins, and recall reads both stores and merges. Also carries the 0.9.3 hardening (interactive-stdin guard,helpas a search term, SIGPIPE-safe suffix parsing). Recipe policy override (the wrappers here are NOT byte-verbatim): the injected default visibility is flipped from eidetic'sprivatetopublic, so a plain/rememberlands the note in./.eidetic/memoryin this repo, kept as part of the repo — pass--visibility privateto route a record to$HOMEinstead.rememberdriveseidetic remember(idempotent upsert of one JSON record or an NDJSON batch on stdin);recalldriveseidetic recallwith four search modes (exact / approximate / keyword / hybrid). EachSKILL.mdis localized only in the illustrative--scope <nick>examples (Provenance keeps "First-party to eidetic-cli"). Runtime dep: theeideticCLI on PATH (else a local eidetic-cli checkout withuv) —eidetic >= 0.10.0for the in-repo routing; on an older CLI the public records still work but are stored in$HOME/.eidetic/memoryinstead of in-repo. Propagated by rollout-cli'seidetic-memoryrecipe.
- Vendored the
remember+recallmemory skills from eidetic-cli (cite-don't-import) — the write/read halves of eidetic's shared$HOME/.eidetic/memorysurface, so this agent (Claude and its colleague backend) can persist facts across sessions and recall them later, sharing one store.rememberdriveseidetic remember(idempotent upsert of one JSON record or an NDJSON batch on stdin, dedup by id + content hash);recalldriveseidetic recallwith four search modes — exact / approximate / keyword / hybrid — each hit carrying text, full provenance metadata, a relevance score, and a freshness signal. The.shwrappers are byte-verbatim from eidetic-cli (their first-party origin); eachSKILL.mdis localized only in the illustrative--scope <nick>examples (Provenance keeps "First-party to eidetic-cli"). Both default to this agent's PRIVATE scope, reading the suffix fromculture.yaml. Runtime dep: theeideticCLI on PATH (else a local eidetic-cli checkout withuv). Propagated by rollout-cli'seidetic-memoryrecipe.
- Identity docs and self-description strings still claimed
backend: claude(prompt fileCLAUDE.md), but this template was promoted to a colleague resident in #14/#15:culture.yamldeclaresbackend: colleague(Qwen) withAGENTS.colleague.mdas the resident prompt. Corrected the stale claim inCLAUDE.md(Identity section),README.md,docs/skill-sources.md, and the two CLI description strings (overviewartifacts andexplain doctor). Thedoctorbackend→prompt-file mapping and the tests were already oncolleague; this aligns the prose and self-description with them.
- pyproject.toml: correct the
licensefield and PyPI classifier from MIT to Apache-2.0 to match theLICENSEfile. The README License section was already corrected in 0.3.2, but the package metadata was missed; the built wheel now reportsLicense-Expression: Apache-2.0.
- ask-colleague skill:
monitor/guide/stoppilot verbs plus a--watchflag to dispatch, watch the live feed of, send mid-flight guidance to, and cooperatively stop a running colleague flight (re-vendored from colleague).
- README: correct the License section from MIT to Apache 2.0 to match the
LICENSEfile.
- CLAUDE.md: add a convention to reach for the
ask-colleagueskill reflexively for explore/review/write/grade — read-onlyreview/exploreare always safe; side-effectingwriteneeds the user's go-ahead.
- AGENTS.colleague.md resident prompt file (backend colleague <-> AGENTS.colleague.md)
- Promote agent identity to a colleague resident: culture.yaml backend
claude -> colleague with a pinned model. The
doctorbackend-consistency map gainscolleague-> AGENTS.colleague.md.
- Re-vendored the
ask-colleagueskill from colleague (now 1.7.0, up from the 0.39.2 sync) — the wrapper had drifted multiple releases behind origin. Picks up thecleanverb (reap stale/corruptcolleague/*branches + orphaned.colleague/artifacts a crashed run left behind), the--jsonflag on every verb (result JSON on stdout, diagnostics/digest on stderr), the_colleague_via_uvlocal-dev resolution that honors--repo, and the tri-state (0/1/2) exit-code contract.scripts/ask-colleague.sh+prompts/are byte-identical to the origin;SKILL.mddiverges only in the one consumer-identifying Provenance clause (face-recognition-cli vendors from guildmaster).docs/skill-sources.mdsync row updated to2026-06-12 (colleague 1.7.0, direct). Refs: colleague#183, #186.
ask-colleagueskill (.claude/skills/ask-colleague/) — the first-party front door to thecolleagueCLI (the renamedconvertible). On top ofexplore/review/writeit adds afeedbackverb (grade a finished work item — the ROI loop), andwritenow previews by default in a throwaway worktree (no side effects) unless--apply/--pris given. Reach for it reflexively —reviewfor a diverse second opinion on a committed diff before opening a PR,explorefor a fresh read of an unfamiliar area.
- Replaced the
outsourceskill withask-colleague.outsourcewas renamed toask-colleagueupstream (colleague#148). Because guildmaster has not re-broadcast the rename yet (its kit still ships the oldoutsource),ask-colleagueis vendored directly from the siblingcolleaguecheckout rather than from guildmaster — a tracked local divergence recorded indocs/skill-sources.md, parallel to theagex→devexone. Vendored verbatim except one consumer-identifying clause in the Provenance paragraph. - Ledger + CLAUDE.md +
.gitignore: pointdocs/skill-sources.mdand the CLAUDE.md Skills section atcolleague/ask-colleague, swap the optional runtime prerequisiteconvertible→colleague(env prefixCONVERTIBLE_*→COLLEAGUE_*, with the legacy names kept as a deprecated fallback), and gitignore the.colleague/run-artifact dir the skill writes (plus the stale.agex/).
- Vendor the
outsourceskill (.claude/skills/outsource/) from guildmaster's canonical copy (originagentculture/convertible, re-broadcast via guildmaster — guildmaster #51). Every agent cloned from this template now inherits the ability to hand a scoped task to a different engine/mind:explore(read-only investigation),review(a diverse second opinion on the committed diff), andwrite(delegate a small implementation).explore/reviewrun isolated in a throwawaygit worktree;writerefuses a dirty tree. Fulfils #8. - Ledger + CLAUDE.md: record
outsourceindocs/skill-sources.md(origin = convertible, re-broadcast via guildmaster; vendored verbatim — it already carriestype: command) and document its optional runtime dependency on theconvertibleCLI (the skill exits with an install hint if absent, so a clone that never uses it is unaffected).
- Expanded the clone-and-rename instructions in
CLAUDE.md: addedREADME.mdto the rename targets and a portablegit grepdiscovery command so a cloner can find every occurrence of the template name (hard-coded in ~100 places across the package, including the CLI command files and_ISSUES_URLinface_recognition_cli/cli/__init__.py) rather than renaming by hand. - Synced
README.md's "Make it your own" checklist withCLAUDE.md: it now listsREADME.mditself as a rename target and points toCLAUDE.md's discovery command as the authoritative procedure, so the two onboarding checklists no longer drift.
- Renamed the PR-lifecycle CLI references
agex/agex-clitodevex(same tool, new name) acrossCLAUDE.md,docs/skill-sources.md,.gitignore, and the vendoredcicd,assign-to-workforce, andcommunicateskills — thecicdscripts now invokedevex pr. - Logged the vendored-skill in-place patch as a local divergence in
docs/skill-sources.md; the matching canonical rename is tracked upstream for guildmaster in agentculture/guildmaster#48 so a future re-sync reconciles cleanly. - Aligned the documented
devexversion floor to>=0.21across the vendoredcicdSKILL.mdandworkflow.shinstall hint (were>=0.1), matchingdocs/skill-sources.mdand theawait-era feature set; flagged upstream on guildmaster#48.
- SonarCloud now reports code coverage — added
relative_files = trueto[tool.coverage.run]socoverage.xmlemits repo-relative paths that map tosonar.sources=face_recognition_cli(absolute /.venvpaths were dropped as unmappable). Mirrors the siblingconvertiblesetup.
- CI gates on the SonarCloud quality gate
(issue #3) —
added
sonar.qualitygate.wait=truetosonar-project.propertiesso a failing gate fails thetestjob whenSONAR_TOKENis set. Token-less repos and fork PRs remain green (the scan step is guarded byif: env.SONAR_TOKEN != '').
- Onboarded into the AgentCulture mesh (issue #1).
- Agent-first CLI cited from teken's (
afi-cli)python-clireference (teken cli cite) — verbswhoami,learn,explain,overview,doctor, and theclinoun group. Runtime is self-contained (dependencies = []);teken>=0.8is a dev dependency only. Passes the seven-bundle agent-first rubric (teken cli doctor . --strict).doctorchecks the agent-identity invariants (prompt-file-present, backend-consistency, skills-present). - Mesh identity:
culture.yaml(suffix: face-recognition-cli,backend: claude) and the matchingCLAUDE.mdprompt file. - Canonical guildmaster skill kit (11 skills) vendored under
.claude/skills/(cite-don't-import):agent-config,assign-to-workforce,cicd,communicate,doc-test-alignment,pypi-maintainer,run-tests,sonarclaude,spec-to-plan,think,version-bump. EverySKILL.mdcarriestype: command(load-bearing for the culture/claude backend);cicd/communicateconsumer-identifying prose adapted, all script bodies verbatim. Provenance indocs/skill-sources.md. Three skills (think,spec-to-plan,assign-to-workforce) originate indevague, re-broadcast via guildmaster. - Build + deploy baseline:
pyproject.toml(hatchling),tests/(pytest, xdist, coverage),.github/workflows/{tests,publish}.yml(CI rubric/lint gate, PyPI Trusted Publishing),.flake8,.markdownlint-cli2.yaml,sonar-project.properties, and.claude/skills.local.yaml.example.