Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 98 additions & 24 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,32 @@
# ── Server ──────────────────────────────────────────────────────────────────
ENGRAPHIS_HOST=127.0.0.1
ENGRAPHIS_PORT=8700
# Clients point at the server via this base URL (derived from host/port):
# export ENGRAPHIS_BASE_URL="http://127.0.0.1:8700"
# customer: dashboard/memory/sync only; vendor: issuance/billing/email only;
# combined: development compatibility mode (never use for either production service).
ENGRAPHIS_SERVICE_MODE=combined
# The dashboard base URL is derived from ENGRAPHIS_HOST:ENGRAPHIS_PORT.
# Set ENGRAPHIS_DASHBOARD_URL for a canonical public HTTPS URL behind a reverse proxy.

# Optional bearer token for the REST API. If set, protected /api routes require
# the header Authorization: Bearer <token>. Hosted deployments must set a strong value
# before hosted trial or first-admin setup; enter it in the corresponding setup field.
# Leave empty only for local, single-user, loopback-bound use.
# Optional shared service/operations bearer. If set, supported protected routes accept
# Authorization: Bearer <token>; managed backup/readiness automation should use a strong,
# independently revocable value. It does not prove hosted deployment ownership and is not
# entered during trial or first-admin setup (use ENGRAPHIS_DEPLOYMENT_TOKEN there).
ENGRAPHIS_API_TOKEN=

# Hosted deployment ownership secret. Railway customer templates require a unique value
# of at least 32 characters. It starts a deployment-bound trial and authorizes the first
# remote admin setup; it is not an agent token or a vendor credential.
ENGRAPHIS_DEPLOYMENT_TOKEN=

# VENDOR RELAY ONLY — token authorizing vendor-wide license administration on the
# shared relay (/license/v1 revoke, keys-by-email, deactivate, device listing).
# Keep it a SEPARATE secret from ENGRAPHIS_API_TOKEN: the API token is handed to
# scripts/agents as a per-instance service credential and must never be able to
# revoke customers' licenses. REQUIRED for those routes as of 0.9.8 — the old
# fallback to ENGRAPHIS_API_TOKEN was removed (it made the separation above
# meaningless). Unset ⇒ the vendor admin routes are DISABLED, not open.
# meaningless). Unset ⇒ the vendor admin routes are DISABLED, not open. Production
# fails closed unless this is 32-4096 non-whitespace characters (no control ASCII). Generate it:
# python -c "import secrets; print(secrets.token_urlsafe(48))"
ENGRAPHIS_VENDOR_ADMIN_TOKEN=

# ── Storage ─────────────────────────────────────────────────────────────────
Expand Down Expand Up @@ -52,15 +62,22 @@ ENGRAPHIS_EMBED_MODEL=sentence-transformers/all-MiniLM-L6-v2
# ── v2 write-path fact extraction (optional) ─────────────────────────────────
# "none" (default): store text as given. "chunk": deterministic offline chunks.
# "llm": free-form fact extraction. "llm_structured": schema-validated typed facts,
# entities, relations, keywords, and confidence using the LLM settings below.
# entities, relations, and keywords using the LLM settings below.
ENGRAPHIS_EXTRACTOR=none
# A successful dashboard connection test turns llm_structured on automatically. The
# Settings On/Off button updates the live engine immediately and persists this flag plus
# ENGRAPHIS_EXTRACTOR only when the project .env is writable. Explicit deployment
# environment variables remain authoritative after restart.
ENGRAPHIS_LLM_AUTO_EXTRACT=1

# ── Knowledge-graph extraction (powers the dashboard Graph tab) ──────────────
# "regex" (default): dependency-free heuristic NER runs on every ingest so the Graph tab
# has nodes — no API key, safe offline. "none": disable heuristic text extraction.
# Validated entity/relation metadata from "llm_structured" still feeds the graph
# automatically. Existing memories are backfilled when a workspace graph first opens.
ENGRAPHIS_GRAPH_EXTRACTOR=regex
# Analytical Galaxy is the default; set 0 for the one-release legacy ForceGraph fallback.
ENGRAPHIS_GRAPH_UI_V2=1

