Skip to content

feat!: consolidate and rename CLI environment variables#180

Open
nicknisi wants to merge 5 commits into
mainfrom
refactor/env-var-cleanup
Open

feat!: consolidate and rename CLI environment variables#180
nicknisi wants to merge 5 commits into
mainfrom
refactor/env-var-cleanup

Conversation

@nicknisi

Copy link
Copy Markdown
Member

What & why

The CLI's environment-variable surface had grown large and inconsistent. This consolidates it.

Removed (derived instead)

  • WORKOS_LLM_GATEWAY_URL → derived as ${WORKOS_API_URL}/llm-gateway
  • WORKOS_TELEMETRY_URL → derived as ${WORKOS_API_URL}/cli

Both endpoints live under the WorkOS API host, so they're now derived from the single WORKOS_API_URL base. api.workos.com is no longer hardcoded in three places, and setting WORKOS_API_URL alone reroutes the API, gateway, and telemetry together.

Removed (redundant)

  • WORKOS_NO_PROMPT → use WORKOS_MODE=agent

It was a legacy alias that mapped to agent interaction + JSON output. WORKOS_MODE=agent already does exactly that (JSON is forced via resolveEffectiveOutputMode), and it's self-documenting — NO_PROMPT described one side effect and hid the other.

Renamed (prefix consistency)

  • INSTALLER_DEVWORKOS_DEV
  • INSTALLER_DISABLE_PROXYWORKOS_DISABLE_PROXY

Anti-drift guard

The workos debug env catalog had already rotted (missing WORKOS_AGENT, WORKOS_SECRET_KEY, WORKOS_CLIENT_ID, and others). Fixed it, and added a test that scans src/ for process.env.WORKOS_* / destructured env.WORKOS_* reads and fails if any isn't cataloged — so the list can't silently drift again.

Breaking change

feat!: → release-please will cut 0.18.0 (minor, per bump-minor-pre-major) with a BREAKING CHANGES changelog entry. Real-world risk is low: 4 of the 5 vars are internal/developer-only, and WORKOS_NO_PROMPT is largely redundant with non-TTY auto-detection.

Verification

  • pnpm typecheck
  • pnpm test ✅ (2092 passing)
  • pnpm build
  • Verified the new guard test fails on drift for both process.env.X and destructured env.X reads.

Reduce env-var sprawl in the CLI:

- Derive the LLM gateway and CLI telemetry URLs from WORKOS_API_URL
  instead of separate WORKOS_LLM_GATEWAY_URL / WORKOS_TELEMETRY_URL vars,
  so api.workos.com is no longer hardcoded in multiple places.
- Remove the redundant WORKOS_NO_PROMPT alias; WORKOS_MODE=agent is the
  single, self-documenting way to force agent interaction + JSON output.
- Standardize the INSTALLER_* prefix to WORKOS_* (WORKOS_DEV,
  WORKOS_DISABLE_PROXY).
- Fix the rotted `workos debug env` catalog (it was missing several vars)
  and add a test that scans src/ for WORKOS_* env reads and fails if any
  is missing from the catalog, preventing future drift.

BREAKING CHANGE: WORKOS_LLM_GATEWAY_URL and WORKOS_TELEMETRY_URL are
removed (derived from WORKOS_API_URL); WORKOS_NO_PROMPT is removed (use
WORKOS_MODE=agent); INSTALLER_DEV is renamed to WORKOS_DEV and
INSTALLER_DISABLE_PROXY to WORKOS_DISABLE_PROXY.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

@greptile-apps

greptile-apps Bot commented Jun 16, 2026

Copy link
Copy Markdown

Greptile Summary

This PR consolidates the CLI's environment-variable surface by removing WORKOS_NO_PROMPT (replaced by WORKOS_MODE=agent via resolveEffectiveOutputMode), deriving LLM gateway and telemetry URLs from a single WORKOS_API_URL base, and renaming the INSTALLER_* prefix vars to WORKOS_*. It also adds an anti-drift guard that scans src/ for process.env.WORKOS_* reads and fails if any aren't in the catalog.

  • URL derivation refactored: getLlmGatewayUrl() and getTelemetryUrl() are now pure derivations, with trailing-slash normalization — overriding a single env var now reroutes all three endpoints atomically.
  • WORKOS_NO_PROMPT removed: Interaction mode + JSON output coupling now lives in resolveEffectiveOutputMode() rather than resolveOutputMode(), so agent mode always forces JSON regardless of TTY state.
  • Catalog drift guard added: env-var-catalog.spec.ts performs a bidirectional check to keep workos debug env accurate going forward.

Confidence Score: 5/5

The change is safe to merge — it is a well-scoped rename/consolidation with no functional regressions in the env-var resolution logic.

All five removed/renamed variables have correct callsite updates throughout the codebase. The new URL-derivation logic in urls.ts is simple and covered by the integration test. The resolveEffectiveOutputMode coupling correctly replicates the WORKOS_NO_PROMPT behavior for WORKOS_MODE=agent. The anti-drift guard closes a real maintenance gap. No new issues were found beyond what the prior review thread already identified.

src/commands/debug.ts — the raw-value exposure of WORKOS_API_KEY in workos debug env output is a pre-existing concern raised in the prior thread that remains unaddressed.

Important Files Changed

