Architecture
How the pieces fit together.
System Overview
Metarium AI is a three-layer system. An AI agent talks to a local management server, which signs requests and forwards them to a cloud-hosted CMS.
+------------------------------+
| AI Agent (Cursor / Vorflux) |
| Reads AGENTS.md, calls API |
| Entry point: mai.net |
+-------------+----------------+
| REST (localhost:8420)
v
+------------------------------+
| Management Server | <- Root of Trust
| (FastAPI, local only) |
| - Key Vault (Substrate) |
| - Canonical JSON signing |
| - Admin/access orchestration|
+-------------+----------------+
| Signed HTTPS
v
+------------------------------+
| Metarium CMS-AE | <- Cloud Data Layer
| (Flask on App Engine) |
| - Google Datastore (NDB) |
| - Google Cloud Storage |
| - Signature verification |
+------------------------------+
Management Server
The management server is a FastAPI application on localhost:8420 — the root of trust for the entire system.
- Framework: FastAPI with automatic OpenAPI/Swagger docs at
/docs - Binding: Localhost only — never exposed to the network
- Key Vault: Encrypted Substrate keypairs, decrypted in memory after unlock
- Signing: Canonical JSON encoding before sending to CMS
- Orchestration: CMS installation, admin grants, access control
Key Vault
Password-protected, thread-safe, in-memory Substrate key store.
- Format: PolkadotJS encrypted JSON (same as Polkadot ecosystem)
- Password hashing: Argon2id — memory-hard, GPU/ASIC resistant
- At-rest: Encrypted JSON files, safe for private repos
- Unlock model:
POST /vault/unlockdecrypts to memory;POST /vault/lockclears - Password never stored: Used to derive key, then discarded
CMS App Engine
The cloud data layer — a Flask app on Google App Engine that stores and serves content with cryptographic verification.
- Metadata: Google Datastore (NDB)
- Files: Google Cloud Storage with chunked uploads
- Auth: Every write requires a valid signature from a recognized admin key
- Read access: Public or gated by channel configuration
The CMS never holds private keys — it only verifies signatures. Clear separation between authority (local) and data (cloud).
Security Model
Localhost Binding
Server only binds to 127.0.0.1. Only local processes can communicate with it.
Encrypted Keys at Rest
PolkadotJS format with Argon2id. Useless without the password even if exposed.
Password Never Stored
Used to derive a decryption key, then immediately discarded. Never in logs, config, or env vars.
Canonical JSON Signing
Deterministic serialization ensures reproducible signatures. CMS verifies against admin key registry.
API Reference
For interactive docs, visit http://localhost:8420/docs when the server is running. Use GET /help at runtime to discover operations.
| Endpoint | Method | Description |
|---|---|---|
/health | GET | Health check — test connectivity |
/status | GET | Vault lock state and loaded key count |
/help | GET | All available operations with descriptions |
/vault/unlock | POST | Unlock the key vault with password |
/vault/lock | POST | Lock vault, clear keys from memory |
/keys/list | GET | List keypairs (public keys only) |
/keys/generate | POST | Generate new Substrate keypair |
/keys/rotate | POST | Rotate keypair — new key, deprecate old |
/cms/sign | POST | Sign message with canonical JSON |
/apps/cms/install | POST | Install and configure CMS-AE instance |
/apps/cms/admin/grant | POST | Grant admin privileges to a key |
/apps/cms/access/grant | POST | Grant channel access to a key |
/apps/cms/access/revoke | POST | Revoke access from a key |