# Optional host-LLM retention supervision. "none" preserves the deterministic write path;
# "llm" sends a bounded excerpt to the configured provider for an advisory
Expand Down Expand Up @@ -97,9 +114,8 @@ ENGRAPHIS_RETENTION_SUPERVISOR=none
# Referrer-Policy, Permissions-Policy, and (over HTTPS only) HSTS. Both variables
# REPLACE the built-in value wholesale; set either to an EMPTY string to omit that
# header entirely, which is what you want when a fronting proxy sets its own.
# The default CSP is same-origin with 'unsafe-inline' (the dashboard is one HTML file
# with inline script/style); it needs no third-party allowances because d3/marked/
# DOMPurify are vendored under /static. Widen it only if you add an external origin.
# The default CSP is strict same-origin and contains no unsafe-inline; dashboard CSS,
# JavaScript, and vendored libraries are served under /static.
# Quote the values — both contain characters a shell would otherwise split on.
# ENGRAPHIS_CSP="default-src 'self'; frame-ancestors 'none'" # replace the policy
# ENGRAPHIS_CSP="" # send no CSP at all
Expand Down Expand Up @@ -145,12 +161,11 @@ ENGRAPHIS_DECAY_HALFLIFE_DAYS=7
# Team license to add seats beyond the first admin; first visit creates the admin.
# ENGRAPHIS_TEAM_MODE=0

# Public URL of your dashboard, included as a sign-in link in the "you've been
# added to a team" notification email sent when an admin adds a member. Without
# it, the email just tells the new member to ask their admin for the address.
# Canonical HTTPS URL of this dashboard. Deployment claims bind this origin, and pending
# invitation emails contain a one-time password-creation link at this origin.
# ENGRAPHIS_DASHBOARD_URL=https://dash.yourcompany.com

# "Add member" invite emails: if THIS instance has its own ENGRAPHIS_RESEND_API_KEY
# Pending-invitation emails: if THIS instance has its own ENGRAPHIS_RESEND_API_KEY
# or ENGRAPHIS_SMTP_* configured (see the email-delivery section below), it sends
# invites directly from your own address. Otherwise it automatically falls back to
# relaying the invite through the VENDOR's mail provider at your Team license's signed
Expand All @@ -163,6 +178,11 @@ ENGRAPHIS_DECAY_HALFLIFE_DAYS=7
# enough for a real team onboarding, low enough to bound abuse of a free key.
# ENGRAPHIS_TEAM_INVITE_DAILY_CAP=10

# Vendor-side hosted password-reset relay limits. Resets are authenticated by an active
# Pro/Team key, origin-bound to the customer deployment, and queued in the durable outbox.
# ENGRAPHIS_PASSWORD_RESET_DAILY_CAP=20
# ENGRAPHIS_PASSWORD_RESET_RECIPIENT_HOURLY_CAP=5

# Where 402 responses / upgrade banners send users. Set to your real checkout at launch.
# ENGRAPHIS_PRO_UPGRADE_URL=https://buy.polar.sh/<your-pro-product>
# ENGRAPHIS_TEAM_UPGRADE_URL=https://buy.polar.sh/<your-team-product>
Expand All @@ -185,31 +205,46 @@ ENGRAPHIS_DECAY_HALFLIFE_DAYS=7
# ENGRAPHIS_AUTOSYNC_LOOP=1
# Override where the auto-sync policy is stored (default: next to ENGRAPHIS_DB_PATH).
# ENGRAPHIS_AUTOSYNC_STATE=/data/.engraphis/autosync.json
# Local client credential for the managed relay. Prefer saving it through the dashboard;
# if supplied here, use only a per-user token from /api/auth/token, never a license key.
# ENGRAPHIS_SYNC_TOKEN=engr_ut_replace_me
# ENGRAPHIS_SYNC_READ_ONLY=0
# Temporary customer migration switch; leave off when no legacy customers exist.
# ENGRAPHIS_LEGACY_TEAM_KEY_SYNC=0

