Feature Flags

There are two kinds of flag in the Features section, and they answer different questions:

Memex deployments are shaped by deploy-time capability toggles bound from the Features configuration section into MemexFeatureOptions. A flag declares which capabilities a deployment ships — independent of whether a given credential key happens to be present. A disabled flag is the operator's intent and wins even if a key is configured.

No-regression default. Every flag defaults to its no-change value, so an absent Features section preserves current behaviour: the capability toggles default to true, and the two opt-ins (Onboarding:InvitationOnly, StaticRepoSync:Partitions) default to off/empty. Operators turn capabilities off (or opt in) explicitly.


How flags are bound

MemexConfiguration.ConfigureMemexServices binds the section once at startup so application code resolves the toggles through standard DI (IOptions<MemexFeatureOptions>):

services.Configure<MemexFeatureOptions>(
    builder.Configuration.GetSection(MemexFeatureOptions.SectionName)); // "Features"

Consumers inject IOptions<MemexFeatureOptions> (e.g. the onboarding gate in Onboarding.razor) rather than re-reading configuration ad hoc.

Where values come from

Configuration is layered (last wins):

  1. appsettings.json
  2. appsettings.{Environment}.json
  3. Environment variables — section nesting uses the double-underscore form (Features__Ai__Providers__OpenAI=false). This flows identically through Azure Container Apps env, Kubernetes env, Docker-compose .env, and ARM createUiDefinition → container env.

Reference

Key Type Default Effect
Features:Ai:Providers:Anthropic bool true Ships the in-process Anthropic chat provider (bring-your-own-key).
Features:Ai:Providers:AzureFoundry bool true Ships the Azure AI Foundry provider.
Features:Ai:Providers:AzureOpenAI bool true Ships the Azure OpenAI provider.
Features:Ai:Providers:OpenAI bool true Ships the OpenAI provider.
Features:Ai:Providers:OpenAICompatible bool true Ships the generic OpenAI-wire provider type (OpenRouter, Groq, Together, a local vLLM, …) — always user-supplied base URL + key, no system default.
Features:Ai:Providers:OpenRouter bool true Ships OpenRouter (https://openrouter.ai/api/v1). System-default endpoint, no model ids; requires an API key. Rides the OpenAI-compatible factory.
Features:Ai:Clis:ClaudeCode bool true Deploys the co-hosted Claude Code CLI runtime (per-user Connect login). The harness is NOT offered to users by default: its catalog node is install-gated (Harness.RequiresInstall) — a user opts in by installing the Claude Code plugin from the Store, which localizes the harness node into {user}/Harness.
Features:Ai:Clis:Copilot bool true Deploys the co-hosted GitHub Copilot CLI runtime. Same per-user install gate as Claude Code.
Features:Onboarding:AllowSelfOnboarding bool true When false, registration is closed — only the first-ever user may onboard.
Features:Onboarding:InvitationOnly bool false When true, only an email with a Pending invitation may onboard. See Invitation-Only Onboarding.
Features:Orleans:Clustering string AzureTables Cluster-membership provider: AzureTables, AdoNet (PostgreSQL), or Localhost (single in-process silo; dev only).
Features:SignalR bool true Opens the SignalR mesh transport (/signalr) for external participants (native clients). false closes the connection surface.
Features:StaticRepoSync:Partitions string[] [] Partitions whose build-time static content is materialized into and served from the database instead of the in-memory read-only static provider (e.g. ["Doc","Agent","Provider","Harness","Skill"] — what the default Helm deployment sets). Empty = every partition keeps the in-memory provider. Matching is case-insensitive; Model is a legacy alias for Provider. See Static Repo Import.
Features:StaticRepoSync:Modes:{Partition} enum (source default) Per-partition prune policy for that import: FullReplace (mirror), Additive (keep user-added nodes), UpsertOnly (never prune). Unlisted partitions use their source's default — FullReplace for most, but the built-in AI catalogs (Skill/Agent/Provider/Harness) default to Additive. Distinct from the per-node SyncBehavior.
Features:Flags:{name} bool or object (undeclared = off) An environment-DECLARED flag, read reactively through IFeatureFlags. The object form adds Packages — what this environment pre-installs, reconciled on every boot, with a declared-but-disabled flag EXCLUDING them. See Environment Composition.

There is no Features:Grpc any more: the gRPC mesh transport (meshweaver.v1.Mesh + gRPC-web — foreign-language participants AND the React GUI's browser data plane) is the MeshWeaver.Hosting.Grpc module, switched by listing/delisting the DLL under Modules:Assemblies — default-on everywhere, see Modules.

A related, separate section — Email — configures outbound system mail (used by invitations). It is documented in Invitation-Only Onboarding → Email.


AI flags — symmetric gating

AI provider/CLI flags gate two tiers symmetrically so a provider can never half-register (which would crash on first use):

if (features.Ai.Clis.ClaudeCode)
    services.AddClaudeCode(config => builder.Configuration.GetSection("ClaudeCode").Bind(config));
// …and the matching catalog source is gated by the same flag in ConfigureMemexMesh.

MemexFeatureOptions.HasAnyChatCapability is true when the deployment ships at least one provider or one CLI — so disabling every provider takes all six Providers flags, not just the four named API vendors. When it is false the portal has no built-in chat via catalog sources (users may still bring their own keys via Model Providers) — surfaced as a startup warning, not a hard failure.

API providers work bring-your-own-key (users add endpoint + key per provider under Settings → Models); see Model Providers. The co-hosted CLIs require the per-user Connect login.


Onboarding modes

The two onboarding flags combine into three modes. The first-user bootstrap exception always applies: a brand-new deployment with zero existing User nodes always lets the very first user onboard (and become platform admin), so the platform can never lock itself out.

InvitationOnly AllowSelfOnboarding Mode Who may onboard
false true (default) Open Anyone who authenticates.
false false Closed First user only — everyone else sees "Registration Closed".
true (any) Invitation-only Only an email with a Pending invitation (plus the first user).

InvitationOnly takes precedence: when it is on, the gate is "has a Pending invitation" regardless of AllowSelfOnboarding. The security boundary is enforced at the CreateUser call in Onboarding.razor (not just the UI). Full treatment: Invitation-Only Onboarding.


Examples

appsettings.json — close self-registration and require invitations:

{
  "Features": {
    "Onboarding": { "AllowSelfOnboarding": false, "InvitationOnly": true },
    "Ai": { "Providers": { "OpenAI": false } }
  }
}

Environment variables (ACA / compose / ARM):

Features__Onboarding__InvitationOnly=true
Features__Ai__Providers__OpenAI=false
Features__Orleans__Clustering=AdoNet

Kubernetes (set on the running deployment):

kubectl -n memex set env deployment/memex-portal-deployment \
  Features__Onboarding__InvitationOnly=true \
  Features__Ai__Clis__Copilot=false

See Memex Cloud Deployment → Enable / Configure AI Providers for the full operational walkthrough.


Reconnecting…
The server was updated. Reloading the page to pick up the latest version.