argus-cortex 0.4.7__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/CHANGELOG.md +28 -1
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/CLAUDE.md +4 -2
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/Makefile +2 -2
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/PKG-INFO +18 -4
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/README.md +17 -3
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/SUITE.md +17 -13
- argus_cortex-0.5.0/consent-schema.json +257 -0
- argus_cortex-0.5.0/provenance-schema.json +125 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/src/argus_cortex/__init__.py +36 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/src/argus_cortex/_version.py +2 -2
- argus_cortex-0.5.0/src/argus_cortex/consent.py +240 -0
- argus_cortex-0.5.0/src/argus_cortex/provenance.py +128 -0
- argus_cortex-0.5.0/tests/test_consent.py +249 -0
- argus_cortex-0.5.0/tests/test_provenance.py +144 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/.copier-answers.yml +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/.cursor/rules/agent-coding-packs.mdc +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/.env.example +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/.github/workflows/ci.yml +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/.github/workflows/release.yml +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/.gitignore +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/AGENTS.md +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/LICENSE +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/pyproject.toml +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/src/argus_cortex/backends.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/src/argus_cortex/gpu.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/src/argus_cortex/moderation/__init__.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/src/argus_cortex/moderation/_http.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/src/argus_cortex/moderation/nudenet.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/src/argus_cortex/moderation/policies.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/src/argus_cortex/moderation/singguard.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/src/argus_cortex/py.typed +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/src/argus_cortex/server.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/src/argus_cortex/store/__init__.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/src/argus_cortex/store/blob.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/src/argus_cortex/store/config.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/src/argus_cortex/store/errors.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/src/argus_cortex/store/lineage.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/src/argus_cortex/store/models.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/src/argus_cortex/store/schema.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/src/argus_cortex/store/vector.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/src/argus_cortex/taxonomy.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/src/argus_cortex/wire.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/src/argus_cortex/xmp.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/taxonomy-schema.json +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/tests/test_backends.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/tests/test_blob.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/tests/test_gpu.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/tests/test_moderation.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/tests/test_policies.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/tests/test_server.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/tests/test_smoke.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/tests/test_store.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/tests/test_store_pg_integration.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/tests/test_taxonomy.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/tests/test_vector.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/tests/test_wire.py +0 -0
- {argus_cortex-0.4.7 → argus_cortex-0.5.0}/tests/test_xmp.py +0 -0
|
@@ -7,6 +7,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.5.0] - 2026-11-14
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **`argus_cortex.provenance`.** `Provenance`, `ProvenanceKind` and `CLEARED_KINDS`, hoisted from
|
|
14
|
+
argus-mask so every package that stores where a face, voice or image came from reads one shape,
|
|
15
|
+
with a committed `provenance-schema.json` (#35).
|
|
16
|
+
- **`argus_cortex.consent`.** `ConsentRecord`, a real person's likeness release as argus-mask#26
|
|
17
|
+
defined it, keyed by the `release_sha256` a `consented` `Provenance` names. `consent_valid()`
|
|
18
|
+
returns a `ConsentVerdict` with one of a closed set of refusal codes, checked in a fixed order
|
|
19
|
+
(`revoked`, `not-yet-signed`, `expired`, `likeness-not-covered`, `use-not-covered`,
|
|
20
|
+
`delivery-not-covered`), so every stage refuses for the same reasons. `consent_matches()` checks
|
|
21
|
+
that a record is the release and subject a provenance names. Committed `consent-schema.json` (#53).
|
|
22
|
+
A record is frozen and its sequences are tuples, so it cannot be changed after its checks pass.
|
|
23
|
+
It is refused when the age check names nobody or comes after signing, when a revocation is
|
|
24
|
+
requested before signing, or when a listed voice delivery is blank (#56).
|
|
25
|
+
- **`Provenance.generator`.** An optional `model`, `model_sha256`, `seed` and `prompt` for how a
|
|
26
|
+
generated source was made, allowed only on `synthetic` and `personal` sources (#53).
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
- **`Provenance` is strict, as argus-mask's is (argus-mask#64).** Unknown fields are refused instead
|
|
30
|
+
of dropped (`additionalProperties: false` in the schema). `licence` is read as `license`; both given
|
|
31
|
+
and different is refused. A `source` of only whitespace is refused. The derived `cleared` in a dumped
|
|
32
|
+
record is dropped on read and recomputed.
|
|
33
|
+
- **README:** lists the `[images]` and `[gpu]` extras, `ARGUS_GPU_DEVICE`, and the moderation policy
|
|
34
|
+
names with their illegal-rule letters (#42).
|
|
35
|
+
|
|
10
36
|
## [0.4.7] - 2026-11-13
|
|
11
37
|
|
|
12
38
|
### Added
|
|
@@ -229,7 +255,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
229
255
|
(`LocalBackend`, `RemoteBackend`, `RemoteProvider`, `with_retries`
|
|
230
256
|
retrying only transient errors, `resolve_device`).
|
|
231
257
|
|
|
232
|
-
[Unreleased]: https://github.com/smk762/argus-cortex/compare/v0.
|
|
258
|
+
[Unreleased]: https://github.com/smk762/argus-cortex/compare/v0.5.0...HEAD
|
|
259
|
+
[0.5.0]: https://github.com/smk762/argus-cortex/compare/v0.4.7...v0.5.0
|
|
233
260
|
[0.4.7]: https://github.com/smk762/argus-cortex/compare/v0.4.6...v0.4.7
|
|
234
261
|
[0.4.6]: https://github.com/smk762/argus-cortex/compare/v0.4.5...v0.4.6
|
|
235
262
|
[0.4.5]: https://github.com/smk762/argus-cortex/compare/v0.4.4...v0.4.5
|
|
@@ -23,6 +23,8 @@ their own rows land here. Keep it short, because it is loaded into every session
|
|
|
23
23
|
`src/argus_cortex/` (top level is pydantic-only; everything heavier is behind an extra and lazily imported):
|
|
24
24
|
|
|
25
25
|
- `taxonomy.py` — the "moat" types every stage inherits verbatim: `TargetProfile`, `TargetStyle`/`TargetCategory` literals, and `taxonomy_schema()` (the source of the committed `taxonomy-schema.json`). Keep it dependency-light; a change here retrains everyone's expectations.
|
|
26
|
+
- `provenance.py` — `Provenance`/`ProvenanceKind`/`CLEARED_KINDS` for face, voice and image sources, hoisted from argus-mask (#19/#57): `personal` (never cleared) vs cleared `stock`/`synthetic`/`consented` (licence required; `consented` needs `subject` + `release_sha256`); `curated` reserved. **argus-mask owns the meaning of each field — change it only in step with mask.** Optional `generator` (model, sha256, seed, prompt) on `synthetic`/`personal` only. `provenance_schema()` renders the committed `provenance-schema.json` (`make schema`; drift-tested).
|
|
27
|
+
- `consent.py` — `ConsentRecord` (keyed by `release_sha256`, the join to a `consented` `Provenance`), `consent_valid()` → `ConsentVerdict` with a closed `ConsentRefusal` reason (checks in a fixed order; the first failure wins), `consent_matches()`, and `consent_schema()` → the committed `consent-schema.json`. Defined in argus-mask#26; **mask owns the meaning — change it only in step with mask.** `consent_valid` takes `at` from the caller (tz-aware, compared as a UTC day) and never reads the clock; an unknown use is refused, not raised. A record names a person: services return verdicts, never records.
|
|
26
28
|
- `wire.py` — the versioned wire-schema toolkit consumers build their contracts on: `make_versioned_base(field_name, current, majors)` (a Pydantic base that stamps + version-checks a field like `proof_version`/`manifest_version`), `check_version()` (the major-compatibility gate), `render_schema()`/`wire_schema()` (the canonical committed-schema string behind each consumer's `schema --check` CLI), and `VersionError`.
|
|
27
29
|
- `backends.py` — the AI-backend contract: `Backend`/`LocalBackend`/`RemoteBackend` (point at a hosted service via `from_host(host, port)` or `from_provider(RemoteProvider.…)`), plus `with_retries()` and `resolve_device()`. httpx is lazy, behind `[remote]`.
|
|
28
30
|
- `server.py` — the shared FastAPI/ASGI scaffolding other repos' micro-servers mount: `WriteGuard` (pure-ASGI method gate), the `constant_refuse()` (read-only/replay) and `cross_site_refuse()` (cross-origin write) predicates, `env_flag()`, and the `UNSAFE_METHODS`/`TRUTHY`/`FALSY` constants. Starlette is behind `[server]`.
|
|
@@ -31,7 +33,7 @@ their own rows land here. Keep it short, because it is loaded into every session
|
|
|
31
33
|
- `moderation/` — content-moderation clients over HTTP: `nudenet.py` (`NudeNetClient`, `NsfwResult`, `DEFAULT_EXPOSED_LABELS` — **the suite's one definition of nudity; don't widen it casually**, every stage's NSFW numbers move with it), `singguard.py` (`SingGuardClient` incl. text-only `check_text()`, `GuardResult`, `rule_matches`), `policies.py` (the named policy texts, the per-policy illegal-rule table and `mode()`: `default`/`sfw-*` are SFW — **a policy's text and its illegal letters change together**), `_http.py` (shared POST, proxy-free opener, `CheckFailed`/`ModerationConfigError`). Stdlib + pydantic; Pillow lazily, behind `[images]`. Never import NudeNet (AGPL) — HTTP only. URLs are passed in; stages own their env config.
|
|
32
34
|
- `store/` — the optional stateful-services layer, opt-in per `CORTEX_*` env var: `lineage.py` (Phase 1 Postgres DAG, `open_lineage_store()`), `vector.py` (Phase 2 Qdrant, `open_vector_store()`), `blob.py` (Phase 3 MinIO/S3, `open_blob_store()`), over `config.py`/`models.py`/`errors.py`. Each `open_*()` returns a `Null*` no-op when its URL is unset. Drivers are behind `[postgres]`/`[qdrant]`/`[s3]`.
|
|
33
35
|
|
|
34
|
-
There is **no CLI in this repo**. The
|
|
36
|
+
There is **no CLI in this repo**. The committed schemas are `taxonomy-schema.json` (from `taxonomy_schema()`), `provenance-schema.json` (from `provenance_schema()`) and `consent-schema.json` (from `consent_schema()`); `make schema` regenerates all three and `tests/test_taxonomy.py` / `tests/test_provenance.py` / `tests/test_consent.py` fail when one is stale. Studio generates its taxonomy types from the first, so a `taxonomy.py`, `provenance.py` or `consent.py` change needs `make schema` in the same commit.
|
|
35
37
|
|
|
36
38
|
## Commands
|
|
37
39
|
|
|
@@ -55,7 +57,7 @@ Run one test: `uv run --no-sync pytest tests/test_wire.py::test_name -q`.
|
|
|
55
57
|
|
|
56
58
|
## Branches
|
|
57
59
|
|
|
58
|
-
`dev` is the default branch and the base for every PR. Cut feature branches from `origin/dev` and bring them up to date by merging `origin/dev`, never `main`. Never
|
|
60
|
+
`dev` is the default branch and the base for every PR. Cut feature branches from `origin/dev` and bring them up to date by merging `origin/dev`, never `main`. Never push work to `main` or open a PR against it, except the release PR from `dev`: `main` must never be ahead of `dev`, with one exception. A release fast-forwards `main` to a `dev` commit that passed CI (`git push origin origin/dev:main`), then tags it. If `main` is protected, the release is a reviewed PR from `dev` into `main`, and merging it leaves a merge commit on `main` alone. That merge commit is the one exception to the rule: it leaves `main` one commit ahead of `dev` with an identical tree. Leave it there and don't merge `main` back into `dev`. Anything else on `main` that `dev` lacks is a mistake (`git diff origin/dev origin/main` must be empty). Once `main` carries such a commit it can't be fast-forwarded, so later releases are PRs too.
|
|
59
61
|
|
|
60
62
|
## CI / release
|
|
61
63
|
|
|
@@ -20,8 +20,8 @@ format: ## Ruff autoformat + autofix
|
|
|
20
20
|
test: ## Run the test suite
|
|
21
21
|
$(UV) run --no-sync pytest --tb=short -q
|
|
22
22
|
|
|
23
|
-
schema: ## Regenerate the committed taxonomy-schema.json
|
|
24
|
-
$(UV) run --no-sync python -c "from pathlib import Path; from argus_cortex.taxonomy import taxonomy_schema; Path(
|
|
23
|
+
schema: ## Regenerate the committed taxonomy-schema.json, provenance-schema.json and consent-schema.json
|
|
24
|
+
$(UV) run --no-sync python -c "from pathlib import Path; from argus_cortex.taxonomy import taxonomy_schema; from argus_cortex.provenance import provenance_schema; from argus_cortex.consent import consent_schema; [Path(f).write_text(r(), encoding='utf-8') for f, r in (('taxonomy-schema.json', taxonomy_schema), ('provenance-schema.json', provenance_schema), ('consent-schema.json', consent_schema))]"
|
|
25
25
|
|
|
26
26
|
build: ## Build sdist + wheel
|
|
27
27
|
$(UV) build
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: argus-cortex
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Shared foundation for the Argus suite: taxonomy, versioned wire-schema tooling, and the local/remote AI backend contract
|
|
5
5
|
Project-URL: Repository, https://github.com/smk762/argus-cortex
|
|
6
6
|
Author: smk762
|
|
@@ -56,12 +56,14 @@ Part of the Argus suite; [SUITE.md](https://github.com/smk762/argus-cortex/blob/
|
|
|
56
56
|
## What's here
|
|
57
57
|
|
|
58
58
|
- **`argus_cortex.taxonomy`** — `TargetProfile` / `TargetStyle` / `TargetCategory`, the "moat" types every stage inherits verbatim. `taxonomy_schema()` renders them into the committed `taxonomy-schema.json` (`make schema` regenerates it; a test fails when it is stale), so non-Python clients generate their types instead of copying the literals.
|
|
59
|
+
- **`argus_cortex.provenance`**: `Provenance` / `ProvenanceKind`, where a face, voice or image came from (the shape argus-mask#19 defined). `personal` needs only a `source` and is never `cleared`; `stock`, `synthetic` and `consented` are cleared, each states its licence, and `consented` also names its `subject` and the `release_sha256` of the signed release (never the document). `curated` is reserved and not cleared. Strict: unknown fields and a blank `source` are refused, `licence` is read as `license`, and a stored `cleared` is recomputed. A `synthetic` or `personal` source may name its `generator` (`model`, `model_sha256`, `seed`, `prompt`; optional, refused on other kinds). `provenance_schema()` renders the committed `provenance-schema.json` (`make schema`; a test fails when it is stale).
|
|
60
|
+
- **`argus_cortex.consent`**: a real person's likeness release, as argus-mask#26 defined it. `ConsentRecord` is keyed by the `release_sha256` a `consented` `Provenance` names, and holds the subject, who collected it, signing and expiry dates (expiry must be stated, `null` for none), the age check (who and when, never the ID), the `face`/`voice` opt-ins, voice `deliveries`, `uses` (`avatar`, `video`, `speech`, `training`; training is off unless listed), sha256s of the reference images and recordings, revocation terms and any `revocation`. `consent_valid(record, use=, likeness=, at=, delivery=)` returns a `ConsentVerdict` (`ok`, `reason`, `detail`), checking in order `revoked`, `not-yet-signed`, `expired`, `likeness-not-covered`, `use-not-covered`, `delivery-not-covered`; `at` must be timezone-aware and dates compare as UTC days, so the check never reads the clock. `consent_matches(record, provenance)` checks the record is the release and subject a provenance names. A record names a person, so services return only verdicts, never records. `consent_schema()` renders the committed `consent-schema.json`.
|
|
59
61
|
- **`argus_cortex.wire`** — the versioned wire-schema toolkit: `check_version()` (major-compatibility gate), `make_versioned_base()` (a Pydantic base that stamps + checks a version field like `proof_version` / `manifest_version`), and `wire_schema()` / `render_schema()` for the committed-schema `schema --check` CLI pattern.
|
|
60
62
|
- **`argus_cortex.backends`** — the AI-backend contract generalised from argus-lens: `Backend` / `LocalBackend` / `RemoteBackend` (point at a hosted service by `base_url`, `host`/`port`, or a known `RemoteProvider`), plus `with_retries()` and `resolve_device()`. httpx lives behind the `[remote]` extra.
|
|
61
63
|
- **`argus_cortex.server`** — shared write-guard + env-flag scaffolding for the suite's FastAPI micro-servers: `WriteGuard` (a pure-ASGI method-gate that never buffers streaming responses), the `constant_refuse()` / `cross_site_refuse()` predicates (read-only/replay mode and cross-site-write protection are two configs of the one guard), the `UNSAFE_METHODS` / `TRUTHY` / `FALSY` constants, and `env_flag()` (warns on a mistyped protection flag rather than silently disabling it). Starlette lives behind the `[server]` extra.
|
|
62
|
-
- **`argus_cortex.xmp`** — the suite's one XMP sidecar implementation (hoisted from argus-lens): `write_xmp()` / `read_xmp()` / `merge_xmp()` / `parse_xmp()` over an `XmpData` model covering `dc` (keywords, description), `xmp` (Rating, Label), `lr` (hierarchical keywords), `Iptc4xmpExt` (PersonInImage), `mwg-rs` face/pet regions, and `argus:ContentRating`. Writes **merge**: each property you set replaces that property (latest write wins), everything else in the sidecar — Lightroom develop settings, GPS, another stage's fields — is preserved. `None` leaves a property alone, an empty value removes it. Writes are atomic; an unparseable existing sidecar raises `XmpError` instead of being clobbered. Stdlib only.
|
|
64
|
+
- **`argus_cortex.xmp`** — the suite's one XMP sidecar implementation (hoisted from argus-lens): `write_xmp()` / `read_xmp()` / `merge_xmp()` / `parse_xmp()` over an `XmpData` model covering `dc` (keywords, description), `xmp` (Rating, Label), `lr` (hierarchical keywords), `Iptc4xmpExt` (PersonInImage), `mwg-rs` face/pet regions, and `argus:ContentRating`. Writes **merge**: each property you set replaces that property (latest write wins), everything else in the sidecar — Lightroom develop settings, GPS, another stage's fields — is preserved. `None` leaves a property alone, an empty value removes it. Writes are atomic; an unparseable existing sidecar raises `XmpError` instead of being clobbered. Stdlib + pydantic only.
|
|
63
65
|
- **`argus_cortex.moderation`** — the suite's content-moderation clients, over HTTP to servers the deployer runs (nothing here imports a detector): `NudeNetClient` (a NudeNet server's `/infer` → `NsfwResult`: detections, per-class maxima, and an **exposed score**) and `SingGuardClient` (a SingGuard server's `/api/guard/check` → `GuardResult`: verdict, the policy rules that fired, explanation; optional custom policy text). `DEFAULT_EXPOSED_LABELS` is the suite's **one definition of nudity**: the five exposed buttocks/breast/genitalia/anus classes — faces, covered parts, and bare feet, belly, armpits or male chest never count. Stdlib + pydantic; Pillow (for SingGuard's downscaling of large images, on by default) is behind `[images]`: without it `SingGuardClient(...)` raises `ModerationConfigError` at construction unless given `downscale=False`. A `user:password@` in a URL is sent as HTTP Basic auth. URLs are passed in, never read from the environment here: each stage owns its config. NudeNet itself is AGPL-3.0, which is why it stays behind an HTTP boundary.
|
|
64
|
-
- **`argus_cortex.gpu`**: GPU tenancy, generalised from argus-lens. `coordinator_from_env()` returns a coordinator whose `lease(caller=, min_vram_mb=)` holds a GPU slot for a block of work. `none` (the default) grants every lease at once. `lease` takes an exclusive `flock` that every argus process on the host shares (one lock for the host, not per GPU), then waits until `free_vram_mb()` (NVML, behind `[gpu]`) reports `min_vram_mb` free across *every* process on the card, ComfyUI and Ollama included, which never take the lock. It raises `GpuLeaseTimeout` after `ARGUS_GPU_LEASE_TIMEOUT_S` (300 s). The VRAM check is a snapshot, not a reservation, and a probe that cannot run lets the lease through. Containers each have their own `/tmp`, so set `ARGUS_GPU_LEASE_PATH` to a file on a volume every GPU service mounts, or the lock coordinates nothing.
|
|
66
|
+
- **`argus_cortex.gpu`**: GPU tenancy, generalised from argus-lens. `coordinator_from_env()` returns a coordinator whose `lease(caller=, min_vram_mb=)` holds a GPU slot for a block of work. `none` (the default) grants every lease at once. `lease` takes an exclusive `flock` that every argus process on the host shares (one lock for the host, not per GPU), then waits until `free_vram_mb()` (NVML, behind `[gpu]`) reports `min_vram_mb` free across *every* process on the card, ComfyUI and Ollama included, which never take the lock. It raises `GpuLeaseTimeout` after `ARGUS_GPU_LEASE_TIMEOUT_S` (300 s). The VRAM check is a snapshot, not a reservation, and a probe that cannot run lets the lease through. Containers each have their own `/tmp`, so set `ARGUS_GPU_LEASE_PATH` to a file on a volume every GPU service mounts, or the lock coordinates nothing. `ARGUS_GPU_DEVICE` (default `0`; an invalid value warns and falls back to `0`) picks which card NVML probes for free VRAM; the lock stays host-wide.
|
|
65
67
|
- **`argus_cortex.store`** — the optional **stateful services layer** (the suite's persistent "memory"). External and opt-in — every store is configured by `CORTEX_*` env vars and no-ops when its URL is unset.
|
|
66
68
|
- **Phase 1 — Postgres lineage store.** Persists the `source_asset → caption → human_edit → dataset_membership → training_run` DAG for LoRA reproducibility, edit capture, and the feedback loop. Backed by a psycopg connection **pool** (concurrent `asyncio.to_thread` calls are safe; a dropped connection is replaced), with a `transaction()` boundary for atomic multi-step writes. `open_lineage_store()` returns a no-op store when `CORTEX_PG_URL` is unset; psycopg lives behind the `[postgres]` extra.
|
|
67
69
|
- **Phase 2 — Qdrant vector store.** Stores image + tag-set embeddings for retrieval-augmented few-shot and near-duplicate curation; put a `caption_id`/`asset_id` in a point's payload and a search hit joins straight back to the lineage. `open_vector_store()` no-ops when `CORTEX_QDRANT_URL` is unset; qdrant-client lives behind the `[qdrant]` extra. cortex stores vectors it's *handed* — computing embeddings is the caller's job.
|
|
@@ -121,7 +123,17 @@ illegal = [r for r in verdict.rules if policies.is_illegal("adult-granular", r)]
|
|
|
121
123
|
policies.mode("adult-granular"), policies.mode("default") # "nsfw", "sfw"
|
|
122
124
|
```
|
|
123
125
|
|
|
124
|
-
Stages ask for a policy by name; `policies` holds each one's text, the rules that mean illegal content under it, and its SFW/NSFW mode (`default` and `sfw-*` are SFW).
|
|
126
|
+
Stages ask for a policy by name; `policies` holds each one's text, the rules that mean illegal content under it, and its SFW/NSFW mode (`default` and `sfw-*` are SFW). The known names are `policies.POLICIES`; any other name raises `ModerationConfigError` (an `sfw-*` name gets mode `sfw` but has no text):
|
|
127
|
+
|
|
128
|
+
| Policy | Mode | Illegal rules |
|
|
129
|
+
|---|---|---|
|
|
130
|
+
| `default` (SingGuard's own rules, no text sent) | sfw | none |
|
|
131
|
+
| `adult` | nsfw | A |
|
|
132
|
+
| `adult-granular` | nsfw | A, H, I |
|
|
133
|
+
| `adult-cautious` | nsfw | A |
|
|
134
|
+
| `adult-cinematic` | nsfw | A |
|
|
135
|
+
|
|
136
|
+
`adult-granular`, `adult-cautious` and `adult-cinematic` are under evaluation against `adult`; one adult policy remains at release, beside `default`.
|
|
125
137
|
|
|
126
138
|
```python
|
|
127
139
|
from argus_cortex.gpu import GpuLeaseTimeout, coordinator_from_env
|
|
@@ -191,6 +203,8 @@ uv pip install "argus-cortex[server]" # + starlette for argus_cortex.server (
|
|
|
191
203
|
uv pip install "argus-cortex[postgres]" # + psycopg for the lineage store
|
|
192
204
|
uv pip install "argus-cortex[qdrant]" # + qdrant-client for the vector store
|
|
193
205
|
uv pip install "argus-cortex[s3]" # + minio for the blob store
|
|
206
|
+
uv pip install "argus-cortex[images]" # + Pillow for SingGuardClient downscaling (on by default)
|
|
207
|
+
uv pip install "argus-cortex[gpu]" # + nvidia-ml-py for the GPU lease's free-VRAM probe
|
|
194
208
|
```
|
|
195
209
|
|
|
196
210
|
The stateful services are configured via `CORTEX_*` env vars — see [`.env.example`](.env.example). Each is optional: leave a URL unset and that feature degrades to a no-op.
|
|
@@ -7,12 +7,14 @@ Part of the Argus suite; [SUITE.md](https://github.com/smk762/argus-cortex/blob/
|
|
|
7
7
|
## What's here
|
|
8
8
|
|
|
9
9
|
- **`argus_cortex.taxonomy`** — `TargetProfile` / `TargetStyle` / `TargetCategory`, the "moat" types every stage inherits verbatim. `taxonomy_schema()` renders them into the committed `taxonomy-schema.json` (`make schema` regenerates it; a test fails when it is stale), so non-Python clients generate their types instead of copying the literals.
|
|
10
|
+
- **`argus_cortex.provenance`**: `Provenance` / `ProvenanceKind`, where a face, voice or image came from (the shape argus-mask#19 defined). `personal` needs only a `source` and is never `cleared`; `stock`, `synthetic` and `consented` are cleared, each states its licence, and `consented` also names its `subject` and the `release_sha256` of the signed release (never the document). `curated` is reserved and not cleared. Strict: unknown fields and a blank `source` are refused, `licence` is read as `license`, and a stored `cleared` is recomputed. A `synthetic` or `personal` source may name its `generator` (`model`, `model_sha256`, `seed`, `prompt`; optional, refused on other kinds). `provenance_schema()` renders the committed `provenance-schema.json` (`make schema`; a test fails when it is stale).
|
|
11
|
+
- **`argus_cortex.consent`**: a real person's likeness release, as argus-mask#26 defined it. `ConsentRecord` is keyed by the `release_sha256` a `consented` `Provenance` names, and holds the subject, who collected it, signing and expiry dates (expiry must be stated, `null` for none), the age check (who and when, never the ID), the `face`/`voice` opt-ins, voice `deliveries`, `uses` (`avatar`, `video`, `speech`, `training`; training is off unless listed), sha256s of the reference images and recordings, revocation terms and any `revocation`. `consent_valid(record, use=, likeness=, at=, delivery=)` returns a `ConsentVerdict` (`ok`, `reason`, `detail`), checking in order `revoked`, `not-yet-signed`, `expired`, `likeness-not-covered`, `use-not-covered`, `delivery-not-covered`; `at` must be timezone-aware and dates compare as UTC days, so the check never reads the clock. `consent_matches(record, provenance)` checks the record is the release and subject a provenance names. A record names a person, so services return only verdicts, never records. `consent_schema()` renders the committed `consent-schema.json`.
|
|
10
12
|
- **`argus_cortex.wire`** — the versioned wire-schema toolkit: `check_version()` (major-compatibility gate), `make_versioned_base()` (a Pydantic base that stamps + checks a version field like `proof_version` / `manifest_version`), and `wire_schema()` / `render_schema()` for the committed-schema `schema --check` CLI pattern.
|
|
11
13
|
- **`argus_cortex.backends`** — the AI-backend contract generalised from argus-lens: `Backend` / `LocalBackend` / `RemoteBackend` (point at a hosted service by `base_url`, `host`/`port`, or a known `RemoteProvider`), plus `with_retries()` and `resolve_device()`. httpx lives behind the `[remote]` extra.
|
|
12
14
|
- **`argus_cortex.server`** — shared write-guard + env-flag scaffolding for the suite's FastAPI micro-servers: `WriteGuard` (a pure-ASGI method-gate that never buffers streaming responses), the `constant_refuse()` / `cross_site_refuse()` predicates (read-only/replay mode and cross-site-write protection are two configs of the one guard), the `UNSAFE_METHODS` / `TRUTHY` / `FALSY` constants, and `env_flag()` (warns on a mistyped protection flag rather than silently disabling it). Starlette lives behind the `[server]` extra.
|
|
13
|
-
- **`argus_cortex.xmp`** — the suite's one XMP sidecar implementation (hoisted from argus-lens): `write_xmp()` / `read_xmp()` / `merge_xmp()` / `parse_xmp()` over an `XmpData` model covering `dc` (keywords, description), `xmp` (Rating, Label), `lr` (hierarchical keywords), `Iptc4xmpExt` (PersonInImage), `mwg-rs` face/pet regions, and `argus:ContentRating`. Writes **merge**: each property you set replaces that property (latest write wins), everything else in the sidecar — Lightroom develop settings, GPS, another stage's fields — is preserved. `None` leaves a property alone, an empty value removes it. Writes are atomic; an unparseable existing sidecar raises `XmpError` instead of being clobbered. Stdlib only.
|
|
15
|
+
- **`argus_cortex.xmp`** — the suite's one XMP sidecar implementation (hoisted from argus-lens): `write_xmp()` / `read_xmp()` / `merge_xmp()` / `parse_xmp()` over an `XmpData` model covering `dc` (keywords, description), `xmp` (Rating, Label), `lr` (hierarchical keywords), `Iptc4xmpExt` (PersonInImage), `mwg-rs` face/pet regions, and `argus:ContentRating`. Writes **merge**: each property you set replaces that property (latest write wins), everything else in the sidecar — Lightroom develop settings, GPS, another stage's fields — is preserved. `None` leaves a property alone, an empty value removes it. Writes are atomic; an unparseable existing sidecar raises `XmpError` instead of being clobbered. Stdlib + pydantic only.
|
|
14
16
|
- **`argus_cortex.moderation`** — the suite's content-moderation clients, over HTTP to servers the deployer runs (nothing here imports a detector): `NudeNetClient` (a NudeNet server's `/infer` → `NsfwResult`: detections, per-class maxima, and an **exposed score**) and `SingGuardClient` (a SingGuard server's `/api/guard/check` → `GuardResult`: verdict, the policy rules that fired, explanation; optional custom policy text). `DEFAULT_EXPOSED_LABELS` is the suite's **one definition of nudity**: the five exposed buttocks/breast/genitalia/anus classes — faces, covered parts, and bare feet, belly, armpits or male chest never count. Stdlib + pydantic; Pillow (for SingGuard's downscaling of large images, on by default) is behind `[images]`: without it `SingGuardClient(...)` raises `ModerationConfigError` at construction unless given `downscale=False`. A `user:password@` in a URL is sent as HTTP Basic auth. URLs are passed in, never read from the environment here: each stage owns its config. NudeNet itself is AGPL-3.0, which is why it stays behind an HTTP boundary.
|
|
15
|
-
- **`argus_cortex.gpu`**: GPU tenancy, generalised from argus-lens. `coordinator_from_env()` returns a coordinator whose `lease(caller=, min_vram_mb=)` holds a GPU slot for a block of work. `none` (the default) grants every lease at once. `lease` takes an exclusive `flock` that every argus process on the host shares (one lock for the host, not per GPU), then waits until `free_vram_mb()` (NVML, behind `[gpu]`) reports `min_vram_mb` free across *every* process on the card, ComfyUI and Ollama included, which never take the lock. It raises `GpuLeaseTimeout` after `ARGUS_GPU_LEASE_TIMEOUT_S` (300 s). The VRAM check is a snapshot, not a reservation, and a probe that cannot run lets the lease through. Containers each have their own `/tmp`, so set `ARGUS_GPU_LEASE_PATH` to a file on a volume every GPU service mounts, or the lock coordinates nothing.
|
|
17
|
+
- **`argus_cortex.gpu`**: GPU tenancy, generalised from argus-lens. `coordinator_from_env()` returns a coordinator whose `lease(caller=, min_vram_mb=)` holds a GPU slot for a block of work. `none` (the default) grants every lease at once. `lease` takes an exclusive `flock` that every argus process on the host shares (one lock for the host, not per GPU), then waits until `free_vram_mb()` (NVML, behind `[gpu]`) reports `min_vram_mb` free across *every* process on the card, ComfyUI and Ollama included, which never take the lock. It raises `GpuLeaseTimeout` after `ARGUS_GPU_LEASE_TIMEOUT_S` (300 s). The VRAM check is a snapshot, not a reservation, and a probe that cannot run lets the lease through. Containers each have their own `/tmp`, so set `ARGUS_GPU_LEASE_PATH` to a file on a volume every GPU service mounts, or the lock coordinates nothing. `ARGUS_GPU_DEVICE` (default `0`; an invalid value warns and falls back to `0`) picks which card NVML probes for free VRAM; the lock stays host-wide.
|
|
16
18
|
- **`argus_cortex.store`** — the optional **stateful services layer** (the suite's persistent "memory"). External and opt-in — every store is configured by `CORTEX_*` env vars and no-ops when its URL is unset.
|
|
17
19
|
- **Phase 1 — Postgres lineage store.** Persists the `source_asset → caption → human_edit → dataset_membership → training_run` DAG for LoRA reproducibility, edit capture, and the feedback loop. Backed by a psycopg connection **pool** (concurrent `asyncio.to_thread` calls are safe; a dropped connection is replaced), with a `transaction()` boundary for atomic multi-step writes. `open_lineage_store()` returns a no-op store when `CORTEX_PG_URL` is unset; psycopg lives behind the `[postgres]` extra.
|
|
18
20
|
- **Phase 2 — Qdrant vector store.** Stores image + tag-set embeddings for retrieval-augmented few-shot and near-duplicate curation; put a `caption_id`/`asset_id` in a point's payload and a search hit joins straight back to the lineage. `open_vector_store()` no-ops when `CORTEX_QDRANT_URL` is unset; qdrant-client lives behind the `[qdrant]` extra. cortex stores vectors it's *handed* — computing embeddings is the caller's job.
|
|
@@ -72,7 +74,17 @@ illegal = [r for r in verdict.rules if policies.is_illegal("adult-granular", r)]
|
|
|
72
74
|
policies.mode("adult-granular"), policies.mode("default") # "nsfw", "sfw"
|
|
73
75
|
```
|
|
74
76
|
|
|
75
|
-
Stages ask for a policy by name; `policies` holds each one's text, the rules that mean illegal content under it, and its SFW/NSFW mode (`default` and `sfw-*` are SFW).
|
|
77
|
+
Stages ask for a policy by name; `policies` holds each one's text, the rules that mean illegal content under it, and its SFW/NSFW mode (`default` and `sfw-*` are SFW). The known names are `policies.POLICIES`; any other name raises `ModerationConfigError` (an `sfw-*` name gets mode `sfw` but has no text):
|
|
78
|
+
|
|
79
|
+
| Policy | Mode | Illegal rules |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| `default` (SingGuard's own rules, no text sent) | sfw | none |
|
|
82
|
+
| `adult` | nsfw | A |
|
|
83
|
+
| `adult-granular` | nsfw | A, H, I |
|
|
84
|
+
| `adult-cautious` | nsfw | A |
|
|
85
|
+
| `adult-cinematic` | nsfw | A |
|
|
86
|
+
|
|
87
|
+
`adult-granular`, `adult-cautious` and `adult-cinematic` are under evaluation against `adult`; one adult policy remains at release, beside `default`.
|
|
76
88
|
|
|
77
89
|
```python
|
|
78
90
|
from argus_cortex.gpu import GpuLeaseTimeout, coordinator_from_env
|
|
@@ -142,6 +154,8 @@ uv pip install "argus-cortex[server]" # + starlette for argus_cortex.server (
|
|
|
142
154
|
uv pip install "argus-cortex[postgres]" # + psycopg for the lineage store
|
|
143
155
|
uv pip install "argus-cortex[qdrant]" # + qdrant-client for the vector store
|
|
144
156
|
uv pip install "argus-cortex[s3]" # + minio for the blob store
|
|
157
|
+
uv pip install "argus-cortex[images]" # + Pillow for SingGuardClient downscaling (on by default)
|
|
158
|
+
uv pip install "argus-cortex[gpu]" # + nvidia-ml-py for the GPU lease's free-VRAM probe
|
|
145
159
|
```
|
|
146
160
|
|
|
147
161
|
The stateful services are configured via `CORTEX_*` env vars — see [`.env.example`](.env.example). Each is optional: leave a URL unset and that feature degrades to a no-op.
|
|
@@ -14,23 +14,23 @@ GitHub: `smk762/<repo>`. Ports are each service's default.
|
|
|
14
14
|
|
|
15
15
|
| Repo | Kind | Port | What it is for |
|
|
16
16
|
|---|---|---|---|
|
|
17
|
-
| **argus-cortex** | library | n/a | Shared foundation: taxonomy, wire-schema versioning, AI-backend contract, server guards, GPU lease, XMP, moderation clients, optional lineage/vector/blob stores. |
|
|
18
|
-
| **argus-quarry** | service | 8102 | Acquire public-domain / CC0 images with provenance and licence into a category-sorted raw pool. Acquisition only. |
|
|
17
|
+
| **argus-cortex** | library | n/a | Shared foundation: taxonomy, wire-schema versioning, AI-backend contract, server guards, GPU lease, XMP, moderation clients, likeness provenance and consent records, optional lineage/vector/blob stores. |
|
|
18
|
+
| **argus-quarry** | service | 8102 | Acquire public-domain / CC0 images with provenance and licence into a category-sorted raw pool. Searches local metadata archives of PD12M and Megalith-10m (filters, plus CLIP semantic and "more like this" search over PD12M) and lands chosen slices, with Megalith's Drawthings mirror as a fallback for photos gone from Flickr. Acquisition only. |
|
|
19
19
|
| **argus-curator** | service | 8101 | Decide which images belong in a LoRA training set (quality, near-dup, faces, NSFW, diversity) and export them with a `manifest.jsonl`. |
|
|
20
|
-
| **argus-lens** | service | 8100 (8080 standalone) | Structured, category-bucketed captions, `.txt` sidecars and XMP keywords. |
|
|
20
|
+
| **argus-lens** | service | 8100 (8080 standalone) | Structured, category-bucketed captions, `.txt` sidecars and XMP keywords. Records live captions to the cortex lineage store (the tape lightbox and replay read); runs read-only with `LENS_READ_ONLY`. |
|
|
21
21
|
| **argus-forge** | service | 8103 | Turn a curated, captioned export into runnable kohya_ss / OneTrainer / diffusers configs. |
|
|
22
22
|
| **argus-proof** | service | 8104 | Evaluate a trained LoRA against its dataset: sample grid, scores, pass/fail. |
|
|
23
23
|
| **argus-atlas** | service | 8105 | Bake georeferenced fantasy-map overlays from real terrain (GDAL controls plus a cartography LoRA), to GeoTIFF / PMTiles. |
|
|
24
24
|
| **argus-darkroom** | service | 8106 | Guarded image generation: checks the prompt, generates via ComfyUI, checks each output, and keeps a record of every attempt. |
|
|
25
|
-
| **argus-survey** | service | 8107 | Point-cloud deliverables for land surveyors: QA, ground, DTM/DSM, contours, volumes, change, ASPRS accuracy. |
|
|
26
|
-
| **argus-mint** | service | 8108 | Provenance tokens for game assets: renders reviewed templates through darkroom,
|
|
27
|
-
| **argus-mask** | service | 8109 | A talking face: audio in, facial-animation frames out, rendered in a browser on any LAN screen. |
|
|
25
|
+
| **argus-survey** | service | 8107 | Point-cloud deliverables for land surveyors (LAS/LAZ/COPC/E57 in): QA, ground, DTM/DSM/CHM, contours, stockpile volumes and cut/fill (grid and ground-scaled), change between epochs, profiles, ASPRS Edition 2 (v2, 2024) accuracy, LAS 1.4 / E57 export for ReCap and Civil 3D. Explicit datum operations (MGA2020, AHD via AUSGeoid2020), every command recorded in `job.json`. PyPI `argus-survey`, image `ghcr.io/smk762/argus-survey`. |
|
|
26
|
+
| **argus-mint** | service | 8108 | Provenance tokens for game assets: renders reviewed templates (fixed variable lists, no free prompts) through darkroom, checks each template against darkroom's checkpoints and workflows before approval, frames cards and writes their bios, and has the moderator and owner (SIWE) approve every image before it is pinned to IPFS. Mints ERC-721 cards and soulbound deeds whose metadata records the render's template, variables, checkpoint, LoRAs and seed, and anchors Merkle roots and commit/reveal secrets (Base). PyPI `argus-mint`, image `ghcr.io/smk762/argus-mint`. |
|
|
27
|
+
| **argus-mask** | service | 8109 | A talking face: audio in (or text through a TTS service), ARKit facial-animation frames out (an energy driver on CPU, or NVIDIA Audio2Face-3D as a separate image), rendered in a browser on any LAN screen. Mesh (`.glb`) and LAM Gaussian-splat heads, each with provenance (`personal` or cleared); an optional face editor builds MakeHuman heads with Blender. PyPI `argus-mask`, image `ghcr.io/smk762/argus-mask`. |
|
|
28
28
|
| **argus-studio** | UI + compose | 3000 | The suite web UI, and the compose stack that runs the services from GHCR images. No backend code. |
|
|
29
|
-
| **argus-safelight** | UI | 3097 | Demo UI for darkroom: prompt,
|
|
30
|
-
| **argus-cull** | UI | 3000 | Demo UI for curator: which images make the set and why, plus the paths to act on. |
|
|
31
|
-
| **argus-lightbox** | UI (static) | 3000 | Demo gallery navigated by lens captions
|
|
32
|
-
| **argus-sightline** | UI | 3107 | Workspace UI for survey. |
|
|
33
|
-
| **argus-assay** | UI | 3108 | Review UI for mint
|
|
29
|
+
| **argus-safelight** | UI | 3097 | Demo UI for darkroom: prompt and pre-flight, text-to-image, image-to-image and inpainting over SSE, the per-policy shield grid, history, and darkroom's docs in `/docs` with in-context help. Follows darkroom's `dev` at a recorded commit (`web/schema/pins.json`: docs, wire types and fixture move together), not a release; built from source by darkroom's compose, no image. |
|
|
30
|
+
| **argus-cull** | UI + compose | 3000 | Demo UI for curator: which images make the set and why, plus the paths to act on. Its compose runs curator with NudeNet, EraX-NSFW and watermark sidecars (NudeNet-shaped `POST /infer`); SingGuard is darkroom's agent-composer. Follows curator's `dev` at a recorded commit, not a release; web image `ghcr.io/smk762/argus-cull`. |
|
|
31
|
+
| **argus-lightbox** | UI (static) + compose | 3000 | Demo gallery navigated by lens captions. Bakes the recorded tape from cortex stores into a static site (the hosted demo), or captions a photo folder through lens in its compose stack, where a small server also lets you pick each photo's final caption. `/docs` links lens's docs at the baked version. |
|
|
32
|
+
| **argus-sightline** | UI | 3107 | Workspace UI for survey: every step over SSE, a map of the derived views with drawing tools, a COPC point view, datums always on screen, a guided demo measured against analytic truth, and a "Made with" line per step from `job.json`. Follows survey's `dev` at a recorded commit (`schema/pins.json`: wire types, demo numbers and docs links move together), not a release; built from source by its compose, no published image yet. |
|
|
33
|
+
| **argus-assay** | UI | 3108 | Review UI for mint. The moderator (token) approves or rejects every card; the owner signs for theirs (EIP-4361 via the wallet) and can change its text and style with a live preview, which both then review again. Templates, frames and bio templates are approved in its catalogue, with sample runs. New drafts render through darkroom on a reviewed checkpoint and LoRAs, or come from mint's pre-rendered portrait library with no GPU, shown as a checkpoint comparison grid. A mock serves mint's recorded fixture for demo mode (`make mock`). Pins a mint release (`web/schema/pins.json`, now v0.2.0: wire types and fixture move together); built from source by its compose, no image. |
|
|
34
34
|
| **argus-halo** | infra | n/a | Terraform for the public demo (`argus.dragonhound.dev`): read-only replay services plus a private data host. |
|
|
35
35
|
| **argus-ci** | infra | n/a | Reusable GitHub Actions workflows (uv, ruff, pytest, build, release). |
|
|
36
36
|
| **argus-pkg-template** | infra | n/a | Copier template for new Argus Python packages; `copier update` pulls tooling changes. |
|
|
@@ -57,14 +57,18 @@ Studio has a page for lens, curator, quarry, forge, proof, atlas and darkroom, a
|
|
|
57
57
|
| Guard a FastAPI server's writes, or run read-only | `argus_cortex.server` (`WriteGuard`, `env_flag`) | Use `BaseHTTPMiddleware`, which buffers streams. |
|
|
58
58
|
| Read or write XMP sidecars | `argus_cortex.xmp` | Overwrite another stage's properties. |
|
|
59
59
|
| Record lineage, embeddings or blobs | `argus_cortex.store` (`open_lineage_store` / `open_vector_store` / `open_blob_store`) | Add a database to a single stage. |
|
|
60
|
+
| Record where a face, voice or image came from, or whether it may be shown publicly | `argus_cortex.provenance` (`Provenance`, `.cleared`, `generator`); non-Python clients use `provenance-schema.json` | Define your own provenance kinds or consent fields. |
|
|
61
|
+
| Check a real person's consent for a use of their face or voice | `argus_cortex.consent` (`ConsentRecord`, `consent_valid` → `ConsentVerdict`, `consent_matches`); non-Python clients use `consent-schema.json`. Records are written by **mask** | Invent refusal reasons, or serve a record (it names a person). |
|
|
60
62
|
| The training target (style, category) | `argus_cortex.taxonomy`; non-Python clients use `taxonomy-schema.json` | Copy the literals. |
|
|
61
63
|
| Acquire source photos with licence and provenance | **quarry** | Scrape inside another stage. |
|
|
64
|
+
| Find public-domain photos by caption, filters or meaning, then land a slice | **quarry** `GET /archives/{name}/search` (`semantic=`, `similar_to=` on PD12M), `POST /archives/{name}/fetch` (opt-in, `QUARRY_ALLOW_FETCH=1`) | Download PD12M or Megalith wholesale to search it. |
|
|
62
65
|
| Score, dedupe or select images; faces; content rating | **curator** | Re-score in a later stage. |
|
|
63
66
|
| Caption or keyword images | **lens** | Write ad-hoc captions. |
|
|
64
67
|
| Training configs, or evaluating a LoRA | **forge**, **proof** | |
|
|
65
68
|
| Terrain, georeferencing, map tiles | **atlas** (stylised), **survey** (survey-grade) | |
|
|
66
|
-
|
|
|
67
|
-
|
|
|
69
|
+
| Point clouds: ground classification, DTM/DSM, volumes, datum transformations (geoid heights, GDA94→GDA2020) | **survey** (CLI, or `POST /jobs/{id}/{step}` over SSE); its GeoTIFFs feed `argus-atlas controls --dem` | Let PROJ pick a transformation, or reproject heights without a geoid grid. |
|
|
70
|
+
| A face that speaks | **mask** `POST /speak?face=<id>` (text), `POST /push?face=<id>` (a WAV or PCM you already have) or the `/session/<id>/source` socket; screens open `/?face=<id>` | Drive a face's animation yourself, or render it per stage. |
|
|
71
|
+
| On-chain provenance, IPFS; game-asset cards from reviewed templates | **mint** (`argus-mint serve`, or the CLI); a consumer supplies template variables, display text and 32-byte leaf hashes | Mint tokens a game reads stats from, or send free text to a model. |
|
|
68
72
|
| Run the whole stack locally | **studio** `compose.yaml` | |
|
|
69
73
|
| A new Python package, or CI | **argus-pkg-template**, **argus-ci** | Copy another repo's tooling by hand. |
|
|
70
74
|
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$defs": {
|
|
3
|
+
"AgeCheck": {
|
|
4
|
+
"additionalProperties": false,
|
|
5
|
+
"description": "The adult check against ID at signing: who did it and when. Never the ID or any copy of it.",
|
|
6
|
+
"properties": {
|
|
7
|
+
"checked_by": {
|
|
8
|
+
"minLength": 1,
|
|
9
|
+
"title": "Checked By",
|
|
10
|
+
"type": "string"
|
|
11
|
+
},
|
|
12
|
+
"checked_on": {
|
|
13
|
+
"format": "date",
|
|
14
|
+
"title": "Checked On",
|
|
15
|
+
"type": "string"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"required": [
|
|
19
|
+
"checked_by",
|
|
20
|
+
"checked_on"
|
|
21
|
+
],
|
|
22
|
+
"title": "AgeCheck",
|
|
23
|
+
"type": "object"
|
|
24
|
+
},
|
|
25
|
+
"ConsentRecord": {
|
|
26
|
+
"additionalProperties": false,
|
|
27
|
+
"description": "One signed likeness release, as the suite checks it. Keyed by ``release_sha256``.\n\nFree-text fields (``exclusions``, ``media``, ``territories``, ``notes``) are for people and are\nnot checked by code. Payment and retention terms stay in the signed document.",
|
|
28
|
+
"properties": {
|
|
29
|
+
"age_check": {
|
|
30
|
+
"$ref": "#/$defs/AgeCheck"
|
|
31
|
+
},
|
|
32
|
+
"collected_by": {
|
|
33
|
+
"minLength": 1,
|
|
34
|
+
"title": "Collected By",
|
|
35
|
+
"type": "string"
|
|
36
|
+
},
|
|
37
|
+
"deliveries": {
|
|
38
|
+
"default": [],
|
|
39
|
+
"items": {
|
|
40
|
+
"type": "string"
|
|
41
|
+
},
|
|
42
|
+
"title": "Deliveries",
|
|
43
|
+
"type": "array"
|
|
44
|
+
},
|
|
45
|
+
"exclusions": {
|
|
46
|
+
"default": [],
|
|
47
|
+
"items": {
|
|
48
|
+
"type": "string"
|
|
49
|
+
},
|
|
50
|
+
"title": "Exclusions",
|
|
51
|
+
"type": "array"
|
|
52
|
+
},
|
|
53
|
+
"expires_on": {
|
|
54
|
+
"anyOf": [
|
|
55
|
+
{
|
|
56
|
+
"format": "date",
|
|
57
|
+
"type": "string"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"type": "null"
|
|
61
|
+
}
|
|
62
|
+
],
|
|
63
|
+
"description": "None means no expiry; it must be stated, not omitted.",
|
|
64
|
+
"title": "Expires On"
|
|
65
|
+
},
|
|
66
|
+
"face": {
|
|
67
|
+
"title": "Face",
|
|
68
|
+
"type": "boolean"
|
|
69
|
+
},
|
|
70
|
+
"media": {
|
|
71
|
+
"default": [],
|
|
72
|
+
"items": {
|
|
73
|
+
"type": "string"
|
|
74
|
+
},
|
|
75
|
+
"title": "Media",
|
|
76
|
+
"type": "array"
|
|
77
|
+
},
|
|
78
|
+
"notes": {
|
|
79
|
+
"default": "",
|
|
80
|
+
"title": "Notes",
|
|
81
|
+
"type": "string"
|
|
82
|
+
},
|
|
83
|
+
"notice_days": {
|
|
84
|
+
"minimum": 0,
|
|
85
|
+
"title": "Notice Days",
|
|
86
|
+
"type": "integer"
|
|
87
|
+
},
|
|
88
|
+
"on_revoke": {
|
|
89
|
+
"enum": [
|
|
90
|
+
"delete",
|
|
91
|
+
"keep-labelled"
|
|
92
|
+
],
|
|
93
|
+
"title": "On Revoke",
|
|
94
|
+
"type": "string"
|
|
95
|
+
},
|
|
96
|
+
"reference_images": {
|
|
97
|
+
"default": [],
|
|
98
|
+
"items": {
|
|
99
|
+
"pattern": "^[0-9a-f]{64}$",
|
|
100
|
+
"type": "string"
|
|
101
|
+
},
|
|
102
|
+
"title": "Reference Images",
|
|
103
|
+
"type": "array"
|
|
104
|
+
},
|
|
105
|
+
"reference_recordings": {
|
|
106
|
+
"default": [],
|
|
107
|
+
"items": {
|
|
108
|
+
"pattern": "^[0-9a-f]{64}$",
|
|
109
|
+
"type": "string"
|
|
110
|
+
},
|
|
111
|
+
"title": "Reference Recordings",
|
|
112
|
+
"type": "array"
|
|
113
|
+
},
|
|
114
|
+
"release_sha256": {
|
|
115
|
+
"pattern": "^[0-9a-f]{64}$",
|
|
116
|
+
"title": "Release Sha256",
|
|
117
|
+
"type": "string"
|
|
118
|
+
},
|
|
119
|
+
"revocable": {
|
|
120
|
+
"title": "Revocable",
|
|
121
|
+
"type": "boolean"
|
|
122
|
+
},
|
|
123
|
+
"revocation": {
|
|
124
|
+
"anyOf": [
|
|
125
|
+
{
|
|
126
|
+
"$ref": "#/$defs/Revocation"
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"type": "null"
|
|
130
|
+
}
|
|
131
|
+
],
|
|
132
|
+
"default": null
|
|
133
|
+
},
|
|
134
|
+
"signed_on": {
|
|
135
|
+
"format": "date",
|
|
136
|
+
"title": "Signed On",
|
|
137
|
+
"type": "string"
|
|
138
|
+
},
|
|
139
|
+
"subject": {
|
|
140
|
+
"minLength": 1,
|
|
141
|
+
"title": "Subject",
|
|
142
|
+
"type": "string"
|
|
143
|
+
},
|
|
144
|
+
"territories": {
|
|
145
|
+
"default": [],
|
|
146
|
+
"items": {
|
|
147
|
+
"type": "string"
|
|
148
|
+
},
|
|
149
|
+
"title": "Territories",
|
|
150
|
+
"type": "array"
|
|
151
|
+
},
|
|
152
|
+
"uses": {
|
|
153
|
+
"items": {
|
|
154
|
+
"enum": [
|
|
155
|
+
"avatar",
|
|
156
|
+
"video",
|
|
157
|
+
"speech",
|
|
158
|
+
"training"
|
|
159
|
+
],
|
|
160
|
+
"type": "string"
|
|
161
|
+
},
|
|
162
|
+
"title": "Uses",
|
|
163
|
+
"type": "array"
|
|
164
|
+
},
|
|
165
|
+
"voice": {
|
|
166
|
+
"title": "Voice",
|
|
167
|
+
"type": "boolean"
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
"required": [
|
|
171
|
+
"release_sha256",
|
|
172
|
+
"subject",
|
|
173
|
+
"collected_by",
|
|
174
|
+
"signed_on",
|
|
175
|
+
"expires_on",
|
|
176
|
+
"age_check",
|
|
177
|
+
"face",
|
|
178
|
+
"voice",
|
|
179
|
+
"uses",
|
|
180
|
+
"revocable",
|
|
181
|
+
"notice_days",
|
|
182
|
+
"on_revoke"
|
|
183
|
+
],
|
|
184
|
+
"title": "ConsentRecord",
|
|
185
|
+
"type": "object"
|
|
186
|
+
},
|
|
187
|
+
"ConsentVerdict": {
|
|
188
|
+
"additionalProperties": false,
|
|
189
|
+
"description": "What a service returns about a record: the verdict and its reason, never the record itself.",
|
|
190
|
+
"properties": {
|
|
191
|
+
"detail": {
|
|
192
|
+
"default": "",
|
|
193
|
+
"title": "Detail",
|
|
194
|
+
"type": "string"
|
|
195
|
+
},
|
|
196
|
+
"ok": {
|
|
197
|
+
"title": "Ok",
|
|
198
|
+
"type": "boolean"
|
|
199
|
+
},
|
|
200
|
+
"reason": {
|
|
201
|
+
"anyOf": [
|
|
202
|
+
{
|
|
203
|
+
"enum": [
|
|
204
|
+
"revoked",
|
|
205
|
+
"not-yet-signed",
|
|
206
|
+
"expired",
|
|
207
|
+
"likeness-not-covered",
|
|
208
|
+
"use-not-covered",
|
|
209
|
+
"delivery-not-covered"
|
|
210
|
+
],
|
|
211
|
+
"type": "string"
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
"type": "null"
|
|
215
|
+
}
|
|
216
|
+
],
|
|
217
|
+
"default": null,
|
|
218
|
+
"title": "Reason"
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
"required": [
|
|
222
|
+
"ok"
|
|
223
|
+
],
|
|
224
|
+
"title": "ConsentVerdict",
|
|
225
|
+
"type": "object"
|
|
226
|
+
},
|
|
227
|
+
"Revocation": {
|
|
228
|
+
"additionalProperties": false,
|
|
229
|
+
"description": "Set by ``consent revoke``. Use stops on ``effective_on``; mask sets it to the day it runs.\n\nThe release's notice period is the subject's commitment, not a grace period for the suite.",
|
|
230
|
+
"properties": {
|
|
231
|
+
"by": {
|
|
232
|
+
"minLength": 1,
|
|
233
|
+
"title": "By",
|
|
234
|
+
"type": "string"
|
|
235
|
+
},
|
|
236
|
+
"effective_on": {
|
|
237
|
+
"format": "date",
|
|
238
|
+
"title": "Effective On",
|
|
239
|
+
"type": "string"
|
|
240
|
+
},
|
|
241
|
+
"requested_on": {
|
|
242
|
+
"format": "date",
|
|
243
|
+
"title": "Requested On",
|
|
244
|
+
"type": "string"
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
"required": [
|
|
248
|
+
"requested_on",
|
|
249
|
+
"effective_on",
|
|
250
|
+
"by"
|
|
251
|
+
],
|
|
252
|
+
"title": "Revocation",
|
|
253
|
+
"type": "object"
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
"title": "argus-cortex consent"
|
|
257
|
+
}
|