LaunchFlag

Docs / Agents

Agents that ship dark.

Your agent writes code you did not read line by line. The skill teaches it to wrap every risky change in a flag. The MCP server lets it create and flip those flags without leaving the editor. You keep the switch.

Set up with your coding agent

#

Paste this into Claude Code, Cursor, Codex or any coding agent. It installs the SDK, the agent skill and the MCP server, then wraps your first risky feature.

Set up with your coding agent

You are setting up LaunchFlag in this project. LaunchFlag is a feature flag service whose job is a kill switch: ship a change turned off, turn it on when you are ready, turn it off from a phone when it breaks, with no deploy.

1. Run: npx launchflag init --key <paste your dev key here> --url https://launchflag.dev
   This installs the launchflag package, writes LAUNCHFLAG_KEY into .env.local, and installs the LaunchFlag skill at .claude/skills/launchflag/SKILL.md. Add --token lfk_... to the same command, with my API token from https://launchflag.dev/app under Install, and it also writes the hosted LaunchFlag MCP server into .mcp.json and .cursor/mcp.json.
   Using pnpm? Run pnpm dlx launchflag init instead of npx.
   If I have not given you a key, ask me for it before running the command. I get it from https://launchflag.dev/app under Environments.
2. Read .claude/skills/launchflag/SKILL.md and follow it from now on. Every risky change ships behind a flag, off by default.
3. Find the riskiest unflagged path in this codebase: payments, auth, deletion, sending email, an external API, or anything generated recently that nobody has read line by line. Wrap the new path in a flag and leave the old path intact and reachable:

   import { flag } from "launchflag";
   if (await flag("checkout_v2", { id: user.id, email: user.email })) return newCheckout();
   return oldCheckout();

   Do not turn the flag on. It registers itself, off, the first time the code runs.
4. The key above is the DEVELOPMENT key, and it only covers where you run the code. A key chooses which environment the SDK reads: the same flag exists in every environment and is off in each one separately, so nothing you do here reaches production.
5. When you are done, tell me: the flag key you created, what it wraps, what happens when it is off, and both of these lines:
   "Turn it on at https://launchflag.dev/app, or turn it off from your phone when it bites."
   "Production needs its own key: set LAUNCHFLAG_KEY on the production host to the Production key from https://launchflag.dev/app, or this flag stays off there and cannot be turned on."

Rules: never enable a flag in production yourself, dev is fine for testing. Keep the key in .env.local and out of client-side code and version control. One flag per feature, not per file. Do not delete the old path in the same change.

Why agents need this

#
  • You did not read every line. An agent can write a checkout rewrite in four minutes. A flag means the whole thing can be off again in four seconds, from a phone, with no rollback and no deploy.
  • The skill changes what the agent writes. It wraps the new path in an if, keeps the old path intact and reachable, and reports the flag key back to you in its final message.
  • The MCP server changes what it can do. It can create a flag, turn it on in dev to test its own work, and promote it to staging. Turning a flag on in production stays yours.

One command setup

#

From the root of your project. It installs the launchflag package, writes your key into .env.local, downloads the skill to .claude/skills/launchflag/SKILL.md, and points Claude Code and Cursor at the hosted MCP server.

Terminal

$ npx launchflag init --key lf_dev_… --token lfk_… --url https://launchflag.dev

Using pnpm? Run pnpm dlx launchflag init instead of npx.

Leave the flags off and it asks for your dev key and your API token. Both are on the dashboard Install page. It also adds .env.local, .mcp.json and .cursor/mcp.json to your .gitignore, because two of those now hold a token.

Manual setup

#

The hosted MCP server is the default: one URL and a token, nothing to install and nothing to keep running. Replace lfk_… with your API token.

Claude Code, hosted

$ claude mcp add --transport http launchflag https://launchflag.dev/mcp --header "Authorization: Bearer lfk_…"

Or commit nothing and check in a project file instead. Claude Code reads .mcp.json at the project root. Because it carries the token, keep it out of git.

.mcp.json

{
  "mcpServers": {
    "launchflag": {
      "type": "http",
      "url": "https://launchflag.dev/mcp",
      "headers": { "Authorization": "Bearer lfk_…" }
    }
  }
}

Cursor reads the same shape from .cursor/mcp.json for a single project, or ~/.cursor/mcp.json for every project.

.cursor/mcp.json

