skills/codex/databricks-spark-declarative-pipelines/SKILL.md
<!-- AUTO-GENERATED by export-skills.py — DO NOT EDIT --> --- name: databricks-spark-declarative-pipelines --- # Lakeflow Spark Declarative Pipelines (SDP) ## Quick Reference | Concept | Details | | ---------------------- | ------------------------------------------------------------------------------------------------------------------- | | **Names** | SDP =
npx skillsauth add frank-luongt/faos-skills-marketplace skills/codex/databricks-spark-declarative-pipelinesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
| Concept | Details |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------- |
| Names | SDP = Spark Declarative Pipelines = LDP = Lakeflow Declarative Pipelines = Lakeflow Pipelines (all interchangeable) |
| Python Import | from pyspark import pipelines as dp |
| Primary Decorators | @dp.table(), @dp.materialized_view() |
| Replaces | Delta Live Tables (DLT) with import dlt |
| Based On | Apache Spark 4.1+ (Databricks' modern data pipeline framework) |
| Docs | https://docs.databricks.com/aws/en/ldp/developer/python-dev |
pyspark.pipelines APIRECOMMENDED: Use databricks pipelines init to create production-ready Asset Bundle projects
with multi-environment support.
Use bundle initialization for New pipeline projects for a professional structure from the start
Use manual workflow for:
I will automatically run this command when you request a new pipeline:
databricks pipelines init
Interactive Prompts:
customer_orders_pipelinemain, prod_catalog)yes for dev (each user gets their own schema), no for prodGenerated Structure:
my_pipeline/
├── databricks.yml # Multi-environment config (dev/prod)
├── resources/
│ └── *_etl.pipeline.yml # Pipeline resource definition
└── src/
└── *_etl/
├── explorations/ # Exploratory code in .ipynb
└── transformations/ # Your .sql or .py files here
Replace the example code created by the init process with custom transformation files in
src/transformations/ based on provided requirements, using best practice guidance from this skill.
# Deploy to workspace (dev by default)
databricks bundle deploy
# Run pipeline
databricks bundle run my_pipeline_etl
# Deploy to production
databricks bundle deploy --target prod
I can run these commands for you using the Bash tool.
For medallion architecture (bronze/silver/gold), two approaches work:
bronze_*.sql, silver_*.sql, gold_*.sqlbronze/orders.sql, silver/cleaned.sql, gold/summary.sqlBoth work with the transformations/** glob pattern. Choose based on preference.
See 8-project-initialization.md for complete details on bundle initialization, migration, and troubleshooting.
For rapid prototyping, experimentation, or when you prefer direct control without Asset Bundles, use the manual workflow with MCP tools.
Use MCP tools to create, run, and iterate on serverless SDP pipelines. The primary tool is
create_or_update_pipeline which handles the entire lifecycle.
IMPORTANT: Always create serverless pipelines (default). Only use classic clusters if user explicitly requires R language, Spark RDD APIs, or JAR libraries.
Create .sql or .py files in a local folder:
my_pipeline/
├── bronze/
│ ├── ingest_orders.sql # SQL (default for most cases)
│ └── ingest_events.py # Python (for complex logic)
├── silver/
│ └── clean_orders.sql
└── gold/
└── daily_summary.sql
SQL Example (bronze/ingest_orders.sql):
CREATE OR REFRESH STREAMING TABLE bronze_orders
CLUSTER BY (order_date)
AS
SELECT
*,
current_timestamp() AS _ingested_at,
_metadata.file_path AS _source_file
FROM read_files(
'/Volumes/catalog/schema/raw/orders/',
format => 'json',
schemaHints => 'order_id STRING, customer_id STRING, amount DECIMAL(10,2), order_date DATE'
);
Python Example (bronze/ingest_events.py):
from pyspark import pipelines as dp
from pyspark.sql.functions import col, current_timestamp
@dp.table(name="bronze_events", cluster_by=["event_date"])
def bronze_events():
return (
spark.readStream.format("cloudFiles")
.option("cloudFiles.format", "json")
.load("/Volumes/catalog/schema/raw/events/")
.withColumn("_ingested_at", current_timestamp())
.withColumn("_source_file", col("_metadata.file_path"))
)
Language Selection:
See 8-project-initialization.md for detailed language detection logic.
# MCP Tool: upload_folder
upload_folder(
local_folder="/path/to/my_pipeline",
workspace_folder="/Workspace/Users/[email protected]/my_pipeline"
)
Use create_or_update_pipeline - the main entry point. It:
id from extra_settings)# MCP Tool: create_or_update_pipeline
result = create_or_update_pipeline(
name="my_orders_pipeline",
root_path="/Workspace/Users/[email protected]/my_pipeline",
catalog="my_catalog",
schema="my_schema",
workspace_file_paths=[
"/Workspace/Users/[email protected]/my_pipeline/bronze/ingest_orders.sql",
"/Workspace/Users/[email protected]/my_pipeline/silver/clean_orders.sql",
"/Workspace/Users/[email protected]/my_pipeline/gold/daily_summary.sql"
],
start_run=True, # Start immediately
wait_for_completion=True, # Wait and return final status
full_refresh=True, # Full refresh all tables
timeout=1800 # 30 minute timeout
)
Result contains actionable information:
{
"success": True, # Did the operation succeed?
"pipeline_id": "abc-123", # Pipeline ID for follow-up operations
"pipeline_name": "my_orders_pipeline",
"created": True, # True if new, False if updated
"state": "COMPLETED", # COMPLETED, FAILED, TIMEOUT, etc.
"catalog": "my_catalog", # Target catalog
"schema": "my_schema", # Target schema
"duration_seconds": 45.2, # Time taken
"message": "Pipeline created and completed successfully in 45.2s. Tables written to my_catalog.my_schema",
"error_message": None, # Error summary if failed
"errors": [] # Detailed error list if failed
}
On Success:
if result["success"]:
# Verify output tables
stats = get_table_details(
catalog="my_catalog",
schema="my_schema",
table_names=["bronze_orders", "silver_orders", "gold_daily_summary"]
)
On Failure:
if not result["success"]:
# Message includes suggested next steps
print(result["message"])
# "Pipeline created but run failed. State: FAILED. Error: Column 'amount' not found.
# Use get_pipeline_events(pipeline_id='abc-123') for full details."
# Get detailed errors
events = get_pipeline_events(pipeline_id=result["pipeline_id"], max_results=50)
get_pipeline_eventsupload_foldercreate_or_update_pipeline again (it will update, not recreate)result["success"] == True| Tool | Description |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| create_or_update_pipeline | Main entry point. Creates or updates pipeline, optionally runs and waits. Returns detailed status with success, state, errors, and actionable message. |
| Tool | Description |
| ----------------------- | ------------------------------------------------------- |
| find_pipeline_by_name | Find existing pipeline by name, returns pipeline_id |
| get_pipeline | Get pipeline configuration and current state |
| start_update | Start pipeline run (validate_only=True for dry run) |
| get_update | Poll update status (QUEUED, RUNNING, COMPLETED, FAILED) |
| stop_pipeline | Stop a running pipeline |
| get_pipeline_events | Get error messages for debugging failed runs |
| delete_pipeline | Delete a pipeline |
| Tool | Description |
| ------------------- | -------------------------------------------------------- |
| upload_folder | Upload local folder to workspace (parallel) |
| get_table_details | Verify output tables have expected schema and row counts |
| execute_sql | Run ad-hoc SQL to inspect data |
Load these for detailed patterns:
dp API vs legacy dlt API comparisonextra_settings parameter
reference and examplesdatabricks pipelines init, Asset Bundles, language detection, and migration guidesdatabricks pipelines init for new projects (creates Asset Bundle)bronze_*.sql, silver_*.sql, gold_*.sql in
transformations/transformations/bronze/, transformations/silver/,
transformations/gold/transformations/** glob pattern - choose based on team preference.sql/.py files, not notebooksModern SDP Best Practice:
spark.read.table() for batch readsspark.readStream.table() for streaming readsdp.read() or dp.read_stream() (old syntax, no longer documented)dlt.read() or dlt.read_stream() (legacy DLT API)Key Point: SDP automatically tracks table dependencies from standard Spark DataFrame operations. No special read APIs are needed.
SDP supports three levels of table name qualification:
| Level | Syntax | When to Use |
| ----------------------- | --------------------------------------------------------- | ----------------------------------------------------------------------------- |
| Unqualified | spark.read.table("my_table") | Reading tables within the same pipeline's target catalog/schema (recommended) |
| Partially-qualified | spark.read.table("other_schema.my_table") | Reading from different schema in same catalog |
| Fully-qualified | spark.read.table("other_catalog.other_schema.my_table") | Reading from external catalogs/schemas |
Best practice for tables within the same pipeline. SDP resolves unqualified names to the pipeline's configured target catalog and schema. This makes code portable across environments (dev/prod).
@dp.table(name="silver_clean")
def silver_clean():
# Reads from pipeline's target catalog/schema (e.g., dev_catalog.dev_schema.bronze_raw)
return (
spark.read.table("bronze_raw")
.filter(F.col("valid") == True)
)
@dp.table(name="silver_events")
def silver_events():
# Streaming read from same pipeline's bronze_events table
return (
spark.readStream.table("bronze_events")
.withColumn("processed_at", F.current_timestamp())
)
Use spark.conf.get() to parameterize external catalog/schema references. Define parameters in
pipeline configuration, then reference them at the module level.
from pyspark import pipelines as dp
from pyspark.sql import functions as F
# Get parameterized values at module level (evaluated once at pipeline start)
source_catalog = spark.conf.get("source_catalog")
source_schema = spark.conf.get("source_schema", "sales") # with default
@dp.table(name="transaction_summary")
def transaction_summary():
return (
spark.read.table(f"{source_catalog}.{source_schema}.transactions")
.groupBy("account_id")
.agg(
F.count("txn_id").alias("txn_count"),
F.sum("txn_amount").alias("account_revenue")
)
)
Configure parameters in pipeline settings:
pipeline.yml under configuration:extra_settings.configuration dict# In resources/my_pipeline.pipeline.yml
configuration:
source_catalog: 'shared_catalog'
source_schema: 'sales'
Use when referencing specific external tables that don't change across environments:
@dp.table(name="enriched_orders")
def enriched_orders():
# Pipeline-internal table (unqualified)
orders = spark.read.table("bronze_orders")
# External reference table (fully-qualified)
products = spark.read.table("shared_catalog.reference.products")
return orders.join(products, "product_id")
| Scenario | Recommended Approach | | -------------------------------------------------------- | -------------------------------------------------------------------------- | | Reading tables created in same pipeline | Unqualified names - portable, uses target catalog/schema | | Reading from external source that varies by environment | Pipeline parameters - configurable per deployment | | Reading from shared/reference tables with fixed location | Fully-qualified names - explicit and clear | | Mixed pipeline (some internal, some external) | Combine approaches - unqualified for internal, parameters for external |
| Issue | Solution |
| ------------------------------- | --------------------------------------------------------------------------------- |
| Empty output tables | Use get_table_details to verify, check upstream sources |
| Pipeline stuck INITIALIZING | Normal for serverless, wait a few minutes |
| "Column not found" | Check schemaHints match actual data |
| Streaming reads fail | Use FROM STREAM(table) for streaming sources |
| Timeout during run | Increase timeout, or use wait_for_completion=False and poll with get_update |
| MV doesn't refresh | Enable row tracking on source tables |
| SCD2 schema errors | Let SDP infer START_AT/END_AT columns |
For detailed errors, the result["message"] from create_or_update_pipeline includes suggested
next steps. Use get_pipeline_events(pipeline_id=...) for full stack traces.
For advanced configuration options (development mode, continuous pipelines, custom clusters, notifications, Python dependencies, etc.), see 7-advanced-configuration.md.
| Requirement | Details | | -------------------- | ----------------------------------------------------------- | | Unity Catalog | Required - serverless pipelines always use UC | | Workspace Region | Must be in serverless-enabled region | | Serverless Terms | Must accept serverless terms of use | | CDC Features | Requires serverless (or Pro/Advanced with classic clusters) |
| Limitation | Workaround | | --------------------- | --------------------------------------------------- | | R language | Not supported - use classic clusters if required | | Spark RDD APIs | Not supported - use classic clusters if required | | JAR libraries | Not supported - use classic clusters if required | | Maven coordinates | Not supported - use classic clusters if required | | DBFS root access | Limited - must use Unity Catalog external locations | | Global temp views | Not supported |
| Constraint | Details | | -------------------- | -------------------------------------------------------------- | | Schema Evolution | Streaming tables require full refresh for incompatible changes | | SQL Limitations | PIVOT clause unsupported | | Sinks | Python only, streaming only, append flows only |
Default to serverless unless user explicitly requires R, RDD APIs, or JAR libraries.
<!-- Source: .faos/custom/skills/cloud/databricks/databricks-spark-declarative-pipelines/SKILL.md -->development
<!-- AUTO-GENERATED by export-skills.py — DO NOT EDIT --> --- name: grpo-rl-training description: GRPO reinforcement learning training with TRL. Use when applying Group Relative Policy Optimization for reasoning and task-specific model training. --- # GRPO/RL Training with TRL Expert-level guidance for implementing Group Relative Policy Optimization (GRPO) using the Transformer Reinforcement Learning (TRL) library. This skill provides battle-tested patterns, critical insights, and production-r
tools
<!-- AUTO-GENERATED by export-skills.py — DO NOT EDIT --> --- name: graphql-architect description: Master modern GraphQL with federation, performance optimization, --- ## Use this skill when - Working on graphql architect tasks or workflows - Needing guidance, best practices, or checklists for graphql architect ## Do not use this skill when - The task is unrelated to graphql architect - You need a different domain or tool outside this scope ## Instructions - Clarify goals, constraints, and
development
<!-- AUTO-GENERATED by export-skills.py — DO NOT EDIT --> --- name: grafana-dashboards description: Create and manage production Grafana dashboards for real-time visualization of system and application metrics. Use when building monitoring dashboards, visualizing metrics, or creating operational observability interfaces. --- # Grafana Dashboards Create and manage production-ready Grafana dashboards for comprehensive system observability. ## Do not use this skill when - The task is unrelated
development
<!-- AUTO-GENERATED by export-skills.py — DO NOT EDIT --> --- name: gptq description: GPTQ post-training quantization for generative models. Use when quantizing large models to 4-bit with calibration-based weight compression. --- # GPTQ (Generative Pre-trained Transformer Quantization) Post-training quantization method that compresses LLMs to 4-bit with minimal accuracy loss using group-wise quantization. ## When to use GPTQ **Use GPTQ when:** - Need to fit large models (70B+) on limited GPU