New flags land as DRAFT — invisible to SDKs until published.
Changing a prod value requires explicit confirmation. The agent gets reach, not a blank cheque.
Customer → Product → Tenant. The Customer is your workspace — billing, users, allowed domains. The Product is what your SDK authenticates as — its own apiKey, its own flag namespace, its own audit stream. The Tenant is the slice your flag value resolves for — a B2B customer organisation, a brand variant of one codebase, a region, a cohort. Same data shape, same override semantics, same audit boundary regardless of what you're slicing by. Every flag, every rule, every audit row is scoped at the storage layer — bypass is impossible because the row can't be written without all three.
MVP runs on Firebase. A custom data plane is a post-PMF decision, not day one.
Each Product has its own apiKey — the SDK uses it to identify which Product's flags to fetch. For multi-tenant Products, the evaluation API also requires a tenantId, enforced server-side. iOS, Android, and Web SDKs ship today, pushing flag changes in real time via Firestore listeners (~1s, no polling). Web ships as two packages — @argus/client for the browser (real-time) and @argus/node for server-side pull / SSR. Edge resolution lands in v1.5.
// scoped, deterministic, reversible const flag = await argus.evaluate({ key: "new_billing_v2", tenant: ctx.tenantId, // required env: "prod", }); if (flag.on) renderNewBilling(); // → audit row written, scoped to tenant. // → reversible from the dashboard in one click. // → impossible to evaluate without a tenant.
The Web SDK ships as two packages that share one read-scoped apiKey. @argus/client runs in the browser: it seeds flag values with a single resolveFlags pull, then subscribes to a Firestore listener so changes land in real time (~1s, no polling). @argus/node runs on the server for SSR and request-scoped evaluation, and serialises resolved flags so the browser hydrates without a second round trip. Same shape as the iOS and Android SDKs — one apiKey per Product, an optional tenantId for multi-tenant resolution.
// browser · real-time via Firestore listener import { init } from "@argus/client"; const argus = await init({ apiKey: import.meta.env.ARGUS_KEY, baseUrl: "https://api.your-argus.cloud", tenantId: "acme_retail", // optional }); if (argus.getFlag("new_billing_v2", false)) renderNewBilling(); // re-renders when a flag flips, live argus.onChange((flags) => paint(flags)); // React: import { useFlag } from "@argus/client/react" argus.close(); // detach the listener
// server · request-scoped pull + SSR hydration import { createClient } from "@argus/node"; const argus = createClient({ apiKey: process.env.ARGUS_KEY, // same key baseUrl: "https://api.your-argus.cloud", }); const ctx = { userId: user.id, tenantId: "acme_retail" }; const on = await argus.getFlag("new_billing_v2", false, ctx); // hand the resolved set to the browser, no re-fetch res.locals.argusState = argus.serialize(ctx); // → @argus/client picks it up to hydrate instantly.
baseUrl is your Cloud Functions origin. One read-scoped apiKey covers both packages — there is no public / secret split. The init and resolution API shown here is shipped today; the npm packages publish with v1 — until then a preview build is available from the SDK repository.
Argus ships a local MCP server (argus-mcp) so an AI coding agent — Claude Code, Cursor, and the like — can manage feature flags from inside a coding session: list, create, and publish flags, set per-environment values, and toggle them, without leaving the editor.
Changing a prod value requires explicit confirmation. The agent gets reach, not a blank cheque.
Each change records actor, timestamp, env, tenant, flag, before, and after — tagged as the agent. Append-only, same as any other change.
No per-agent tokens yet. A productized, multi-tenant MCP with per-agent revocable tokens is on the roadmap.
Tenant override documents are first-class — not a special case of segments. They have their own audit stream and resolution lane.
Approval is a flow, not a checkbox. Requested → assigned → approved → applied. Each step writes an audit row.
A contributor changes dev and proposes everything higher. An approver approves changes and sets dev / staging directly. A super_user owns prod and user management.
Every resolution response carries the source of the value (default · rule · override · rollout). Every change writes a row you can query by product and tenant.
Honest comparison against the alternatives most teams already run. We update this page as the tools ship changes.