{
  "mcpServers": {
    "launchflag": {
      "type": "http",
      "url": "https://launchflag.dev/mcp",
      "headers": { "Authorization": "Bearer lfk_…" }
    }
  }
}

Codex

$ export LAUNCHFLAG_TOKEN=lfk_…
$ codex mcp add launchflag --url https://launchflag.dev/mcp --bearer-token-env-var LAUNCHFLAG_TOKEN

Codex has no header flag. It reads the bearer token from the environment every time it starts, so put the export in your shell profile rather than running it once.

Anything else that reads an mcpServers block takes the same JSON on one line.

Any other client

{"mcpServers":{"launchflag":{"type":"http","url":"https://launchflag.dev/mcp","headers":{"Authorization":"Bearer lfk_…"}}}}

The alternative, if you would rather the process ran locally: launchflag-mcp is a separate package with the same tools over stdio, reading the token from the environment instead of a header. You do not need it for the hosted server above.

Local stdio, the alternative

$ claude mcp add launchflag -e LAUNCHFLAG_TOKEN=lfk_… -e LAUNCHFLAG_URL=https://launchflag.dev -- npx -y launchflag-mcp@latest

The tools

#
ToolWhat it does
list_flagsEvery flag with its dev, staging and prod state, fail mode and variants.
cleanup_flagsThe flags whose rollout is over, each with the reason and what to remove.
create_flagCreate a flag, off in every environment, and get the snippet to wrap the new path in.
set_flagTurn a flag on or off in one environment, or change who it targets.
promote_flagCopy one environment's config forward: dev to staging, staging to prod.
depend_flagHold a flag off while another one is off, or clear that dependency.
delete_flagDelete a flag, once the code paths behind it are gone.
emergency_offDisable every non-essential flag in the project at once, or lift it.
list_projectsYour projects and their environment keys.

Every tool takes an optional project id and uses your first project when you leave it out. Errors come back as text the agent can read, not exceptions.

The skill workflow

#

The skill is served at https://launchflag.dev/skill.md and lives in your repo at .claude/skills/launchflag/SKILL.md. It fires on any user-facing feature, rewrite, payment, auth, email or deletion path, new agent tool, or prompt change. It tells the agent to:

  • Write the if. Wrap the new path, leave the old one intact and reachable, never delete it in the same change.
  • Ship it dark. No dashboard step. The flag registers itself the first time the code runs, off everywhere, fail closed.
  • Never turn it on in prod. Dev is fair game for testing its own work, staging by promotion. The staging to prod step is yours.
  • Tell you the key. Every final message names the flag, its fail mode, and the one line that turns it on.
  • Offer cleanup later. Once a feature has been fully on for weeks, it offers a change that deletes the flag and the old path.

What the agent writes

import { flag } from "launchflag";

if (await flag("checkout_v2", user.id)) {
  return newCheckout(cart);   // new path
}
return oldCheckout(cart);     // old path, untouched

Not using Claude Code? The file is plain markdown. Point any agent at it, or paste it into your AGENTS.md. npx launchflag init appends a short LaunchFlag section to an existing AGENTS.md for you.

Token safety

#
  • A token is per user, not per project: it reaches every project you own. Give each thing that calls the API its own, so revoking one does not break the rest, and pick the smallest scope that works.
  • Full. Everything you can do, in every environment.
  • CI. Flags in dev and staging. Never prod, never Emergency off.
  • Read only. Reads flags, audit and insights. Changes nothing.
  • It is shown once, when you create it. Only a hash is stored. Lost it, or leaked it: revoke that one from Settings, create another, and re-run npx launchflag init.
  • .mcp.json and .cursor/mcp.json hold the token in plain text. Keep both out of git. The init command adds them to .gitignore for you.
  • The token is not the same thing as an environment key. lfk_… manages flags, lf_dev_… and its siblings only evaluate them. Never give an agent a production environment key it does not need.

Troubleshooting

#
SymptomWhat it means
401 Missing API tokenNo Authorization header reached us, or it does not start with lfk_. Check the header is on the MCP entry and not the outer object.
401 Invalid API tokenThe token was revoked or regenerated. Create a new one in Settings and update every client that holds it.
429 Rate limited120 requests a minute per token. The response carries retry-after in seconds. An agent looping over list_flags is the usual cause.
Unknown projectThe project id does not belong to you, or you have no project yet. Run list_projects.
Tools do not appearThe endpoint is POST only and stateless. A client that opens a GET stream first will see a 405; use a Streamable HTTP client, or the stdio server instead.