Configuration
The settings that matter, the ones that will bite you, and the four keys you must not lose.
Veefore is configured entirely through the environment. No runtime configuration file, no settings table that can disagree with the process that booted. Configuration is validated at startup, and an invalid value stops the process rather than degrading it.
The complete list is Configuration reference,
generated from .env.example. This page covers the ones with consequences.
#The four keys
Lose these and you lose data
| Key | Protects | Losing it means |
|---|---|---|
VEEFORE_DATA_ENCRYPTION_KEY |
Sealed credential material | Every credential becomes unreadable |
VEEFORE_SIGNING_PRIVATE_KEY |
Agent passports | Every issued passport stops verifying |
VEEFORE_SESSION_SECRET |
Human sessions | Everyone is logged out. Recoverable |
VEEFORE_AUDIT_CHAIN_SECRET |
The audit hash chain | Integrity can no longer be verified |
The first, second and fourth are not recoverable by re-deriving. Back them up where you back up your other root secrets, and inject them from a secret manager rather than a file.
.env.example ships with development keys so the stack boots out of the box.
They are shared with everyone who has ever cloned the repository, so they are
not secret by definition. Replace all four before anything that matters.
#Rotating them
| Key | Rotation |
|---|---|
VEEFORE_SESSION_SECRET |
Safe. Everyone re-authenticates |
VEEFORE_SIGNING_PRIVATE_KEY |
Invalidates issued passports. Issue new ones, let partners pick up the new published key, then retire the old |
VEEFORE_DATA_ENCRYPTION_KEY |
Requires re-sealing every credential. Plan as a migration |
VEEFORE_AUDIT_CHAIN_SECRET |
Breaks verification of the existing chain. Export and archive first |
The last two are not config changes. Treat them as projects.
#Database
iniDATABASE_URL=postgres://veefore:veefore@127.0.0.1:55432/veefore
DATABASE_SSL=true
DATABASE_POOL_MAX=20
DATABASE_STATEMENT_TIMEOUT_MS=15000
DATABASE_ENABLE_RLS=false
PGLITE_DATA_DIR=memory://
`PGLITE_DATA_DIR` is per-process
The embedded PGlite driver is genuinely useful for isolated tests. It is the wrong choice for running the stack, because each process gets its own private copy of the database — the control plane, the gateway and the worker would see none of each other's writes.
The symptom is confusing rather than obviously broken: an agent you just created
does not exist. Set DATABASE_URL for anything multi-process.
DATABASE_ENABLE_RLS=true turns on PostgreSQL row-level security as a second,
independent isolation layer under the application-level tenant scoping. Enable
it in production. See Tenant isolation.
DATABASE_POOL_MAX is per process instance. Three control plane instances at 20
each is 60 connections, plus the gateway, plus the worker. Size PostgreSQL's
max_connections for the total, not for one process.
#Egress
iniGATEWAY_ALLOW_REAL_EGRESS=false
GATEWAY_EGRESS_TIMEOUT_MS=15000
false is the default, and with it the tool runtime produces deterministic
simulated responses — every one carrying simulated: true. Nothing is ever
presented as output from a real system when it is not.
`GATEWAY_ALLOW_REAL_EGRESS=true` means real outbound calls
Including webhook delivery. Turn it on deliberately, per environment, once the destination allowlists on your tools are correct.
With it off, webhook deliveries are recorded as failed with an explicit reason rather than reported as delivered — a webhook claimed as delivered when nothing was sent would be a lie in the one record you would later rely on.
#Sessions and tokens
iniSESSION_TTL_SECONDS=43200 # 12 hours
SESSION_IDLE_TIMEOUT_SECONDS=3600 # 1 hour idle
STEP_UP_TTL_SECONDS=300 # 5 minutes
AGENT_TOKEN_TTL_SECONDS=900 # 15 minutes
PASSPORT_TTL_SECONDS=2592000 # 30 days
MAX_LOGIN_ATTEMPTS=10
LOGIN_LOCKOUT_SECONDS=900
STEP_UP_TTL_SECONDS is the window in which a step-up authentication stays
valid. Five minutes is already generous: step-up exists so an unattended browser
session cannot revoke an agent, and a long window reintroduces exactly that.
Do not raise it for convenience.
AGENT_TOKEN_TTL_SECONDS is short because there is no refresh token — an agent
re-signs with its key. Lowering it costs a few extra signatures; raising it
extends how long a stolen token is useful.
#CORS
iniCORS_ALLOWED_ORIGINS=https://console.example.com
Exact origins, comma-separated. If you change the console's port or host and forget this, the browser refuses every request and the console appears completely broken with no useful error.
#Credentials
iniCREDENTIAL_BROKER_PROVIDER=local
CREDENTIAL_DEFAULT_TTL_SECONDS=600
local seals material in PostgreSQL with VEEFORE_DATA_ENCRYPTION_KEY. For
production, point it at your secret manager so material lives where the rest of
your secrets live and inherits that system's rotation, auditing and access
control.
#Observability
iniOTEL_ENABLED=true
OTEL_SERVICE_NAME=veefore
METRICS_ENABLED=true
LOG_LEVEL=info
See Observability.
#The console's build-time values
iniVITE_API_BASE_URL=https://veefore.example.com
VITE_GATEWAY_BASE_URL=https://gateway.veefore.example.com
These are baked in at build time
VITE_* values are compiled into the bundle. Changing them requires a rebuild
and redeploy of the console — restarting a server does nothing.
If the console is pointing at the wrong API after a config change, that is why.
#Loading order
- Real environment variables win.
- Then the repository root
.env.
That order holds for every process, including the console's Vite config, which
reads the root .env so ports stay consistent across the stack.
Ambient variables leak between runs
A shell with VEEFORE_AGENT_ID exported from an earlier session will quietly
make a test authenticate as the wrong agent. Shell environments persist across
commands.
If something is behaving as though it is a different agent or a different
organization, env | grep Veefore before anything else.
#Checking it
bashcurl -s http://localhost:4000/v1/meta/info
No authentication. Returns the version, the environment, both public URLs, and the published capability and exclusion lists. The fastest way to confirm a deployment is configured the way you think it is.
bashveefore doctor --strict
Audits the posture, including TLS, MFA enforcement, local file permissions and network restrictions.