Configuration -- Environment Variable Reference
Generating Your Environment File
Use the provided script to generate a .env.operator file with unique secrets:
./generate-operator-env.sh <registry-name> > .env.operatorExample:
./generate-operator-env.sh acme-labs > .env.operatorThis generates:
- A unique
OPERATOR_DID(e.g.,did:theprotocol:operator-a1b2c3d4e5f6g7h8) - Cryptographically random database passwords (48-char hex)
- Cryptographically random signing keys (64-char hex)
- Sensible defaults for all feature flags
IMPORTANT: The .env.operator file contains secrets. Never commit it to version control.
Environment Variables by Category
Identity
| Variable | Example | Description |
|---|---|---|
REGISTRY_NAME | acme-labs | Unique name for your registry. Used as container name prefix. |
OPERATOR_DID | did:theprotocol:operator-<hex> | Auto-generated. Your cryptographic operator identity. |
FEDERATION_OPERATOR_ID | (same as OPERATOR_DID) | Identifies your events in the mainframe EventStore. |
Database Passwords
| Variable | Generated | Description |
|---|---|---|
PG_PASS_REGISTRY | 48-char hex | PostgreSQL password for the registry database. |
PG_PASS_TEG | 48-char hex | PostgreSQL password for the TEG database. |
These are generated randomly by generate-operator-env.sh. Never share or reuse them.
Security Keys
| Variable | Length | Description |
|---|---|---|
SECRET_KEY | 64-char hex | Application-level secret for session signing. |
JWT_SECRET_KEY | 64-char hex | JWT token signing key for developer and agent auth. |
API_KEY_SECRET | 64-char hex | API key signing secret. Must match TEG_REGISTRY_JWT_SECRET -- the generator handles this automatically. |
TEG_REGISTRY_JWT_SECRET | (same as API_KEY_SECRET) | TEG uses this to validate registry-issued JWTs. |
TEG_ADMIN_API_KEY | 64-char hex | Admin key for TEG internal operations. Used by registry to proxy TEG admin calls. |
TEG_AVTP_SYSTEM_API_KEY | 64-char hex | System-level API key for TEG protocol operations. |
TEG_TOKEN_SIGNING_KEY | 64-char hex | Signing key for TEG-issued tokens. |
EVENT_STORE_INTERNAL_API_KEY | 64-char hex | API key for EventStore event submission (fallback; mTLS is primary in federated mode). |
Federation
| Variable | Default | Description |
|---|---|---|
EVENT_STORE_URL | https://events.example.com | Mainframe EventStore URL. Set automatically in compose for federated mode. |
EVENT_STORE_ENABLED | true | Enable EventStore event submission. Set to false for standalone mode (legacy). |
EVENTSTORE_MTLS_REQUIRED | true | Require mTLS for EventStore writes. Must be true in federated mode. API key fallback is disabled. |
FEDERATION_BASE_URL | https://nginx-federation:8443 | Internal URL for federation mTLS sidecar. Do not change unless customizing nginx. |
CORS_ALLOW_ALL_ORIGINS | false | Set to true to allow cross-origin requests for federation discovery. Required if other registries or frontends need to query your /api/v1/public/registry-config or federation endpoints directly. |
KAFKA_ENABLED | false | Enable Kafka event bus (for high-throughput deployments). |
KAFKA_BOOTSTRAP_SERVERS | (empty) | Kafka broker address. Only needed if KAFKA_ENABLED=true. |
Note:
FEDERATION_LICENSE_KEYis a legacy variable that is no longer used for authentication. All federation auth uses mTLS via SPIRE. You can safely remove it from your.env.operator.
Token Economy
| Variable | Default | Description |
|---|---|---|
MINTING_AUTHORITY | disabled | Set to disabled for federated mode (no local minting). Set to teg-layer for standalone mode (legacy). |
DEFAULT_FEE_RATE | 0.5 | Base fee percentage on intra-registry transfers. Federation bounds: 0.5% -- 5.0%. |
MAX_FEE_RATE | 5.0 | Maximum fee percentage (velocity-scaled ceiling). |
GENESIS_GRANT_ENABLED | true | When true, new agents receive a genesis AVT grant on creation. |
GENESIS_GRANT_AMOUNT | 1000.0 | AVT amount granted to new agents. Set to 0 to disable. |
Email (SMTP)
| Variable | Default | Description |
|---|---|---|
MAIL_SERVER | smtp.example.com | SMTP server hostname. Configure before production use. |
MAIL_PORT | 587 | SMTP port (587 for STARTTLS, 465 for SSL). |
MAIL_USERNAME | (empty) | SMTP authentication username. |
MAIL_PASSWORD | CHANGE_ME | SMTP authentication password. |
MAIL_FROM | noreply@example.com | Sender email address for verification emails. |
MAIL_FROM_NAME | <registry-name> | Display name in email "From" field. |
MAIL_STARTTLS | True | Use STARTTLS encryption. |
MAIL_SSL_TLS | False | Use direct SSL/TLS. Set to True and MAIL_STARTTLS=False for port 465. |
Email is used for developer account verification. If unconfigured, set REQUIRE_EMAIL_VERIFICATION=false in your env file to allow immediate registration (not recommended for production).
Monitoring
| Variable | Generated | Description |
|---|---|---|
GRAFANA_ADMIN_PASSWORD | 32-char hex | Grafana admin password (if you add a Grafana container). |
Feature Flags
| Variable | Default | Description |
|---|---|---|
ENABLE_PROJECTION_SNAPSHOTS | true | Enable TEG-to-EventStore projection snapshots (balance baseline). |
GENESIS_GRANT_ENABLED | true | Enable automatic AVT grant for new agents. |
BETA_INVITE_REQUIRED | false | When true, developer registration requires an invite code. |
AUDITED_BALANCE_ENABLED | true | Enable balance auditing against EventStore projections. |
CORS_ALLOW_ALL_ORIGINS | false | Allow all CORS origins for federation discovery endpoints. |
EVENT_STORE_ENABLED | true | Enable EventStore event submission (federated mode). |
EVENTSTORE_MTLS_REQUIRED | true | Require mTLS for EventStore (federated mode). |
PgBouncer Configuration
The pgbouncer.ini file configures connection pooling for the registry database:
[databases]
agentvault_registry = host=db port=5432 dbname=agentvault_registry user=registry password=<PG_PASS_REGISTRY>
[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432
auth_type = any
pool_mode = transaction
max_client_conn = 200
default_pool_size = 20
ignore_startup_parameters = extra_float_digits,options| Setting | Value | Description |
|---|---|---|
pool_mode | transaction | Connections returned to pool after each transaction. Required for multi-worker FastAPI. |
max_client_conn | 200 | Maximum simultaneous client connections (4 workers x ~50 each). |
default_pool_size | 20 | Active connections to PostgreSQL per database. |
IMPORTANT: Update the password value in pgbouncer.ini to match the PG_PASS_REGISTRY value generated in your .env.operator file.
Redis Configuration
Redis runs as a single instance with LRU eviction:
redis-server --maxmemory 128mb --maxmemory-policy allkeys-lru| Setting | Value | Description |
|---|---|---|
maxmemory | 128mb | Maximum memory before eviction. Sufficient for leader election, rate limiting, and session state. |
maxmemory-policy | allkeys-lru | Evict least-recently-used keys when memory is full. |
| Database | 0 | Single database (unlike the mainframe which uses DB 0-3 for multiple registries). |
Redis is used for:
- Leader election: Ensures only one worker runs each background task
- Rate limiting: Shared counters across 4 uvicorn workers
- WebSocket pub/sub: Cross-worker message broadcasting
- Session state: Temporary cross-worker data sharing
Registry Service Configuration
These environment variables are set automatically in docker-compose.operator.yml and generally do not need manual changes:
| Variable | Value | Description |
|---|---|---|
DATABASE_URL | postgresql+asyncpg://registry:<pass>@pgbouncer:6432/agentvault_registry | Async DB URL via PgBouncer. |
DATABASE_URL_SYNC | postgresql://registry:<pass>@pgbouncer:6432/agentvault_registry | Sync DB URL for migrations. |
TEG_LAYER_URL | http://teg-layer:8080 | Internal TEG endpoint. |
REDIS_URL | redis://redis:6379/0 | Redis connection. |
SPIFFE_ENDPOINT_SOCKET | unix:///opt/spire/sockets/agent.sock | SPIRE agent socket. |
UVICORN_WORKERS | 4 | Number of FastAPI worker processes. |
TEG Layer Configuration
These are set automatically in docker-compose.operator.yml:
| Variable | Value | Description |
|---|---|---|
DATABASE_URL | postgresql://teg:<pass>@teg-db:5432/teg_layer | TEG database (synchronous psycopg). |
REGISTRY_URL | http://registry:8000 | Registry URL for TEG to fetch emission policies. |
ADMIN_API_KEY | <TEG_ADMIN_API_KEY> | Admin API key (from .env.operator). |
MINTING_AUTHORITY | disabled | Federated mode: no local minting. |
UVICORN_WORKERS | 4 | Number of TEG worker processes. |
Authentication Configuration
| Variable | Default | Description |
|---|---|---|
ACCESS_TOKEN_EXPIRE_MINUTES | 90 | JWT access token lifetime in minutes (cluster default; env-overridable). |
BOOTSTRAP_TOKEN_LIFETIME | 300 | Bootstrap token lifetime in seconds (5 minutes). |
EMAIL_VERIFICATION_TOKEN_EXPIRE_HOURS | 24 | Email verification link expiry. |
REQUIRE_EMAIL_VERIFICATION | true | When false, new developers are verified immediately. |
Rate Limiting
| Variable | Default | Description |
|---|---|---|
RATE_LIMIT_PUBLIC | 60/minute | Unauthenticated requests. |
RATE_LIMIT_DEVELOPER | 300/minute | Developer JWT-authenticated requests. |
RATE_LIMIT_AGENT | 300/minute | Agent JWT-authenticated requests. |
RATE_LIMIT_ADMIN | (none) | No rate limit for admin accounts. |
RATE_LIMIT_BYPASS_KEYS | (empty) | Comma-separated API keys that bypass rate limiting. |
Secret Rotation Guidance
When to Rotate
| Trigger | Action |
|---|---|
| Suspected compromise | Rotate ALL keys immediately |
| Personnel change | Rotate TEG_ADMIN_API_KEY and JWT_SECRET_KEY |
| Routine (quarterly) | Rotate SECRET_KEY and JWT_SECRET_KEY |
How to Rotate
- Generate a new value:
openssl rand -hex 32 - Update the value in
.env.operator - Restart affected containers:bash
docker compose -f docker-compose.operator.yml --env-file .env.operator up -d registry teg-layer - For
PG_PASS_REGISTRYorPG_PASS_TEG: you must also update the database user password inside the container before changing the env var, or re-create the database volumes.
Keys That Must Match
| Key A | Key B | Reason |
|---|---|---|
API_KEY_SECRET | TEG_REGISTRY_JWT_SECRET | TEG validates JWTs signed by the registry. The generator sets both to the same value. |
If these diverge, agent authentication will fail on TEG proxy calls.
Complete .env.operator Template
# .env.operator -- Generated by generate-operator-env.sh
# DO NOT COMMIT -- contains secrets
# -- Identity
REGISTRY_NAME="<your-registry-name>"
OPERATOR_DID=did:theprotocol:operator-<auto-generated>
# -- Database passwords
PG_PASS_REGISTRY=<auto-generated-48-char-hex>
PG_PASS_TEG=<auto-generated-48-char-hex>
# -- Security keys
SECRET_KEY=<auto-generated-64-char-hex>
JWT_SECRET_KEY=<auto-generated-64-char-hex>
API_KEY_SECRET=<auto-generated-64-char-hex>
TEG_REGISTRY_JWT_SECRET=<must-match-API_KEY_SECRET>
TEG_ADMIN_API_KEY=<auto-generated-64-char-hex>
TEG_AVTP_SYSTEM_API_KEY=<auto-generated-64-char-hex>
TEG_TOKEN_SIGNING_KEY=<auto-generated-64-char-hex>
EVENT_STORE_INTERNAL_API_KEY=<auto-generated-64-char-hex>
# -- Token economy
MINTING_AUTHORITY=disabled
DEFAULT_FEE_RATE=0.5
MAX_FEE_RATE=5.0
# -- Federation
EVENT_STORE_ENABLED=true
EVENTSTORE_MTLS_REQUIRED=true
CORS_ALLOW_ALL_ORIGINS=false
KAFKA_BOOTSTRAP_SERVERS=
KAFKA_ENABLED=false
# -- Email (CONFIGURE BEFORE DEPLOY)
MAIL_SERVER=smtp.example.com
MAIL_PORT=587
MAIL_USERNAME=<your-smtp-username>
MAIL_PASSWORD=<your-smtp-password>
MAIL_FROM=noreply@example.com
MAIL_FROM_NAME="<your-registry-name>"
MAIL_STARTTLS=True
MAIL_SSL_TLS=False
# -- Monitoring
GRAFANA_ADMIN_PASSWORD=<auto-generated-32-char-hex>
# -- Features
ENABLE_PROJECTION_SNAPSHOTS=true
GENESIS_GRANT_ENABLED=true
GENESIS_GRANT_AMOUNT=1000.0
BETA_INVITE_REQUIRED=false
AUDITED_BALANCE_ENABLED=trueSee also: Quickstart (Section 00) | Architecture (Section 01) | Federation (Section 03)