Config & Environment
Core runtime
Section titled “Core runtime”| Variable | Required | Purpose |
|---|---|---|
SLACK_SIGNING_SECRET |
Yes | Verifies Slack request signatures. |
SLACK_BOT_TOKEN or SLACK_BOT_USER_TOKEN |
Yes | Posts thread replies and calls Slack APIs. |
REDIS_URL |
Yes | Runtime state, locks, and durable background task records. Vercel Queues only deliver wakeups. |
DATABASE_URL |
Yes | Standard Neon/Vercel Postgres URL for Junior SQL records and reporting. |
JUNIOR_DATABASE_DRIVER |
No | SQL client driver for Junior records: neon or postgres. Defaults to neon; set postgres for local Postgres or node-postgres deployments. |
JUNIOR_SQL_STATEMENT_TIMEOUT_MS |
No | PostgreSQL runtime statement timeout in milliseconds. Defaults to 30000 (30 seconds); set 0 to disable. This does not limit junior upgrade migrations. |
JUNIOR_CONVERSATION_WORK_ENABLED |
No | Operational kill switch for queue processing and heartbeat recovery. Defaults to true; set false to acknowledge wakes without running or recovering conversation work. |
JUNIOR_SECRET |
Yes | Signs internal queue/callback payloads and sandbox egress actor context. |
JUNIOR_BOT_NAME |
No | Bot display/config naming. |
JUNIOR_SLASH_COMMAND |
No | Slack slash command for account-management flows. Defaults to /jr; the Slack app command must match this value. |
JUNIOR_CROSS_ACTOR_MID_RUN_MODE |
No | Cross-actor Slack steering policy. Defaults to follow_up; see below. |
AI_MODEL |
No | Standard model for main agent runs. Defaults to xai/grok-4.5. |
AI_REASONING_LEVEL |
No | Fixed main-agent reasoning level: none, low, medium, high, or xhigh. Unset by default; only the unset state enables per-turn reasoning routing. |
AI_FAST_MODEL |
No | Faster model for lightweight tasks and routing/classification passes before the main turn begins. Defaults to anthropic/claude-haiku-4.5. |
AI_GUARDIAN_MODEL |
No | Model for Guardian action review. Defaults to openai/gpt-5.6-luna. |
AI_HANDOFF_MODEL |
No | Model for the built-in handoff profile. Defaults to openai/gpt-5.6-sol. |
AI_MODEL_PROFILES |
No | JSON object mapping additional named handoff profiles to model IDs, for example {"coding":"openai/gpt-5.6-sol"}. Names must match ^[a-z][a-z0-9_-]*$; standard and handoff are reserved. |
AI_EMBEDDING_MODEL |
No | Embedding model for plugin-owned vector retrieval. Defaults to openai/text-embedding-3-small; memory v1 stores fixed 1536-dimensional vectors. |
AI_VISION_MODEL |
No | Dedicated image-understanding model; unset disables vision features. |
AI_WEB_SEARCH_MODEL |
No | Override for the webSearch tool model. Defaults to openai/gpt-5.4; does not fall through to AI_MODEL. |
SANDBOX_VCPUS |
No | Legacy fallback for sandbox vCPUs and the build-time snapshot command. Prefer createApp({ sandbox: { vcpus } }) for runtime sandboxes. Each vCPU provides 2 GB of memory. |
VERCEL_SANDBOX_KEEPALIVE_MS |
No | Extends an active sandbox by this duration on each tool acquire. Disabled when unset or 0; 900000 (15 minutes) is recommended for production Vercel deployments. |
JUNIOR_BASE_URL |
No | Main base URL for callback and authorization URLs. |
JUNIOR_STATE_KEY_PREFIX |
No | Optional namespace prepended to all state-adapter keys, locks, and queues. Use separate prefixes when sharing one Redis database across environments. |
CRON_SECRET or JUNIOR_SCHEDULER_SECRET |
Conditional | Bearer token for the internal heartbeat route; use CRON_SECRET with Vercel Cron, or JUNIOR_SCHEDULER_SECRET for a non-Vercel heartbeat caller. |
JUNIOR_TIMEZONE |
No | Default IANA timezone for scheduler authoring when the scheduler plugin is enabled. Defaults to America/Los_Angeles. |
AI_GATEWAY_API_KEY |
No | Fallback AI Gateway auth when Vercel OIDC is unavailable (local/CI/non-Vercel hosts). On Vercel, prefer project OIDC so usage attributes to the project. |
BLOB_STORE_ID |
Conditional | Vercel Blob store for durable conversation attachments and published public artifacts. Vercel sets this when an OIDC-enabled Blob store is connected to the project. |
BLOB_READ_WRITE_TOKEN |
Conditional | Static Vercel Blob credential when OIDC is unavailable. Vercel sets this for a token-connected store. |
For Vercel deployments, create a private Blob store and connect it to the
project before using sendFiles or publishImage. Prefer an OIDC connection.
It supplies BLOB_STORE_ID and uses Vercel’s short-lived OIDC credential. Use
BLOB_READ_WRITE_TOKEN for local development, CI, non-Vercel hosts, or as a
fallback. See Deploy to Vercel.
Junior applies JUNIOR_SQL_STATEMENT_TIMEOUT_MS through PostgreSQL statement_timeout for both the Neon and node-postgres drivers. junior upgrade does not apply this runtime limit because schema migrations can legitimately take longer.
JUNIOR_CROSS_ACTOR_MID_RUN_MODE=follow_up keeps another actor’s mid-run ask
for its own turn. Set it to steer to preserve collaborative steering across
actors. In follow_up mode, a user can start one message with !! to steer the
active turn explicitly.
Model profile names are durable conversation bindings. Each later turn resolves the stored name through current configuration; the exact model ID recorded when an epoch opens is audit evidence, not a runtime pin. Changing a mapping retargets existing conversations, while removing or renaming a referenced profile makes those conversations fail until that name is configured again.
Guardian action review sends the configured Guardian model a bounded review request with
hook-adjusted semantic input (starting from validated tool arguments and
excluding hook-injected environment values), current actor and destination
context, and bounded user, assistant, tool-call, and tool-result evidence using
the Codex Guardian transcript selection rules. Guardian defaults to
openai/gpt-5.6-luna; set AI_GUARDIAN_MODEL to override it. Input and output
payloads from this review are excluded from telemetry.
Generate JUNIOR_SECRET with Node, then store the generated value in every environment that runs the same app:
node -e "console.log(require('node:crypto').randomBytes(32).toString('base64url'))"Use one stable value per deployment. Rotating it invalidates pending internal queue callbacks and sandbox actor context signed with the previous value.
Dashboard auth
Section titled “Dashboard auth”If you mount @sentry/junior-dashboard, set these browser-auth variables:
| Variable | Required | Purpose |
|---|---|---|
GOOGLE_CLIENT_ID |
Yes | Google OAuth client ID. |
GOOGLE_CLIENT_SECRET |
Yes | Google OAuth client secret. |
BETTER_AUTH_SECRET |
No | Optional override for dashboard cookies. Defaults to JUNIOR_SECRET. |
Configure allowed Google Workspace domains in createApp({ dashboard }) and juniorNitro({ dashboard }) for normal deployments. Set these optional policy variables when you prefer environment-managed dashboard authorization:
| Variable | Required | Purpose |
|---|---|---|
JUNIOR_DASHBOARD_GOOGLE_DOMAINS |
No | Comma-separated or JSON array of allowed Google domains. |
JUNIOR_DASHBOARD_ALLOWED_EMAILS |
No | Comma-separated or JSON array of explicit email allowlist. |
JUNIOR_DASHBOARD_TRUSTED_ORIGINS |
No | Comma-separated or JSON array of Better Auth trusted origins. |
JUNIOR_DASHBOARD_MOCK_CONVERSATIONS |
No | Set to true to replace conversation API responses with local/demo visual-QA fixtures. |
For local/demo dashboard visual QA, set JUNIOR_DASHBOARD_MOCK_CONVERSATIONS=true to replace conversation API responses with sample fixtures.
Build-time snapshot warmup
Section titled “Build-time snapshot warmup”If your build command runs junior snapshot create:
REDIS_URLmust be available during build.VERCEL_OIDC_TOKENmust be available during build (via Vercel OIDC settings).
| Variable | Required | Purpose |
|---|---|---|
SANDBOX_SNAPSHOT_FLOATING_MAX_AGE_MS |
No | Maximum cached age for snapshots with floating dependencies. Defaults to seven days. |
SANDBOX_SNAPSHOT_REBUILD_EPOCH |
No | Operator-controlled value that forces a new snapshot profile when changed. |
Sandbox credential egress
Section titled “Sandbox credential egress”If enabled plugins use host-managed credentials inside Vercel Sandbox, Junior forwards registered provider domains through its credential egress proxy. The proxy verifies each Vercel-signed sandbox request and requires a signed actor context before it injects credentials lazily.
The egress proxy verifies Vercel-signed Sandbox OIDC tokens per request to authenticate the sandbox VM; actor authorization comes from the forwarding-route context signed with JUNIOR_SECRET and bound to that VM session. No separate audience, project, or team env vars are required for the proxy.
| Variable | Required | Purpose |
|---|---|---|
JUNIOR_BASE_URL |
Conditional | Public URL for the credential egress proxy, unless Vercel URL envs cover it. |
Plugin environment variables
Section titled “Plugin environment variables”Provider credentials and other plugin-specific variables live on each plugin setup page under Extend. Keep this page limited to core runtime configuration.
Experimental features
Section titled “Experimental features”Unstable product surfaces opt in through createApp({ experimental }), the same
pattern used by frameworks such as Next.js. Features default off, may change
without a stable migration path, and should stay unset in production unless you
are deliberately dogfooding them. There is no environment-variable opt-in.
import { createApp } from "@sentry/junior";
const app = await createApp({ experimental: { // ACP v1 Streamable HTTP for one-process development and testing. acp: true, // Model-facing spawnAgent for durable child agent work. Incomplete; keep off // unless you are testing the #879 runtime. subagents: true, },});junior chat enables experimental subagents automatically because it is the
local createApp-equivalent entrypoint and already wires the child-worker path.
acp mounts GET, POST, and DELETE /api/acp. Every request needs a Junior
personal token in the bearer authorization header. The current transport keeps
connection state in one Node process. Use it only for local or single-process
testing. Run pnpm acp:local in this repository for a loopback test with the
official ACP SDK client.
Install-wide config defaults
Section titled “Install-wide config defaults”Pass configDefaults to createApp() to set provider defaults across all conversations:
import { createApp } from "@sentry/junior";
const app = await createApp({ configDefaults: { "sentry.org": "sentry", "github.org": "myorg", "github.repo": "myorg/myrepo", },});Keys should be registered plugin config keys. Junior retains unregistered defaults but warns at startup because they usually indicate missing plugin wiring. Channel-scoped overrides (jr-rpc config set) take precedence.
Sandbox configuration
Section titled “Sandbox configuration”Pass sandbox sizing to createApp(). Each vCPU provides 2 GB of memory, so this creates 8 GB runtime sandboxes:
import { createApp } from "@sentry/junior";
const app = await createApp({ sandbox: { vcpus: 4, },});The app setting takes precedence over SANDBOX_VCPUS. Snapshot warmup runs before createApp(), so junior snapshot create still reads SANDBOX_VCPUS when its build sandbox also needs explicit sizing.
Pass sandbox.egressTracePropagationDomains when sandboxed commands should keep Sentry trace context across sandbox network egress:
import { createApp } from "@sentry/junior";
const app = await createApp({ sandbox: { egressTracePropagationDomains: ["sentry.io", "*.sentry.io"], },});Configured non-provider domains receive trace-header transforms without requiring credential proxying.
Entries may be exact domains or leading wildcard domains. The wildcard form matches subdomains, not the apex domain, so include both forms when needed.
Verification
Section titled “Verification”- Validate required variables exist in deployment environment.
- Redeploy after variable changes.
- Run one end-to-end Slack thread action per enabled integration.
Next step
Section titled “Next step”Use Plugin Auth & Context to verify plugin auth and target-context behavior after env changes, then monitor with Observability.