In this post we are going to cover how to build a Claude skill for data quality, with a real Python and DuckDB script that checks a CSV file before you load it. We see what a skill is, create one with Claude Code on a small shop project, look inside the SKILL.md file, and let Claude pick the skill up by itself to check an orders file. Then we call it ourselves with /data-quality, and the last step is a look at skills in the Claude app.
A skill is a folder with a SKILL.md file inside. The file holds instructions for Claude, and the folder can also hold scripts and other files. Claude uses a skill when your request matches its description, or you call it yourself with a slash and the skill name. For a data engineer that means a check your team runs by hand, in a slightly different way each time, becomes the same steps in the same order, every time, no matter who asks.
Part 7 of the Claude for Data Engineers series on TechBrothersIT.
Let's create some sample data
Our project is shop-quality. Incoming extracts from the online shop land in data/ before they are loaded into the warehouse: a clean customers file with 8 customers, an orders file with 13 rows, and a payments file with 10 rows. The orders and payments files have a few problems on purpose. The CLAUDE.md says the files are source extracts that are never edited by hand, and lists the allowed order statuses and payment methods. Here are all the starting files.
customer_id,first_name,last_name,email,country
1,Sara,Khan,sara.khan@example.com,US
2,Omar,Ali,omar.ali@example.com,UK
3,Maya,Chen,maya.chen@example.com,US
4,Liam,Brooks,liam.brooks@example.com,US
5,Ana,Silva,ana.silva@example.com,BR
6,Noah,Weber,noah.weber@example.com,DE
7,Zara,Ahmed,zara.ahmed@example.com,UK
8,Ethan,Park,ethan.park@example.com,USorder_id,customer_id,order_date,status,amount
1001,1,2026-10-02,completed,99.50
1002,3,2026-10-05,completed,158.00
1003,4,2026-10-07,returned,32.00
1004,6,2026-10-11,completed,64.00
1005,7,2026-10-14,shipped,22.75
1006,3,2026-10-18,completed,81.20
1007,8,2026-10-21,completed,99.00
1007,8,2026-10-21,completed,99.00
1008,2,2026-10-25,placed,44.10
1009,,2026-10-26,placed,18.40
1010,6,2026-10-29,shipped,51.30
1011,5,2026-10-30,refunded,-20.00
1012,1,2026-11-01,placed,60.00payment_id,order_id,method,amount
1,1001,card,74.50
2,1001,gift_card,25.00
3,1002,card,158.00
4,1003,card,32.00
5,1004,bank_transfer,64.00
6,1005,card,22.75
7,1006,paypal,81.20
8,1007,paypal,99.00
9,1008,card,
10,1010,card,51.30# shop-quality
Incoming extracts from the online shop land in data/ before they are loaded into the warehouse.
- Python 3.13 with DuckDB
- Files in data/ are source extracts: never edit them by hand
- Order status values: placed, shipped, completed, returned
- Payment methods: card, paypal, gift_card, bank_transferWhat a skill is
Before we build one, here is the idea on one card.
A skill is a folder
- SKILL.md: instructions, plus scripts and other files
- Only name + description load up front; the rest loads when used
- Used automatically when it fits, or with
/skill-name - Project
.claude/skills/<name>/· personal~/.claude/skills/<name>/
At the start of a session, Claude only sees the name and the description of each skill. The full instructions load only when the skill is used, so skills cost very little context. That is why you can have many of them.
Skills follow an open standard called Agent Skills. And there are two places for your own skills. A project skill lives in .claude/skills/<name>/ in your repo, so you share it with your team. A personal skill lives in the same folder under your home directory, ~/.claude/skills/<name>/, and works in every project.
Step 1: Create the skill with Claude Code
Let's build one. We want a data quality check that anyone on the team can run, before a file goes into the warehouse. We ask Claude to create a project skill called data-quality, with a DuckDB script that does the actual checks.
Create a project skill "data-quality": SKILL.md plus a DuckDB script that profiles a CSV and checks keys, nulls, allowed values and minimums. Test it on data/customers.csv.We stay in auto mode for this one. Claude says it will create the skill in .claude/skills/data-quality/, with SKILL.md for the steps and scripts/dq_check.py for the checks. Files in the .claude folder are protected, so auto mode has its safety check review each of these writes. Then Claude tests the script on the customers file, which we know is clean. In auto mode this local test runs without a prompt.
---
name: data-quality
description: Check a CSV extract for data-quality problems before it is loaded. Use when the user asks if a file is clean, valid or ready to load.
argument-hint: "[csv-file]"
---
# Data-quality check
Check $ARGUMENTS (or the file the user names) with the script in this skill.
Never edit the data file: report problems, do not hide them.
1. Profile the file first:
`python .claude/skills/data-quality/scripts/dq_check.py FILE --profile`
2. From the profile, choose the checks: the key column, columns that must not be null,
columns with a fixed set of values, and amounts that must not be negative. Run them:
`python .claude/skills/data-quality/scripts/dq_check.py FILE --key ID --not-null A,B --allowed COL=a,b --min COL=0`
3. Report every FAIL line with its bad values and one suggested fix,
then say whether the file is safe to load.
The script exits with code 1 when a check fails. That is the expected result, not a bug."""Data-quality checks for one CSV file, with DuckDB.
python dq_check.py FILE --profile row count, then per column: type, nulls, distinct values, min, max
python dq_check.py FILE --key ID [--not-null A,B] [--allowed COL=a,b,c] [--min COL=0]
Exits with code 1 when any check fails, so it also works in CI.
"""
import argparse, sys
import duckdb
ap = argparse.ArgumentParser()
ap.add_argument("file")
ap.add_argument("--profile", action="store_true")
ap.add_argument("--key")
ap.add_argument("--not-null", default="")
ap.add_argument("--allowed", action="append", default=[])
ap.add_argument("--min", action="append", default=[])
a = ap.parse_args()
con = duckdb.connect()
con.execute(f"CREATE VIEW t AS SELECT * FROM read_csv('{a.file}', header = true)")
rows = con.execute("SELECT count(*) FROM t").fetchone()[0]
cols = con.execute("DESCRIBE t").fetchall()
print(f"{a.file}: {rows} rows, {len(cols)} columns")
if a.profile:
con.sql(" UNION ALL ".join(
f"SELECT '{c}' AS column_name, '{typ}' AS type, count(*) - count(\"{c}\") AS nulls, "
f"count(DISTINCT \"{c}\") AS n_distinct, min(\"{c}\")::varchar AS min, max(\"{c}\")::varchar AS max FROM t"
for c, typ, *_ in cols)).show(max_width=200)
sys.exit(0)
checks = [] # (check, number of bad rows or values, example values)
if a.key:
bad = con.execute(f'SELECT "{a.key}" FROM t GROUP BY 1 HAVING count(*) > 1 ORDER BY 1').fetchall()
checks.append((f"unique {a.key}", len(bad), [r[0] for r in bad]))
for c in filter(None, a.not_null.split(",")):
n = con.execute(f'SELECT count(*) FROM t WHERE "{c}" IS NULL').fetchone()[0]
checks.append((f"not null {c}", n, []))
for rule in a.allowed:
c, vals = rule.split("=", 1)
ok = ", ".join(f"'{v}'" for v in vals.split(","))
bad = con.execute(f'SELECT DISTINCT "{c}" FROM t WHERE "{c}" NOT IN ({ok}) ORDER BY 1').fetchall()
checks.append((f"{c} in ({vals})", len(bad), [r[0] for r in bad]))
for rule in a.min:
c, lo = rule.split("=", 1)
bad = con.execute(f'SELECT "{c}" FROM t WHERE "{c}" < {lo} ORDER BY 1').fetchall()
checks.append((f"{c} >= {lo}", len(bad), [r[0] for r in bad]))
for check, n, examples in checks:
detail = f" (bad: {', '.join(map(str, examples[:5]))})" if examples else f" ({n} row{'s' if n > 1 else ''})" if n else ""
print(f"{'PASS' if n == 0 else 'FAIL'} {check}{detail}")
failed = sum(1 for _, n, _ in checks if n)
print(f"{len(checks) - failed} of {len(checks)} checks passed")
sys.exit(1 if failed else 0)python .claude/skills/data-quality/scripts/dq_check.py data/customers.csv --key customer_id --not-null email,countrydata/customers.csv: 8 rows, 5 columns
PASS unique customer_id
PASS not null email
PASS not null country
3 of 3 checks passedThe script reads the CSV with DuckDB and has two modes. --profile prints the row count and, for every column, the type, the nulls, the distinct values, and the min and max. The check mode takes --key, --not-null, --allowed and --min, prints a PASS or FAIL line for each check, and exits with code 1 when any check fails. On data/customers.csv all three checks pass: unique customer_id, not null email and not null country, so the result is 3 of 3 checks passed.
Put the logic in a script, and the steps in the skill. A script gives the same answer every time.
Inside SKILL.md
Now let's look inside the SKILL.md file, because this is where most skills succeed or fail.
SKILL.md
---
name: data-quality
description: Check a CSV extract for data-quality problems before it is loaded. Use when the user asks if a file is clean, valid or ready to load.
argument-hint: "[csv-file]"
---
# Data-quality check
Check $ARGUMENTS (or the file the user names) with the script in this skill.
Never edit the data file: report problems, do not hide them.
1. Profile the file first:
`python .claude/skills/data-quality/scripts/dq_check.py FILE --profile`
2. From the profile, choose the checks: the key column, columns that must not be null,
columns with a fixed set of values, and amounts that must not be negative. Run them:
`python .claude/skills/data-quality/scripts/dq_check.py FILE --key ID --not-null A,B --allowed COL=a,b --min COL=0`
3. Report every FAIL line with its bad values and one suggested fix,
then say whether the file is safe to load.
The script exits with code 1 when a check fails. That is the expected result, not a bug.On top is the front matter, between two lines of dashes. The name becomes the slash command. If you leave it out, the folder name is used.
The description is the most important line. Claude reads it to decide when the skill fits, so write it with the words your team really uses, like clean, valid or ready to load. The argument-hint shows what to type after the slash command, and $ARGUMENTS in the body is replaced by whatever you type there.
The body is plain Markdown with three steps: profile the file, choose the checks from the profile, and report every failure with a fix. It also has one rule that matters: never edit the data file. A quality check should report problems, not hide them. The last line tells Claude that exit code 1 is the expected result when a check fails, not a bug.
Keep this file short. The docs suggest under 500 lines. Longer reference files can sit next to it, and they load only when needed.
Step 2: Claude picks it up by itself
Now the real test. We start a new session, and we do not mention the skill at all. We just ask a normal question.
Is data/orders.csv clean enough to load?Claude matches the question to the skill's description. It says this is what the data-quality skill is for, and that it will follow its steps. Step one from the skill is the profile.
python .claude/skills/data-quality/scripts/dq_check.py data/orders.csv --profiledata/orders.csv: 13 rows, 5 columns
┌─────────────┬─────────┬───────┬────────────┬────────────┬────────────┐
│ column_name │ type │ nulls │ n_distinct │ min │ max │
│ varchar │ varchar │ int64 │ int64 │ varchar │ varchar │
├─────────────┼─────────┼───────┼────────────┼────────────┼────────────┤
│ order_id │ BIGINT │ 0 │ 12 │ 1001 │ 1012 │
│ customer_id │ BIGINT │ 1 │ 8 │ 1 │ 8 │
│ order_date │ DATE │ 0 │ 12 │ 2026-10-02 │ 2026-11-01 │
│ status │ VARCHAR │ 0 │ 5 │ completed │ shipped │
│ amount │ DOUBLE │ 0 │ 12 │ -20.0 │ 158.0 │
└─────────────┴─────────┴───────┴────────────┴────────────┴────────────┘13 rows, but only 12 distinct values in order_id. customer_id has 1 null, status has 5 distinct values, and the smallest amount is -20.0. Step two: Claude picks the checks from the profile and from the status list in CLAUDE.md, and runs them.
python .claude/skills/data-quality/scripts/dq_check.py data/orders.csv --key order_id --not-null customer_id,order_date,amount --allowed status=placed,shipped,completed,returned --min amount=0data/orders.csv: 13 rows, 5 columns
FAIL unique order_id (bad: 1007)
FAIL not null customer_id (1 row)
PASS not null order_date
PASS not null amount
FAIL status in (placed,shipped,completed,returned) (bad: refunded)
FAIL amount >= 0 (bad: -20.0)
2 of 6 checks passedFour of the six checks fail, and the script exits with code 1, as the skill expects. Order 1007 appears twice, one row has no customer_id, there is a status called refunded, and one amount is -20.0. Claude reports each failure with a fix and says the file is not ready to load.
data/orders.csv is not ready to load: 4 of 6 checks fail.
order_id1007 appears twice: check the two rows are identical, then keep one- 1 order has no
customer_id: ask the source team, or hold that row back - status
refundedis not an allowed value, and one amount is -20.0: are refunds meant to be in this extract? If yes, addrefundedto the allowed values and handle negative amounts on purpose.
Look at the refund. Claude does not just delete it. It asks if refunds are meant to be in this extract, because that is a business question, not a data fix.
The skill runs because the description matches the question. If Claude does not pick up your skill, rewrite the description with the words people really type.
Step 3: Call it with /data-quality
You can also call a skill yourself, with a slash and its name. We type /data-quality and the payments file as the argument.
/data-quality data/payments.csvThe argument fills the $ARGUMENTS placeholder in the skill, so Claude knows which file to check. It follows the same steps, profile first.
python .claude/skills/data-quality/scripts/dq_check.py data/payments.csv --profiledata/payments.csv: 10 rows, 4 columns
┌─────────────┬─────────┬───────┬────────────┬───────────────┬─────────┐
│ column_name │ type │ nulls │ n_distinct │ min │ max │
│ varchar │ varchar │ int64 │ int64 │ varchar │ varchar │
├─────────────┼─────────┼───────┼────────────┼───────────────┼─────────┤
│ payment_id │ BIGINT │ 0 │ 10 │ 1 │ 10 │
│ order_id │ BIGINT │ 0 │ 9 │ 1001 │ 1010 │
│ method │ VARCHAR │ 0 │ 4 │ bank_transfer │ paypal │
│ amount │ DOUBLE │ 1 │ 9 │ 22.75 │ 158.0 │
└─────────────┴─────────┴───────┴────────────┴───────────────┴─────────┘10 rows, 4 columns, and 1 null in the amount column. Then the checks, with the payment methods from CLAUDE.md.
python .claude/skills/data-quality/scripts/dq_check.py data/payments.csv --key payment_id --not-null order_id,amount --allowed method=card,paypal,gift_card,bank_transfer --min amount=0data/payments.csv: 10 rows, 4 columns
PASS unique payment_id
PASS not null order_id
FAIL not null amount (1 row)
PASS method in (card,paypal,gift_card,bank_transfer)
PASS amount >= 0
4 of 5 checks passedFour checks pass and one fails: not null amount with 1 row, so the result is 4 of 5 checks passed. One payment has no amount, and Claude says to ask the source team for the value before loading.
Because this skill lives in the project folder, it goes into git with the code. Everyone on the team gets the same checks the next time they pull.
Step 4: Skills in the Claude app
Skills are not only for Claude Code. You can use them in the Claude app too. In the app, skills live under Customize, in the Skills tab. There is also a Discover tab, to browse skills that are ready to use.
Zip the data-quality folder (SKILL.md + scripts) and upload the ZIP with Upload skill.
To add your own, zip the skill folder and upload it with Upload skill. In a chat, the + button in the message box has a Skills item too.
Skills need code execution and file creation. Built-in skills: Excel, Word, PowerPoint, PDF.
Skills in the app need code execution and file creation turned on. And Anthropic already ships skills for Excel, Word, PowerPoint and PDF files. Your sidebar may look a little different from mine, because the new app layout is still rolling out.
One note for our skill: its steps call the script by its path in the project, .claude/skills/data-quality/scripts/dq_check.py. Try the uploaded copy once in the app before you rely on it.
Skills that work
Here is what makes a data skill work well on a real team.
Four habits for skills that work
- The description decides when it runs: use your team’s words
- Logic in a script, steps in SKILL.md
- Report problems, never edit the source data
- Commit project skills ·
/skillslists them ·/reload-skillsfor a new skills folder
The description decides when the skill runs, so use the words your team really says. Put the logic in a script, and the steps in SKILL.md. Report problems, and never let the skill quietly fix or edit the source data. And commit project skills to git. /skills lists them. Edits are picked up live, and if the skills folder is new, run /reload-skills.
Key points to remember
- What a skill is
- SKILL.md + a DuckDB check script
- Description, argument hint, steps
- Claude used it by itself
- /data-quality with an argument
- Skills in the Claude app
The full script
This bash script writes every file Claude wrote, in the same order, and runs every command, so you can reproduce all the results without Claude.
Show the full script (every file and every command, in order)
#!/usr/bin/env bash
# Claude for Data Engineers #7: Claude Skills for Data Work: Build a Data-Quality Skill
# Rebuilds the demo project without Claude: writes every file Claude wrote, in the same order,
# and runs every command from the video. Run it in an empty folder.
# Tools used in the video: Python 3.13, DuckDB 2.0.0, pandas 3.0.5, PySpark 4.3.0 (local mode, Java 21),
# dbt-core 1.12.6 with dbt-duckdb 1.11.0, PostgreSQL 16. Install the ones this project uses first.
mkdir -p shop-quality && cd shop-quality
# ---------- starting files ----------
mkdir -p data
cat > data/customers.csv <<'CLAUDE_DE_EOF'
customer_id,first_name,last_name,email,country
1,Sara,Khan,sara.khan@example.com,US
2,Omar,Ali,omar.ali@example.com,UK
3,Maya,Chen,maya.chen@example.com,US
4,Liam,Brooks,liam.brooks@example.com,US
5,Ana,Silva,ana.silva@example.com,BR
6,Noah,Weber,noah.weber@example.com,DE
7,Zara,Ahmed,zara.ahmed@example.com,UK
8,Ethan,Park,ethan.park@example.com,US
CLAUDE_DE_EOF
mkdir -p data
cat > data/orders.csv <<'CLAUDE_DE_EOF'
order_id,customer_id,order_date,status,amount
1001,1,2026-10-02,completed,99.50
1002,3,2026-10-05,completed,158.00
1003,4,2026-10-07,returned,32.00
1004,6,2026-10-11,completed,64.00
1005,7,2026-10-14,shipped,22.75
1006,3,2026-10-18,completed,81.20
1007,8,2026-10-21,completed,99.00
1007,8,2026-10-21,completed,99.00
1008,2,2026-10-25,placed,44.10
1009,,2026-10-26,placed,18.40
1010,6,2026-10-29,shipped,51.30
1011,5,2026-10-30,refunded,-20.00
1012,1,2026-11-01,placed,60.00
CLAUDE_DE_EOF
mkdir -p data
cat > data/payments.csv <<'CLAUDE_DE_EOF'
payment_id,order_id,method,amount
1,1001,card,74.50
2,1001,gift_card,25.00
3,1002,card,158.00
4,1003,card,32.00
5,1004,bank_transfer,64.00
6,1005,card,22.75
7,1006,paypal,81.20
8,1007,paypal,99.00
9,1008,card,
10,1010,card,51.30
CLAUDE_DE_EOF
cat > CLAUDE.md <<'CLAUDE_DE_EOF'
# shop-quality
Incoming extracts from the online shop land in data/ before they are loaded into the warehouse.
- Python 3.13 with DuckDB
- Files in data/ are source extracts: never edit them by hand
- Order status values: placed, shipped, completed, returned
- Payment methods: card, paypal, gift_card, bank_transfer
CLAUDE_DE_EOF
# ---------- step 1: Create the skill: SKILL.md and the check script, then test it on a clean file ----------
mkdir -p .claude/skills/data-quality
cat > .claude/skills/data-quality/SKILL.md <<'CLAUDE_DE_EOF'
---
name: data-quality
description: Check a CSV extract for data-quality problems before it is loaded. Use when the user asks if a file is clean, valid or ready to load.
argument-hint: "[csv-file]"
---
# Data-quality check
Check $ARGUMENTS (or the file the user names) with the script in this skill.
Never edit the data file: report problems, do not hide them.
1. Profile the file first:
`python .claude/skills/data-quality/scripts/dq_check.py FILE --profile`
2. From the profile, choose the checks: the key column, columns that must not be null,
columns with a fixed set of values, and amounts that must not be negative. Run them:
`python .claude/skills/data-quality/scripts/dq_check.py FILE --key ID --not-null A,B --allowed COL=a,b --min COL=0`
3. Report every FAIL line with its bad values and one suggested fix,
then say whether the file is safe to load.
The script exits with code 1 when a check fails. That is the expected result, not a bug.
CLAUDE_DE_EOF
mkdir -p .claude/skills/data-quality/scripts
cat > .claude/skills/data-quality/scripts/dq_check.py <<'CLAUDE_DE_EOF'
""Data-quality checks for one CSV file, with DuckDB.
python dq_check.py FILE --profile row count, then per column: type, nulls, distinct values, min, max
python dq_check.py FILE --key ID [--not-null A,B] [--allowed COL=a,b,c] [--min COL=0]
Exits with code 1 when any check fails, so it also works in CI.
""
import argparse, sys
import duckdb
ap = argparse.ArgumentParser()
ap.add_argument("file")
ap.add_argument("--profile", action="store_true")
ap.add_argument("--key")
ap.add_argument("--not-null", default="")
ap.add_argument("--allowed", action="append", default=[])
ap.add_argument("--min", action="append", default=[])
a = ap.parse_args()
con = duckdb.connect()
con.execute(f"CREATE VIEW t AS SELECT * FROM read_csv('{a.file}', header = true)")
rows = con.execute("SELECT count(*) FROM t").fetchone()[0]
cols = con.execute("DESCRIBE t").fetchall()
print(f"{a.file}: {rows} rows, {len(cols)} columns")
if a.profile:
con.sql(" UNION ALL ".join(
f"SELECT '{c}' AS column_name, '{typ}' AS type, count(*) - count(\"{c}\") AS nulls, "
f"count(DISTINCT \"{c}\") AS n_distinct, min(\"{c}\")::varchar AS min, max(\"{c}\")::varchar AS max FROM t"
for c, typ, *_ in cols)).show(max_width=200)
sys.exit(0)
checks = [] # (check, number of bad rows or values, example values)
if a.key:
bad = con.execute(f'SELECT "{a.key}" FROM t GROUP BY 1 HAVING count(*) > 1 ORDER BY 1').fetchall()
checks.append((f"unique {a.key}", len(bad), [r[0] for r in bad]))
for c in filter(None, a.not_null.split(",")):
n = con.execute(f'SELECT count(*) FROM t WHERE "{c}" IS NULL').fetchone()[0]
checks.append((f"not null {c}", n, []))
for rule in a.allowed:
c, vals = rule.split("=", 1)
ok = ", ".join(f"'{v}'" for v in vals.split(","))
bad = con.execute(f'SELECT DISTINCT "{c}" FROM t WHERE "{c}" NOT IN ({ok}) ORDER BY 1').fetchall()
checks.append((f"{c} in ({vals})", len(bad), [r[0] for r in bad]))
for rule in a.min:
c, lo = rule.split("=", 1)
bad = con.execute(f'SELECT "{c}" FROM t WHERE "{c}" < {lo} ORDER BY 1').fetchall()
checks.append((f"{c} >= {lo}", len(bad), [r[0] for r in bad]))
for check, n, examples in checks:
detail = f" (bad: {', '.join(map(str, examples[:5]))})" if examples else f" ({n} row{'s' if n > 1 else ''})" if n else ""
print(f"{'PASS' if n == 0 else 'FAIL'} {check}{detail}")
failed = sum(1 for _, n, _ in checks if n)
print(f"{len(checks) - failed} of {len(checks)} checks passed")
sys.exit(1 if failed else 0)
CLAUDE_DE_EOF
python .claude/skills/data-quality/scripts/dq_check.py data/customers.csv --key customer_id --not-null email,country
# ---------- step 2: Skill step 1: profile orders.csv ----------
python .claude/skills/data-quality/scripts/dq_check.py data/orders.csv --profile
# ---------- step 3: Skill step 2: run the checks on orders.csv (four fail) ----------
python .claude/skills/data-quality/scripts/dq_check.py data/orders.csv --key order_id --not-null customer_id,order_date,amount --allowed status=placed,shipped,completed,returned --min amount=0 # expected to fail
# ---------- step 4: /data-quality data/payments.csv: profile ----------
python .claude/skills/data-quality/scripts/dq_check.py data/payments.csv --profile
# ---------- step 5: /data-quality data/payments.csv: checks (one fails) ----------
python .claude/skills/data-quality/scripts/dq_check.py data/payments.csv --key payment_id --not-null order_id,amount --allowed method=card,paypal,gift_card,bank_transfer --min amount=0 # expected to fail
Part 8: Hooks, Sub-agents and Parallel Agents for Data Pipelines
The project and its data are invented for teaching. Every file on this page is the real file from the demo project, and every output is the real output of the command above it, captured when the video was made (each step ran twice in a fresh folder and the outputs were compared). The Claude screens in the video are a simplified recreation for teaching. Always review what Claude changes and runs. Claude plans, features and limits are current as of November 2026; check the official Claude and Claude Code documentation before you rely on them. Part of the Claude for Data Engineers series on TechBrothersIT.


