Install
$ agentstack add skill-growthbook-skills-flag-publish ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
flag-publish
Get a GrowthBook feature flag draft revision live, or undo a change. Handles the full publish flow including the two common failure modes — approval-required (blocked) and merge conflict (stale base) — and the escape hatches: discard and revert.
All API calls go through the bundled helper: ${CLAUDE_PLUGIN_ROOT}/scripts/gb-call. It needs GB_API_KEY set in env or written to ~/.config/growthbook/.env by /growthbook:setup.
Workflow
Pick the path that matches what the user asked for. Each path ends at Report — do not continue into another path after completing one.
- Publish → steps 1 → 2 → (3a or 3b only if step 2 fails) → 6
- Discard → step 4 → 6
- Revert → step 5 → 6
1. Identify the revision
If a version number is already in context (threaded from a previous write skill in this session), skip ahead — use it directly.
If the user provides a flag ID but no version, use /latest:
# User's own most recent active draft:
gb-call GET '/api/v2/features//revisions/latest?mine=true'
# Most recently updated active draft by anyone:
gb-call GET /api/v2/features//revisions/latest
If /latest returns 404, there are no active drafts on this flag — nothing to publish. Confirm with the user and stop.
If there are likely concurrent drafts, list and let the user choose:
# User's own active drafts:
gb-call GET '/api/v2/features//revisions?status=all-drafts&mine=true'
# All active drafts:
gb-call GET '/api/v2/features//revisions?status=all-drafts'
If the user has no flag ID (returning after a lost session, describing the flag by what it does), query approved drafts across all features:
# Find all approved drafts the user is involved in:
gb-call GET '/api/v2/flag-revisions?status=approved&mine=true'
If the list has one entry, confirm with the user by surfacing the flag ID, revision number, who approved it, and a summary of what changed. If there are multiple, show them all and ask the user to pick.
When no flag ID is known and the user describes the flag by content (e.g. "the boolean flag with the country = US rule"), there is no API filter for rule content — resolution requires fetching each candidate revision, inspecting its rules against the description, and confirming with the user before publishing. Never assume a match.
Capture the version number before continuing.
2. Attempt to publish
echo '{"comment":""}' \
| gb-call POST /api/v2/features//revisions//publish -
Branch on response:
- 2xx → step 6 (done).
- 400 with approval-required body → step 3a.
- 409 → step 3b (merge conflict).
- Other 4xx → halt and surface the raw body.
3a. Approval-required branch
The draft exists but publish is blocked by the org's approval policy. Branch on the revision's status from step 1 — the right response differs:
If pending-review: someone has already been asked to approve. Nothing to do but wait. > "Revision `` is already pending review. Once a teammate approves it in GrowthBook, re-run flag-publish to finish." Stop here.
If approved: the revision is approved but publish is still failing — the issue is the token or org bypass setting, not the review state. Skip option A and present only the bypass options: > "Revision ` is approved but the API key lacks publish permission. Pick one: > > **A. Org-wide bypass** — an admin enables "REST API always bypasses approval requirements" under Settings → General → Approvals. Re-run flag-publish after that. > > **B. Per-token bypass** — use a Personal Access Token whose role grants bypassApprovalChecks on this project. Update GBAPIKEY`, then re-run."
If draft or changes-requested: review hasn't been requested yet. Offer to request it now, and offer to open the UI: > "Your org requires approval before this revision can publish. Options: > > A. Standard review flow (recommended) — I'll request review now. A teammate approves it in GrowthBook, then re-run flag-publish to finish. Want me to open the flag page so your reviewer can find it? > > B. Review in the UI — open the flag page directly and manage the review there. > > C. Org-wide bypass — an admin enables "REST API always bypasses approval requirements" under Settings → General → Approvals. > > D. Per-token bypass — use a Personal Access Token whose role grants bypassApprovalChecks on this project. Update GB_API_KEY, then re-run."
If the user wants the UI opened (option B, or as a companion to A):
# macOS:
open /features/?v=
# Linux:
xdg-open /features/?v=
If the user picks A, request review and stop:
echo '{"comment":"Requesting review — re-run flag-publish after approval"}' \
| gb-call POST /api/v2/features//revisions//request-review -
Do not attempt submit-review — self-approval is rejected server-side.
If the user picks a bypass option, stop with a one-line note. The existing draft picks up the new permission on retry.
Do not silently retry, ignore the error, or discard and recreate to work around the policy.
3b. Merge-conflict branch
A 409 means the draft's base revision is stale — the live flag changed since the draft was created. The draft still exists; it just needs to be rebased before it can publish.
For non-trivial conflicts, the GrowthBook UI is the better tool — it shows a side-by-side diff and lets the user resolve field-by-field visually. Offer to open it:
> "There's a merge conflict on ``. Want to resolve it in the GrowthBook UI (recommended for complex changes), or should I walk through it here?"
If the user wants the UI:
# macOS:
open /features/?v=
# Linux:
xdg-open /features/?v=
Derive ` from GBAPIURL by replacing api. → app. (cloud default: https://app.growthbook.io`). Stop here — tell the user to rebase in the UI and re-run flag-publish when done.
If the user wants to resolve via API, continue:
Step 3b-i: Get the conflict details.
gb-call GET /api/v2/features//revisions//merge-status
Returns { hasConflicts: true, conflicts: [...] }. Each conflict object has:
key— which field collided (defaultValue,rules,prerequisites,environmentsEnabled.)name— human-readable label for the fieldrevision— the draft's valuelive— the current live valuebase— the value when the draft was originally created
Possible conflict keys: defaultValue, rules, prerequisites, environmentsEnabled. (e.g., environmentsEnabled.production).
Step 3b-ii: For each conflict, show the user both versions and ask which to keep.
Use the revision field for the draft's version and live for the current live version. Present them side-by-side and ask:
- overwrite — keep the draft's version (
revisionwins; the concurrent live change is discarded) - discard — keep the live version (
livewins; the draft's change to this field is dropped)
Do not auto-resolve any conflict. Each one requires a human judgment call about which version is correct.
Step 3b-iii: Rebase.
echo '{"conflictResolutions":{"defaultValue":"overwrite","rules":"discard"}}' \
| gb-call POST /api/v2/features//revisions//rebase -
Only include keys for fields that had conflicts.
Step 3b-iv: Retry publish. Return to step 2. The rebased draft should publish cleanly unless new conflicts arose during the rebase (rare).
4. Discard path (abandon the draft entirely)
Confirm clearly before proceeding:
> "Discard revision ` on `? All pending changes in this draft will be permanently lost."
gb-call POST /api/v2/features//revisions//discard
Works on any non-terminal status — draft, pending-review, approved, and changes-requested can all be discarded directly. Only published and discarded are blocked by the server.
5. Revert path (restore a prior published revision)
List recent published revisions so the user can pick a target:
gb-call GET '/api/v2/features//revisions?status=published&limit=10'
Confirm the intent: "Restore flag ` to how it looked at revision (published `)?"
echo '{"strategy":"draft"}' \
| gb-call POST /api/v2/features//revisions//revert -
strategy: "draft" creates a new draft with the prior state — the user reviews it via flag-publish before it goes live. This is the default and recommended path.
strategy: "publish" creates and publishes immediately. Only offer this if the user explicitly asks for an immediate rollback. Org approval settings still apply.
6. Report
- Flag ID and outcome (published / approval-requested / discarded / reverted).
- Revision version and new status (from the publish response).
- UI link — derive `
fromGBAPIURLby replacingapi.→app.(cloud default:https://app.growthbook.io). Open or display:/features/?v=`. - For publish: optionally fetch the full flag state to summarize what's now live:
``bash gb-call GET /api/v2/features/ `` Surface: which environments are enabled, the default value, and a one-line summary of the active rules. Skip this call if the user is in a hurry — the UI link gives them the full picture.
Guardrails
- A 409 is a merge conflict, not a transient error. Don't blindly retry — it will keep failing.
- Never auto-rebase. Each conflict field requires a human decision. Guessing "overwrite" on everything could silently discard concurrent teammate changes.
- Never discard a draft to escape a merge conflict. The draft contains user work. Help them rebase instead.
- Self-approval is blocked server-side. If the user who created the draft tries to approve it in step 3a, it will fail. They need a different reviewer.
- After a successful rebase, the draft is still in
draftstatus. Retry publish explicitly — rebase does not auto-publish. - Discard is irreversible. The draft cannot be recovered. Confirm before calling.
strategy: "publish"on revert bypasses review. Org approval settings may still gate it. Default to"draft"strategy; only offer"publish"when the user explicitly wants an immediate rollback.- Conflict resolution keys are exact strings. For environment-level toggles the key is
environmentsEnabled.(e.g.,environmentsEnabled.production) — include the full string inconflictResolutions. - 400 approval-required vs 403 permission error. A 400 with an approval body means the policy gate is working as intended. A 403 may mean the token lacks permission entirely — check GBAPIKEY permissions if the error body doesn't mention approval.
Endpoints used
GET /api/v2/features/:id/revisions— list revisions for draft selectionGET /api/v2/features/:id/revisions/latest— get most recent draftPOST /api/v2/features/:id/revisions/:version/publish(body: optional comment)GET /api/v2/features/:id/revisions/:version/merge-statusPOST /api/v2/features/:id/revisions/:version/rebase(body:{ conflictResolutions: { key: "overwrite"|"discard" } })POST /api/v2/features/:id/revisions/:version/request-review(approval-required branch only)POST /api/v2/features/:id/revisions/:version/discardPOST /api/v2/features/:id/revisions/:version/revert(body:{ strategy: "draft"|"publish" })
Handoffs
flag-review— for the approval workflow (triggered in step 3a)flag-revisions— to list and inspect drafts before publishing
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: growthbook
- Source: growthbook/skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.