s3-explore — Claude Code skill: query S3 without downloading
This skill lists what sits in a bucket and runs SQL against Parquet, CSV and JSON files on object storage in place.
npx skills add duckdb/duckdb-skills --skill s3-explore -a claude-codeWhat s3-explore does
The skill fires when a message contains an s3://, r2://, gs:// or gcs:// URL. The agent picks the provider and sets up access: AWS S3, Cloudflare R2 and GCS go through CREATE SECRET with PROVIDER credential_chain, while MinIO and other S3-compatible stores need KEY_ID, SECRET and ENDPOINT. Public buckets such as Overture Maps skip that step entirely.
Point it at a bucket or folder and you get a file listing with sizes and modification dates. Point it at a single file or a glob and you get the schema, a row count and the first 20 rows. Parquet is handled through parquet_metadata, so row counts and compressed sizes come from metadata rather than a download.
Analytical questions turn into SQL. DuckDB pushes predicates into Parquet on S3, which keeps filtering cheap on large remote datasets. Everything runs through the duckdb CLI and the httpfs extension, so a local duckdb has to be there — when the command is missing, the skill hands off to /duckdb-skills:install-duckdb. A 403 usually means credentials need a look via aws configure or environment variables; a 404 points at the URL or region.
What it helps with
- see which files a bucket holds and how big they are
- read the schema of a remote Parquet file before pulling it
- count rows in an S3 dataset from metadata
- run a SQL filter over data in object storage
- check whether a bucket is reachable and the keys still work
Example prompts for the agent
- /s3-explore s3://my-bucket/data/ — what's in there?
- /s3-explore s3://my-bucket/events.parquet how many rows last week?
- /s3-explore gs://public-bucket/ — show the schema and first rows
How to install s3-explore
1Skills CLI (Vercel)
npx skills add duckdb/duckdb-skills --skill s3-explore -a claude-code2Manually: put the files in place
~/.claude/skills/s3-explore/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/s3-explore/
1Skills CLI (Vercel)
npx skills add duckdb/duckdb-skills --skill s3-explore -a codex2Manually: put the files in place
.agents/skills/s3-explore/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add duckdb/duckdb-skills --skill s3-explore -a cursor2Manually: put the files in place
.cursor/skills/s3-explore/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install duckdb/duckdb-skills s3-explore2Manually: put the files in place
.github/skills/s3-explore/SKILL.md1Skills CLI (Vercel)
npx skills add duckdb/duckdb-skills --skill s3-explore -a gemini-cli2Platform CLI
gemini skills install https://github.com/duckdb/duckdb-skills --path skills/s3-exploreManually: put the files in place
.devin/skills/s3-explore/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add duckdb/duckdb-skills --skill s3-explore -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 s3-explore
How do I install s3-explore in Claude?
Run npx skills add duckdb/duckdb-skills --skill s3-explore -a claude-code. The skill file lands at ~/.claude/skills/s3-explore/SKILL.md.
What does s3-explore do?
It lists bucket contents, shows the schema and row count of remote files, and runs SQL against Parquet, CSV and JSON on S3, R2, GCS and MinIO without downloading the data.
What do I need for the skill to work?
A local duckdb with the httpfs extension and working storage credentials. For AWS that means aws configure or environment variables; for MinIO, KEY_ID, SECRET and ENDPOINT inside CREATE SECRET.
Source text
SKILL.md · MIT
---
name: s3-explore
description: >
Explore and query data on S3, Cloudflare R2, GCS, MinIO, or any S3-compatible storage.
Use when the user mentions an s3://, r2://, gs://, or gcs:// URL, asks "what's in this bucket",
wants to list remote files, preview remote Parquet/CSV/JSON, or query data on object storage
without downloading it. Also triggers when the user wants to know the size, schema, or row count
of remote datasets.
argument-hint: <s3-url> [question about the data]
allowed-tools: Bash
---
You are helping the user explore data on remote object storage using DuckDB.
URL: `$0`
Question: `${1:-list and describe what's there}`
## Step 1 — Detect provider and set up credentials
Based on the URL or user context, prepend the appropriate secret configuration:
| Provider | URL patterns | Secret setup |
|---|---|---|
| **AWS S3** | `s3://` | `CREATE SECRET (TYPE S3, PROVIDER credential_chain);` |
| **Cloudflare R2** | `r2://`, `s3://` with R2 endpoint | `CREATE SECRET (TYPE R2, PROVIDER credential_chain);` |
| **GCS** | `gs://`, `gcs://` | `CREATE SECRET (TYPE GCS, PROVIDER credential_chain);` |
| **MinIO / custom** | `s3://` with custom endpoint | `CREATE SECRET (TYPE S3, KEY_ID '...', SECRET '...', ENDPOINT '...', USE_SSL true);` |
For R2, if the user provides an account ID, the endpoint is `<account_id>.r2.cloudflarestorage.com`. R2 URLs like `r2://bucket/path` should be rewritten to `s3://bucket/path` with the R2 secret.
For public buckets (e.g., Overture Maps, AWS open data), no secret is needed — skip this step.
Always prepend:
```sql
LOAD httpfs;
```
## Step 2 — Determine what the URL points to
If the URL looks like a **directory or bucket** (no file extension, or ends with `/`), list its contents with sizes:
```bash
duckdb -c "
LOAD httpfs;
<SECRET_SETUP>
SELECT filename, (size / 1024 / 1024)::DECIMAL(10,1) AS size_mb, last_modified
FROM read_blob('<URL>/*')
ORDER BY filename
LIMIT 50;
"
```
Note: only select `filename`, `size`, `last_modified` — never select `content`, which would download the actual files.
If the URL points to a **specific file or glob pattern** (has a file extension or contains `*`), preview it:
```bash
duckdb -c "
LOAD httpfs;
<SECRET_SETUP>
DESCRIBE FROM '<URL>';
SELECT count(*) AS row_count FROM '<URL>';
FROM '<URL>' LIMIT 20;
"
```
For **Parquet files**, get row counts and sizes from metadata (no data download):
```bash
duckdb -c "
LOAD httpfs;
<SECRET_SETUP>
SELECT file_name,
sum(row_group_num_rows) AS total_rows,
(sum(row_group_compressed_bytes) / 1024 / 1024)::DECIMAL(10,1) AS compressed_mb
FROM parquet_metadata('<URL>')
GROUP BY file_name;
"
```
## Step 3 — Answer the question
Using the listing, schema, or sample data, answer:
`${1:-list and describe what's there}`
If the user asks an analytical question (e.g., "how many rows match X"), write and run the appropriate SQL query. DuckDB pushes predicates down into Parquet on S3, so filtering is efficient even on large remote datasets.
## Error handling
- **`duckdb: command not found`** → delegate to `/duckdb-skills:install-duckdb`
- **Access denied / 403** → suggest the user check credentials: `aws configure`, environment variables, or provide explicit key/secret
- **Bucket not found / 404** → check the URL and region
- **Timeout on large listing** → suggest narrowing the glob pattern or adding a prefix
© duckdb · MIT · duckdb/duckdb-skills