On this page

Claude Commander reference

This page states facts. Nothing here teaches, argues or recommends; the reasons live on the admin, DevOps, developer and application pages. Every key, route, frame type and status code below was read out of the tree at d2907aa, version 3.0.15. Where a count is given it is the count found at that commit, not a target.

Two conventions run through everything on this page:

Machine-readable descriptions

ArtefactStandardStatusContents
/v2-assets/commander-documentation/openapi.jsonOpenAPI 3.1.0shipped160 paths, 192 operations, generated from the route inventory
./asyncapi.yamlAsyncAPI 3.0P1 — not yet writtenthe WebSocket PTY channel; until it exists, the frame protocol below is the description

openapi.yaml is generated, not hand-maintained: scripts/route-inventory.mjs parses the route table out of server.js and lib/*.js, and scripts/build-openapi.mjs merges it with the hand enrichments in openapi.overrides.json (keyed by operationId). Regenerate with:

node scripts/build-openapi.mjs

The generator emits three vendor extensions and refuses to write a document whose $refs do not resolve:

ExtensionMeaning
x-sourcefile:line of the route handler that serves the operation
x-entitlement{ anyOf: [...] } — the feature keys that satisfy the route's requireFeature(...)
x-operator-handthe operation touches the login seam or the promotion ladder; it is pressed by an operator, never driven by an agent
x-rate-limiteda rate limiter is mounted in front of the handler

Error responses are named components (components/responses/BadRequest, Unauthorized, Forbidden, NotFound, Conflict, UnprocessableContent, StepUpRequired), each carrying the single Error schema. Two security schemes are declared, both the same opaque token: cookieAuth (commander_token cookie) and headerAuth (x-auth-token header). The server URL is a template variable — the document names no instance.

commander.settings key catalogue

commander.settings is a key, value, encrypted, updated_at table. Values are text; the reader coerces. 178 distinct keys are read by the server at this commit, grouped below by the area that reads them. Three sub-classes behave differently from the rest:

getSettings() caches the whole map for 30 s; PATCH /api/settings invalidates it, so an edit applies within one cache window without a restart.

Authentication and the login seam (25)

Read by lib/auth.js, lib/auth-guard.js, lib/auth-oidc.js, server.js. Every key here is step-up guarded — see errors.

KeyControls
app_passwordwrite-only inbound; hashed to app_password_hash (argon2id) and stored blank
app_password_hashthe stored argon2id verifier; served masked, never written directly
auth_modelocal, oidc or hybrid
auth_oidc_issuerOIDC issuer; falls back to mcp_auth_base_url
auth_oidc_client_id, auth_oidc_client_secretrelying-party credentials
auth_oidc_providerprovider profile name
auth_oidc_flowauto, code or broker
auth_oidc_scopes, auth_oidc_profile_claimsrequested scopes; claims copied into the session profile
auth_oidc_redirect_uriexplicit redirect URI; empty derives it from the request host
auth_oidc_well_known_pathdiscovery path (RFC 8414)
auth_oidc_allowed_algsaccepted JWS algorithms
auth_oidc_allowed_emails, auth_oidc_allowed_domains, auth_oidc_allowed_subjectsauthorisation allowlists; all empty means any active subject of the issuer
auth_oidc_clock_skew_sectolerated clock skew on token validation
auth_oidc_discovery_ttl_ms, auth_oidc_jwks_ttl_ms, auth_oidc_state_ttl_ms, auth_oidc_http_timeout_msdiscovery/JWKS cache lifetimes, state lifetime, upstream timeout
auth_rate_max, auth_rate_window_mslogin rate limiter
auth_session_idle_hours, auth_session_absolute_hourssession idle and absolute lifetimes

Sessions, transcripts and sweeps (13)

Read by server.js and lib/claude-sessions.js.

KeyControls
session_park_enabledwhether a session can be parked instead of closed
session_close_defaultthe default action of the close control
session_archive_park_idle_minutesidle minutes before a parked session is archived
session_recovery_direct_rejoininterrupted sessions jump straight to the rejoin confirm
session_active_output_msoutput window that still counts a terminal as active
session_list_decorate_budget_mstime the session list spends attaching conversation titles before answering
session_usage_poll_msper-session usage poll cadence served to the client
transcript_excluded_dirscomma-separated transcript populations excluded from summarisation
transcript_flood_threshold, transcript_flood_window_hoursflood-alert threshold and window
transcript_unknown_alert_pctwarn above this share of unclassifiable transcripts
archive_sweep_interval_mshot→cold roll cadence
trash_sweep_interval_mspurge cadence for trashed transcripts past retention

Terminal and WebSocket (12)

KeyControls
term_default_cols, term_default_rowsPTY geometry before the browser reports its size
term_max_cols, term_max_rowsclamp applied to a resize frame
term_scrollback_linesserver-side shadow emulator scrollback
scroll_persist_charscharacters of scrollback persisted to the session row
term_block_suspendswallow the suspend keystroke in the terminal
term_jump_refresh_ms, term_jump_blank_fraction, term_scroll_dblclick_msjump-to-bottom refresh, blank-screen heuristic, double-click window
osc52_clipboard_enabledallow OSC 52 clipboard writes from the PTY
ws_handshake_timeout_msclient-side WebSocket handshake budget

Claude Code launch and injection (21)

Read by server.js, lib/cc-config.js, lib/cc-version.js, lib/cc-watch.js.

KeyControls
cc_configthe instance layer of the Claude Code layered config (JSON)
cc_config_enabledwhether the layered config is resolved and written at all
cc_version_command, cc_version_ttl_mshow the installed CLI version is detected, and its cache lifetime
cc_pretrust_enabledpre-trust the working directory so the CLI does not ask
cc_disable_remote_controlset the CLI's remote-control opt-out for launched sessions
cc_resume_promptsuppress or native — the CLI's own resume prompt
cc_resume_threshold_minutes, cc_resume_token_thresholdthresholds handed to the CLI when the prompt is suppressed
claude_cli_pathpath to the Claude Code binary
claude_active_pattern, claude_idle_patternoutput patterns that classify a session as working or idle
claude_trash_retention_daysretention before a trashed transcript is purged
claude_usage_urlexternal usage help link served to the client
inject_ready_pattern, inject_ready_timeout_msreadiness detection before injecting a boot prompt
inject_settle_ms, inject_shell_delay_mssettle delays around injection
inject_dialog_pattern, inject_dialog_affirm_pattern, inject_dialog_max_stepsfirst-run dialog detection, the affirmative answer, and the step ceiling

Git panel and git tracking (7)

KeyControls
git_probe_timeout_msper-command timeout for quick status/branch probes
git_details_timeout_mstimeout for history and diff reads
git_diff_max_bytes, git_file_max_bytestruncation caps on a served diff and a served file
git_file_history_limitcommits listed in per-file history
commit_meta_max_hasheshashes resolved in one commit-metadata request
github_tokenGitHub credential (encrypted, masked)

Deploy, ladder and platform (5)

KeyControls
promote_run_testswhether the ladder's test rung runs
deploy_manifest_signing_keykey id used to sign a version manifest
deploy_badge_poll_msdeploy-badge poll cadence served to the client
ecosystem_pathpm2 ecosystem file reported by the platform monitor
guardian_status_api_keyGuardian link credential (encrypted, masked)

Every other ladder parameter is per-project ladder JSON, not a settings key — see the DevOps reference.

Heartbeat and host monitoring (7)

KeyControls
heartbeat_poll_interval_msmonitor poll cadence
heartbeat_pct_warn, heartbeat_pct_errload/memory/disk warn and error thresholds
heartbeat_steal_warn, heartbeat_steal_errCPU-steal warn and error thresholds
heartbeat_log_lines, heartbeat_log_lines_maxdefault and maximum pm2 log lines

Usage, windows and pricing (13)

Read by lib/usage-stats.js and lib/usage-window.js.

KeyControls
usage_stats_daysdefault window of the stats scan
usage_stats_cache_s, usage_stats_resp_cache_maxscan cache lifetime and response-cache size
usage_stats_fold_maxentries kept in the per-transcript-file fold cache (LRU)
usage_session_window_ms, usage_weekly_window_msthe two rate-window meter spans
usage_window_budgets_jsonper-window budgets the meters measure against
usage_window_warn_pct, usage_window_crit_pctmeter warn and critical thresholds
usage_stats_poll_ms, usage_meter_poll_msclient poll cadences, served
model_pricing_jsonoperator override of the embedded pricing registry
pricing_stale_daysage at which the embedded registry is flagged stale

Artifacts (6)

All six are live tunables; see live tunables for bounds.

KeyControls
artifact_sync_enabled, artifact_sync_interval_msthe incremental transcript scan and its cadence
artifact_scan_batch_records, artifact_scan_max_line_bytesrecords per extractor batch; the single-line out-of-memory guard
artifact_list_maxrows the Artifacts panel loads per scope
artifact_serve_max_byteslargest local artifact the built-in viewer serves

Integrations and provider credentials (5)

KeyControls
anthropic_api_keylegacy credential row (encrypted, masked); accounts are the live path
anthropic_api_key_billing_enabledwhether API-key billing may be used for launches
openai_api_key, google_api_keyone-time auto-seed sources for provider accounts at first boot
integration_probe_timeout_mshow long an integration health probe waits

Password Vault (2)

KeyControls
vault_password_lengthlength of a generated password (12–128)
vault_reveal_autohide_mshow long a revealed secret stays visible

MCP broker and consumer (14)

Read by lib/mcp-broker.js and lib/mcp-routes.js.

KeyControls
mcp_broker_modeoff, local or brokered
mcp_auth_base_urlAuth issuer (also the OIDC issuer fallback — step-up guarded)
mcp_gateway_base_urlgateway the injected servers point at
mcp_client_id, mcp_client_authbroker client identity and client-authentication method
mcp_instance_id, mcp_app_scopethis instance's identity and requested scope
mcp_contract_majoraccepted contract major version
mcp_well_known_path, mcp_entitlements_pathdiscovery and entitlement paths on the broker
mcp_entitlement_ttl_s, mcp_token_max_ttl_sentitlement cache lifetime, ceiling on an issued token's lifetime
mcp_broker_timeout_msupstream timeout
mcp_sender_constraintsender-constraint requirement on issued tokens

Licence plane and entitlements (16)

Read by lib/entitlements.js and lib/lighthouse.js.

KeyControls
licensing_enforcedmaster switch; false (the default) resolves tier unenforced
license_jwtthe installed Ed25519-signed licence document
licensing_hwmclock-rollback high-water mark (server-written)
ui_feature_overridesJSON map that force-disables entitled features; narrowing only
lighthouse_base_url, lighthouse_instance_key, lighthouse_license_keyplane endpoint and credentials (key encrypted, masked)
lighthouse_contract_majoraccepted contract major (1.0.2 at this commit)
lighthouse_activate_path, lighthouse_renew_path, lighthouse_availability_pathplane paths
lighthouse_renew_interval_s, lighthouse_renew_ahead_hoursrenewal cadence and lead time
lighthouse_availability_ttl_s, lighthouse_timeout_msavailability cache lifetime, upstream timeout
lighthouse_last_resultlast plane result (server-written)

Agent manifest and persona sync (7)

KeyControls
agent_manifest_enabledserve /.well-known/agents/manifest.jws (default off)
agent_manifest_namespace, agent_manifest_cache_smanifest namespace and cache lifetime
agent_sync_enabled, agent_sync_interval_s, agent_sync_stale_after_sgoverned persona sync switch, cadence and staleness horizon (default off)
agent_sync_last_resultlast sync result (server-written)

Projects and filesystem (5)

KeyControls
default_modelmodel a launch falls back to
default_shellshell the PTY spawns
default_project_color, project_environmentsdefaults applied when a project is created
fs_extra_rootsextra absolute paths added to the filesystem root allowlist

Screenshots (3)

KeyControls
screenshot_categoriescategory vocabulary served to the gallery
screenshot_ai_model, screenshot_ai_max_tokensmodel and token ceiling for screenshot description

UI surfaces and cadences (17)

KeyControls
themestored UI theme
ui_native_context_menunative right-click policy (FEAT-054)
quick_actionsJSON descriptor list for the quick-actions rail
docs_ui, docs_activity_weeksdocs-surface layout JSON; weeks of commit activity summarised
header_usage_meters_enabledheader rate-window meter tiles
releases_tab_enabledReleases tab and its endpoints
blueprint_wizard_enabledBlueprint wizard mount
login_alert_enabled, login_alert_max_age_ms, login_alert_poll_msapp-wide login-expiry alert
active_model_poll_ms, active_model_stale_msactive-model badge poll and staleness
slug_check_debounce_msslug-availability debounce
screenshots_page_max, prompt_list_limit, prompt_list_limit_maxlist page sizes and caps

/api/client-config

Unauthenticated, read-only, served by server.js. 59 top-level keys at this commit. The browser must render from these and hardcode nothing.

KeyShapeSource
appVersionstringpackage.json
wsPortnumberthe port the WebSocket listener actually bound
blueprintWizard{mount, enabled}mount constant + blueprint_wizard_enabled
mcp{mode, orgEnabled, authBaseUrl}broker config; authBaseUrl is the public issuer, never a secret
defaultModelstring or nulldefault_model
handshakeTimeoutMsnumberws_handshake_timeout_ms
termJumpRefreshMs, termScrollDblclickMs, termJumpBlankFraction, termBlockSuspendnumber/number/float/boolterm_*
deployBadgePollMs, slugCheckDebounceMsnumbersame-named settings
usageMeterPollMs, usageStatsPollMs, sessionUsagePollMsnumberusage poll cadences
headerUsageMetersEnabledboolheader_usage_meters_enabled
osc52ClipboardEnabledboolosc52_clipboard_enabled
claudeUsageUrlstringclaude_usage_url
activeModelPollMs, activeModelStaleMsnumberactive_model_*
heartbeatPollIntervalMs, heartbeatPctWarn, heartbeatPctErr, heartbeatStealWarn, heartbeatStealErrnumberheartbeat_*
loginAlertEnabled, loginAlertMaxAgeMs, loginAlertPollMsbool/number/numberlogin_alert_*
integrationsEnabled, vaultEnabledboolpresence of the backing table
vaultRevealAutohideMsnumbertunable vault_reveal_autohide_ms
vaultCategories, integrationCategories, integrationProviderTypesarrayslib/vault.js, lib/integration-providers.js vocabularies
projectsBaseDirstringserved start directory for the file browser
injectReadyTimeoutMs, injectSettleMs, injectShellDelayMs, injectReadyPattern, injectDialogPattern, injectDialogAffirmPattern, injectDialogMaxStepsnumber/stringinject_*
ccDefaultSettingsPathstring or nullshared --settings fallback path; null means the mitigation is off
claudeActivePattern, claudeIdlePatternstringclaude_*_pattern
nativeContextMenustringresolved FEAT-054 policy
sessionArchiveParkIdleMinutes, sessionParkEnabled, sessionCloseDefault, sessionRecoveryDirectRejoinnumber/bool/string/boolsession_*
screenshotCategoriesarrayscreenshot_categories, split on commas
anthropicApiKeyBillingEnabledboolresolved billing policy
releasesTabEnabledboolresolved Releases-tab flag
entitlements{enforced, tier, state, features, limits, trialUntil, installedLicense}resolved entitlements
licensingCatalog{features, tiers, limits, trialTier}the non-secret tier↔feature vocabulary
docsUiobject incl. imageExtsdocs layout config
lighthouse{configured}whether a licence plane is configured
quickActionsarray of descriptorsquick_actions
floodPollMsnumbertranscript flood re-check cadence

Nested members raise the total addressable name count past the top-level 59 (blueprintWizard.mount, mcp.mode, entitlements.features, docsUi.imageExts and so on). No key on this route is a secret; integrationsEnabled and vaultEnabled report a table's presence, not its contents.

Live tunables (29)

lib/tunables.js is one registry and one resolver: settings row (valid) → environment variable (valid) → named default. An invalid value warns once and falls through rather than being honoured. GET /api/tunables returns the descriptor plus the current resolution and its provenance (settings, env or default) for the Settings ▸ Advanced renderer; PATCH /api/settings validates a tunable on write, and a blank value restores the default. All 29 are live: true at this commit — a save applies within the 30 s settings-cache window, with no restart.

KeyTypeDefaultBoundsGroupControls
artifact_sync_enabledbooltrueartifactsrun the periodic artifact scan
artifact_sync_interval_msint600000≥30000artifactsscan cadence
artifact_scan_batch_recordsint2000100–100000artifactsrecords per extractor batch
artifact_scan_max_line_bytesint8388608≥65536artifactsdrop (and log) a longer single line
artifact_list_maxint50020–5000artifactsrows per scope in the panel
artifact_serve_max_bytesint26214400≥1048576artifactsviewer file cap
trash_sweep_interval_msint3600000≥60000transcriptspurge cadence
archive_sweep_interval_msint3600000≥60000transcriptshot→cold roll cadence
session_list_decorate_budget_msint2500–10000transcriptstitle-decoration budget
session_active_output_msint10000≥1000transcriptsactive-session output window
transcript_unknown_alert_pctfloat50–100transcriptsunknown-kind alert threshold
term_default_colsint12020–1000terminalinitial PTY width
term_default_rowsint405–500terminalinitial PTY height
term_max_colsint50040–5000terminalresize clamp
term_max_rowsint30010–2000terminalresize clamp
git_probe_timeout_msint5000≥500externalquick git probes
git_details_timeout_msint10000≥500externalheavy git reads
integration_probe_timeout_msint12000≥1000externalintegration test
heartbeat_log_linesint10010–5000limitsdefault pm2 log lines
heartbeat_log_lines_maxint50010–20000limitsrequestable ceiling
screenshots_page_maxint50020–5000limitsgallery page cap
prompt_list_limitint10010–5000limitsprompt library page
prompt_list_limit_maxint50010–20000limitsrequestable ceiling
docs_activity_weeksint121–104limitsdocs activity window
pricing_stale_daysint901–3650limitspricing staleness horizon
default_project_colorcolor#3b82f6#rrggbbprojectscolour for a new project
project_environmentscsvproduction,test,devnon-emptyprojectsenvironments created with a project
vault_password_lengthint2012–128vaultgenerated password length
vault_reveal_autohide_msint300003000–600000vaultreveal auto-hide

Each entry also carries env (the variable name, the tunable key upper-cased), unit, label and help; the seven groups are artifacts, transcripts, terminal, external, limits, projects, vault.

Environment inventory

The full environment inventory is generated into tracking/features/FEAT-055.md (one table row per variable, with where it is read and its disposition). It is not repeated here — 248 rows would drift the moment a variable moves. The triage classes are:

ClassCountMeaning
A · exposed29in the tunables registry, editable live in Settings ▸ Advanced
B · settings-backed elsewhere14already has its own control in Settings outside the Advanced tab
C · wave-2 candidate99read once at boot or module init; exposable through the same registry after the consumer is converted to a use-time read or scheduleLoop, or with live: false
D · env-only by design106deployment shape (bind hosts, paths, CSP, blocklists, argv, identities, protocol URLs) or secrets; these belong to the process config, never to a settings row

Read the disposition column before adding a variable: a new tunable belongs in the registry, and a new deployment-shape variable belongs in class D with no settings row at all.

WebSocket frame protocol

One channel, path /ws, on its own HTTPS listener (default port 3201, COMMANDER_WS_PORT). Both query parameters are required and must be UUIDs:

wss://<host>:<wsPort>/ws?session=<sessionId>&project=<projectId>

Frames are JSON text (RFC 8259) with a type discriminator. An AsyncAPI 3.0 description is P1; this table is the normative description until it lands.

Client → server

typePayloadEffect
input{data: string}written to the PTY verbatim
resize{cols, rows}clamped by clampDim to the term_max_* bounds; a garbage value falls back to the default rather than throwing
reviveonly accepted after a session_dead frame; spawns or attaches once, then ignores repeats

A frame that is not valid JSON, or whose type is unknown, is dropped. The first malformed frame on a socket is logged and further ones are suppressed, so a flood cannot become a log flood.

Server → client

typePayloadWhen
connected{sessionId, project, reconnected, cols, rows, replay}on attach; replay is the serialised current screen, never the raw byte history
output{data: string}PTY output, fanned out to every subscriber
model{sessionId, model, …, scope: 'session'}debounced push when the acting model changes in the transcript tail
cc-watch{sessionId, watch, extract}a registered output watch matched
cc-credit-prompt{sessionId}the CLI's credit prompt was detected
exit{code}the PTY exited
session_dead{sessionStatus, scrollback}the session ran before but no PTY is live; nothing spawns until a revive arrives
error{message}refusal or failure; the socket is usually closed straight after

Transport hardening

Implemented in lib/ws-hardening.js (pure functions) and wired in server.js:

ControlBehaviour
Origin allowlistRFC 6454 Origin checked against the connected host, plus WS_ALLOWED_ORIGINS (full origins or bare hostnames). No Origin header is treated as a non-browser client and allowed — the session token still gates it. An unparseable Origin or Host fails closed. RFC 6455 §10.2 leaves this policy to the server.
Authenticationthe same opaque session token as /api, from the commander_token cookie. A password is never accepted here.
Embedded scope refuseda session whose profile mode is embedded is refused with error and closed — the terminal is full shell access and is not in the embedded contract
Session/project bindingthe session row must belong to the project named in the query, or the socket is refused
maxPayloadWS_MAX_PAYLOAD_BYTES, default 1048576
Keepaliveserver ping every WS_KEEPALIVE_MS (default 30000); a socket that misses a pong is terminated. 0 disables it for tests.
Backpressurea subscriber more than WS_MAX_BUFFERED_BYTES behind is terminated as a slow consumer
Containmentany rejection inside the handshake is contained to that one socket; it can never take the process (and every other terminal) down

Error and status conventions

JSON bodies (RFC 8259) on every error, HTTP semantics per RFC 9110.

StatusBodyRaised by
400{error}shape and range validation, including an invalid tunable write ({error, key})
401{error}no live session on an authenticated route
403{error, feature, tier, upgrade}requireFeature(...) when no listed feature is entitled
403{error, path, hint}a path outside the filesystem root allowlist. The hint names the two remedies: register the location as a project, or extend FS_EXTRA_ROOTS / settings.fs_extra_roots
403{error, guardedKeys}step-up proof supplied but wrong, or no step-up path exists
409{error}name clash on a unique column (integration, vault entry), an existing working_dir, a stale OAuth flow, restart-cc with no live process, or a systemd verb Commander will not run for you (which also carries {needsManualStart, manager, name})
409{error, ...}optimistic-concurrency skew on an If-Match-style write (RFC 7232 semantics; personas and per-account CC config)
413{error}a cap exceeded — prompt title, body, category, tag count and tag length each have their own
422{error, guardedKeys}a coherent-state refusal: switching auth_mode to oidc with no issuer would strand the login path
428{error, guardedKeys}step-up required (RFC 6585). Resend the identical request with the x-current-password header. Guarded keys are the enumerated floor app_password, auth_mode, mcp_auth_base_url, plus everything matching the auth_oidc_ prefix, plus anything AUTH_CRITICAL_KEYS_EXTRA adds. The floor and the prefix are not shrinkable from the surface they guard. Step-up follows NIST SP 800-63B §5 re-authentication.
500{error}handler failure. One deliberate case: writing a credential-class setting with no COMMANDER_ENCRYPTION_KEY configured is refused rather than persisted in plaintext.

Two conventions sit outside the table. Licence-plane errors are RFC 9457 application/problem+json documents, produced and parsed by lib/lighthouse.js (with tolerance for Lighthouse's pre-contract error shape). And a guarded settings write is always logged — refused or allowed, with the key list — because a change to the login seam must never be silent.

Entitlement keys

lib/entitlements.js declares the closed vocabulary. requireFeature(f) throws at boot for an unknown key, so a typo fails the process rather than a request. 19 feature keys, carried by 39 routes (36 through requireFeature, which is also the count the generated OpenAPI document marks with x-entitlement; plus 3 through the usage plan gate):

Feature keyRoutes carrying it
tasks-notes13 — the git-tracking notes and tasks routes plus the DB task routes
session-managersession-rejoin (any-of)8 — /api/artifacts*, GET /api/claude-sessions, unarchive, restart-cc, GET /api/transcripts/stats
deploy-ladder3 — promote, rollback, rollback-candidates
releases-tab3 — the release-notes routes
session-manager3 — brief, trash, GET /api/transcripts/export
token-analytics3 — /api/usage/stats, /api/usage/stats/progress, /api/usage/window (plan gate)
git-history2 — git-file-history, git-file-at-ref
session-rejoin1 — archived sessions for a project
session-rejoinsession-manager1 — GET /api/claude-sessions/:sid/exists
transcript-searchsession-manager1 — GET /api/claude-sessions/:sid/prompts
docs-visuals1 — GET /api/files/activity
custom-agents, doc-viewer-plus, git-file-panel, llm-runtime-controls, quick-actions-toolbar, multi-account, multi-project, project-nesting, shell-sessions, usage-analyticsno route gate — UI-surface keys, or enforced as a numeric limit

Numeric limits are separate from features: checkLimit() reads limits['projects:max'] and limits['accounts:max'], both capped at 1 for the community tier and absent (unlimited) above it.

Enforcement is off by default in v3.0.15. licensing_enforced resolves from LICENSING_ENFORCED then the settings row, defaulting to false; unenforced resolves tier unenforced with every feature on, so a gated route answers and the client still renders the installed licence's tier and expiry for display. Turning enforcement on switches the resolver to the licence document: an unlicensed install falls to community, TRIAL_TIER (team) covers a trial, and ui_feature_overrides can only narrow what a licence grants — never widen it.

You've seen the proof

Ready for a number? Scope your deployment and we'll price it against your own economics.

Get your quote →