← Back to list

How to Build an Enterprise-Grade SKILL.md for Cortex Code — Part 3: Scaling and Polishing

A practitioner’s guide to writing custom AI agent skills that actually work — with patterns extracted from a real enterprise data…

Srivathsan Venkatesan · 2026-05-03 03:14 · 25 claps · 10.3 min read
#snowflake #coco #data-vault #data-engineering #artificial-intelligence
Open on Medium ↗
Wiki topics: AGT · AI Agents AI · AI · General 🔧 · Data Engineering

How to Build an Enterprise-Grade SKILL.md for Cortex Code — Part 3: Scaling and Polishing

A practitioner’s guide to writing custom AI agent skills that actually work — with patterns extracted from a real enterprise data engineering project.

This is a 3-part series. Each post stands alone, but they build on each other.

Part 1 — Designing Your Skill — Anatomy, Frontmatter, and Domain Context — skill structure, frontmatter, domain context, and the Source Profile Dictionary

Part 2 — Building the Workflow — Tools, Steps, and Guardrails — tool declarations, workflow steps, mandatory stopping points, and quality gates

Part 3 — Scaling and Polishing — Output, Multi-File, Business Rules, and Patterns (this post)

This is Part 3 of a 3-part series on building enterprise-grade SKILL.md files for Cortex Code. In Part 1, we designed the skill foundation — anatomy, frontmatter, domain context, and the Source Profile Dictionary. In Part 2, we built the workflow and its guardrails: tool declarations, workflow steps, stopping points, and quality gates. Now we scale up and polish.

Part 10: The Output Section

Every skill should document what it produces:

The base skill produces this output section:

## Output

A source profile dictionary containing column metadata (names, inferred types,
null percentages, distinct ratios, format patterns), Data Vault role classifications,
and hub entity assignments for each column. Passed to SKILL_datavault.md for
DV model generation and SKILL_pipeline.md for pipeline generation.

The DV sub-skill produces this output section:

## Output

A validated SQL file (`.sql`) containing:
1. `CREATE TABLE` statements for hub tables with hash keys and metadata columns
2. `CREATE TABLE` statements for link tables with hash keys and FK hash references
3. `CREATE TABLE` statements for satellite tables with hashdiff columns
4. A summary comment header listing all vault entities and their relationships

The pipeline sub-skill produces this output section:

## Output

A validated SQL file (`.sql`) containing:
1. Staging table DDL (`CREATE TABLE STG_{source_name}`)
2. File format DDL (`CREATE FILE FORMAT` if needed)
3. `COPY INTO` statement for loading source data into staging
4. Hash staging DDL and `INSERT INTO ... SELECT` with hash key computation (if three-layer)
5. Raw vault load SQL for hubs, links, and satellites
6. A summary comment header listing all generated objects

The output section serves three audiences:

  1. The agent — Knows exactly what artifact to produce
  2. The user — Knows what to expect as a deliverable and how to consume or hand it off
  3. Other skills — Can understand what to expect as input if they consume this skill’s output

What Makes a Well-Defined Output Section

A precise output section answers four questions:

  1. What type of artifact? File written to disk, in-memory object passed between skills, or text block presented to the user
  2. What format? SQL, markdown, JSON, YAML, Python dict, plain text
  3. What does it contain? A numbered list of components — not “a SQL file” but “a SQL file containing X, Y, and Z”
  4. Who receives it? The user for review, a downstream sub-skill, or an external tool

The three output sections above answer all four. That precision is what allows the agent to reproduce them consistently across invocations, and what allows sub-skills to declare their prerequisites against a concrete contract.

Choosing the Right Output Format

Output format is not arbitrary. The format you specify determines how the artifact is consumed, validated, and handed off:

The DV series uses three of these: an in-memory dict (base skill → sub-skills), a SQL file (DV sub-skill), and a SQL file (pipeline sub-skill). Each was chosen because it matches how the artifact is consumed — the dict is an internal handoff that never touches disk, the SQL files are external deliverables that require human review before anything runs.

The Generate vs Execute Boundary

When the output is SQL, the separation between generation and execution is a safety boundary, not a preference. The skill generates the file; the user reviews and executes it manually. This holds even when the agent has access to execution tools like execute_sql.

Make it explicit in the output section itself:

## Output

