# ── Database (required) ─────────────────────────────── # Neon Postgres connection string — the app runs a `pg` pool against it. # Prefer the Neon POOLER endpoint (…:6432) over the direct one (…:5432). # Optional: DB_POOL_MAX (default 10). DATABASE_URL=postgresql://user:pass@ep-xxx-pooler.us-east-2.aws.neon.tech:6432/versions # ── Auth (required) ─────────────────────────────────── # Generate with: openssl rand -hex 32 NEXTAUTH_SECRET=generate-a-random-32-char-string-here NEXTAUTH_URL=http://localhost:3000 # ── Arc L1 settlement ───────────────────────────────── # NETWORK: currently Arc TESTNET. Arc MAINNET launches 2026-09-16 — swap # ARC_RPC_URL / ARC_USDC_CONTRACT to mainnet values then (see README). # Omit both to run the Arc adapter in mock mode (deterministic hashes, no on-chain calls). ARC_RPC_URL=https://rpc.testnet.arc.network ARC_USDC_CONTRACT=0x3600000000000000000000000000000000000000 # ERC-8183 Agentic Commerce (license = job). Defaults to Arc testnet reference. ARC_ERC8183_CONTRACT=0x0747EEf0706327138c69792bF28Cd525089e4583 # ERC-8004 Identity Registry (agent identity). Defaults to Arc testnet reference. ARC_ERC8004_REGISTRY=0x8004A818BFB912233c491871b3d84c89A494BD9e NEXT_PUBLIC_ARC_ERC8183_CONTRACT=0x0747EEf0706327138c69792bF28Cd525089e4583 # Wallet that receives the platform share of each settlement leg. PLATFORM_WALLET= # Optional: server-side signer for automated settlement. When set, the # settlement service will sign and broadcast real ERC-20 transfers from # PLATFORM_WALLET. SECURITY: this is a hot wallet; use a dedicated treasury # key and rotate/restrict it after the hackathon/demo. PLATFORM_WALLET_PRIVATE_KEY= # ── Inference (OpenRouter — free tier) ───────────────── # One key enables live LLM + text embeddings. Get a key at https://openrouter.ai/keys # Omit to run mock mode (deterministic reviews + hash embeddings). OPENROUTER_API_KEY= # Optional overrides (defaults shown): # LLM_MODEL=openai/gpt-oss-20b:free # EMBEDDING_MODEL=nvidia/nemotron-3-embed-1b:free OPENROUTER_SITE_URL= OPENROUTER_APP_NAME=VERSIONS # ── LLM (custom provider — overrides OpenRouter when LLM_API_KEY is set) ─ LLM_API_URL= LLM_API_KEY= LLM_MODEL=gpt-4o-mini # ── LLM fallback chain (Venice → HF Qwen → TokenRouter → OpenRouter) ─── # Agent reviews walk this chain on failure; mock is the last resort. # Venice (reliable, keyed — recommended primary): VENICE_API_KEY= # VENICE_MODEL=venice-uncensored # HF public Qwen3.8-27B (free, keyless, rate-limited ~30 req/min): HF_QWEN_API_URL= # HF_QWEN_MODEL=Qwen/Qwen3.8-27B # TokenRouter free DeepSeek (free; base URL is service-specific — both # TOKENROUTER_API_KEY and TOKENROUTER_API_URL must be set to activate): TOKENROUTER_API_KEY= TOKENROUTER_API_URL= # TOKENROUTER_MODEL=deepseek/deepseek-v4-pro-0813-free # ── CLAP audio embeddings (custom — overrides OpenRouter when set) ─────── # Hosted CLAP service for audio-native vectors. When unset, OpenRouter # embeds catalog text (title + placement brief) instead of raw audio. EMBEDDING_API_URL= EMBEDDING_API_KEY= EMBEDDING_MODEL=clap-default EMBEDDING_DIMENSIONS=512 # ── Agent + A&R wallets ─────────────────────────────── # Preferred: set AGENT_KEY_SEED to give every agent its own deterministic # testnet wallet (privkey = sha256(seed:label)) that genuinely signs its # USDC transfers on Arc. TESTNET ONLY — anyone with the seed can recompute # every agent key. AGENT_KEY_SEED= # Optional explicit overrides (take precedence over seed-derived addresses). # Omit everything to use deterministic placeholder addresses (stable across # restarts; transfers from them settle as flagged mocks). AGENT_WALLET_PRODUCTION= AGENT_WALLET_PERFORMANCE= AGENT_WALLET_MARKET= AR_WALLET= # ── Upload storage (Grove — Lens) ───────────────────── # Immutable uploads need no API key. chain_id selects ACL/retention # (232 = Lens Chain mainnet; 37111 = Lens testnet — testnet may GC). # https://lens.xyz/docs/storage/usage/upload GROVE_CHAIN_ID=232 # GROVE_MOCK=1 # force offline mock (tests set this via Vitest) # GROVE_DISABLED=1 # refuse Grove; only local disk if LOCAL_UPLOADS=1 # When 0/false, submissions require Grove — no data/uploads fallback. LOCAL_UPLOADS=0 # ── Split hosting (UI on Netlify, API on box) ───────── # Server-only override for RSC fetches (listing page, sitemap, OG). # Defaults to NEXT_PUBLIC_API_URL when unset. INTERNAL_API_URL= # Opportunistic sweep on SSE connect (1=on). Set 0 to rely on cron only. SWEEP_ON_SSE=1 # ── Client-side (NEXT_PUBLIC_*, inlined at build time) ─ # WalletConnect project ID — https://cloud.walletconnect.com NEXT_PUBLIC_WC_PROJECT_ID= # Public site URL (attribution links, OG). Defaults to versions.persidian.com. NEXT_PUBLIC_APP_URL=https://versions.persidian.com # API origin when the UI is hosted separately (e.g. Netlify). Empty = same # origin as the page (monolith). Example: https://versions.persidian.com NEXT_PUBLIC_API_URL= # Client-side Arc RPC fallback (defaults to ARC_RPC_URL server-side). NEXT_PUBLIC_ARC_RPC_URL=https://rpc.testnet.arc.network # Explorer base for tx/address links shown in the UI (economy ticker, dashboards). NEXT_PUBLIC_ARC_EXPLORER_URL=https://testnet.arcscan.app # Client-side submit receipt polling timeout (ms). Default 60000. NEXT_PUBLIC_SUBMIT_RECEIPT_TIMEOUT_MS=60000 # ── Server tunables ─────────────────────────────────── # Submit receipt polling timeout for server-side workers (sweeper). Default 60000. SUBMIT_RECEIPT_TIMEOUT_MS=60000 # Upload storage directory. Defaults to /tmp/uploads on Vercel, ./data/uploads locally. UPLOAD_DIR= # Rate limiter window + per-IP caps. RATE_LIMIT_WINDOW_MS=60000 RATE_LIMIT_AUDIO_MAX=30 # Money-adjacent write routes get their own caps. These were unrated before, # which let one caller create unbounded slot reservations or usage rows. RATE_LIMIT_USAGE_MAX=30 RATE_LIMIT_SLOT_CREATE_MAX=20 RATE_LIMIT_SLOT_PAY_MAX=10 # Optional hard ceiling on how often one channel may report one listing, in # hours. UNSET (the default) means no time-based window — the exact-repeat # guard (uq_usage_dedup) is the real protection, and a window on top of it # would refuse legitimate batched delivery reports and provenance corrections. # Set this only to cap a specific abuse investigation. USAGE_REPORT_COOLDOWN_HOURS= # HTTP body / timeout / cache tunables. JSON_BODY_LIMIT=256kb UPSTREAM_TIMEOUT_MS=12000 SEMANTIC_CACHE_TTL_MS=30000 AUDIO_CACHE_TTL_MS=45000 # CORS — comma-separated UI origins for credentialed cross-origin API # access (e.g. https://your-app.netlify.app,http://localhost:3000). # Unset keeps legacy Access-Control-Allow-Origin: *. ALLOWED_ORIGINS= # API host image (CI → GHCR). deploy.sh defaults to # ghcr.io/thisyearnofear/versions:; override if needed. # VERSIONS_IMAGE=ghcr.io/thisyearnofear/versions:latest # GHCR_USER=thisyearnofear # GHCR_TOKEN= # only if the package is private # Log level: trace|debug|info|warn|error LOG_LEVEL=info # ── Upstash Redis (globally-coherent rate limiting) ──── # Omit both to use the in-memory rate limiter (per-instance, not # globally coherent across serverless deployments). UPSTASH_REDIS_REST_URL= UPSTASH_REDIS_REST_TOKEN= # ── Monitoring (optional) ───────────────────────────── # Set SENTRY_DSN to enable error + trace reporting (instrumentation.ts). # Empty = SDK inert, zero overhead. SENTRY_ORG/SENTRY_PROJECT are only # needed if the build should upload source maps to Sentry. SENTRY_DSN= SENTRY_ORG= SENTRY_PROJECT= POSTHOG_KEY= # ── Optional demo catalog enrichment ─────────────────── # Set to enable live ccMixter Query API ingestion; unset = deterministic mock mode. CCMIXTER_API_URL= # ── Cron (recommended for production) ─────────────────────────── # Shared secret guarding POST/GET /api/cron/sweep (settlement retries, # outbox drain, retention deletes). Generate with: openssl rand -hex 32 # When unset the route fails open with a warning; when set, the cron job # must send it as the `x-cron-secret` header. CRON_SECRET= # ── CC catalog (optional) ───────────────────────────────────── # ccMixter Query API 2.0 (public, keyless). When set, the ingest script # pulls real CC-BY tracks into the demo catalog; when unset it runs in # deterministic mock mode (no network). CCMIXTER_API_URL= # ── Retention (optional overrides, days) ───────────────────── # Pruned by the sweep cron (max once / 30 min). Only processed/old rows are # deleted; settlement_legs, licenses, and unprocessed outbox rows are kept. RETENTION_OUTBOX_DAYS=14 RETENTION_TELEMETRY_DAYS=30 RETENTION_SEARCHES_DAYS=90 RETENTION_AUDIT_DAYS=365