# ── Commercial / vendor (ONLY if you SELL Engraphis — not needed to self-host) ──
# Server-side of cloud enforcement + fulfillment. Set these on your vendor host.
#
# Vendor Ed25519 signing seed — signs issued license KEYS and short-lived LEASES.
# 64-char hex inline (how Railway/Fly set it) OR a path to a file with that hex.
# A file must be a regular file no larger than 1 KiB and, on POSIX, owner-only
# (chmod 600); non-regular or group/world-readable targets are refused.
# MUST correspond to the pinned public key in engraphis/licensing.py (_VENDOR_PUBKEY_HEX),
# else every key you issue fails to verify on clients. Verify with:
# python -m scripts.license_admin verify-key
# python -m scripts.license_admin verify '<license-key>'
# ENGRAPHIS_VENDOR_SIGNING_KEY=<64-char-hex-seed or /path/to/vendor_signing.key>
#
# Registry + relay + registrations DB (issued keys, revocations, sync bundles, device
# seats). Put it on a PERSISTENT volume or revoked keys un-revoke on restart.
# ENGRAPHIS_RELAY_DB=/data/.engraphis/relay.db
# Durable Polar delivery/order claims and Team seat baselines. This must also live on the
# persistent vendor volume. Vendor-mode backup fails closed if this file or the relay DB is
# absent, so initialize the real stores before enabling the daily backup workflow.
# ENGRAPHIS_WEBHOOK_STATE=/data/.engraphis/polar-webhooks.db
#
# Lease lifetime (hours). Lower = faster revocation takes effect, more phone-home.
# Default 24 (license_registry.LEASE_TTL_HOURS_DEFAULT), floored at 5 minutes.
# ENGRAPHIS_LEASE_TTL_HOURS=24
#
# REQUIRED to offer self-serve trials. The public https:// base URL of THIS relay, used
# REQUIRED on the vendor control plane. The public https:// base URL of THIS service, used
# to build the emailed magic-link. There is deliberately no fallback: deriving it from
# the request would mean deriving it from the client-supplied Host header, which let an
# attacker have a victim emailed a confirmation link pointing at attacker-controlled
# infrastructure (fixed 2026-07-18). Unset ⇒ /license/v1/start-trial answers 503.
# ENGRAPHIS_RELAY_PUBLIC_URL=https://team.engraphis.com
# ENGRAPHIS_RELAY_PUBLIC_URL=https://license.engraphis.com
# Development-only escape hatch for the pre-GA key-copy trial route. Never enable on the
# production vendor service; readiness and onboarding use /license/v1/trial-claims.
# ENGRAPHIS_ENABLE_LEGACY_TRIAL_FLOW=0
#
# Per-account relay storage ceilings. Defaults 2 GiB / 64 workspaces. The per-workspace
# caps alone bound nothing — workspace ids are caller-supplied — and the relay DB shares
Expand All @@ -218,19 +253,35 @@ ENGRAPHIS_DECAY_HALFLIFE_DAYS=7
# ENGRAPHIS_RELAY_MAX_ACCOUNT_BYTES=2147483648
# ENGRAPHIS_RELAY_MAX_WORKSPACES_PER_ACCOUNT=64
#
# Per-IP burst cap on the unauthenticated key-verifying routes: /license/v1/register and
# /license/v1/team-invite share ONE budget (per minute, per process), so alternating
# Per-IP burst cap on the unauthenticated key-verifying routes: /license/v1/register,
# /license/v1/team-invite, and /license/v1/password-reset share ONE budget (per minute,
# per process), so alternating
# between them buys no extra work. Guards the ~3 ms pure-Python Ed25519 verify from being
# used as an unauthenticated CPU DoS. 0 disables. Default 60.
# ENGRAPHIS_REGISTER_RATE_PER_MINUTE=60
#
# Per-IP burst cap on the authenticated sync relay's OWN token bucket (one full sync round
# is many requests), kept separate from the register bucket above so sync traffic is not
# throttled by the unauthenticated verify routes. 0 disables. Default 600.
# ENGRAPHIS_RELAY_RATE_PER_MINUTE=600
#
# Polar billing webhook (auto-fulfill: order.paid -> signed key -> email).
# Use Polar's generated value. Raw secrets, or the decoded bytes of legacy whsec_
# values, must contain at least 16 bytes of key material or readiness fails closed.
# POLAR_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxxxxxxxxx
# POLAR_ORGANIZATION_ID= # optional: verify the webhook's org matches
# POLAR_ORGANIZATION_ID= # required in vendor production
# These values must match engraphis/commercial_manifest.json exactly. Unknown products
# and wrong-organization events are rejected rather than heuristically fulfilled.
# POLAR_PRO_MONTHLY_PRODUCT_ID=6349d29a-b4c0-4b8e-b9e8-071705351c9c
# POLAR_PRO_ANNUAL_PRODUCT_ID=5e10d5d2-607a-4e9c-ad1c-88cb48c37e11
# POLAR_TEAM_MONTHLY_PRODUCT_ID=6444a48a-7a61-4c8e-8045-07a930f8f381
# POLAR_TEAM_ANNUAL_PRODUCT_ID=929d926a-2981-4ad7-95bd-f52dabf0794e
#
# Outbound email (license-key delivery AND team invite notifications). Resend
# API (preferred) OR SMTP.
# ENGRAPHIS_RESEND_API_KEY=re_xxxxxxxxxxxx
# Use Resend's generated value; its raw/decoded signing key must be at least 16 bytes.
# RESEND_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxxxxxxxxx
# ENGRAPHIS_SMTP_FROM=licenses@yourdomain.com
# ENGRAPHIS_SMTP_HOST= # alternative to Resend
# ENGRAPHIS_SMTP_PORT=587
Expand All @@ -239,13 +290,36 @@ ENGRAPHIS_DECAY_HALFLIFE_DAYS=7
#
# ── Client side (end-user machines) ─────────────────────────────────────────
# Paid keys require a revocable, machine-bound lease from the managed service. The
# built-in default is https://team.engraphis.com; override only for a different vendor
# built-in default is https://license.engraphis.com; override only for a different vendor
# deployment. Free-tier use remains local and does not require the service.
# ENGRAPHIS_CLOUD_URL=https://team.engraphis.com
# ENGRAPHIS_CLOUD_URL=https://license.engraphis.com

