Oblive Docs
Configuration

Local Stack

Complete reference for the canonical machine-local JSON configuration.

The ignored config/local-stack.json file is the canonical machine-local configuration. The tracked config/local-stack.example.json contains safe placeholders, and config/local-stack.schema.json describes the same contract used by the launcher.

Top-level Fields

FieldPurpose
modedevelopment for bind-mounted watchers or production for built images
persistencePreserve named volumes or use disposable local data
codexAgent authentication mode and source
workerReplicasNumber of task-worker service replicas
portsHost ports for infrastructure and applications
postgresLocal database name and credentials
garageLocal S3-compatible storage settings
agentServiceTokenBackend authentication for trusted agent runtimes
integrationCredentialKeyEncryption key for integration credential envelopes
publicFrontendUrlOptional public HTTPS product origin for browser returns and Vite
googleOAuthOptional Google client credentials and provider callback
metaAdsOAuthOptional deployment-level Meta OAuth client ID and provider callback
xOAuthOptional organic X OAuth 2.0 client credentials and provider callback
xAdsOAuthOptional X Ads OAuth 1.0a consumer credentials and provider callback
metaAdsMeta Ads operational provider; defaults to direct Graph API tools

Mode

development mounts source and runs watchers. production builds and runs the service-owned images. This is an image/runtime mode, not a complete production deployment guide.

Persistence

Use persistent to keep named volumes across normal stop/start cycles. Use disposable behavior only when losing local database, Redis, object-store, and Codex container state is intended.

Codex

FieldMeaning
authModelocal or api_key
localHomeHost Codex home used only to locate auth.json in local mode
apiKeyEnvironmentVariableName of the host variable read in API-key mode
authSyncIntervalSecondsFallback local-auth scan interval; 10–86,400 seconds, default 60 seconds

Local mode watches auth.json for immediate changes and uses authSyncIntervalSeconds only as a fallback. One synchronizer writes validated newer generations into the shared container-owned Codex state. Chat and task workers do not mount or scan the host credential themselves.

Ports

Each port is a host binding. Containers use Compose service names and their internal service ports. Do not reuse a host loopback URL inside a container.

PostgreSQL

Set a local user, password, and database. PostgreSQL with pgvector is the canonical operational store. Migrations run as a one-shot startup dependency.

Garage

Garage provides the supported local S3-compatible service. The application remains provider-neutral and consumes the S3 environment contract. Configure region, bucket, access key, secret key, RPC secret, admin token, and metrics token.

Workers and the backend use the Compose-only http://garage:3900 endpoint. This is sufficient for Meta Ads, organic X, and X Ads media transfer: workers upload directly to Garage, then the backend streams or chunks the private object to the provider. Garage does not need a public hostname or CDN. A split deployment must set an S3 endpoint reachable from both worker and backend execution networks. Production buckets should expire abandoned integration staging objects after 24 hours.

Integration Credential Key

The value must satisfy the schema’s base64 key contract. Changing it after credentials have been stored makes existing credential envelopes unreadable; disconnect or migrate integrations before rotating it.

Google OAuth

When googleOAuth is present, the generator writes the Google client values and callback URI. googleOAuth.redirectUri is optional and must be the exact HTTPS callback ending in /oauth/google/callback. When omitted, it falls back to the loopback backend callback generated from ports.backend. Omit the whole block when Google Workspace is not needed.

Meta Ads OAuth and Operations

The generator always writes the generic local managed-MCP callback URI. Providers such as Apollo discover their authorization server, dynamically register the client, and retain this generic callback.

Meta Ads uses a deployment-level public OAuth client for connection and reconnection. Add its client ID when this deployment should offer Meta Ads:

{
  "metaAdsOAuth": {
    "clientId": "replace-with-meta-approved-oauth-client-id",
    "redirectUri": "https://api.example.com/oauth/mcp/callback"
  },
  "metaAds": {
    "operationsProvider": "graph"
  }
}

The Meta connection flow uses PKCE and does not require a client secret. The deployment client is shared infrastructure identity, not an ad-account credential: one configured client can authorize multiple organization integrations, while each organization keeps its own encrypted Meta token.

metaAdsOAuth.redirectUri is optional in the local-stack contract and falls back to the generic loopback callback. Meta requires a public HTTPS callback for this client in normal local testing, so set the exact public URL ending in /oauth/mcp/callback.

The Meta-specific callback takes precedence only for Meta. Apollo and other managed MCP providers continue using MCP_OAUTH_REDIRECT_URI. The selected callback is stored with the one-use OAuth state so authorization and token exchange use the identical URI even if deployment configuration changes while consent is open.

Deployments that do not use the local-stack generator set META_ADS_OAUTH_CLIENT_ID and META_ADS_OAUTH_REDIRECT_URI on the backend. Set META_ADS_OPERATIONS_PROVIDER=graph for Oblive’s direct Marketing API provider. graph is also the default when the variable is absent. hosted_mcp remains an explicit rollback mode; it restores hosted discovery and operations and may again be limited by Meta’s account rollout.

