argus-cortex 0.5.0__tar.gz → 0.6.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.5.0 → argus_cortex-0.6.0}/.cursor/rules/agent-coding-packs.mdc +5 -1
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/.github/workflows/release.yml +1 -1
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/.gitignore +2 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/AGENTS.md +5 -1
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/CHANGELOG.md +69 -1
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/CLAUDE.md +5 -3
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/Makefile +2 -2
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/PKG-INFO +30 -5
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/README.md +26 -4
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/SUITE.md +18 -14
- argus_cortex-0.6.0/gpu-lease-schema.json +476 -0
- argus_cortex-0.6.0/gpu-tenant-schema.json +369 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/pyproject.toml +7 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/src/argus_cortex/_version.py +2 -2
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/src/argus_cortex/backends.py +24 -12
- argus_cortex-0.6.0/src/argus_cortex/gpu.py +449 -0
- argus_cortex-0.6.0/src/argus_cortex/gpu_broker.py +577 -0
- argus_cortex-0.6.0/src/argus_cortex/gpu_wire.py +368 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/src/argus_cortex/moderation/policies.py +10 -2
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/src/argus_cortex/moderation/singguard.py +21 -10
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/src/argus_cortex/server.py +40 -7
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/src/argus_cortex/store/blob.py +7 -3
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/src/argus_cortex/store/lineage.py +12 -2
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/src/argus_cortex/store/schema.py +34 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/src/argus_cortex/store/vector.py +30 -16
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/src/argus_cortex/xmp.py +92 -18
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/tests/test_backends.py +56 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/tests/test_blob.py +8 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/tests/test_gpu.py +31 -0
- argus_cortex-0.6.0/tests/test_gpu_broker.py +534 -0
- argus_cortex-0.6.0/tests/test_gpu_wire.py +193 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/tests/test_moderation.py +10 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/tests/test_policies.py +3 -1
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/tests/test_server.py +15 -1
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/tests/test_store.py +13 -2
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/tests/test_store_pg_integration.py +14 -1
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/tests/test_vector.py +8 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/tests/test_xmp.py +86 -0
- argus_cortex-0.5.0/src/argus_cortex/gpu.py +0 -242
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/.copier-answers.yml +0 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/.env.example +0 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/.github/workflows/ci.yml +0 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/LICENSE +0 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/consent-schema.json +0 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/provenance-schema.json +0 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/src/argus_cortex/__init__.py +0 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/src/argus_cortex/consent.py +0 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/src/argus_cortex/moderation/__init__.py +0 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/src/argus_cortex/moderation/_http.py +0 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/src/argus_cortex/moderation/nudenet.py +0 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/src/argus_cortex/provenance.py +0 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/src/argus_cortex/py.typed +0 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/src/argus_cortex/store/__init__.py +0 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/src/argus_cortex/store/config.py +0 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/src/argus_cortex/store/errors.py +0 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/src/argus_cortex/store/models.py +0 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/src/argus_cortex/taxonomy.py +0 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/src/argus_cortex/wire.py +0 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/taxonomy-schema.json +0 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/tests/test_consent.py +0 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/tests/test_provenance.py +0 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/tests/test_smoke.py +0 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/tests/test_taxonomy.py +0 -0
- {argus_cortex-0.5.0 → argus_cortex-0.6.0}/tests/test_wire.py +0 -0
|
@@ -17,13 +17,17 @@ The audit API base URL is `$AI_AUDIT_PUBLIC_BASE_URL`. The real host/IP is in th
|
|
|
17
17
|
CLI equivalent: `ai-audit packs --bundle --repo argus-cortex`.
|
|
18
18
|
2. **Claim** the specialist pack you pick:
|
|
19
19
|
`POST $AI_AUDIT_PUBLIC_BASE_URL/audit/packs/<id>/status` `{"status":"claimed"}`
|
|
20
|
-
(send `X-API-Token: $AI_AUDIT_API_TOKEN
|
|
20
|
+
(send `X-API-Token: $AI_AUDIT_API_TOKEN`; the token is in your environment, set for Claude Code
|
|
21
|
+
in `~/.claude/settings.json`. If it is empty or you get a 401, ask the user; don't search env files).
|
|
21
22
|
3. **Fix:** `ai-audit repair --pack-id <id>` (agent-composer repair loop; fetches the pack for you;
|
|
22
23
|
HTTP: `POST http://127.0.0.1:9150/api/repair/run` `{"pack_id":"<id>","mode":"review"}`),
|
|
23
24
|
or read `GET $AI_AUDIT_PUBLIC_BASE_URL/audit/packs/<id>` / `.../brief` and implement it yourself.
|
|
24
25
|
4. **Close:** `POST $AI_AUDIT_PUBLIC_BASE_URL/audit/validate_patch` `{"repo":"argus-cortex","patch":"<diff>","pack_id":"<id>"}`
|
|
25
26
|
— a passing run marks the pack `resolved`.
|
|
26
27
|
|
|
28
|
+
**Search** before crawling: `GET $AI_AUDIT_PUBLIC_BASE_URL/audit/search?q=<question>&repo=argus-cortex&kind=wiki`
|
|
29
|
+
(wiki sections and packs with links; CLI `ai-audit search "<question>" --repo argus-cortex`).
|
|
30
|
+
|
|
27
31
|
World-model constraints (ownership, boundaries, scan branch `dev`) win over guesswork.
|
|
28
32
|
Full flow: ai-code-auditor `AGENTS.md`.
|
|
29
33
|
<!-- ai-audit:agent-packs:end -->
|
|
@@ -159,7 +159,7 @@ jobs:
|
|
|
159
159
|
exit 1
|
|
160
160
|
fi
|
|
161
161
|
failed=0
|
|
162
|
-
for repo in argus-curator argus-lens argus-proof argus-forge argus-darkroom; do
|
|
162
|
+
for repo in argus-curator argus-lens argus-proof argus-forge argus-darkroom argus-mint; do
|
|
163
163
|
if gh api "repos/${GITHUB_REPOSITORY_OWNER}/${repo}/dispatches" \
|
|
164
164
|
-f event_type=cortex-released -f "client_payload[version]=${tag#v}"; then
|
|
165
165
|
echo "Dispatched cortex-released to $repo"
|
|
@@ -12,13 +12,17 @@ The audit API base URL is `$AI_AUDIT_PUBLIC_BASE_URL`. The real host/IP is in th
|
|
|
12
12
|
CLI equivalent: `ai-audit packs --bundle --repo argus-cortex`.
|
|
13
13
|
2. **Claim** the specialist pack you pick:
|
|
14
14
|
`POST $AI_AUDIT_PUBLIC_BASE_URL/audit/packs/<id>/status` `{"status":"claimed"}`
|
|
15
|
-
(send `X-API-Token: $AI_AUDIT_API_TOKEN
|
|
15
|
+
(send `X-API-Token: $AI_AUDIT_API_TOKEN`; the token is in your environment, set for Claude Code
|
|
16
|
+
in `~/.claude/settings.json`. If it is empty or you get a 401, ask the user; don't search env files).
|
|
16
17
|
3. **Fix:** `ai-audit repair --pack-id <id>` (agent-composer repair loop; fetches the pack for you;
|
|
17
18
|
HTTP: `POST http://127.0.0.1:9150/api/repair/run` `{"pack_id":"<id>","mode":"review"}`),
|
|
18
19
|
or read `GET $AI_AUDIT_PUBLIC_BASE_URL/audit/packs/<id>` / `.../brief` and implement it yourself.
|
|
19
20
|
4. **Close:** `POST $AI_AUDIT_PUBLIC_BASE_URL/audit/validate_patch` `{"repo":"argus-cortex","patch":"<diff>","pack_id":"<id>"}`
|
|
20
21
|
— a passing run marks the pack `resolved`.
|
|
21
22
|
|
|
23
|
+
**Search** before crawling: `GET $AI_AUDIT_PUBLIC_BASE_URL/audit/search?q=<question>&repo=argus-cortex&kind=wiki`
|
|
24
|
+
(wiki sections and packs with links; CLI `ai-audit search "<question>" --repo argus-cortex`).
|
|
25
|
+
|
|
22
26
|
World-model constraints (ownership, boundaries, scan branch `dev`) win over guesswork.
|
|
23
27
|
Full flow: ai-code-auditor `AGENTS.md`.
|
|
24
28
|
<!-- ai-audit:agent-packs:end -->
|
|
@@ -7,6 +7,73 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.6.0] - 2026-11-15
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **GPU broker client (`argus_cortex.gpu_broker`).** `BrokerCoordinator` asks argus-iris, the suite's GPU broker,
|
|
14
|
+
for a lease; iris places it on a node, queues it by priority, reserves the VRAM and evicts idle models to make
|
|
15
|
+
room. Select it with `ARGUS_GPU_COORDINATOR=broker` and `ARGUS_GPU_BROKER_URL` (optional
|
|
16
|
+
`ARGUS_GPU_BROKER_TOKEN`, `ARGUS_GPU_TENANT`, `ARGUS_GPU_TENANT_MANIFEST`). A lease long-polls while queued,
|
|
17
|
+
heartbeats in the background, re-attaches if the broker restarts, and reports its outcome (`ok`, `failed`,
|
|
18
|
+
`oom`, `cancelled`) and peak VRAM on release. Each request carries a `request_id`, so the one retry after a
|
|
19
|
+
lost response gets the same lease. It fails open: if the broker is unreachable or answers 5xx, the lease comes
|
|
20
|
+
from `ARGUS_GPU_BROKER_FALLBACK` (`lease`, the default, or `none`). A 4xx or an incompatible version raises
|
|
21
|
+
`BrokerError`; a refusal raises the new `GpuLeaseRefused`. httpx is behind `[remote]` (#78).
|
|
22
|
+
- **GPU wire models (`argus_cortex.gpu_wire`).** The lease contract (`LeaseRequest`, `LeaseStatus`, `Heartbeat`,
|
|
23
|
+
`HeartbeatReply`, `LeaseRelease`; `lease_version` 1.0) and `TenantManifest` (`tenant_version` 1.0), the
|
|
24
|
+
`gpu-tenant.yaml` every repo that uses a GPU commits: its kinds of work with target, footprint (`vram_mb`, and
|
|
25
|
+
`model_mb` for the weights that stay loaded), priority and preemptibility, and its resident models with the
|
|
26
|
+
routes and hints the broker uses to reach, unload, evict and warm them. Committed `gpu-lease-schema.json` and
|
|
27
|
+
`gpu-tenant-schema.json` (#78).
|
|
28
|
+
- **`lease()` options and handle.** Every coordinator's `lease()` takes optional `priority`, `target`, `kind`,
|
|
29
|
+
`preemptible`, `constraints` and `model_mb`, which only the broker uses, and yields a `GpuLease` (`node`,
|
|
30
|
+
`base_url`, `should_yield()`, `report_peak_vram()`). Every coordinator gains an async `alease()`. Existing
|
|
31
|
+
`with coordinator.lease(caller=, min_vram_mb=):` calls are unchanged (#78).
|
|
32
|
+
- **`[yaml]` extra** (PyYAML) for `load_tenant_manifest()` reading YAML; JSON needs nothing (#78).
|
|
33
|
+
- `SUITE.md`: a row for argus-handbook, the suite's public docs at docs.dragonhound.dev.
|
|
34
|
+
- `brand/`: the suite's identity (vesica-iris suite mark, one mark per package, Panoptes lettering font, the
|
|
35
|
+
identity sheet, and `brand/tools/panoptes.py` to regenerate them). Panoptes 0.2 adds capitals, digits and basic
|
|
36
|
+
punctuation (85 glyphs); glyphs made only of dots, like the colon, keep every dot in the font build. Favicon sets
|
|
37
|
+
for every web UI (`mark/favicon/`, `packages/<pkg>/favicon/`) and `panoptes.py favicons` to regenerate them;
|
|
38
|
+
`brand/README.md` says where each UI puts them. Not part of the package: excluded from the wheel and the sdist.
|
|
39
|
+
|
|
40
|
+
### Changed
|
|
41
|
+
- `SUITE.md`: the "Share the GPU" row points at the broker and asks each repo to declare its GPU use in a
|
|
42
|
+
`gpu-tenant.yaml` (#78). argus-studio's row says its `/docs` keeps only the captioning concept pages; the setup
|
|
43
|
+
guides and package docs moved to argus-handbook, and the old paths 301 there.
|
|
44
|
+
- `release.yml` also sends `cortex-released` to argus-mint, whose image installs cortex from its `server` extra's
|
|
45
|
+
range and now rebuilds on it (argus-mint#29).
|
|
46
|
+
- **Behaviour changes a stage may notice on this bump (#73):**
|
|
47
|
+
- `cross_site_refuse()` no longer trusts a same-host write by bare hostname (DNS rebinding). A same-host
|
|
48
|
+
`Origin` passes only when the host is an IP literal, `localhost`, or listed in the new `trusted_hosts`
|
|
49
|
+
argument; a server reached by a DNS name must pass it (or list the origin in `trusted_origins`).
|
|
50
|
+
- `RemoteBackend.post_json()` retries only failures where the request never reached the server (connect
|
|
51
|
+
errors, pool timeouts), not a `ReadTimeout`; pass `idempotent=True` to keep the old retries.
|
|
52
|
+
- `policies.mode()` raises `ModerationConfigError` for an unknown policy name instead of returning `nsfw`.
|
|
53
|
+
- `QdrantVectorStore.search()` returns the key passed to `upsert()` as `VectorHit.id`, not its UUID5; the
|
|
54
|
+
original key rides in the reserved `_point_id` payload field (`POINT_ID_FIELD`), stripped from `payload`.
|
|
55
|
+
- `SingGuardClient` refuses a multi-frame image (animated GIF/WebP/APNG, multi-page TIFF) with
|
|
56
|
+
`GuardCheckFailed` instead of judging frame 0.
|
|
57
|
+
- `CORTEX_S3_ENDPOINT` refuses a scheme other than `http://`/`https://`.
|
|
58
|
+
|
|
59
|
+
### Fixed
|
|
60
|
+
- `LeaseCoordinator` refuses a symlinked or non-regular lock file and chmods it only when it owns it (#73).
|
|
61
|
+
- The lineage schema refuses a dataset membership whose `edit_id` belongs to another caption (a trigger, so it
|
|
62
|
+
reaches existing tables) (#73).
|
|
63
|
+
- XMP: regions are written as valid RDF (no `parseType` on attribute-form structs) and read back from nested
|
|
64
|
+
`rdf:Description` forms; a sidecar's prefixes no longer rebind the process-wide ElementTree registry; concurrent
|
|
65
|
+
`write_xmp()` merges into one directory take an exclusive lock so neither drops the other's properties (#73).
|
|
66
|
+
- `ensure_schema()` serialises on a Postgres advisory lock and creates the membership trigger in one statement, so
|
|
67
|
+
several stages starting against one database no longer fail with "tuple concurrently updated" or "trigger
|
|
68
|
+
already exists".
|
|
69
|
+
- `BrokerCoordinator` gives up a queued request whenever the wait ends without a grant (a 5xx or a dropped
|
|
70
|
+
connection mid-poll, a bad payload, an interrupt), not only on timeout or cancellation, so the broker never grants
|
|
71
|
+
an orphaned lease while the work runs on the fallback.
|
|
72
|
+
- `LeaseCoordinator.alease()` waits on its own thread instead of the loop's default executor, so more concurrent
|
|
73
|
+
waiters than executor threads can no longer starve the holder's release.
|
|
74
|
+
- Docs: `slow` and `cascade` are supported by agent-composer's guard router as well as argus-cull's `singguard`
|
|
75
|
+
service, not by argus-cull's alone (`SingGuardClient` docstrings, README). Code is unchanged.
|
|
76
|
+
|
|
10
77
|
## [0.5.0] - 2026-11-14
|
|
11
78
|
|
|
12
79
|
### Added
|
|
@@ -255,7 +322,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
255
322
|
(`LocalBackend`, `RemoteBackend`, `RemoteProvider`, `with_retries`
|
|
256
323
|
retrying only transient errors, `resolve_device`).
|
|
257
324
|
|
|
258
|
-
[Unreleased]: https://github.com/smk762/argus-cortex/compare/v0.
|
|
325
|
+
[Unreleased]: https://github.com/smk762/argus-cortex/compare/v0.6.0...HEAD
|
|
326
|
+
[0.6.0]: https://github.com/smk762/argus-cortex/compare/v0.5.0...v0.6.0
|
|
259
327
|
[0.5.0]: https://github.com/smk762/argus-cortex/compare/v0.4.7...v0.5.0
|
|
260
328
|
[0.4.7]: https://github.com/smk762/argus-cortex/compare/v0.4.6...v0.4.7
|
|
261
329
|
[0.4.6]: https://github.com/smk762/argus-cortex/compare/v0.4.5...v0.4.6
|
|
@@ -28,12 +28,14 @@ their own rows land here. Keep it short, because it is loaded into every session
|
|
|
28
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`.
|
|
29
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]`.
|
|
30
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
|
-
- `gpu.py` — GPU tenancy (from argus-lens): the `GpuCoordinator` protocol (`lease(caller=, min_vram_mb=)`), `NullCoordinator`, `LeaseCoordinator` (host-wide `flock` **then** a wait for NVML free VRAM, so tenants outside the lock like ComfyUI and Ollama are accounted for), `free_vram_mb()`, `coordinator_from_env()` (`ARGUS_GPU_*` — host-wide names on purpose: every process must agree). NVML lazily, behind `[gpu]`; a probe that cannot run grants the lease. **The lock file must be on a volume every GPU container mounts** — per-container `/tmp` coordinates nothing.
|
|
31
|
+
- `gpu.py` — GPU tenancy (from argus-lens): the `GpuCoordinator` protocol (`lease(caller=, min_vram_mb=, priority=, target=, kind=, preemptible=, constraints=)` and async `alease()`, both yielding a `GpuLease` handle; local coordinators ignore the broker-only arguments), `NullCoordinator`, `LeaseCoordinator` (host-wide `flock` **then** a wait for NVML free VRAM, so tenants outside the lock like ComfyUI and Ollama are accounted for), `free_vram_mb()`, `coordinator_from_env()` (`ARGUS_GPU_*` — host-wide names on purpose: every process must agree). NVML lazily, behind `[gpu]`; a probe that cannot run grants the lease. **The lock file must be on a volume every GPU container mounts** — per-container `/tmp` coordinates nothing.
|
|
32
|
+
- `gpu_wire.py` — the GPU broker's wire models (pydantic only): `LeaseRequest`/`LeaseStatus`/`Heartbeat`/`HeartbeatReply`/`LeaseRelease` (`lease_version`) and `TenantManifest` (`tenant_version`, the `gpu-tenant.yaml` every GPU-using repo commits), with `lease_schema()`/`tenant_schema()` rendering the committed `gpu-lease-schema.json`/`gpu-tenant-schema.json`. **argus-iris serves this contract — change it only in step with iris**, and additively within a major (replies ignore unknown fields; manifests forbid them, so a new manifest field needs the schema regenerated and iris bumped).
|
|
33
|
+
- `gpu_broker.py` — `BrokerCoordinator`, the client for argus-iris (`ARGUS_GPU_COORDINATOR=broker`): register manifest → `POST /leases` → long-poll `GET /leases/{id}?wait_s=` → background heartbeat (sets `should_yield()`, re-attaches with `resume` on 404) → `POST /leases/{id}/release` with outcome and peak VRAM. **Fails open** to its fallback coordinator on transport errors, 5xx or a missing route; raises `BrokerError` on other 4xx or an incompatible major. httpx lazily, behind `[remote]`.
|
|
32
34
|
- `xmp.py` — the suite's XMP sidecar read/merge/write (`write_xmp`/`read_xmp`/`merge_xmp`/`parse_xmp`, `XmpData`/`XmpRegions`, `XmpError`), used by lens (keywords/caption) and curator (faces, content rating). Stdlib `xml.etree` only. **Writes merge — latest wins per property, foreign properties preserved; keep that.** `None` = leave untouched, empty = remove. A DTD is refused and an unparseable sidecar raises rather than being overwritten. The `argus` namespace URI is a wire contract — don't change it.
|
|
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.
|
|
35
|
+
- `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, the known adult policies NSFW, any other name raises — **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.
|
|
34
36
|
- `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]`.
|
|
35
37
|
|
|
36
|
-
There is **no CLI in this repo**. The committed schemas are `taxonomy-schema.json` (from `taxonomy_schema()`), `provenance-schema.json` (from `provenance_schema()`)
|
|
38
|
+
There is **no CLI in this repo**. The committed schemas are `taxonomy-schema.json` (from `taxonomy_schema()`), `provenance-schema.json` (from `provenance_schema()`), `consent-schema.json` (from `consent_schema()`), and `gpu-lease-schema.json` / `gpu-tenant-schema.json` (from `gpu_wire`); `make schema` regenerates all five and `tests/test_taxonomy.py` / `tests/test_provenance.py` / `tests/test_consent.py` / `tests/test_gpu_wire.py` fail when one is stale. Studio generates its taxonomy types from the first, so a `taxonomy.py`, `provenance.py`, `consent.py` or `gpu_wire.py` change needs `make schema` in the same commit.
|
|
37
39
|
|
|
38
40
|
## Commands
|
|
39
41
|
|
|
@@ -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
|
|
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))]"
|
|
23
|
+
schema: ## Regenerate the committed taxonomy, provenance, consent, gpu-lease and gpu-tenant schemas
|
|
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; from argus_cortex.gpu_wire import lease_schema, tenant_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), ('gpu-lease-schema.json', lease_schema), ('gpu-tenant-schema.json', tenant_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.6.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
|
|
@@ -25,6 +25,7 @@ Requires-Dist: pillow>=10.0; extra == 'dev'
|
|
|
25
25
|
Requires-Dist: psycopg[binary,pool]>=3.1; extra == 'dev'
|
|
26
26
|
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
27
27
|
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: pyyaml>=6.0; extra == 'dev'
|
|
28
29
|
Requires-Dist: qdrant-client>=1.10; extra == 'dev'
|
|
29
30
|
Requires-Dist: ruff==0.15.16; extra == 'dev'
|
|
30
31
|
Requires-Dist: starlette>=0.37; extra == 'dev'
|
|
@@ -45,9 +46,16 @@ Requires-Dist: certifi>=2026.10.19; extra == 's3'
|
|
|
45
46
|
Requires-Dist: minio>=7.2; extra == 's3'
|
|
46
47
|
Provides-Extra: server
|
|
47
48
|
Requires-Dist: starlette>=0.37; extra == 'server'
|
|
49
|
+
Provides-Extra: yaml
|
|
50
|
+
Requires-Dist: pyyaml>=6.0; extra == 'yaml'
|
|
48
51
|
Description-Content-Type: text/markdown
|
|
49
52
|
|
|
50
|
-
|
|
53
|
+
<h1>
|
|
54
|
+
<picture>
|
|
55
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/smk762/argus-cortex/dev/brand/packages/cortex/argus-cortex-lockup-dark.svg">
|
|
56
|
+
<img alt="argus-cortex" src="https://raw.githubusercontent.com/smk762/argus-cortex/dev/brand/packages/cortex/argus-cortex-lockup-light.svg" height="52">
|
|
57
|
+
</picture>
|
|
58
|
+
</h1>
|
|
51
59
|
|
|
52
60
|
Shared foundation for the Argus suite: taxonomy, versioned wire-schema tooling, and the local/remote AI backend contract.
|
|
53
61
|
|
|
@@ -60,10 +68,12 @@ Part of the Argus suite; [SUITE.md](https://github.com/smk762/argus-cortex/blob/
|
|
|
60
68
|
- **`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`.
|
|
61
69
|
- **`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.
|
|
62
70
|
- **`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.
|
|
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.
|
|
71
|
+
- **`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; a same-host write is trusted only for an IP literal, `localhost` or a name in `trusted_hosts`, so DNS rebinding cannot pass it), 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.
|
|
64
72
|
- **`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.
|
|
65
73
|
- **`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.
|
|
66
74
|
- **`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.
|
|
75
|
+
- **Broker.** `ARGUS_GPU_COORDINATOR=broker` asks the suite's GPU broker, argus-iris, at `ARGUS_GPU_BROKER_URL` (bearer `ARGUS_GPU_BROKER_TOKEN`, optional) instead. The broker places the lease on a node (morpheus, dragon, jarrah), queues it by priority, holds a real VRAM reservation, and evicts idle models to make room. `lease()` now also takes optional `priority` (`realtime`/`interactive`/`batch`/`background`), `target` (`comfyui`, `ollama:<model>`, `in-process`), `kind`, `preemptible`, `constraints` (`GpuConstraints`: `node`, `min_cc`, `bf16`) and `model_mb` (the part of `min_vram_mb` that is weights the service keeps loaded after the lease, such as a ComfyUI checkpoint or an Ollama model, so the broker counts them once rather than per lease); the local coordinators ignore them. Every coordinator yields a `GpuLease`: `node` and `base_url` say where the broker placed the work (call that URL; `None` means use your own), `should_yield()` turns true when the broker wants the GPU back (release at the next safe point; nothing is killed), and `report_peak_vram(mb)` feeds the broker's footprint learning. `alease()` is the async form on every coordinator; the file lease waits in a worker thread. Each lease carries a fresh `request_id`, so the one retry after a lost POST response returns the same lease rather than a second one. A broker lease heartbeats in the background, re-attaches if the broker restarts, and reports its outcome (`ok`/`failed`/`oom`/`cancelled`) on release. **It fails open**: unreachable or 5xx, and the lease comes from `ARGUS_GPU_BROKER_FALLBACK` (`lease`, the default, or `none`) with `via="fallback"`; a 4xx or an incompatible `lease_version` raises `BrokerError`, a refusal `GpuLeaseRefused`. httpx behind `[remote]`.
|
|
76
|
+
- **Tenant manifests.** Every repo that uses a GPU commits a `gpu-tenant.yaml` (`argus_cortex.gpu_wire.TenantManifest`): its kinds of work with target, declared VRAM, default priority and preemptibility, and the models it keeps resident with keepalive and idle-kill hints. `ARGUS_GPU_TENANT_MANIFEST` points the broker coordinator at it, and it is registered with the broker before the first lease; `ARGUS_GPU_TENANT` names the tenant if there is no manifest. `load_tenant_manifest()` reads YAML (behind `[yaml]`) or JSON. The lease wire models and the manifest render the committed `gpu-lease-schema.json` and `gpu-tenant-schema.json` (`make schema`; drift-tested), so non-Python callers and repos validate against those.
|
|
67
77
|
- **`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.
|
|
68
78
|
- **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.
|
|
69
79
|
- **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.
|
|
@@ -107,7 +117,7 @@ result.exposed_score # 0.0-1.0 over DEFAULT_EXPOSED_LABELS; result.labels = p
|
|
|
107
117
|
guard = SingGuardClient("http://guard:9150", policy=None) # None = SingGuard's default rules
|
|
108
118
|
# thinking="fast" (default) is a verdict and rule; "fast-slow" also writes why; "slow" writes why
|
|
109
119
|
# with no fast verdict ahead of the reasoning; "cascade" is fast, then slow only for what fast
|
|
110
|
-
# flagged (the last two: argus-cull's singguard service
|
|
120
|
+
# flagged (the last two: agent-composer's guard or argus-cull's singguard service).
|
|
111
121
|
verdict = guard.check(image_bytes, text="the prompt, if any")
|
|
112
122
|
preflight = guard.check_text("the prompt") # no image: judge a prompt before it is run
|
|
113
123
|
verdict.safe, verdict.rules # False, ["B. Real-World Crimes & Public Safety"]
|
|
@@ -146,6 +156,20 @@ except GpuLeaseTimeout:
|
|
|
146
156
|
... # no slot in time: back off, or answer 503
|
|
147
157
|
```
|
|
148
158
|
|
|
159
|
+
Through the broker, the same code can ask for a placement and honour a yield:
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
gpu = coordinator_from_env() # ARGUS_GPU_COORDINATOR=broker, ARGUS_GPU_BROKER_URL=http://morpheus:8120
|
|
163
|
+
async with gpu.alease(caller="expand", min_vram_mb=6000, target="ollama:qwen3:8b", priority="interactive") as lease:
|
|
164
|
+
ollama = lease.base_url or settings.ollama_url # dragon, or jarrah when dragon is full
|
|
165
|
+
...
|
|
166
|
+
with gpu.lease(caller="bake", min_vram_mb=9000, target="comfyui", priority="batch", preemptible=True) as lease:
|
|
167
|
+
for tile in tiles:
|
|
168
|
+
if lease.should_yield():
|
|
169
|
+
break # requeue the rest; a higher-priority job wants the card
|
|
170
|
+
bake(tile)
|
|
171
|
+
```
|
|
172
|
+
|
|
149
173
|
Each `check()` raises `CheckFailed` (`NudeNetCheckFailed` / `GuardCheckFailed`) for a network error or an unusable answer, so a caller checking many images can record "unchecked" against the one image — and should treat unchecked as *not* safe. Bad configuration raises `ModerationConfigError`, whose message never echoes the URL.
|
|
150
174
|
|
|
151
175
|
```python
|
|
@@ -198,13 +222,14 @@ link = blobs.url(sha, expires=3600) # presigned GET URL
|
|
|
198
222
|
|
|
199
223
|
```bash
|
|
200
224
|
uv pip install argus-cortex # core (pydantic only)
|
|
201
|
-
uv pip install "argus-cortex[remote]" # + httpx for RemoteBackend
|
|
225
|
+
uv pip install "argus-cortex[remote]" # + httpx for RemoteBackend and the GPU broker client
|
|
202
226
|
uv pip install "argus-cortex[server]" # + starlette for argus_cortex.server (WriteGuard, env_flag)
|
|
203
227
|
uv pip install "argus-cortex[postgres]" # + psycopg for the lineage store
|
|
204
228
|
uv pip install "argus-cortex[qdrant]" # + qdrant-client for the vector store
|
|
205
229
|
uv pip install "argus-cortex[s3]" # + minio for the blob store
|
|
206
230
|
uv pip install "argus-cortex[images]" # + Pillow for SingGuardClient downscaling (on by default)
|
|
207
231
|
uv pip install "argus-cortex[gpu]" # + nvidia-ml-py for the GPU lease's free-VRAM probe
|
|
232
|
+
uv pip install "argus-cortex[yaml]" # + PyYAML for reading a gpu-tenant.yaml (JSON needs nothing)
|
|
208
233
|
```
|
|
209
234
|
|
|
210
235
|
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.
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
<h1>
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/smk762/argus-cortex/dev/brand/packages/cortex/argus-cortex-lockup-dark.svg">
|
|
4
|
+
<img alt="argus-cortex" src="https://raw.githubusercontent.com/smk762/argus-cortex/dev/brand/packages/cortex/argus-cortex-lockup-light.svg" height="52">
|
|
5
|
+
</picture>
|
|
6
|
+
</h1>
|
|
2
7
|
|
|
3
8
|
Shared foundation for the Argus suite: taxonomy, versioned wire-schema tooling, and the local/remote AI backend contract.
|
|
4
9
|
|
|
@@ -11,10 +16,12 @@ Part of the Argus suite; [SUITE.md](https://github.com/smk762/argus-cortex/blob/
|
|
|
11
16
|
- **`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`.
|
|
12
17
|
- **`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.
|
|
13
18
|
- **`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.
|
|
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.
|
|
19
|
+
- **`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; a same-host write is trusted only for an IP literal, `localhost` or a name in `trusted_hosts`, so DNS rebinding cannot pass it), 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.
|
|
15
20
|
- **`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.
|
|
16
21
|
- **`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.
|
|
17
22
|
- **`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.
|
|
23
|
+
- **Broker.** `ARGUS_GPU_COORDINATOR=broker` asks the suite's GPU broker, argus-iris, at `ARGUS_GPU_BROKER_URL` (bearer `ARGUS_GPU_BROKER_TOKEN`, optional) instead. The broker places the lease on a node (morpheus, dragon, jarrah), queues it by priority, holds a real VRAM reservation, and evicts idle models to make room. `lease()` now also takes optional `priority` (`realtime`/`interactive`/`batch`/`background`), `target` (`comfyui`, `ollama:<model>`, `in-process`), `kind`, `preemptible`, `constraints` (`GpuConstraints`: `node`, `min_cc`, `bf16`) and `model_mb` (the part of `min_vram_mb` that is weights the service keeps loaded after the lease, such as a ComfyUI checkpoint or an Ollama model, so the broker counts them once rather than per lease); the local coordinators ignore them. Every coordinator yields a `GpuLease`: `node` and `base_url` say where the broker placed the work (call that URL; `None` means use your own), `should_yield()` turns true when the broker wants the GPU back (release at the next safe point; nothing is killed), and `report_peak_vram(mb)` feeds the broker's footprint learning. `alease()` is the async form on every coordinator; the file lease waits in a worker thread. Each lease carries a fresh `request_id`, so the one retry after a lost POST response returns the same lease rather than a second one. A broker lease heartbeats in the background, re-attaches if the broker restarts, and reports its outcome (`ok`/`failed`/`oom`/`cancelled`) on release. **It fails open**: unreachable or 5xx, and the lease comes from `ARGUS_GPU_BROKER_FALLBACK` (`lease`, the default, or `none`) with `via="fallback"`; a 4xx or an incompatible `lease_version` raises `BrokerError`, a refusal `GpuLeaseRefused`. httpx behind `[remote]`.
|
|
24
|
+
- **Tenant manifests.** Every repo that uses a GPU commits a `gpu-tenant.yaml` (`argus_cortex.gpu_wire.TenantManifest`): its kinds of work with target, declared VRAM, default priority and preemptibility, and the models it keeps resident with keepalive and idle-kill hints. `ARGUS_GPU_TENANT_MANIFEST` points the broker coordinator at it, and it is registered with the broker before the first lease; `ARGUS_GPU_TENANT` names the tenant if there is no manifest. `load_tenant_manifest()` reads YAML (behind `[yaml]`) or JSON. The lease wire models and the manifest render the committed `gpu-lease-schema.json` and `gpu-tenant-schema.json` (`make schema`; drift-tested), so non-Python callers and repos validate against those.
|
|
18
25
|
- **`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.
|
|
19
26
|
- **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.
|
|
20
27
|
- **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.
|
|
@@ -58,7 +65,7 @@ result.exposed_score # 0.0-1.0 over DEFAULT_EXPOSED_LABELS; result.labels = p
|
|
|
58
65
|
guard = SingGuardClient("http://guard:9150", policy=None) # None = SingGuard's default rules
|
|
59
66
|
# thinking="fast" (default) is a verdict and rule; "fast-slow" also writes why; "slow" writes why
|
|
60
67
|
# with no fast verdict ahead of the reasoning; "cascade" is fast, then slow only for what fast
|
|
61
|
-
# flagged (the last two: argus-cull's singguard service
|
|
68
|
+
# flagged (the last two: agent-composer's guard or argus-cull's singguard service).
|
|
62
69
|
verdict = guard.check(image_bytes, text="the prompt, if any")
|
|
63
70
|
preflight = guard.check_text("the prompt") # no image: judge a prompt before it is run
|
|
64
71
|
verdict.safe, verdict.rules # False, ["B. Real-World Crimes & Public Safety"]
|
|
@@ -97,6 +104,20 @@ except GpuLeaseTimeout:
|
|
|
97
104
|
... # no slot in time: back off, or answer 503
|
|
98
105
|
```
|
|
99
106
|
|
|
107
|
+
Through the broker, the same code can ask for a placement and honour a yield:
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
gpu = coordinator_from_env() # ARGUS_GPU_COORDINATOR=broker, ARGUS_GPU_BROKER_URL=http://morpheus:8120
|
|
111
|
+
async with gpu.alease(caller="expand", min_vram_mb=6000, target="ollama:qwen3:8b", priority="interactive") as lease:
|
|
112
|
+
ollama = lease.base_url or settings.ollama_url # dragon, or jarrah when dragon is full
|
|
113
|
+
...
|
|
114
|
+
with gpu.lease(caller="bake", min_vram_mb=9000, target="comfyui", priority="batch", preemptible=True) as lease:
|
|
115
|
+
for tile in tiles:
|
|
116
|
+
if lease.should_yield():
|
|
117
|
+
break # requeue the rest; a higher-priority job wants the card
|
|
118
|
+
bake(tile)
|
|
119
|
+
```
|
|
120
|
+
|
|
100
121
|
Each `check()` raises `CheckFailed` (`NudeNetCheckFailed` / `GuardCheckFailed`) for a network error or an unusable answer, so a caller checking many images can record "unchecked" against the one image — and should treat unchecked as *not* safe. Bad configuration raises `ModerationConfigError`, whose message never echoes the URL.
|
|
101
122
|
|
|
102
123
|
```python
|
|
@@ -149,13 +170,14 @@ link = blobs.url(sha, expires=3600) # presigned GET URL
|
|
|
149
170
|
|
|
150
171
|
```bash
|
|
151
172
|
uv pip install argus-cortex # core (pydantic only)
|
|
152
|
-
uv pip install "argus-cortex[remote]" # + httpx for RemoteBackend
|
|
173
|
+
uv pip install "argus-cortex[remote]" # + httpx for RemoteBackend and the GPU broker client
|
|
153
174
|
uv pip install "argus-cortex[server]" # + starlette for argus_cortex.server (WriteGuard, env_flag)
|
|
154
175
|
uv pip install "argus-cortex[postgres]" # + psycopg for the lineage store
|
|
155
176
|
uv pip install "argus-cortex[qdrant]" # + qdrant-client for the vector store
|
|
156
177
|
uv pip install "argus-cortex[s3]" # + minio for the blob store
|
|
157
178
|
uv pip install "argus-cortex[images]" # + Pillow for SingGuardClient downscaling (on by default)
|
|
158
179
|
uv pip install "argus-cortex[gpu]" # + nvidia-ml-py for the GPU lease's free-VRAM probe
|
|
180
|
+
uv pip install "argus-cortex[yaml]" # + PyYAML for reading a gpu-tenant.yaml (JSON needs nothing)
|
|
159
181
|
```
|
|
160
182
|
|
|
161
183
|
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,25 +14,26 @@ 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, likeness provenance and consent records, optional lineage/vector/blob stores. |
|
|
17
|
+
| **argus-cortex** | library | n/a | Shared foundation: taxonomy, wire-schema versioning, AI-backend contract, server guards, GPU lease and the GPU broker client, XMP, moderation clients, likeness provenance and consent records, optional lineage/vector/blob stores. |
|
|
18
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
|
-
| **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. Records live captions to the cortex lineage store (the tape lightbox and replay read); runs read-only with `LENS_READ_ONLY`. |
|
|
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` (2.3: each row's primary face and the set's age). Its `face_source` preset shortlists source portraits for mask: one adult identity, frontal, sharp, eyes open, close to a reference. PyPI `argus-curator`. |
|
|
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`. Each caption request may pick its backend (`backend`, pinned with `ARGUS_ALLOWED_BACKENDS`). `serve` binds loopback unless given `--host`, and `POST /caption/url` fetches only public hosts or those in `LENS_URL_ALLOWED_HOSTS`. PyPI `argus-lens`, image `ghcr.io/smk762/argus-lens`. |
|
|
21
21
|
| **argus-forge** | service | 8103 | Turn a curated, captioned export into runnable kohya_ss / OneTrainer / diffusers configs. |
|
|
22
|
-
| **argus-proof** | service | 8104 | Evaluate a trained LoRA against its dataset: sample grid, scores, pass/fail. |
|
|
22
|
+
| **argus-proof** | service | 8104 | Evaluate a trained LoRA (SDXL or Flux) against its dataset: generates a sample grid (ComfyUI, diffusers, A1111 or a remote engine; every model pinned by SHA256 in a `RunManifest`), scores identity, quality, diversity, nudity (NudeNet server) and policy categories (Llama Guard 3), and gives a pass/fail verdict over near-duplicate groups with HITL review. Serves a passed run's validated setup at `GET /report/{id}/manifest`; devmode `POST /purge` clears QA runs. PyPI `argus-proof`, image `ghcr.io/smk762/argus-proof`. |
|
|
23
23
|
| **argus-atlas** | service | 8105 | Bake georeferenced fantasy-map overlays from real terrain (GDAL controls plus a cartography LoRA), to GeoTIFF / PMTiles. |
|
|
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 (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`. |
|
|
24
|
+
| **argus-darkroom** | service | 8106 | Guarded image generation: checks the prompt (and any input image), generates via ComfyUI, checks each output, and keeps a record of every attempt. Text-to-image, image-to-image and inpainting, on SDXL, Flux, Flux Klein and SD3.5 checkpoints. PyPI `argus-darkroom`, image `ghcr.io/smk762/argus-darkroom`. |
|
|
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`. Reference docs (`docs/`: datums, steps, methods, provenance, API, CLI) are imported by sightline and the handbook. PyPI `argus-survey`, image `ghcr.io/smk762/argus-survey`. |
|
|
26
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
|
-
| **argus-studio** | UI + compose | 3000 | The suite web UI, and the compose stack that runs the services from GHCR images. No backend code. |
|
|
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; a generated face records its model, seed and prompt in `generator`), and procedural backdrops behind a mesh face (`?scene=ftl`, also in `record`); an optional face editor builds MakeHuman heads with Blender, and its Voices page makes cloned voices with provenance. A real person's face or voice is used only under a consent record (`argus-mask consent new\|list\|revoke`, cortex's `ConsentRecord`), and is always shown with a disclosure label. PyPI `argus-mask`, image `ghcr.io/smk762/argus-mask`. |
|
|
28
|
+
| **argus-studio** | UI + compose | 3000 | The suite web UI, and the compose stack that runs the services from GHCR images. No backend code. `/forge` starts, follows and cancels forge training runs when the opt-in `compose.train.yaml` arms forge's `-train` image on a trusted GPU host (never a public demo). `/darkroom` links on to Forge, and to mask and assay when their URLs are set. Its `/docs` holds the captioning concept pages; the setup guides and package docs moved to argus-handbook, and its old `/docs/setup` and `/docs/packages` paths 301 there. |
|
|
29
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
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
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
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
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
|
+
| **argus-handbook** | docs (static) | n/a | The suite's public docs at docs.dragonhound.dev: setup of the external services (ComfyUI, Ollama, NudeNet, SingGuard, models, GPU host), the moderation stack across packages, a what-to-run matrix per UI, and each package's README and `docs/` imported at its `dev` HEAD behind an opsec gate. Static export, deployed from CI. The private `argus-docs` repo is ai-code-auditor's DeepWiki export bundle, which the handbook will build in under `/wiki/`. |
|
|
34
35
|
| **argus-halo** | infra | n/a | Terraform for the public demo (`argus.dragonhound.dev`): read-only replay services plus a private data host. |
|
|
35
|
-
| **argus-ci** | infra | n/a | Reusable GitHub Actions workflows (uv, ruff, pytest, build,
|
|
36
|
+
| **argus-ci** | infra | n/a | Reusable GitHub Actions workflows, pinned `@v1`: `python-ci.yml` (uv, ruff, pytest matrix, build), `suite-check.yml` (CLAUDE.md suite block + SUITE.md row), `docs-check.yml` (generated Typer `docs/cli.md` must match the CLI; published docs scanned for private IPs, home/server paths, emails and a private denylist). Not release: PyPI trusted publishing can't run in a reusable workflow, so `release.yml` comes from argus-pkg-template. |
|
|
36
37
|
| **argus-pkg-template** | infra | n/a | Copier template for new Argus Python packages; `copier update` pulls tooling changes. |
|
|
37
38
|
|
|
38
39
|
**How they fit.** The LoRA pipeline is `quarry → curator → lens → forge → (trainer) → proof → atlas`; curator, lens,
|
|
@@ -43,15 +44,15 @@ atlas. Every Python service except quarry depends on cortex. UIs are thin client
|
|
|
43
44
|
shows.
|
|
44
45
|
|
|
45
46
|
**API and UI pairs.** darkroom ↔ safelight · curator ↔ cull · lens ↔ lightbox · survey ↔ sightline · mint ↔ assay.
|
|
46
|
-
Studio has a page for lens, curator, quarry, forge, proof, atlas and darkroom, and links out to sightline.
|
|
47
|
+
Studio has a page for lens, curator, quarry, forge, proof, atlas and darkroom, and links out to sightline, mask and assay.
|
|
47
48
|
|
|
48
49
|
## Need it? Use it
|
|
49
50
|
|
|
50
51
|
| Need | Use | Don't |
|
|
51
52
|
|---|---|---|
|
|
52
|
-
| Generate an image (a plate, a background, art, a sample) | **darkroom** `POST /generate/stream` (SSE), `GET /image/{id}`. Its record id, model and seed are your provenance. Example client: mint's `DarkroomClient`. | Call ComfyUI directly or generate without checks. |
|
|
53
|
+
| Generate an image (a plate, a background, art, a sample), or rework or inpaint one | **darkroom** `POST /generate/stream` (SSE; `init_image`, with `mask_base64` to inpaint), `GET /image/{id}`. Its record id, model and seed are your provenance. Example client: mint's `DarkroomClient`. | Call ComfyUI directly or generate without checks. |
|
|
53
54
|
| Check an image for nudity, or text/an image against a policy | `argus_cortex.moderation` (`NudeNetClient`, `SingGuardClient`, `policies`) | Write your own nudity definition or policy text. |
|
|
54
|
-
| Share the GPU with other services | `argus_cortex.gpu` (`coordinator_from_env()`, `lease()`) | Assume the GPU is free. |
|
|
55
|
+
| Share the GPU with other services | `argus_cortex.gpu` (`coordinator_from_env()`, `lease()`/`alease()`); `ARGUS_GPU_COORDINATOR=broker` asks argus-iris, which places, prioritises and makes room across nodes. Declare your GPU use in a committed `gpu-tenant.yaml` (`gpu-tenant-schema.json`). | Assume the GPU is free, or keep your own idle-unload or keep-alive policy. |
|
|
55
56
|
| Call a local or hosted model | `argus_cortex.backends` (`LocalBackend`, `RemoteBackend`, `with_retries`) | Hand-roll an HTTP client per model. |
|
|
56
57
|
| Version a wire payload, commit its schema | `argus_cortex.wire` (`make_versioned_base`, `render_schema`) | Ship an unversioned contract. |
|
|
57
58
|
| Guard a FastAPI server's writes, or run read-only | `argus_cortex.server` (`WriteGuard`, `env_flag`) | Use `BaseHTTPMiddleware`, which buffers streams. |
|
|
@@ -63,14 +64,17 @@ Studio has a page for lens, curator, quarry, forge, proof, atlas and darkroom, a
|
|
|
63
64
|
| Acquire source photos with licence and provenance | **quarry** | Scrape inside another stage. |
|
|
64
65
|
| 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. |
|
|
65
66
|
| Score, dedupe or select images; faces; content rating | **curator** | Re-score in a later stage. |
|
|
66
|
-
|
|
|
67
|
+
| Shortlist source portraits for a mask face | **curator** `face_source` on `POST /scan/{id}/select` / `POST /export` (CLI `--face-source`, `--face-reference`); each image left out says which check it failed | Pick a face source by eye, or take one from quarry. |
|
|
68
|
+
| Caption or keyword images | **lens** `POST /caption` (upload), `/caption/folder` or `/caption/manifest` (paths under its source root), `/caption/url` (public or allow-listed hosts); optional `backend` per request | Write ad-hoc captions, or hand lens a LAN URL it hasn't been told to trust. |
|
|
67
69
|
| Training configs, or evaluating a LoRA | **forge**, **proof** | |
|
|
70
|
+
| Reuse the checkpoint, LoRAs and sampling a LoRA passed evaluation with | **proof** `GET /report/{run_id}/manifest` (field names from `ModelRef`, `LoRARef`, `SamplingParams`; `410` once the run dir is pruned) | Re-enter the setup by hand. |
|
|
68
71
|
| Terrain, georeferencing, map tiles | **atlas** (stylised), **survey** (survey-grade) | |
|
|
69
72
|
| 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
|
|
73
|
+
| A face that speaks | **mask** `POST /speak` (JSON `{"face", "text"}`), `POST /push?face=<id>` (a WAV or PCM you already have) or the `/session/<id>/source` socket; screens open `/?face=<id>` (`&scene=ftl` for a backdrop) | Drive a face's animation yourself, or render it per stage. |
|
|
71
74
|
| 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. |
|
|
72
75
|
| Run the whole stack locally | **studio** `compose.yaml` | |
|
|
73
76
|
| A new Python package, or CI | **argus-pkg-template**, **argus-ci** | Copy another repo's tooling by hand. |
|
|
77
|
+
| A logo, favicon, README header or social preview for a repo, demo or UI | **cortex** `brand/` (suite mark, one mark per package, lockups, Panoptes font; `brand/README.md`) | Draw a new mark, recolour one, or set "argus" in another font. |
|
|
74
78
|
|
|
75
79
|
## Shared rules
|
|
76
80
|
|