A validated SQL file (`.sql`). Generated and presented for review.
**Do NOT execute** — hand to the user for manual execution after review.

One line prevents the most common misuse of code-generating skills: an agent that writes and immediately runs DDL without a human seeing it first.

Skill output format selection guide — five formats mapped to their use cases, skill examples, and key constraints; choose based on how the artifact is consumed downstream.

Skill output format selection guide — five formats mapped to their use cases, skill examples, and key constraints; choose based on how the artifact is consumed downstream.

Part 11: Splitting into Multiple Files — The Multi-Skill Architecture

For complex workflows, a single SKILL.md becomes unwieldy. The solution is a base skill + sub-skill architecture.

When to Split

Split when:

  • Your workflow has distinct phases that produce different artifact types (DV model DDL vs pipeline SQL)
  • Sub-workflows have their own rules and quality gates that would clutter the base skill
  • You want composability — invoke sub-skills independently or together
  • A single file exceeds ~300 lines and becomes hard to maintain

The Three-File Pattern

All three files are available on GitHub: srivathsan-v91/cortex-code-subskill

How Sub-Skills Connect to the Base

Each sub-skill starts with a Prerequisites section that documents exactly what it expects from the base skill:

## Prerequisites (from Base Skill)

This sub-skill expects the following inputs from SKILL.md Step 2:
- **Source profile dictionary** - column metadata with inferred types,
  null percentages, distinct ratios, DV role classifications, and hub entity assignments
- **Source metadata** - `{source_name}`, `{target_schema}`, `{stage_path}`
- **User preferences** - `pipeline_layers` (2 or 3)

For the pipeline sub-skill, it optionally uses the DV sub-skill’s output:

## Prerequisites (from Base Skill + optional DV Skill)

**From SKILL.md (base skill):**
- **Source profile dictionary** - column metadata with inferred types
- **Source metadata** - `{source_name}`, `{target_schema}`, `{stage_path}`
**From SKILL_datavault.md (optional):**
- **Vault entity list** - if DV model was generated, the pipeline
  can include vault-load INSERT statements for each hub, link, and satellite

Step Numbering Convention

Maintain continuous step numbering across files:

  • SKILL.md → Steps 1-2
  • SKILL_datavault.md → Steps 3-4, 4b
  • SKILL_pipeline.md → Steps 5-6, 6b

The 4b and 6b suffixes are for "write to file" steps that happen after approval. This keeps the numbering linear while acknowledging that file writes are a sub-step of the approval gate.

Linking with parent_skill

Sub-skills declare their parent in the frontmatter:

---
name: dv-model-generator
parent_skill: data-onboarding-generator
---

This creates a discoverable hierarchy. When someone explores the base skill, they can find the sub-skills through the parent_skill linkage.

Why this matters: Without parent_skill, a skill ecosystem is a flat list. With it, the hierarchy is traversable — any tool or agent walking skill relationships can map the full chain. It also makes the sub-skill self-documenting: anyone reading SKILL_datavault.md knows immediately which base skill it belongs to, without having to search for it.

Delegation Pattern in the Base Skill

The base skill’s Step 2 ends with explicit delegation instructions:

**Next:** Pass the source profile dictionary, source metadata, and user
preferences to the sub-skills:
- **If `generate_dv = true`**, invoke **SKILL_datavault.md**
  (dv-model-generator) → Steps 3-4
- **If `generate_pipeline = true`**, after DV model is approved (if
  applicable), invoke **SKILL_pipeline.md** (pipeline-generator) → Steps 5-6
- **If both**, run DV model first, then pipeline — the pipeline can use
  the vault entity definitions for load SQL

Multi-file skill architecture — SKILL.md (base) passes the source profile dictionary to SKILL_datavault.md and SKILL_pipeline.md; dashed arrows show parent_skill linkage back to the base.

Multi-file skill architecture — SKILL.md (base) passes the source profile dictionary to SKILL_datavault.md and SKILL_pipeline.md; dashed arrows show parent_skill linkage back to the base.

Part 12: Encoding Business Rules and Transformation Logic

Many enterprise skills need to encode specific transformation or inference rules. Here’s how to document them clearly so the agent follows them precisely.

Data Vault Classification Rules

The following rules are embedded verbatim in Step 2 of the base skill — the agent reads them and applies them for every column it profiles:

