🔄 Synced from the AI-Factory monorepo (append-only history). Pull requests are welcome — merged PRs are imported back and re-synced here. Issues · Pull requests
Should this AI agent be allowed into your business? —
landing → ·
dashboards / console → ·
Alien Monitor → ·
run locally → ·
full tutorial → ·
Hub admission →
THEMIS (Θέμις) — publish-time admission gate for AIMarket
Signed approve / review / reject · not Metis cognition · not WARDEN runtime
English · Русский · Español · Français · 中文 · Localization glossary
Receipt cards below are screenshots of the live admission console at
/ui/ after a real local /invoke (safe → approve, unsafe → reject).
Capability id: agent.security.supply-chain.audit@v1.
Public dashboards (no factory admin):
| Surface | URL |
|---|---|
| Landing | https://alexar76.github.io/themis/ |
| Admission console (Pages) | https://alexar76.github.io/themis/console/ |
| Alien Monitor (telemetry) | https://monitor.modelmarket.dev/ |
| Local operator UI | http://127.0.0.1:8080/ui/ after uv run python agent.py |
uv run python agent.py
# open http://127.0.0.1:8080/ui/![]() |
![]() |
| Approve · score 100 · risk_tier low | Reject · fail-closed findings |
| Raw signed /invoke · approve | Raw signed /invoke · reject |
|
|
| THEMIS admits · WARDEN gates invoke · Metis advises | |
Businesses are adding agents to real workflows, while the agent itself may execute code, read secrets, spend money, write to external systems, or call an unreviewed dependency. The OWASP Top 10 for Agentic Applications now explicitly includes identity and privilege abuse, AI-agent supply chain vulnerabilities, insecure inter-agent communication, cascading failures, and human-agent trust exploitation.
This reference agent turns a candidate AIMarket manifest, declared permissions, evidence, expected usage, and a buyer policy into one bounded report:
approve,review, orreject;- a deterministic score and risk tier;
- projected monthly cost;
- specific findings and remediations;
- OWASP Agentic risk mappings;
- an optional asynchronous Metis second opinion;
- a request-bound Ed25519 signature (receipt).
It does not certify compliance or predict future behaviour. It helps a human make a better procurement decision from explicit evidence — and, when Hub admission mode is enabled, it is the publish admission check before a third-party capability enters the public catalogue.
Listing on Hub is already multi-layer (operator publish token, stake, manifest, signatures, trust
floors) — not open signup. Consuming the ecosystem via ARGUS / aimarket-mcp does not require
THEMIS. See supply-chain admission.
candidate manifest + permissions + evidence + usage + policy
│
▼
deterministic policy engine
│
┌─────────────────┴─────────────────┐
▼ ▼
signed decision immediately lazy Metis advisory job
approve / review / reject pending → completed
Metis never overrides the deterministic decision. It reviews the consistency of the report, not the truth or future safety of the candidate agent.
git clone https://github.com/alexar76/themis.git
cd themis
uv sync --extra dev
uv run python configure_provider.py
uv run python -m pytest -q
uv run python agent.py
# open http://127.0.0.1:8080/ui/ — live admission consoleIn another terminal:
curl --fail-with-body -sS \
-X POST http://127.0.0.1:8080/invoke \
-H 'Content-Type: application/json' \
--data-binary @examples/safe_candidate.jsonThe safe sample returns decision: approve. Open /ui/, load unsafe example, and observe a
fail-closed REJECT receipt with live findings.
| Block | Meaning |
|---|---|
candidate |
AIMarket manifest being considered |
permissions |
Declared powers: code, secrets, money, writes, network, personal data |
evidence |
HTTPS references such as an SBOM, security policy, or independent audit |
usage |
Expected call volume and data classification |
policy |
Buyer's price, budget, identity, evidence, and verification requirements |
request_metis |
Start an advisory Metis job without blocking the main decision |
All models reject unknown fields. The service never fetches evidence URLs, so untrusted input cannot turn it into an SSRF proxy.
Copy .env.example to .env and set METIS_API_KEY on the server. Do not send it from a browser.
With request_metis: true, /invoke returns immediately:
{
"metis": {
"status": "pending",
"verification_id": "...",
"poll_url": "/verification/..."
}
}Poll GET /verification/{verification_id} until completed, not_performed, timeout,
unavailable, or failed. Jobs are memory-bounded and expire; upstream errors are reduced to an
allowlisted reason rather than leaking infrastructure details.
GET /mcp/verdict?package=npm:<name> (or pypi:<name>, or endpoint=https://…) returns approve, review, reject or unknown for an MCP server or package, with every reason, decided on HISTOR's evidence and signed by this provider's key (X-Provider-Signature, capability agent.security.mcp.verdict@v1, over the exact query). HISTOR's own signed /check answer travels with it as the evidence.
Policy themis-mcp/2: reject for block-tier patterns, decoy credential access/transmission, persistence or an extra recipient observed in the sandbox; review for provenance/publisher/dependency changes, lookalikes, network attempts (including tool calls), advisory patterns, classifier flags or recent definition changes; unknown for missing, incomplete, stale or mismatched evidence. Approve requires all mandatory checks to be complete and bound to the observed subject. Package build attestation presence is not verification: a package needs verified artifact evidence before approval.
THEMIS verifies the exact signed HISTOR /check answer and its query binding. Set THEMIS_HISTOR_ISSUER_DID to pin the issuer; otherwise key discovery uses the configured HISTOR HTTPS origin. No unsigned second record enters the decision. Invalid signatures or unavailable evidence return 503. A stale signed answer yields unknown. The decision carries all evidence used and is cached for ten minutes. See observer and evidence limitations.
- request bodies are bounded to 256 KiB;
- duplicate JSON keys and unknown fields are rejected;
- candidate URLs are parsed but never contacted;
- evidence references are never fetched;
- an evidence reference counts toward the buyer's evidence floor only when it is bound to a SHA-256 digest, so decorative links cannot satisfy procurement;
- attestations are verified offline against their own canonical statement — never by fetching;
- a signature that does not verify is a finding, while a merely absent one is scored only when policy asks for it;
- the provider identity is a persistent Ed25519 key stored with mode
0600; - the response signature covers the exact submitted input and result;
- Metis credentials remain server-side;
- Metis jobs have hard capacity, concurrency, response-size, timeout, and TTL bounds;
- Metis job state is per-process by default;
METIS_JOB_DBmoves it to a shared store so any replica can answer any poll, andTHEMIS_REPLICAS>1without one refuses to start; - Python dependencies are locked in
uv.lock, including the Docker image build; - OpenAPI, Swagger, and ReDoc routes are disabled;
- the Docker image runs as an unprivileged user and expects a persistent key volume;
- direct callers are not authenticated or billed: keep the port private behind Hub and HTTPS ingress.
See SECURITY.md and the architecture.
A URL is a claim. A URL with a digest identifies an artifact. A URL with a digest and a signature is a claim someone put their key behind — the only one of the three this service can check without fetching anything.
uv run python attest.py evidence --kind sbom \
--url https://vendor.example.com/sbom.json --sha256 <64-hex>
uv run python attest.py permissions --dossier examples/safe_candidate.jsonPaste the printed object into the dossier as evidence[].attestation or
permissions_attestation. The report's attestations block then records exactly what was
verified: how many references were signed, whether any issuer was independent of the candidate,
and whether the permission declaration is bound to provider_pubkey.
| Policy field | Default | Effect |
|---|---|---|
require_evidence_digests |
true |
Undigested references never count toward the evidence floor |
require_evidence_attestation |
false |
Every counted reference needs a verified signature |
require_independent_attestation |
false |
At least one issuer must not be the candidate's own key |
require_permission_attestation |
false |
The declaration must be signed by provider_pubkey |
trusted_evidence_issuers |
[] |
When set, only these issuer keys satisfy an attestation |
Declared permissions remain a declaration — this does not make them true. It makes a false one signed, attributable and therefore slashable.
Replace invoke_url with the deployed HTTPS endpoint and set a stable publisher_id, then:
uv run python configure_provider.py
uv run python validate_manifest.py
aimarket publish capability.json --hub https://modelmarket.devPublishing remains an explicit operator action because Hub identity, stake, trust policy, and production reachability cannot safely be inferred by a project generator.
After Hub registration and a real Hub invoke, admission telemetry appears on the Alien Monitor
THEMIS node (dossier-free receipts from Hub GET /supply/audits). This repository does not
inject its own permanent 3D node from an unauthenticated client.
The five-language lesson starts from the actual command below and recreates this repository step by step:
uvx create-aimarket-agent themis --kind tool --metisOpen the complete English tutorial.
MIT. OWASP names and identifiers are used for mapping and remain property of their respective owner.


