$npx -y skills add forcedotcom/sf-skills --skill data360-code-extension-generateDevelop and deploy Data Cloud Code Extensions using SF CLI plugin. Use this skill when creating custom Python transformations for Data Cloud, deploying code extensions, or testing data transformations. Supports init, run, scan, and deploy operations.
| 1 | # data360-code-extension-generate Skill |
| 2 | |
| 3 | ## Overview |
| 4 | |
| 5 | This skill provides a complete workflow for developing, testing, and deploying custom Python code extensions to Salesforce Data Cloud. Code extensions allow you to write Python transformations that read from and write to Data Lake Objects (DLOs) and Data Model Objects (DMOs). |
| 6 | |
| 7 | ## When to Use |
| 8 | |
| 9 | - User wants to create a new code extension project |
| 10 | - User needs to test a code extension locally |
| 11 | - User wants to scan code for required permissions |
| 12 | - User needs to deploy a code extension to Data Cloud |
| 13 | - User is working with Data Cloud transformations |
| 14 | - User wants to read/write DLO or DMO data programmatically |
| 15 | |
| 16 | ## Prerequisites Check |
| 17 | |
| 18 | Before executing any code extension commands, verify prerequisites: |
| 19 | |
| 20 | 1. **SF CLI with plugin installed** |
| 21 | ```bash |
| 22 | sf plugins --core | grep data-code-extension |
| 23 | ``` |
| 24 | If not installed: |
| 25 | ```bash |
| 26 | sf plugins install @salesforce/plugin-data-code-extension |
| 27 | ``` |
| 28 | |
| 29 | 2. **Python 3.11** |
| 30 | ```bash |
| 31 | python --version # Should show 3.11.x |
| 32 | ``` |
| 33 | |
| 34 | 3. **Data Cloud Custom Code SDK** |
| 35 | ```bash |
| 36 | pip list | grep salesforce-data-customcode |
| 37 | ``` |
| 38 | If not installed: |
| 39 | ```bash |
| 40 | pip install salesforce-data-customcode |
| 41 | ``` |
| 42 | |
| 43 | 4. **Docker running** (for deploy only) |
| 44 | ```bash |
| 45 | docker ps |
| 46 | ``` |
| 47 | |
| 48 | 5. **Authenticated org** |
| 49 | ```bash |
| 50 | sf org display --target-org <org_alias> --json |
| 51 | ``` |
| 52 | |
| 53 | ## Skill Workflow |
| 54 | |
| 55 | ### Phase 1: Initialize Project |
| 56 | |
| 57 | Create a new code extension project with scaffolding. |
| 58 | |
| 59 | **Commands:** |
| 60 | |
| 61 | For **script-based** code extensions (batch transformations): |
| 62 | ```bash |
| 63 | sf data-code-extension script init --package-dir <directory> |
| 64 | ``` |
| 65 | |
| 66 | For **function-based** code extensions (real-time): |
| 67 | ```bash |
| 68 | sf data-code-extension function init --package-dir <directory> |
| 69 | ``` |
| 70 | |
| 71 | **Required Option:** |
| 72 | - `--package-dir, -p` - Directory path where the package will be created |
| 73 | |
| 74 | **What it creates:** |
| 75 | ```text |
| 76 | my-transform/ # Project root |
| 77 | ├── payload/ # CRITICAL: This is what --package-dir must point to for deploy |
| 78 | │ ├── entrypoint.py # Main transformation code |
| 79 | │ └── config.json # Code extension configuration |
| 80 | ├── requirements.txt # Python dependencies |
| 81 | └── README.md |
| 82 | ``` |
| 83 | |
| 84 | ## Directory Context During Workflow |
| 85 | |
| 86 | **IMPORTANT:** Understanding the directory structure is critical for successful deployment. |
| 87 | |
| 88 | **Commands and their directory requirements:** |
| 89 | |
| 90 | | Command | Run From | Path/File Argument | |
| 91 | |---------|----------|-------------------| |
| 92 | | `init` | Parent directory | `<project-name>` or `.` | |
| 93 | | `scan` | Project root | `./payload/entrypoint.py` | |
| 94 | | `run` | Project root | `./payload/entrypoint.py` | |
| 95 | | `deploy` | Project root | `--package-dir ./payload` (**REQUIRED**) | |
| 96 | |
| 97 | **CRITICAL: The `--package-dir` argument in deploy command MUST point to the `payload` directory, not the project root.** |
| 98 | |
| 99 | ### Phase 2: Develop Transformation |
| 100 | |
| 101 | Edit `payload/entrypoint.py` with transformation logic. |
| 102 | |
| 103 | **Script Example (Batch):** |
| 104 | ```python |
| 105 | from datacustomcode import Client |
| 106 | |
| 107 | client = Client() |
| 108 | |
| 109 | # Read from DLO |
| 110 | df = client.read_dlo('Employee__dll') |
| 111 | |
| 112 | # Transform data (uppercase position field) |
| 113 | df['position_upper'] = df['position'].str.upper() |
| 114 | |
| 115 | # Write to output DLO |
| 116 | client.write_to_dlo('Employee_Upper__dll', df, 'overwrite') |
| 117 | ``` |
| 118 | |
| 119 | **Function Example (Real-time):** |
| 120 | ```python |
| 121 | from datacustomcode import FunctionClient |
| 122 | |
| 123 | def transform(event, context): |
| 124 | client = FunctionClient(context) |
| 125 | input_data = event['data'] |
| 126 | output = { |
| 127 | 'name': input_data['name'].upper(), |
| 128 | 'status': 'processed' |
| 129 | } |
| 130 | return output |
| 131 | ``` |
| 132 | |
| 133 | **Common Operations:** |
| 134 | - `client.read_dlo('DLO_Name__dll')` - Read from DLO |
| 135 | - `client.read_dmo('DMO_Name')` - Read from DMO |
| 136 | - `client.write_to_dlo('DLO_Name__dll', df, 'overwrite')` - Write to DLO |
| 137 | - `client.write_to_dmo('DMO_Name', df, 'upsert')` - Write to DMO |
| 138 | |
| 139 | ### Phase 3: Scan for Permissions |
| 140 | |
| 141 | Scan the entrypoint file to detect required permissions and generate config.json. |
| 142 | |
| 143 | **Command:** |
| 144 | ```bash |
| 145 | sf data-code-extension script scan --entrypoint ./payload/entrypoint.py |
| 146 | ``` |
| 147 | |
| 148 | **What it detects:** |
| 149 | - Read permissions for DLOs/DMOs |
| 150 | - Write permissions for DLOs/DMOs |
| 151 | - Python package dependencies |
| 152 | - Updates `config.json` and `requirements.txt` |
| 153 | |
| 154 | ### Phase 4: Validate DLO Schema (Pre-Test Check) |
| 155 | |
| 156 | **CRITICAL: Before running tests locally, validate that all DLOs used in your code exist and have the expected fields.** |