**DV Role Classification Rules:**

For each column in the source profile, classify its Data Vault role based on:
| Column Characteristic          | DV Role                                | Priority |
|-------------------------------|----------------------------------------|----------|
| High cardinality, unique or near-unique, NOT NULL | `HUB_BK` (business key)   | HIGH     |
| References another entity's BK (naming pattern or FK) | `LINK_FK` (foreign key) | HIGH     |
| Date/timestamp with "created", "updated", "loaded" | `METADATA`              | MEDIUM   |
| Columns named "source", "origin", "system"   | `METADATA`                     | MEDIUM   |
| Non-key descriptive attributes (names, amounts, status) | `SAT_ATTR`            | LOW      |
| Ambiguous - could be BK or FK depending on context | `UNKNOWN` - flag for user | LOW      |
**Hub entity naming:** Derive hub names from business key column names.
  - `customer_id` → `HUB_CUSTOMER`
  - `order_number` → `HUB_ORDER`
  - `product_code` → `HUB_PRODUCT`
**Link detection:** When a source has columns classified as `HUB_BK` for
one entity and `LINK_FK` referencing another, generate a link table.
  - Source with `order_id` (HUB_BK) + `customer_id` (LINK_FK) →
    `LNK_ORDER_CUSTOMER`
**Composite business keys:** When multiple columns together form a business
key (e.g., `policy_number` + `rider_number`), concatenate them into a single
hash key: `MD5(CONCAT(UPPER(TRIM(col1)), '||', UPPER(TRIM(col2))))`. Flag
composite BK candidates with `quality_risk = MEDIUM` (see Part 1, Key Concepts for risk tiers) and require user
confirmation before proceeding - the agent should NOT silently decide
which columns form a composite key.
**⚠️ MANDATORY STOPPING POINT:** Before classifying any columns as a composite business key, the skill must pause and confirm with the user:
- Which columns together form the composite BK (e.g., `policy_number` + `rider_number`)
- The concatenation order - left-to-right order is fixed in the hash; swapping columns produces a different hash key
- Whether to model as a single composite hash key or treat each column independently
The agent cannot safely infer composite membership from column names alone - an incorrect composite key produces a hash that cannot be joined back to its source entities.
**Self-referencing links (hierarchical):** When a `LINK_FK` references the
same entity as the source's `HUB_BK` (e.g., `manager_id` referencing
`employee_id` in the same table), generate a hierarchical link:
`HLNK_{entity}` with two foreign hash keys pointing to the same hub.
**⚠️ MANDATORY STOPPING POINT:** Before generating any `HLNK_` table, the
skill must pause and confirm with the user:
- Which column triggered the detection (e.g., `manager_id` → `employee_id` on `HUB_EMPLOYEE`)
- The intended parent and child hash key column names
- Whether to model as `HLNK_{entity}` or exclude entirely
This is one of the few cases where the agent cannot make a sensible default decision - two different `HLNK_` designs may both be syntactically valid but semantically wrong. The stopping point prevents a silently incorrect model from being written to disk.
**Exception:** If the user specifies `vault_style = hub_only`, skip link
generation. If `vault_style = full`, generate all entities.
Default: `full`.

Safe Casting Rules

The following rules are embedded in the pipeline sub-skill to govern all type conversions in generated SQL:

**Safe Casting Rules (Pipeline):**

