Zero-friction .well-known/aiep/ pipeline for any website.
Converts any HTML website into a machine-readable AIEP mirror surface — a set of structured, cryptographically-bound JSON artefacts that AI systems, crawlers, validators, and automated agents can consume with full verifiability.
Three commands. Works with any static site generator. Zero runtime dependencies.
pip install aiep-mirrorOr with pipx (isolated global install, recommended for CLI use):
pipx install aiep-mirror# 1. Initialise — creates .aiep-mirror.json in the current directory
aiep-mirror init
# 2. Build your site (Astro, Next.js, Hugo, Jekyll, or plain HTML)
npm run build # or: hugo, jekyll build, make build, etc.
# 3. Build mirror artefacts (reads .aiep-mirror.json automatically)
aiep-mirror build
# 4. Verify the output
aiep-mirror verifyThat's it. Your .well-known/aiep/ surface is ready to deploy.
aiep-mirror init creates this file. Edit site_base and in_dir to match your project:
{
"site_base": "https://yourdomain.com",
"in_dir": "./dist",
"out_dir": ".",
"visibility_default": "PRIVATE",
"public_prefixes": ["/blog", "/docs", "/products"],
"private_prefixes": ["/admin", "/account", "/api"]
}| Field | Default | Meaning |
|---|---|---|
site_base |
— | Your deployed domain (required) |
in_dir |
./dist |
Directory containing your HTML build output |
out_dir |
. |
Root where .well-known/ will be written |
visibility_default |
PRIVATE |
Page visibility if no prefix matches (FC §7) |
public_prefixes |
[] |
URL prefixes to mark PUBLIC |
private_prefixes |
[] |
URL prefixes to mark PRIVATE (takes precedence) |
| Framework | in_dir | Integration |
|---|---|---|
| Astro | ./dist |
postbuild script in package.json |
| Next.js (static) | ./out |
postbuild + output: 'export' |
| Hugo | ./public |
Add after hugo command |
| Jekyll | ./_site |
Add to Makefile or CI |
| Plain HTML | any dir | Set in_dir to your folder |
{
"scripts": {
"build": "astro build",
"postbuild": "aiep-mirror build",
"aiep:verify": "aiep-mirror verify",
"aiep:status": "aiep-mirror status"
}
}Full guides: Astro · Next.js · GitHub Actions
.well-known/
aiep-manifest.json ← WellKnownManifest (P61)
aiep-index.json ← SiteIndexEntry list, searchable (P62)
aiep/
pages/{content_hash}.json ← MirrorPage per page (P60)
proofs/{content_hash}.json ← cryptographic proof per page
proofs/manifest.json ← manifest-level proof
mirror_policy.json ← visibility policy (FC §4)
Every artefact is self-verifiable — all hashes are recomputable from the artefact's own fields. No external database, no token, no secret.
aiep-mirror init Create .aiep-mirror.json in current directory
aiep-mirror build Build mirror artefacts (reads .aiep-mirror.json)
aiep-mirror verify Verify artefacts
aiep-mirror status Show config and last build info
aiep-mirror --self-test Verify LOCKFILE + Canon self-test, then exit
Build flags (all optional when .aiep-mirror.json is present):
--in-dir PATH HTML source directory
--site-base URL Deployed site base URL
--out-dir PATH Output directory
--public Set all pages PUBLIC
--public-prefix P Mark URL prefix PUBLIC (repeatable)
--private-prefix P Mark URL prefix PRIVATE (repeatable)
--config PATH Use alternate config file
from aiep_mirror import build_mirror, verify_manifest, run_self_test
# Startup health check — fail fast if Canon is broken
run_self_test()
# Build from your HTML build output
result = build_mirror(
in_dir="./dist",
site_base="https://example.com",
out_dir=".",
visibility_default="PRIVATE",
private_prefixes=["/admin"],
public_prefixes=["/blog"],
)
print(result["manifest_hash"]) # 64-char hex
print(result["page_count"]) # int
print(result["capability_hash"]) # FC §3 binding — on every artefact
print(result["policy_hash"]) # FC §4 binding — on every artefact
# Verify (no HTML source needed — anyone can verify)
vr = verify_manifest("./.well-known/aiep-manifest.json")
assert vr["verified"]
# vr["findings"] ← list of ✓/✗ per checkOutput to S3, GCS, a CDN, a database — plug in any transport:
from aiep_mirror import MirrorAdapter, build_mirror
class S3Adapter(MirrorAdapter):
def write_page(self, page_id: str, record: dict) -> None:
self.s3.put_object(
Key=f".well-known/aiep/pages/{page_id}.json",
Body=json.dumps(record),
ContentType="application/json",
)
# override write_proof, write_manifest, write_index, write_policy
build_mirror(..., adapter=S3Adapter(bucket="my-cdn"))python examples/run_example.pyFull build + verify against a 3-page sample site. Prints every hash and every check. Output: 3 pages, 24 verification checks, all PASS.
aiep-mirror buildaiep-mirror verify- Deploy your site root. Ensure
.well-known/is served with:Content-Type: application/json Access-Control-Allow-Origin: * - Confirm:
curl https://yourdomain.com/.well-known/aiep-manifest.json
CORS header config for Vercel and Netlify is in the integration guides.
Every artefact carries three provenance bindings from the GENOME governance architecture:
| Field | Formula | FC ref |
|---|---|---|
lockfile_version |
Pinned "1.0.0" |
FC §2, AIEP-NMR-001 |
capability_hash |
sha256(canonical_json(cap_core)) |
FC §3 |
policy_hash |
sha256(canonical_json(policy_core)) |
FC §4 |
These fields appear on every MirrorPage, every proof, the manifest, and the index. A third party can verify exactly what capability set and policy governed any artefact without needing the original HTML.
| Hash | Formula | Spec |
|---|---|---|
content_hash |
sha256(canonical_json(data)) |
P60 |
page_id |
== content_hash |
P60 |
proof_hash |
concat_hash(page_id, content_hash, manifest_hash) |
P60 |
manifest_hash |
concat_hash(canonical_manifest, aiep_version, site) |
P61 |
index_hash |
concat_hash(url, content_hash, last_modified) |
P62 |
policy_hash |
sha256(canonical_json(policy_core)) |
FC §4 |
capability_hash |
sha256(canonical_json(cap_core)) |
FC §3 |
concat_hash(...) = SHA-256 of length-prefixed (8-byte big-endian) parts (R7).
All hashes are recomputable from fields in the same JSON record.
| Rule | Definition |
|---|---|
| R1 | Keys sorted lexicographic UTF-8 byte order |
| R2 | Compact — no whitespace between tokens |
| R3 | Unicode NFC normalised; ensure_ascii=False |
| R4 | SHA-256, lowercase hex, 64 chars |
| R5 | No scientific notation; trailing zeros trimmed; minus-zero forbidden |
| R6 | UTF-8 strict encoding |
| R7 | Multi-part concat: 8-byte big-endian length prefix per part |
| R8 | Timestamps are data — never datetime.now() in hash inputs |
pip install "aiep-mirror[dev]"
pytest
# 90 passed in 3.5sApache License 2.0. See LICENSE.
Priority filings: GB2519711.2 · GB2519798.9 (filed 20 November 2025)