Use for the fabric-cicd Python library (`pip install fabric-cicd`, v1.3 Aug 2026, Python 3.9–3.13) — Microsoft's official code-first CI/CD library for Fabric workspaces: `FabricWorkspace`, `publish_all_items`, `unpublish_all_orphan_items`, `deploy_with_config` + config.yml, and `parameter.yml` (find_replace, key_value_replace, spark_pool, semantic_model_binding, $workspace/$items dynamic vars, $ENV:, _ALL_, regex, extend). Covers the explicit-TokenCredential requirement (v1.0 breaking change)...
Scanned 9/1/2026
Install to Claude Code
npx -y skills add wardawgmalvicious/agent-config --skill fabric-cicd --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Fabric Cicd?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/wardawgmalvicious-fabric-cicd)More formats (shields.io, HTML) on the badges page.
---
name: fabric-cicd
description: "Use for the fabric-cicd Python library (`pip install fabric-cicd`, v1.3 Aug 2026, Python 3.9–3.13) — Microsoft's official code-first CI/CD library for Fabric workspaces: `FabricWorkspace`, `publish_all_items`, `unpublish_all_orphan_items`, `deploy_with_config` + config.yml, and `parameter.yml` (find_replace, key_value_replace, spark_pool, semantic_model_binding, $workspace/$items dynamic vars, $ENV:, _ALL_, regex, extend). Covers the explicit-TokenCredential requirement (v1.0 breaking change), feature flags (enable_lakehouse_unpublish, enable_bulk_publish, enable_shortcut_publish, enable_hard_delete, include/exclude), per-item-type caveats (Warehouse/SQL DB, Lakehouse, Variable Library), Azure DevOps / GitHub Actions + OIDC, Fabric notebook usage, and troubleshooting (change_log_level, FABRIC_CICD_FILE_LOGGING_ENABLED, configure_fabric_fqdn). Invoke when the user mentions fabric-cicd, FabricWorkspace, publish_all_items, parameter.yml, or code-first Fabric deployment from Git."
model: inherit
# effort: medium # unset = inherit session effort; there is no 'effort: inherit'
disable-model-invocation: false
---
# fabric-cicd (Python deployment library)
Microsoft's official open-source Python library for **code-first CI/CD into Fabric workspaces**. It abstracts the Fabric REST item-definition APIs: point it at a Git checkout of a Fabric Git-synced workspace folder and it publishes every in-scope item into the target workspace.
**Version / install:** current is v1.3.x (August 2026). `pip install fabric-cicd` (or `uv add fabric-cicd`). Python 3.9–3.13. Docs: [microsoft.github.io/fabric-cicd](https://microsoft.github.io/fabric-cicd/latest/) · repo: [github.com/microsoft/fabric-cicd](https://github.com/microsoft/fabric-cicd).
**v1.0 (April 2026) was a breaking release**: `token_credential` became **required** — the `DefaultAzureCredential` fallback and implicit Fabric-notebook auth were removed. Any pre-1.0 sample that omits the credential no longer runs.
## Which deployment surface am I on?
| Surface | Source of truth | When |
|---|---|---|
| **fabric-cicd** (this skill) | Git | Python-scripted deploys in ADO / GitHub Actions / notebooks; finest control (feature flags, orphan cleanup, selective publish) |
| `fab deploy --config config.yml` | Git | Same engine, CLI wrapper — one-command deploys; see fabric-cli skill |
| Fabric deployment pipelines (service-side) | Workspace | Dev workspace promoted stage-to-stage in the portal / REST; no local code involved |
`fab deploy` **wraps fabric-cicd** and consumes the same `config.yml` / `parameter.yml`. Don't mix Git-driven deploys and service-side deployment pipelines on the same workspaces. Decision guide: [Choose the best Fabric CI/CD workflow](https://learn.microsoft.com/fabric/cicd/manage-deployment).
## Deployment model
- **Full deployment every run** — no commit-diff inspection. The target workspace converges to the repository state; drift is overwritten. (`get_changed_items(repository_directory, git_compare_ref="HEAD~1")` exists if you want to scope a run yourself.)
- Source layout = what Fabric Git integration writes: `<item-name>.<ItemType>/` folders (plus optional workspace subfolders) and an optional `parameter.yml` / `config.yml` at the repository-directory root. Don't hand-craft item folders — commit them from the portal.
- Only item types with source-control + public-API support are deployable (34 types as of v1.3).
- Deploys into the tenant of the executing identity.
## Quick start
```python
from azure.identity import AzureCliCredential
from fabric_cicd import FabricWorkspace, publish_all_items, unpublish_all_orphan_items
workspace = FabricWorkspace(
workspace_id="<target-workspace-guid>", # or workspace_name=
environment="PROD", # must match parameter.yml env keys
repository_directory="<path-to-workspace-folder>",
item_type_in_scope=["Notebook", "DataPipeline", "Environment"], # omit → all types
token_credential=AzureCliCredential(), # REQUIRED since v1.0
)
publish_all_items(workspace)
unpublish_all_orphan_items(workspace) # delete workspace items not in repo
```
## Core API
```python
FabricWorkspace(*, repository_directory, token_credential,
item_type_in_scope=None, environment="N/A",
workspace_id=None, workspace_name=None)
# workspace_id takes precedence over workspace_name; one is required.
publish_all_items(ws, item_name_exclude_regex=None,
folder_path_exclude_regex=None, folder_path_to_include=None,
items_to_include=None, # ["Name.ItemType", ...]
shortcut_exclude_regex=None)
unpublish_all_orphan_items(ws, item_name_exclude_regex="^$", # default excludes nothing
items_to_include=None)
deploy_with_config(config_file_path, *, token_credential,
environment="N/A", config_override=None) # → DeploymentResult
append_feature_flag(flag) / remove_feature_flag(flag) / get_supported_feature_flags()
change_log_level("DEBUG")
configure_fabric_fqdn(workspace_id) # private-link workspaces — call BEFORE FabricWorkspace
get_changed_items(repository_directory, git_compare_ref="HEAD~1")
```
The selective-publish parameters (`items_to_include`, `folder_path_*`, `shortcut_exclude_regex`) require their **experimental feature flags** (below) or they're ignored.
## Authentication
Pass any `azure.identity` `TokenCredential`:
| Context | Credential |
|---|---|
| Local dev | `AzureCliCredential()` / `AzurePowerShellCredential()` |
| ADO / GitHub SPN | `ClientSecretCredential(client_id=..., client_secret=..., tenant_id=...)` |
| OIDC / federated | `WorkloadIdentityCredential()` |
| Self-hosted agent / Azure VM | `ManagedIdentityCredential()` |
| Fabric notebook | custom wrapper below |
Running **inside a Fabric notebook** (implicit auth was removed):
```python
import time
from azure.core.credentials import TokenCredential, AccessToken
class FabricNotebookCredential(TokenCredential):
def get_token(self, *scopes, **kwargs):
return AccessToken(notebookutils.credentials.getToken("pbi"), int(time.time()) + 3600)
```
The identity needs Contributor+ on the target workspace (Admin for `enable_hard_delete`). SPNs additionally need the tenant setting *Service principals can use Fabric APIs* — same prerequisites as any Fabric REST automation (see fabric-auth skill).
## parameter.yml
Environment-specific value substitution applied to file contents at publish time, keyed by the `environment` passed to `FabricWorkspace`. Lives at the repository-directory root.
### find_replace — string / regex replacement
```yaml
find_replace:
- find_value: "123e4567-e89b-12d3-a456-426614174000" # dev lakehouse GUID as committed
replace_value:
PPE: "f47ac10b-58cc-4372-a567-0e02b2c3d479"
PROD: "9b2e5f4c-8d3a-4f1b-9c3e-2d5b6e4a7f8c"
item_type: "Notebook" # optional filters
item_name: ["Hello World"] # exact, case-sensitive
file_path: "**/notebook-content.py" # abs / relative / glob
```
Optional: `is_regex: "true"` (then `find_value` is a regex; **capture group 1** is what gets replaced — include surrounding context in the pattern), `ignore_case: "true"`.
```yaml
# Re-point a notebook's default lakehouse to the target workspace's copy
- find_value: \#\s*META\s+"default_lakehouse":\s*"([0-9a-fA-F-]{36})"
replace_value:
_ALL_: "$items.Lakehouse.Example_LH.$id"
is_regex: "true"
item_type: "Notebook"
```
### key_value_replace — JSONPath-targeted replacement
```yaml
key_value_replace:
- find_key: $.properties.activities[?(@.name=="Load_Intake")].typeProperties.source.datasetSettings.externalReferences.connection
replace_value:
PPE: "6c517159-d27a-41d5-b71e-ca1ecff6542b"
PROD: "0f2ef3d1-1f34-4e0e-9483-6c8dbc077514"
item_type: "DataPipeline"
```
### spark_pool — Environment-item pool remapping
```yaml
spark_pool:
- instance_pool_id: "72c68dbc-0775-4d59-909d-a47896f4573b"
replace_value:
PPE: { type: "Capacity", name: "CapacityPool_Medium" }
PROD: { type: "Capacity", name: "CapacityPool_Large" }
```
### semantic_model_binding — post-deploy connection binding
```yaml
semantic_model_binding:
default:
connection_id:
_ALL_: "<connection-guid>" # or per-env keys; string or list
models:
- semantic_model_name: "Sales Model"
connection_id:
PPE: "<guid>"
PROD: "<guid>"
```
### Dynamic replacement variables
Usable in `replace_value` (not combinable with `is_regex`):
| Variable | Resolves to |
|---|---|
| `$workspace.$id` / `$workspace.$name` / `$workspace.$name_encoded` | Target workspace id / name / URL-encoded name |
| `$workspace.<name>.$id` | Another workspace's id by name |
| `$items.<Type>.<name>.$id` | Deployed item's id (type/name **case-sensitive**, attribute lowercase) |
| `$items.<Type>.<name>.$sqlendpoint` | Lakehouse / Warehouse / MirroredDatabase / SQLDatabase connection string |
| `$items.<Type>.<name>.$sqlendpointid` | Lakehouse / MirroredDatabase endpoint id |
| `$items.Eventhouse.<name>.$queryserviceuri` | Eventhouse query URI |
### Other mechanics
- `_ALL_` env key = same replacement for every environment.
- `$ENV:var_name` in `replace_value` reads a pipeline/OS environment variable — requires the `enable_environment_variable_replacement` feature flag.
- `extend:` — list of relative paths to split parameter files into templates.
- Validation runs automatically at deploy start (deployment halts on failure); pre-validate with `devtools/debug_parameterization.py`.
- Dynamic variables **disable bulk publish mode**, and using any of them triggers eager SQL-endpoint resolution for all Lakehouses/Warehouses in the target workspace.
## Config-file deployment (`deploy_with_config`)
Single-call deployment driven by a `config.yml` — the same file `fab deploy` consumes. **Every field accepts either a scalar (all envs) or a per-env mapping** (`dev:` / `test:` / `prod:`).
```yaml
core:
workspace_id: # or workspace: <name>; id wins
dev: "8b6e2c7a-..."
prod: "7c3e1f8b-..."
repository_directory: "." # relative to config.yml
item_types_in_scope: [Notebook, DataPipeline, Environment, Lakehouse]
parameter: "parameter.yml"
publish: # optional; omitted → publish everything
exclude_regex: "^DONT_DEPLOY.*"
folder_exclude_regex: { dev: "^/DONT_DEPLOY_FOLDER" } # flag-gated; mutually
folder_path_to_include: { prod: ["/DEPLOY_FOLDER"] } # exclusive per env
items_to_include: ["Hello World.Notebook"] # flag-gated
skip: { dev: true, test: false, prod: false }
unpublish: # optional; omitted → orphans ARE unpublished
exclude_regex: "^DEBUG.*"
skip: { prod: true }
features: # feature flags to enable
- enable_shortcut_publish
constants: # override fabric_cicd.constants values
DEFAULT_API_ROOT_URL: "https://api.fabric.microsoft.com"
```
```python
deploy_with_config("config.yml", token_credential=cred, environment="prod",
config_override={"publish": {"skip": {"prod": False}}})
```
## Feature flags (`append_feature_flag`)
| Flag | Effect |
|---|---|
| `enable_lakehouse_unpublish` / `enable_warehouse_unpublish` / `enable_sqldatabase_unpublish` / `enable_eventhouse_unpublish` / `enable_kqldatabase_unpublish` | Allow orphan deletion of **data-bearing items** — off by default as data-loss protection |
| `enable_hard_delete` | Bypass workspace recycle bin on unpublish; requires workspace **Admin** |
| `enable_shortcut_publish` / `continue_on_shortcut_failure` | Deploy Lakehouse shortcuts / tolerate shortcut failures |
| `disable_workspace_folder_publish` | Don't create workspace subfolders |
| `enable_environment_variable_replacement` | Activate `$ENV:` in parameter.yml |
| `enable_response_collection` | `publish_all_items` returns collected API responses |
| `enable_experimental_features` + `enable_bulk_publish` | Single bulk-import API call instead of per-item (beta; non-prod) |
| `enable_experimental_features` + `enable_items_to_include` / `enable_exclude_folder` / `enable_include_folder` / `enable_shortcut_exclude` | Activate the selective-publish parameters |
Enumerate at runtime: `get_supported_feature_flags()`.
## Item-type caveats (the ones that bite)
- **Warehouse / SQL Database**: **shell only** — no tables/views/procs deployed. Pair with SqlPackage/dacpac for schema (see fabric-database skill).
- **Lakehouse**: shell + (flag-gated) shortcuts; schemas only deployed when a schema contains a shortcut. Deletion blocked unless `enable_lakehouse_unpublish`.
- **Notebook**: `.py` and `.ipynb` supported; attached-lakehouse GUIDs need parameterization (regex example above); notebook resources aren't source-controlled.
- **Environment**: custom pool references need the `spark_pool` section; resources not source-controlled.
- **Semantic Model / Report**: use `semantic_model_binding` for connections; report→model rebinding handled when both deploy together.
- **Dataflow**: same-workspace dependencies auto-ordered; first deployment still needs a manual publish/refresh.
- **Variable Library**: the **active value set is selected by the `environment` value** — the deploy picks the value set matching the environment name.
- **Eventhouse / KQL Database**: parameterization not applied to these types; KQL table data not source-controlled.
- **Data Pipeline / Copy Job / Mirrored Database / Paginated Report**: connection references are **not** source-controlled — parameterize connection GUIDs (`key_value_replace` on `externalReferences.connection`) and pre-create connections in the target.
- **ML Experiment / Mounted Data Factory**: shell only / requires the external ADF to exist.
Full 34-type matrix: [reference/item_types](https://microsoft.github.io/fabric-cicd/latest/reference/item_types/).
## Pipeline wiring (ADO / GitHub Actions)
Canonical pattern — auth step establishes an Azure context, then a plain Python step runs the deploy script:
- **Azure DevOps**: `AzureCLI@2` or `AzurePowerShell@5` task with a service connection, inline step runs `python deploy.py`; SPN secrets via a Key-Vault-linked variable group. Tutorial: [CI/CD with Azure DevOps + fabric-cicd](https://learn.microsoft.com/fabric/cicd/tutorial-fabric-cicd-azure-devops).
- **GitHub Actions**: `azure/login` with **OIDC federated credentials** (`permissions: id-token: write`), branch→environment mapping via `environment: ${{ github.ref_name }}`, workspace ids from environment-scoped `vars`/`secrets`.
- Inside the script, branch/environment name selects the `environment` argument, which selects the parameter.yml / config.yml env keys.
Full YAML: [example/release_pipeline](https://microsoft.github.io/fabric-cicd/latest/example/release_pipeline/).
## Troubleshooting
| Symptom | Cause / fix |
|---|---|
| 401 / "credential required" | v1.0 removed implicit auth — pass an explicit `TokenCredential`; check workspace role |
| Old sample without `token_credential` fails | Same breaking change — update the constructor call |
| Parameter not substituted | Env name mismatch with `replace_value` keys; `find_value` not byte-exact; validate with `devtools/debug_parameterization.py` |
| Item deploy fails, vague error | `change_log_level()` + set `FABRIC_CICD_FILE_LOGGING_ENABLED` — full stack traces go **only** to `fabric_cicd.error.log` |
| Recreate-after-delete fails | Wait ~5 min between deleting and recreating an item with the same name |
| Orphan Lakehouse/Warehouse not deleted | Intentional — needs the matching `enable_*_unpublish` flag |
| `items_to_include` / folder filters ignored | Missing `enable_experimental_features` + the specific flag |
| Bulk publish "Dependencies could not be resolved" | All dependent items must be in the same batch; also: dynamic parameter variables disable bulk mode |
| Private-link workspace unreachable | `configure_fabric_fqdn(workspace_id)` **before** constructing `FabricWorkspace` |
| 429 rate limiting | Smaller batches; retry-after in the error log |
| Selective run wanted despite full-deploy model | `get_changed_items()` + `items_to_include`, or accept full deploys (the design intent) |
## Reference
- Docs: [microsoft.github.io/fabric-cicd](https://microsoft.github.io/fabric-cicd/latest/) — [getting started](https://microsoft.github.io/fabric-cicd/latest/how_to/getting_started/) · [parameterization](https://microsoft.github.io/fabric-cicd/latest/how_to/parameterization/) · [config deployment](https://microsoft.github.io/fabric-cicd/latest/how_to/config_deployment/) · [feature flags](https://microsoft.github.io/fabric-cicd/latest/how_to/optional_feature/) · [troubleshooting](https://microsoft.github.io/fabric-cicd/latest/how_to/troubleshooting/) · [changelog](https://microsoft.github.io/fabric-cicd/latest/changelog/)
- Microsoft Learn: [Fabric ci-cd overview](https://learn.microsoft.com/rest/api/fabric/articles/fabric-ci-cd) · [Choose the best CI/CD workflow](https://learn.microsoft.com/fabric/cicd/manage-deployment) · [ADO tutorial](https://learn.microsoft.com/fabric/cicd/tutorial-fabric-cicd-azure-devops)
- Repo: [github.com/microsoft/fabric-cicd](https://github.com/microsoft/fabric-cicd) (issues, `devtools/` debug scripts)
## See also
- fabric-cli skill — `fab deploy` wrapper over this library; service-side deployment-pipeline REST via `fab api -A powerbi`
- fabric-auth skill — token audiences, SPN setup, 401 debugging
- fabric-rest-api skill — the underlying item-definition / LRO API patterns
- fabric-variable-library skill — value-set selection semantics this library keys off `environment`
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!