Never use raw `CAST()` in the staging or vault-load layers - always use safe
alternatives that return NULL on failure instead of aborting the load:
| Source Type → Target Type | Safe Cast Expression                    |
|--------------------------|-----------------------------------------|
| VARCHAR → NUMBER         | `TRY_TO_NUMBER(col)`                    |
| VARCHAR → DATE           | `TRY_TO_DATE(col, 'YYYY-MM-DD')`       |
| VARCHAR → TIMESTAMP      | `TRY_TO_TIMESTAMP(col)`                 |
| VARCHAR → BOOLEAN        | `TRY_TO_BOOLEAN(col)`                   |
| VARCHAR → VARCHAR(N)     | `LEFT(col, N)` (truncate, don't fail)   |
**Ambiguous dates:** If the date format is ambiguous (e.g., `01/02/2026`
could be MM/DD or DD/MM), flag it to the user at the stopping point.
Do NOT silently pick a format.

Pattern: Rule + Exception + Example

The most effective rule documentation follows this pattern:

  1. State the rule — “Use TRYTO* for all type casts”
  2. State the exception — “Unless the user explicitly requests strict mode”
  3. Show concrete mappings — Table of source type → safe expression

This three-part pattern eliminates ambiguity. The agent knows exactly when to apply the rule and when the exception kicks in.

DV role classification decision tree — each source column follows a priority-ordered path to its assigned vault role (HUB_BK, LINK_FK, METADATA, SAT_ATTR, or UNKNOWN).

DV role classification decision tree — each source column follows a priority-ordered path to its assigned vault role (HUB_BK, LINK_FK, METADATA, SAT_ATTR, or UNKNOWN).

Part 13: Iterative Refinement — Auditing and Improving Skills

Skills are never perfect on the first draft. Here’s the audit process I use to refine them.

The Skill Audit Checklist

After writing a skill, run through these checks:

Frontmatter:

  • name is unique and kebab-case
  • description includes trigger keywords after "Use when:"
  • Sub-skills have parent_skill pointing to the base

Structure:

  • Every section has a clear heading (## level)
  • Workflow steps are numbered continuously across files
  • Every step has a **Goal:** line
  • Every step ends with **Next:**

Stopping Points:

  • Format is **⚠️ MANDATORY STOPPING POINT:** (bold, emoji prefix)
  • Every stopping point includes the exact prompt text
  • Summary table at the bottom has markers
  • Every irreversible action has a stopping point before it

Quality Gates:

  • Every sub-skill has its own quality gate
  • Gate items are binary (pass/fail)
  • Gate items are specific and checkable
  • No vague items like “output looks correct”

Tools:

  • Every tool has “When to use” and “When NOT to use”
  • Tool usage is scoped to specific steps
  • Destructive tools have explicit safety constraints

Consistency:

  • Same terminology used throughout (no “source file” in one place and “input data” in another)
  • Variable placeholders are consistent ({source_name} everywhere, not sometimes {src})
  • No duplicate actions (e.g., “present to user” in two different steps)

Common Fixes from Real Audits

These are actual issues I’ve found and fixed during iterative refinement of skills:

The skill refinement loop — each iteration drives open audit items toward zero

The skill refinement loop — each iteration drives open audit items toward zero

Part 14: Patterns and Anti-Patterns

Do This

Don’t Do This

Conclusion

Building an enterprise-grade SKILL.md is not about writing a prompt — it’s about engineering a workflow. Across this series, the patterns that matter most:

  1. Domain Context turns a generic assistant into a subject matter expert
  2. Mandatory Stopping Points keep humans in the loop at every critical juncture
  3. Quality Gates automate self-validation before output reaches the user
  4. Multi-file architecture keeps complex workflows composable and maintainable
  5. Iterative refinement through structured audits catches issues before they compound

The investment in a well-crafted skill pays off immediately. Instead of re-explaining your workflow every session, you invoke the skill and the agent already knows your domain, your rules, your quality standards, and your preferred output format.

Start with a single SKILL.md. Get it working for one use case. Then split into sub-skills as complexity grows. And always, always put stopping points before irreversible actions.

The data onboarding example in this series — profiling sources, generating Data Vault models, building ingestion pipelines — is one pattern. The same architecture works for schema migrations, SCD implementations, test generation, API scaffolding, or any multi-phase workflow where you want the agent to follow your rules, not its defaults.

This series was written based on patterns extracted from building multi-file skill systems for enterprise data engineering workflows. Let me know what other topic/skill would interest you next.


메타데이터
post_id
610a0b7ffba0
slug
how-to-build-an-enterprise-grade-skill-md-for-cortex-code-part-3-scaling-and-polishing-610a0b7ffba0
url
https://medium.com/@srivathsan.v91/how-to-build-an-enterprise-grade-skill-md-for-cortex-code-part-3-scaling-and-polishing-610a0b7ffba0
canonical_url
https://medium.com/@srivathsan.v91/how-to-build-an-enterprise-grade-skill-md-for-cortex-code-part-3-scaling-and-polishing-610a0b7ffba0
author_url
https://medium.com/@srivathsan.v91
status
ok
fetched_at
2026-06-15 20:49:13