Skip to content
Agent Orchestration
Skill

/unleash-flag

This skill should be used when the user asks to "add a feature flag", "gate a feature", "put this behind a flag", "add a workspace flag", "feature flag this", "make this configurable per workspace", "configure Unleash", or references "flags.json", "useWorkspaceFlag", "useFlag",

BOOST
From plugin
platform
13121 skills6 agents11 commands3 MCP
Install
$ npx -y skills add ambient-code/platform --skill unleash-flag --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/unleash-flag

Context preview

The summary Claude sees to decide when to auto-load this skill.

This skill should be used when the user asks to "add a feature flag", "gate a feature", "put this behind a flag", "add a workspace flag", "feature flag this", "make this configurable per workspace", "configure Unleash", or references "flags.json", "useWorkspaceFlag", "useFlag",

SKILL.md

unleash-flag.SKILL.md
name: unleash-flag
description: This skill should be used when the user asks to "add a feature flag", "gate a feature", "put this behind a flag", "add a workspace flag", "feature flag this", "make this configurable per workspace", "configure Unleash", or references "flags.json", "useWorkspaceFlag", "useFlag", "SyncFlags", or "controlled rollout" of a feature.

Unleash Feature Flag

Workspace-scoped feature flags for the Ambient Code Platform — naming, gating, evaluation, and lifecycle management.

Checklist

Every new flag requires these steps. Skip none.

1. **Define the flag** in `components/manifests/base/core/flags.json` 2. **Gate the frontend** using the correct hook for scope 3. **Update tests** to mock the flag hook 4. **Verify** type-check and tests pass

1. Define the Flag

Add to `components/manifests/base/core/flags.json`:

{
  "name": "category.feature-name.enabled",
  "description": "Human-readable purpose of this flag",
  "tags": [
    {
      "type": "scope",
      "value": "workspace"
    }
  ]
}

Naming Convention

**All new flags** must use the `category.feature-name.enabled` format:

category.feature-name.enabled

| Segment | Rules | Examples | |---------|-------|---------| | `category` | One of the standard categories below | `runner`, `model`, `integration` | | `feature-name` | Lowercase, hyphen-separated, descriptive | `gemini-cli`, `coderabbit` | | `.enabled` | Required suffix for all new flags | — |

**Standard categories:**

| Category | When | Example | |----------|------|---------| | `integration` | External service integrations | `integration.coderabbit.enabled` | | `runner` | Runner type availability | `runner.gemini-cli.enabled` | | `model` | Model availability (auto-generated by SyncFlags) | `model.claude-sonnet-4-5.enabled` | | `feature` | Platform capabilities | `feature.scheduled-export.enabled` |

**Grandfathered flags** (do not rename):

  • `jira-write`
  • `ldap.autocomplete.enabled`
  • `scheduled-session.reuse.enabled`

These predate the convention. New flags must not follow their patterns.

**Rules:**

  • **Unique across the entire system** — never reuse a retired flag name
  • **Descriptive** — someone unfamiliar should understand the scope from the name alone
  • **Dot-delimited** with category prefix — enables grouping in workspace settings UI
  • **Lowercase with hyphens** within segments (not underscores, not camelCase)

Workspace Settings Visibility

The `scope:workspace` tag is what makes a flag appear in the workspace settings UI. Without it, the flag exists in Unleash but workspace admins cannot toggle it.

Backend `SyncFlags` runs at startup: reads `flags.json`, creates flags in Unleash (type: `release`, disabled by default, 0% rollout), and tags them. Flags without `EnabledByDefault: true` start **off**.

To force a re-sync, restart the backend. To clear a stuck flag, archive + purge it in Unleash admin before restarting.

2. Gate the Frontend

Choosing the Right Hook

**Default: `useWorkspaceFlag`** — always prefer this hook. It respects ConfigMap overrides set by workspace admins.

import { useWorkspaceFlag } from "@/services/queries/use-feature-flags-admin";
const { enabled } = useWorkspaceFlag(projectName, "category.feature.enabled");

**Exception: `useFlag`** — only for the rare case where no project context is available (e.g., cluster-level admin pages like `/integrations`). It bypasses workspace overrides entirely and returns only the Unleash global default. Do not use it in project-scoped pages.

import { useFlag } from "@/lib/feature-flags";
const enabled = useFlag("category.feature.enabled");

| Hook | Scope | Evaluation | |------|-------|------------| | `useWorkspaceFlag` | Project-scoped pages (default) | ConfigMap override > Unleash default | | `useFlag` | Cluster-scoped pages only (exception) | Unleash default only |

Gating Patterns

**Conditionally render a component:**

const { enabled: featureEnabled } = useWorkspaceFlag(projectName, "category.feature.enabled");

// In JSX:
{featureEnabled && <FeatureComponent />}

**Conditionally include in an array:**

const items = [
  { key: "always-visible", name: "Always" },
  ...(featureEnabled
    ? [{ key: "gated", name: "Gated Feature" }]
    : []),
];

**Extract project name from route params** (when not passed as prop):

import { useParams } from "next/navigation";
const params = useParams();
const projectName = params.name as string;

Backend Gating (when needed)

For full-stack gating (not always necessary — frontend-only is often sufficient):

// Global check
if !FeatureEnabled("category.feature.enabled") {
    c.JSON(http.StatusForbidden, gin.H{"error": "Feature not enabled"})
    return
}

// Request-scoped (includes user/IP context for Unleash strategies)
if !FeatureEnabledForRequest(c, "category.feature.enabled") {
    c.JSON(http.StatusForbidden, gin.H{"error": "Feature not enabled"})
    return
}

Backend Middleware Gating

For endpoints that should be entirely hidden behind a flag, create a middleware in `routes.go` that checks `FeatureEnabledForRequest()` and returns 404 when the flag is off:

// routes.go — gate an entire route group
flagged := router.Group("/api/v1/feature")
flagged.Use(func(c *gin.Context) {
    if !handlers.FeatureEnabledForRequest(c, "category.feature.enabled") {
        c.AbortWithStatus(http.StatusNotFound)
        return
    }
    c.Next()
})
{
    flagged.GET("/resource", handlers.ListResource)
    flagged.POST("/resource", handlers.CreateResource)
}

This returns 404 (not 403) when the flag is off, so the endpoint appears not to exist. Use this for features that shouldn't even be discoverable until enabled.

E2E Testing with Feature Flags

When writing E2E tests for flagged features, the Unleash admin token must be set as an environment variable. **Never paste or export the token inline in a shell session** — this

Read more
Ships withplatform

Kubernetes-native AI automation platform for intelligent agentic sessions

Get the whole plugin

Other skills on platform.