Filename Overview
src/utils/urls.ts Core refactor: LLM gateway and telemetry URLs are now derived from getWorkOSApiUrl() with trailing-slash normalization; getLlmGatewayUrlFromHost alias removed cleanly.
src/commands/debug.ts Catalog extended with WORKOS_CLIENT_ID, WORKOS_AGENT, doctor-check vars, and renamed WORKOS_DEV/WORKOS_DISABLE_PROXY; WORKOS_API_KEY raw value still printed in plain text (flagged in prior thread).
src/commands/env-var-catalog.spec.ts New bidirectional drift guard scans non-spec TS for dot-access WORKOS_* reads; CATALOG_ONLY escape hatch for non-dot-access patterns is clearly documented.
src/utils/interaction-mode.ts WORKOS_NO_PROMPT branch and workos_no_prompt source type cleanly removed; InteractionModeSource union narrowed accordingly.
src/utils/output.ts WORKOS_NO_PROMPT check removed from resolveOutputMode; resolveEffectiveOutputMode correctly forces json for agent and ci interaction sources.
src/lib/settings.ts getLlmGatewayUrl and getTelemetryUrl removed from settings; llmGatewayUrl/telemetryUrl fields dropped from InstallerConfig interface and config object.
src/bin-command-telemetry.integration.spec.ts WORKOS_TELEMETRY_URL replaced by WORKOS_API_URL pointing to unroutable host; comment correctly explains the scope change.
src/lib/agent-interface.ts INSTALLER_DISABLE_PROXY renamed to WORKOS_DISABLE_PROXY; getLlmGatewayUrlFromHost import replaced with getLlmGatewayUrl from urls.ts.
src/cli.config.ts Removed hardcoded llmGatewayUrl and telemetryUrl from config; comment explains why they now live in urls.ts instead.
README.md WORKOS_NO_PROMPT removed from environment variables table and legacy-compatibility notes updated to reference WORKOS_MODE=agent throughout.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["WORKOS_API_URL\n(env var, default: https://api.workos.com)"] --> B["getWorkOSApiUrl()\n(trailing slash removed)"]
    B --> C["getLlmGatewayUrl()\n= base + /llm-gateway"]
    B --> D["getTelemetryUrl()\n= base + /cli"]
    B --> E["Direct API calls"]
    F["WORKOS_DASHBOARD_URL"] --> G["getWorkOSDashboardUrl()"]
    H["WORKOS_AUTHKIT_DOMAIN"] --> I["getAuthkitDomain()"]
    subgraph "Interaction to Output coupling"
        J["WORKOS_MODE=agent"] --> K["resolveEffectiveOutputMode() forces json"]
        L["WORKOS_FORCE_TTY=1"] --> M["human output (overridden by agent mode)"]
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A["WORKOS_API_URL\n(env var, default: https://api.workos.com)"] --> B["getWorkOSApiUrl()\n(trailing slash removed)"]
    B --> C["getLlmGatewayUrl()\n= base + /llm-gateway"]
    B --> D["getTelemetryUrl()\n= base + /cli"]
    B --> E["Direct API calls"]
    F["WORKOS_DASHBOARD_URL"] --> G["getWorkOSDashboardUrl()"]
    H["WORKOS_AUTHKIT_DOMAIN"] --> I["getAuthkitDomain()"]
    subgraph "Interaction to Output coupling"
        J["WORKOS_MODE=agent"] --> K["resolveEffectiveOutputMode() forces json"]
        L["WORKOS_FORCE_TTY=1"] --> M["human output (overridden by agent mode)"]
    end
Loading

Reviews (4): Last reviewed commit: "test: stop counting env writes as reads ..." | Re-trigger Greptile

Comment thread src/commands/env-var-catalog.spec.ts Outdated
Comment thread src/commands/env-var-catalog.spec.ts Outdated
nicknisi added 3 commits June 15, 2026 21:33
Address code review on the env-var cleanup:

- Move getLlmGatewayUrl/getTelemetryUrl from settings.ts into urls.ts so the
  derived endpoints sit next to their base (getWorkOSApiUrl). This removes the
  backwards settings->urls import and makes urls.ts a dependency-free leaf that
  is the single home for WorkOS endpoint resolution. getAuthkitDomain stays in
  settings.ts since it's config-backed, not API-host-derived.
- Normalize the trailing slash once inside getWorkOSApiUrl instead of repeating
  the strip at each derivation site.
- Scope the env-var-catalog guard test's claim to dot-access reads and document
  the forms it doesn't cover (bracket access, destructuring).
- Fix a stale docstring on getCliAuthClientId (it is not env-overridable).
- Replace the hand-rolled recursive file walk with fast-glob, the pattern
  already used across src/ (environment.ts, validator.ts, integrations).
- Read source files concurrently instead of in a sequential await loop.
- Make the catalog check bidirectional: it now also fails on stale entries
  (cataloged vars no longer read anywhere), not just missing ones, with an
  explicit CATALOG_ONLY escape hatch for any future non-dot-access reads.
  This subsumes the old WORKOS_-prefix assertion.
Comment thread src/commands/debug.ts Outdated
WORKOS_SECRET_KEY is only written (migrations.ts sets it for the downstream
migrations SDK), never read by the CLI. The guard's regex matched the
assignment's left-hand side and "discovered" it, so it was catalogued as an
input credential — misleading, since the CLI ignores any user-provided value.

Tighten the discovery regex to exclude assignment targets (with an end-anchor
so the greedy capture can't backtrack to a truncated name), and drop the
write-only WORKOS_SECRET_KEY entry. The catalog now means exactly what its
docstring claims: WORKOS_ vars the CLI reads.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant