read-file — Claude Code skill: open any data file with DuckDB
Reads a CSV, Parquet, Excel, SQLite file or a remote link over S3 and HTTPS, then reports the schema and sample rows. Handy when a dataset lands in the repo and you need a quick look.
npx skills add duckdb/duckdb-skills --skill read-file -a claude-codeWhat read-file does
The skill takes a path or a URL as $0 plus an optional question in ${1:-describe the data}. A bare filename without a slash gets resolved to a full path through find. Then one duckdb call defines the read_any macro and runs three statements: the schema, a row count, the first 20 rows.
The reader follows the file extension. JSON and JSONL use read_json_auto; CSV and TSV use read_csv; Parquet, Avro, read_xlsx, st_read for spatial data and sqlite_scan for databases each have their own branch. Notebooks in .ipynb are handled separately, pulling the cell type, its source text and the execution counter. Anything unrecognised falls through to read_blob.
Remote paths need httpfs loaded first, and s3://, gs:// or az:// also need a secret built with credential_chain. No duckdb binary in PATH means the first step fails; the skill then hands off to /duckdb-skills:install-duckdb. A missing extension such as spatial or sqlite_scanner gets fixed by prefixing INSTALL and LOAD. Source code files are outside its scope — ask another tool for those.
What it helps with
- inspect the schema and row count of an unfamiliar dataset
- open a Parquet file without adding a library
- see what an Excel export or SQLite database holds
- read a data file hosted on S3 or behind an HTTPS link
- scan notebook cells as plain text
Example prompts for the agent
- Read
orders.parquetand list its columns with the row count - What's inside
report.xlsx? Describe the field types - Open
s3://bucket/events.jsonland show me the first rows
How to install read-file
1Skills CLI (Vercel)
npx skills add duckdb/duckdb-skills --skill read-file -a claude-code2Manually: put the files in place
~/.claude/skills/read-file/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/read-file/
1Skills CLI (Vercel)
npx skills add duckdb/duckdb-skills --skill read-file -a codex2Manually: put the files in place
.agents/skills/read-file/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add duckdb/duckdb-skills --skill read-file -a cursor2Manually: put the files in place
.cursor/skills/read-file/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install duckdb/duckdb-skills read-file2Manually: put the files in place
.github/skills/read-file/SKILL.md1Skills CLI (Vercel)
npx skills add duckdb/duckdb-skills --skill read-file -a gemini-cli2Platform CLI
gemini skills install https://github.com/duckdb/duckdb-skills --path skills/read-fileManually: put the files in place
.devin/skills/read-file/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add duckdb/duckdb-skills --skill read-file -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about read-file
How do I install read-file in Claude Code?
Run npx skills add duckdb/duckdb-skills --skill read-file -a claude-code, then confirm that ~/.claude/skills/read-file/SKILL.md is in place.
What does read-file do?
It builds a DuckDB macro that picks a reader by extension, then answers your question from the schema, the row count and sample rows.
Which formats does it handle?
CSV, TSV, JSON and JSONL, Parquet, Avro, Excel, spatial formats, SQLite and .ipynb notebooks; anything else is read as a blob.
Source text
SKILL.md · MIT
---
name: read-file
description: >
Read any data file (CSV, JSON, Parquet, Avro, Excel, spatial, SQLite) or remote URL (S3, HTTPS).
Use when user references a data file, asks "what's in this file", or wants to preview/profile a dataset.
Not for source code.
argument-hint: <filename or URL> [question about the data]
allowed-tools: Bash
---
You are helping the user read and analyze a data file using DuckDB.
Filename given: `$0`
Question: `${1:-describe the data}`
## Step 1 — Read it
`RESOLVED_PATH` is `$0`. If the user gave a bare filename (no `/`), resolve it to a full path with `find` first.
Run a single DuckDB command that defines the `read_any` macro inline and reads the file.
For **remote files**, prepend the necessary LOAD/SECRET before the macro:
| Protocol | Prepend |
|---|---|
| `https://` / `http://` | `LOAD httpfs;` |
| `s3://` | `LOAD httpfs; CREATE SECRET (TYPE S3, PROVIDER credential_chain);` |
| `gs://` / `gcs://` | `LOAD httpfs; CREATE SECRET (TYPE GCS, PROVIDER credential_chain);` |
| `az://` / `azure://` / `abfss://` | `LOAD httpfs; LOAD azure; CREATE SECRET (TYPE AZURE, PROVIDER credential_chain);` |
For **local files**, no prefix needed.
```bash
duckdb -csv -c "
CREATE OR REPLACE MACRO read_any(file_name) AS TABLE
WITH json_case AS (FROM read_json_auto(file_name))
, csv_case AS (FROM read_csv(file_name))
, parquet_case AS (FROM read_parquet(file_name))
, avro_case AS (FROM read_avro(file_name))
, blob_case AS (FROM read_blob(file_name))
, spatial_case AS (FROM st_read(file_name))
, excel_case AS (FROM read_xlsx(file_name))
, sqlite_case AS (FROM sqlite_scan(file_name, (SELECT name FROM sqlite_master(file_name) LIMIT 1)))
, ipynb_case AS (
WITH nb AS (FROM read_json_auto(file_name))
SELECT cell_idx, cell.cell_type,
array_to_string(cell.source, '') AS source,
cell.execution_count
FROM nb, UNNEST(cells) WITH ORDINALITY AS t(cell, cell_idx)
ORDER BY cell_idx
)
FROM query_table(
CASE
WHEN file_name ILIKE '%.json' OR file_name ILIKE '%.jsonl' OR file_name ILIKE '%.ndjson' OR file_name ILIKE '%.geojson' OR file_name ILIKE '%.geojsonl' OR file_name ILIKE '%.har' THEN 'json_case'
WHEN file_name ILIKE '%.csv' OR file_name ILIKE '%.tsv' OR file_name ILIKE '%.tab' OR file_name ILIKE '%.txt' THEN 'csv_case'
WHEN file_name ILIKE '%.parquet' OR file_name ILIKE '%.pq' THEN 'parquet_case'
WHEN file_name ILIKE '%.avro' THEN 'avro_case'
WHEN file_name ILIKE '%.xlsx' OR file_name ILIKE '%.xls' THEN 'excel_case'
WHEN file_name ILIKE '%.shp' OR file_name ILIKE '%.gpkg' OR file_name ILIKE '%.fgb' OR file_name ILIKE '%.kml' THEN 'spatial_case'
WHEN file_name ILIKE '%.ipynb' THEN 'ipynb_case'
WHEN file_name ILIKE '%.db' OR file_name ILIKE '%.sqlite' OR file_name ILIKE '%.sqlite3' THEN 'sqlite_case'
ELSE 'blob_case'
END
);
DESCRIBE FROM read_any('RESOLVED_PATH');
SELECT count(*) AS row_count FROM read_any('RESOLVED_PATH');
FROM read_any('RESOLVED_PATH') LIMIT 20;
"
```
**If this fails:**
- **`duckdb: command not found`** → invoke `/duckdb-skills:install-duckdb` and retry.
- **Missing extension** (e.g. spatial files, xlsx, sqlite) → retry with `INSTALL spatial; LOAD spatial;` or `INSTALL sqlite_scanner; LOAD sqlite_scanner;` prepended before the macro.
- **Wrong reader / parse error** → use the correct `read_*` function directly instead of `read_any`.
## Step 2 — Answer
Using the schema, row count, and sample rows, answer:
`${1:-describe the data: summarize column types, row count, and any notable patterns.}`
© duckdb · MIT · duckdb/duckdb-skills