Skip to content
AI & Agents
Skill

/experience-ui-bundle-2gp-deploy

MUST activate when the user wants to package, distribute, or install/upgrade/uninstall/promote a UI Bundle as a Salesforce second-generation (2GP) package (project may contain uiBundles/ or sfdx-project.json for packaging tasks; install/upgrade tasks may lack local bundle

From plugin
forcedotcom-sf-skills
997200 skills2 agents14 commands3 MCP
Install
$ npx -y skills add forcedotcom/afv-library --skill experience-ui-bundle-2gp-deploy --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/experience-ui-bundle-2gp-deploy

Context preview

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

MUST activate when the user wants to package, distribute, or install/upgrade/uninstall/promote a UI Bundle as a Salesforce second-generation (2GP) package (project may contain uiBundles/ or sfdx-project.json for packaging tasks; install/upgrade tasks may lack local bundle

SKILL.md

experience-ui-bundle-2gp-deploy.SKILL.md
name: experience-ui-bundle-2gp-deploy
description: "MUST activate when the user wants to package, distribute, or install/upgrade/uninstall/promote a UI Bundle as a Salesforce second-generation (2GP) package (project may contain uiBundles/ or sfdx-project.json for packaging tasks; install/upgrade tasks may lack local bundle files). Handles making a bundle packageable, choosing managed/unlocked flavor, creating package/version with sf package, installing/upgrading in another org, and debugging failures. TRIGGER on packaging, 2GP, managed package, unlocked package, AppExchange, package version, sf package, sf package install, sf package upgrade, install a package, upgrade a package, cross-org distribution. DO NOT TRIGGER for plain source deploy to one org (use experience-ui-bundle-deploy) or scaffolding a new bundle (use experience-ui-bundle-project-generate). Apply piecemeal — do ONLY the part asked."
metadata:
  version: "1.0"
  domains: ["Experience"]
  minApiVersion: "58.0"
  relatedSkills:
    - "experience-ui-bundle-deploy"
    - "experience-ui-bundle-project-generate"
  accessCheck:
    - type: "orgPref"
      value: "Package2Enabled"
  cliTools:
    - tool: ["jq"]
      semver: ">=1.6"
    - tool: ["node"]
      semver: ">=18.0.0"
    - tool: ["npm"]
      semver: ">=7.0.0"
    - tool: ["sf"]
      semver: ">=2.0.0"

Package an existing UI Bundle (2GP)

How to take a **UI Bundle that already exists in the current project** (under `<packageDir>/uiBundles/<name>/`, where `<packageDir>` is the package directory from `sfdx-project.json` — commonly `force-app/main/default`) and ship it as a **second-generation package** (2GP), then install / upgrade / uninstall it in another org.

**This is reference knowledge, not a runbook to execute top-to-bottom.** The user already has a project and a built (or buildable) bundle. Read their intent and apply only the matching part:

**Answer only what was asked.** Give the commands for the one part the user needs plus the org each targets and any genuine caveat — nothing else. Do **not** restate the other parts, re-explain the flavor table, or replay the full build→create→install→promote sequence when the user asked about a single step. A debug question wants the fix, not a packaging tutorial; an install question wants the `sf package install` line and the subscriber-vs-Dev-Hub distinction, not Part 1 and Part 2. Brevity is correctness here.

| The user wants to… | Go to | |---|---| | Decide managed vs. unlocked | [Choose a flavor](#choose-a-flavor) | | Make the bundle packageable / wire a CustomApplication | [Part 1](#part-1--make-the-existing-bundle-packageable) | | Create the package or a new version | [Part 2](#part-2--create-the-package-dev-hub-only) | | Install / upgrade / uninstall / promote | [Part 3](#part-3--install--upgrade--uninstall--promote) | | Debug a failure | [Part 4](#part-4--debug--inspect) + [Troubleshooting](#troubleshooting) |

This skill is for **packaging and cross-org distribution** (`sf package …`). For plain source deploy of a bundle into one org (`sf project deploy …`), use **experience-ui-bundle-deploy** instead. Never `sf project generate` or `sf template generate ui-bundle` here — the project and bundle exist. `MyReactApp` / `force-app` / `force-app/main/default` are placeholders; substitute the user's real bundle name and their `<packageDir>` everywhere they appear below. Resolve `<packageDir>` deterministically — never guess `[0]` in a multi-package project — with:

packageDir="$(scripts/find-bundle-package-dir.sh <bundleName>)"   # walks packageDirectories; picks the entry whose tree contains uiBundles/<bundleName>/

---

Step 0 — Confirm the orgs (do this before touching any org)

Do **not** assume the default org. Ask the user, or read `sf org list`, then restate what you'll use:

  • **Dev Hub** (`devhub`) — where the package is created, versions are built, and

source is deployed. **Always required.**

  • **Subscriber** (`subscriber`) — the org you install into. **Only required for

install / upgrade / uninstall.**

sf org list                                            # connected orgs + default Dev Hub
sf org list --json | jq -r '.result.nonScratchOrgs[]?.alias'

Rules:

  • **Create-only task** (package or version) → one Dev Hub is enough; **don't ask

for a subscriber.**

  • **Install task** → confirm **both**, and confirm *which is which*. Installing

into the Dev Hub by mistake is a common, messy error.

Substitute the real aliases for `devhub` / `subscriber` everywhere below.

**ID legend (packaging):** `0Ho…` package · `04t…` installable version (SubscriberPackageVersionId) · `05i…` Package2Version · `08c…` version-create request · `0Hf…` install request · `06y…` uninstall request.

**ID legend (runtime, useful when debugging a broken subscriber):** `9YE…` UI Bundle row · `9YF…` UIBundleApplication junction · `02u…` CustomApplication / TabSet · `0Zu…` ManagedContentSpace (workspace) · `0ap…` ManagedContentChannel (WEB_APP). A missing App Launcher tile after install almost always traces back to one of these being absent or misprovisioned.

---

Prerequisite — the 2GP toggle everyone forgets

2GP needs a **manual Setup toggle on the Dev Hub** that no CLI command or metadata deploy can flip. **Setup → Dev Hub**, both on:

1. **Enable Dev Hub**, and 2. **Enable Unlocked Packages and Second-Generation Managed Packages** ← the real gate.

Until #2 is on, `sf package create` returns `NOT_FOUND` and any `Package2` query returns `sObject type 'Package2' is not supported`. There is no CLI workaround — flip the toggle. Verify before starting:

# clean "0 records" = 2GP ON;  "sObject type 'Package2' is not supported" = toggle OFF
sf data query --target-org devhub --use-tooling-api --query "SELECT Id FROM Package2 LIMIT 1"
sf org display --target-org devhub --json | jq '.result.isDevHub'

---

Choose a flavor

All three are 2GP (same `sf package` CLI). Pick before crea

Read more
Ships withforcedotcom-sf-skills

This repository provides a curated collection of Salesforce agent skills for building applications.

Get the whole plugin

Other skills on forcedotcom-sf-skills.