In graph mode, the backend registers a fixed local MCP tool set and calls graph.facebook.com/v25.0 with the encrypted organization token. Operational discovery, reads, writes, reporting, and action execution do not contact mcp.facebook.com. The hosted endpoint is used only when operationsProvider is explicitly hosted_mcp.

X And X Ads OAuth

The organic X and X Ads connectors are independent. Organic X uses OAuth 2.0 Authorization Code with PKCE. X Ads requires Ads API access and three-legged OAuth 1.0a; it does not reuse the organic X token or permission set.

{
  "xOAuth": {
    "clientId": "replace-with-x-oauth2-client-id",
    "clientSecret": "replace-with-x-oauth2-client-secret",
    "redirectUri": "https://api.example.com/oauth/mcp/callback"
  },
  "xAdsOAuth": {
    "consumerKey": "replace-with-x-ads-consumer-key",
    "consumerSecret": "replace-with-x-ads-consumer-secret",
    "redirectUri": "https://api.example.com/oauth/mcp/callback"
  }
}

Both callback values are optional in the local-stack contract and fall back to the generic loopback callback. Use the exact public HTTPS /oauth/mcp/callback registered with each X developer App for normal external testing. For local X Ads authorization, approve http://127.0.0.1:3000/oauth/mcp/callback in the X developer App before using the loopback default.

Set xOAuth.clientSecret for a Web App, Automated App, or Bot. Omit it for a Native App or SPA. PKCE is used in both cases. The secret switches token exchange, refresh, and revocation to confidential-client Basic authentication and remains backend-only.

Deployments that do not use the generator set X_OAUTH_CLIENT_ID, optional X_OAUTH_CLIENT_SECRET, and X_OAUTH_REDIRECT_URI for organic X. Set X_ADS_OAUTH_CONSUMER_KEY, X_ADS_OAUTH_CONSUMER_SECRET, and X_ADS_OAUTH_REDIRECT_URI for X Ads. Both secrets remain backend-only.

Public Frontend and Provider Callbacks

Public URLs are opt-in and independent:

{
  "publicFrontendUrl": "https://app.example.com",
  "googleOAuth": {
    "clientId": "replace-with-google-oauth-client-id.apps.googleusercontent.com",
    "clientSecret": "replace-with-google-oauth-client-secret",
    "redirectUri": "https://api.example.com/oauth/google/callback"
  },
  "metaAdsOAuth": {
    "clientId": "replace-with-meta-approved-oauth-client-id",
    "redirectUri": "https://api.example.com/oauth/mcp/callback"
  },
  "xOAuth": {
    "clientId": "replace-with-x-oauth2-client-id",
    "clientSecret": "replace-with-x-oauth2-client-secret",
    "redirectUri": "https://api.example.com/oauth/mcp/callback"
  },
  "xAdsOAuth": {
    "consumerKey": "replace-with-x-ads-consumer-key",
    "consumerSecret": "replace-with-x-ads-consumer-secret",
    "redirectUri": "https://api.example.com/oauth/mcp/callback"
  },
  "metaAds": {
    "operationsProvider": "graph"
  }
}
  • publicFrontendUrl must be an HTTPS origin with no path, credentials, query, or fragment.
  • Provider callback values must use HTTPS and their exact callback paths, with no query, credentials, or fragment.
  • An omitted field retains its current loopback fallback; Google and Meta can be enabled independently.
  • publicFrontendUrl changes browser return URLs and Vite’s public origin/allowed hostname only. BACKEND_URL remains Compose DNS inside containers and loopback for host-run services.

For an externally managed Cloudflare Tunnel or equivalent reverse proxy:

Public HostnameLocal TargetRequirement
app.example.comhttp://127.0.0.1:3001Forward HTTP and development WebSockets
api.example.comhttp://127.0.0.1:3000Forward callbacks and backend HTTP

Oblive does not create a cloudflared service or store tunnel credentials. Vite allows only the configured app hostname; it never enables an unrestricted host allowlist. See Vite server options.

The local control plane has no end-user authentication gate. Never expose it through an unrestricted public tunnel. Protect both hostnames with an external access policy and restrict them to intended testers.

Register the exact generated callbacks in the Google and Meta applications. After changing any public URL, run bun run stack env and restart the frontend and backend. Existing generated files remain authoritative until regeneration.

Generate Runtime Files

bun run stack env

This generates complete environment files for the backend, frontend, chat agent, worker agent, and containers. Edit the JSON input rather than the generated files.

Inspect Before Starting

bun run stack config

Use this after changing ports, persistence, replicas, authentication, or local infrastructure credentials.

Lifecycle Commands

bun run stack up
bun run stack ps
bun run stack logs -f
bun run stack down

Read-only commands such as ps, logs, and config should not rewrite environment files or trigger watcher restarts.

Reset Local Data

bun run stack reset --confirm

This removes local stack volumes. Use it only when the loss of local state is acceptable.

Developers adding a field should follow Local Stack and Migrations.