DevOps Center Pipeline Management
Manages the complete pipeline lifecycle in DevOps Center — from creation against a repository, through stage and environment configuration and project attachment, to activation of a ready-to-promote release pipeline. Provides headless CLI-driven operations for autonomous release workflows.
Scope
- In scope: List pipelines, get pipeline details, create a pipeline (linked to an existing or new Git repo), add/delete/rename stages, add/delete Salesforce environments on stages, attach/detach projects, and activate/deactivate/rename the pipeline
- Out of scope: Work-item lifecycle, promotion/deployment execution, conflict detection, standalone project creation (separate skills)
Required Inputs
Gather or infer before proceeding:
- Operation type: list, get, create, add-stage, delete-stage, rename-stage, add-environment, delete-environment, attach-project, detach-project, activate, or deactivate
- For get / any stage or environment op: pipeline ID (required) — obtain via
sf devops pipeline list --json
- For create: pipeline name (required) and a Git repo (
--repo, required). Repo flags differ by scenario:
- Existing repo (GitHub or Bitbucket): only --repo <url> — do not pass --repo-type/--create-repo - New GitHub repo: --repo <name> --create-repo --repo-type github --repo-owner <org-or-user> - New Bitbucket repo: --repo <name> --create-repo --repo-type bitbucket --bitbucket-workspace <workspace> (--bitbucket-project-key <key> optional) - Description (--description) optional in all cases
- For add-stage: pipeline ID, new stage name, and
--next-stage-id (the stage the new one precedes) — get stage IDs via sf devops pipeline get
- For add-environment: pipeline ID, stage ID, environment name, and
--org-type (Production or Sandbox)
- For attach/detach-project: pipeline ID and project ID
- For activate/deactivate/rename: pipeline ID
Defaults unless specified:
- Output format:
--json for headless consumption
- Target org: use
--target-org <alias> if not relying on the default org
If the user gives a clear request ("create a pipeline on repo myorg/myrepo", "add a UAT stage before Production", "activate pipeline 0XB..."), proceed immediately without unnecessary questions.
Workflow
All operations use sf devops pipeline and sf devops stage CLI commands with --json output for structured consumption. Pipeline IDs and stage IDs are the primary identifiers — resolve them via list and get before mutating.
Phase 1 — Identify Operation
- Determine the operation type from user intent:
- "list", "show all pipelines" → list; "details of pipeline", "show stages" → get - "create", "set up", "new pipeline" → create - "add stage", "insert stage" → add-stage; "rename stage" → rename-stage; "remove/delete stage" → delete-stage - "connect environment", "add org to stage" → add-environment; "remove environment" → delete-environment - "attach project", "connect project" → attach-project; "detach project" → detach-project - "activate", "turn on"; "deactivate", "turn off"; "rename pipeline" → lifecycle update
Phase 2 — Execute Operation
- Verify org authentication before any operation:
``bash sf org display --json ` - If no default org is set or auth has expired, instruct the user to run sf org login web --set-default --alias <alias> - Confirm the org has DevOps Center enabled by running sf devops pipeline list --json - Add --target-org <alias>` to every command when targeting a specific org
- Inspect pipelines:
``bash sf devops pipeline list --json # all pipelines in the org sf devops pipeline get --pipeline-id <pipeline-id> --json # one pipeline, with stages/repos/projects ` - list returns SObject records under .result.pipelines[] with capitalized fields (.Id, .Name, .IsActive) — it does not include stages or connected projects - get returns a single pipeline under .result with camelCase fields (.id, .name, .stages[], .connectedProjects[]); each stage has .id, .name, .nextStageId, .branchName, and .environment.{id,name}. Stages are a linked list — order is defined by nextStageId, and the terminal stage has nextStageId: null. Use get` to discover stage IDs before any stage or environment operation
- Create a pipeline — the pipeline must be linked to a Git repository.
--name and --repo are always required; the remaining flags depend on the repo scenario:
```bash # Existing repo (GitHub or Bitbucket) — pass the full repo URL, nothing else sf devops pipeline create --name "<pipeline-name>" --repo <repo-url> --json
# New GitHub repo — requires --repo-owner sf devops pipeline create --name "<pipeline-name>" --repo <repo-name> \ --create-repo --repo-type github --repo-owner <org-or-user> --json
# New Bitbucket repo — requires --bitbucket-workspace (--bitbucket-project-key optional) sf devops pipeline create --name "<pipeline-name>" --repo <repo-name> \ --create-repo --repo-type bitbucket --bitbucket-workspace <workspace> \ --bitbucket-project-key <key> --json
# Custom stage chain (any scenario) — repeat --stage in promotion order sf devops pipeline create --name "<pipeline-name>" --repo <repo-url> \ --stage Dev --stage QA --stage Prod --json `` - Provider-specific required flags: GitHub new repo → --repo-owner; Bitbucket new repo → --bitbucket-workspace. Omitting the provider's required flag fails the create - Do not pass --repo-type/--create-repo for an existing repo — supply only the repo URL via --repo - Custom stages at create time: a new pipeline seeds the default stage chain Integration → UAT → Staging → Production. To seed different stages, repeat -s/--stage once per stage in promotion order — e.g. --stage Dev --stage QA --stage Prod. This avoids adding/renaming stages afterward - Add --description "<text>" optionally in any scenario - Capture the returned pipeline ID for subsequent stage/environment/project/activation steps - Idempotency: the CLI does not dedupe. Before creating, run sf devops pipeline list --json and check for a pipeline with the same name/repo; return the existing one if found. See references/parsing-patterns.md` for the check-before-create snippet
- Configure stages — a stage is added relative to an existing stage, then bound to an environment. Read
references/cli-commands.md for full flag details before multi-stage work:
``bash # Insert an empty stage BEFORE an existing stage (get the next-stage-id from pipeline get) sf devops pipeline stage add --pipeline-id <id> --name "<stage-name>" --next-stage-id <stage-id> --json # Rename a stage sf devops pipeline stage update --pipeline-id <id> --stage-id <stage-id> --name "<new-name>" --json # Delete a stage (predecessor auto-relinks to successor) sf devops pipeline stage delete --pipeline-id <id> --stage-id <stage-id> --json ` - stage add inserts an empty stage (no branch/environment) before --next-stage-id`; configure its environment separately - Build the promotion chain by inserting each new stage before the stage that should follow it
- Bind environments to stages — attach a Salesforce org to a stage:
``bash # Validate the org-type against the fixed enum BEFORE calling the CLI bash scripts/validate-org-type.sh "<Production|Sandbox>" # exits non-zero on an invalid value sf devops stage environment add --pipeline-id <id> --stage-id <stage-id> \ --environment-name "<env-name>" --org-type <Production|Sandbox> --json # Remove an environment (pipeline must be inactive) sf devops stage environment delete --pipeline-id <id> --environment-id <env-id> --json ` - --org-type must be exactly Production or Sandbox — run scripts/validate-org-type.sh <value> first and only proceed on exit 0 - Headless caveat: stage environment add triggers an OAuth browser flow. In headless/CI runs pass --no-browser` — the CLI prints a redirect URL for manual authentication
- Attach / detach a project — a project can be attached to only one pipeline:
``bash sf devops pipeline project add --pipeline-id <id> --project-id <project-id> --json sf devops pipeline project delete --pipeline-id <id> --project-id <project-id> --json ` - If the user names a project instead of providing its ID, resolve it via sf devops project list --json (see references/parsing-patterns.md`)
- Activate / deactivate / rename the pipeline:
``bash # Before activating, confirm the deterministic ≥1-stage prerequisite bash scripts/check-activation-ready.sh <id> [target-org] # exits non-zero if stage-less sf devops pipeline update --pipeline-id <id> --activate --json # activate sf devops pipeline update --pipeline-id <id> --deactivate --json # deactivate sf devops pipeline update --pipeline-id <id> --name "<new-name>" --json # rename ` - Before --activate, run scripts/check-activation-ready.sh <id> and only proceed on exit 0 — it fails with an actionable message when the pipeline has no stages - Stages cannot be modified after the pipeline is activated and changes are promoted through it — finish stage/environment configuration before activating - --activate and --deactivate are mutually exclusive; --deactivate and --name` may be combined in one command
Phase 3 — Verify and Report
- Verify operation success — use
scripts/verify-operation.sh, which performs the deterministic JSON-status and post-state field checks and exits non-zero with an actionable message on mismatch:
``bash # Assert a captured command's JSON status is 0 (pipe the CLI output in) sf devops pipeline update --pipeline-id <id> --activate --json | bash scripts/verify-operation.sh status - # Assert post-state after activate / stage / project ops bash scripts/verify-operation.sh active <id> true [target-org] # isActive == true bash scripts/verify-operation.sh has-stage <id> "<stage>" [target-org] # stage present in chain bash scripts/verify-operation.sh has-project <id> "<project>" [target-org] # project connected ` - Create: confirm the pipeline appears in sf devops pipeline list --json by .Name and capture its .Id - Stage / environment / project changes: verify with the has-stage / has-project modes above (they read sf devops pipeline get and check .result.stages[] / .result.connectedProjects[]) - Activate: verify with the active <id> true` mode
- Report results:
- List: pipeline name, ID, and active state per pipeline (no stages — that's what get is for) - Get: pipeline name, ID, active state, stage chain (each stage's name → environment → branch, ordered via nextStageId), connected projects - Create: pipeline ID, name, and linked repo (or "existing pipeline returned" on idempotent match) - Stage / environment / project op: the resulting stage chain with each stage's environment, in promotion order - Lifecycle: the new active state and/or name
Verification Checklist (gate before reporting success)
Confirm the items for the operation you performed. Do not report success until every applicable box holds:
Rules / Constraints
| Constraint |
Rationale |
All sf devops commands must use --json flag |
Structured output is required for headless consumption; human-readable output is unreliable for parsing |
| A pipeline requires a Git repo at create time |
sf devops pipeline create requires --name and --repo; for an existing repo pass only the URL, for a new repo add --create-repo and --repo-type |
| New-repo create needs provider-specific flags |
GitHub requires --repo-owner; Bitbucket requires --bitbucket-workspace (--bitbucket-project-key optional). The wrong provider's flags fail the command |
| Pipeline ID required for get, update, and all stage/environment/project ops |
These commands identify the pipeline only by --pipeline-id; obtain it via sf devops pipeline list |
Stage IDs come from pipeline get |
stage add (--next-stage-id), stage update/delete (--stage-id), and stage environment add (--stage-id) all need stage IDs |
stage add inserts an empty stage before --next-stage-id |
Stages carry no environment until one is added; build the chain by anchoring to the following stage |
--org-type must be exactly Production or Sandbox |
The flag is a fixed enum; other values fail |
| Pipeline must have ≥1 stage before activation |
sf devops pipeline update --activate rejects a stage-less pipeline |
| Do not modify stages after activate + promote |
DevOps Center locks stage structure once changes have been promoted through an active pipeline |
| Environment delete requires an inactive pipeline |
stage environment delete only succeeds while the pipeline is inactive |
| A project attaches to only one pipeline |
pipeline project add fails if the project is already attached elsewhere; detach first |
| Idempotent create via check-before-create |
The CLI does not dedupe; list existing pipelines and return the match instead of erroring |
Prefer --no-browser in headless runs |
stage environment add opens an OAuth browser flow; --no-browser prints a redirect URL for CI |
Gotchas
| Issue |
Resolution |
| No default org set |
Run sf org display --json first; if it fails, instruct user to run sf org login web --set-default |
| Create fails — missing repo |
--repo is required; pass an existing repo URL, or --create-repo + --repo-type for a new repo |
| New-repo create fails — missing provider flag |
GitHub new repo needs --repo-owner; Bitbucket new repo needs --bitbucket-workspace. Don't mix providers' flags (--repo-owner with bitbucket, or --bitbucket-workspace with github) |
stage add fails — no next-stage-id |
--next-stage-id is required; run sf devops pipeline get --pipeline-id <id> --json to find the stage IDs and pick the one the new stage should precede |
| Environment add hangs in CI |
The OAuth browser flow blocks headless runs; add --no-browser and complete auth via the printed redirect URL |
| Activation rejected |
The pipeline needs at least one stage; add a stage (and its environment) before --activate |
| Cannot modify stages |
The pipeline is active and has promoted changes; stage structure is locked — configuration must complete before activation |
| Environment delete fails |
The pipeline is active; deactivate with pipeline update --deactivate before deleting the environment |
| Project already attached |
A project attaches to only one pipeline; detach from the other pipeline first via pipeline project delete |
| Pipeline / stage / project not found |
The ID is invalid; run sf devops pipeline list --json, sf devops pipeline get --json, or sf devops project list --json to find valid IDs |
Output Expectations
Deliverables vary by operation:
- List: pipelines with ID, name, and active state (no stages/projects in the list view)
- Get: a pipeline with ID, name, active state, its stage chain (each with environment and branch, ordered via
nextStageId), and connected projects
- Create: pipeline ID, name, and linked repository (or the pre-existing pipeline on idempotent match)
- Stage op: the updated ordered stage chain
- Environment op: the stage with its bound environment (name, org-type)
- Project op: confirmation of attach/detach
- Lifecycle: the new active state and/or pipeline name
Outputs are derived from sf devops pipeline and sf devops stage CLI commands.
Cross-Skill Integration
| Delegate to |
When |
dx-devops-work-item-manage |
The user wants to create or advance work items once the pipeline is active |
If a project the user wants to attach can't be found, resolve or list existing projects with sf devops project list --json (see references/parsing-patterns.md) rather than delegating — project creation is out of scope for this skill.
Reference File Index
| File |
When to read |
references/cli-commands.md |
When you need detailed CLI flag documentation and JSON output schemas for each sf devops pipeline / sf devops stage command |
references/parsing-patterns.md |
When you need jq snippets to parse the JSON (stage chains, pipeline/project ID resolution), error-handling reference, the check-before-create idempotent pattern, or auth requirements |
examples/common-workflows.md |
When the user's request matches a common pattern (end-to-end pipeline setup, inserting a stage, binding an environment, attaching a project, activation) |
scripts/validate-org-type.sh |
Run before stage environment add to validate --org-type against the Production/Sandbox enum |
scripts/check-activation-ready.sh |
Run before pipeline update --activate to confirm the pipeline has ≥1 stage |
scripts/verify-operation.sh |
Run in Phase 3 to assert a command's JSON status and post-state fields (status / active / has-stage / has-project) |