# Server-side license enforcement (vendor/fulfillment server only): when set, every key
# minted by the Polar webhook carries a signed enforce:"cloud" claim + this URL, and the
# client requires a live lease from it (revocable, seat-counted, useless offline).
# Set this to the canonical managed-service URL for newly issued keys. Older keys carrying
# the retired Railway hostname are migrated by the client without changing their signature.
# ENGRAPHIS_KEY_CLOUD_URL=https://team.engraphis.com
# ENGRAPHIS_KEY_CLOUD_URL=https://license.engraphis.com

# ── Encrypted commercial backups ────────────────────────────────────────────
# Exact 32-byte key as 64 hex characters, supplied only through the production secret
# store. Mount off-volume storage and schedule scripts/commercial_backup.py daily.
# ENGRAPHIS_BACKUP_KEY=
# ENGRAPHIS_BACKUP_OUTPUT_DIR=/backup/engraphis
# ENGRAPHIS_BACKUP_STATUS_FILE=/data/.engraphis/backup-status.json
# ENGRAPHIS_BACKUP_RETENTION_DAYS=30
# ENGRAPHIS_BACKUP_MAX_AGE_SECONDS=93600
# ENGRAPHIS_CUSTOMER_MIN_FREE_BYTES=268435456
# ENGRAPHIS_REJECTED_LEASE_ALERT_THRESHOLD=50
# ENGRAPHIS_REJECTED_LEASE_ALERT_WINDOW_SECONDS=3600
# Control-plane readiness fails when pending/retrying mail is too old, a message exhausts
# retries, or the 24-hour bounce/complaint rate is too high after the minimum sample size.
# ENGRAPHIS_EMAIL_MAX_BACKLOG_AGE_SECONDS=900
# ENGRAPHIS_EMAIL_MAX_BOUNCE_RATE=0.05
# ENGRAPHIS_EMAIL_BOUNCE_MIN_SAMPLE=20
# ENGRAPHIS_JSON_LOGS=1
# Customer deployments with local Resend/SMTP retry durable email every 30 seconds.
# ENGRAPHIS_EMAIL_OUTBOX_LOOP=1
# Example (destination must be a separate mounted device in production):
# python -m scripts.commercial_backup backup --output-dir /backup/engraphis \
# --marker /data/.engraphis/backup-status.json --retention-days 30
Loading