From airtable
Use when the user mentions Airtable, bases, tables, records, spreadsheets, or needs to query/manage structured data. Provides CLI utilities for connection testing, record CRUD, batch operations, schema management, and webhooks.
How this skill is triggered — by the user, by Claude, or both
Slash command
/airtable:airtableThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
You are an Airtable integration assistant that helps users access and manage their Airtable bases, tables, and records using Python CLI scripts.
You are an Airtable integration assistant that helps users access and manage their Airtable bases, tables, and records using Python CLI scripts.
Before any Airtable operation, ensure:
If the token is not configured, guide the user:
Set up Airtable API access:
- Go to https://airtable.com/create/tokens
- Create a new token with scopes:
data.records:read(read records)data.records:write(create/update/delete records)schema.bases:read(view base structure)schema.bases:write(create tables/fields)webhook:manage(for webhook operations)- Add access to the required bases
- Set the environment variable:
export AIRTABLE_API_TOKEN="patXXXXXXXX.XXXXXXX"
Always follow privacy.md for data handling. Key rules:
--fields and --max-recordsAll scripts use uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/<script>.py pattern.
Test connectivity and discover accessible bases.
# Test API connection
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/connection.py test
# List all accessible bases
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/connection.py bases
# List bases with JSON output
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/connection.py bases --json
Inspect and modify table structures.
# List all tables in a base
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/schema.py tables list --base-id appXXX
# Describe table fields
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/schema.py tables describe --base-id appXXX --table "Contacts"
# Create a new table
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/schema.py tables create --base-id appXXX --name "Tasks" \
--fields '[{"name": "Task Name", "type": "singleLineText"}, {"name": "Due Date", "type": "date"}]'
# Delete a table
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/schema.py tables delete --base-id appXXX --table "Old Table"
# Add a field to existing table
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/schema.py fields create --base-id appXXX --table "Contacts" \
--field '{"name": "Notes", "type": "multilineText"}'
# Update field name or description
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/schema.py fields update --base-id appXXX --table "Contacts" \
--field-id fldXXX --name "Contact Notes"
# JSON output for any command
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/schema.py tables list --base-id appXXX --json
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/schema.py tables describe --base-id appXXX --table "Contacts" --json
Supported field types: singleLineText, multilineText, number, email, url, phoneNumber, singleSelect, multipleSelects, checkbox, date, dateTime, currency, percent, duration, rating, richText, multipleRecordLinks, multipleAttachments, multipleLookupValues, rollup
# List all views on a table
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/schema.py views list --base-id appXXX --table "Contacts"
# List views with JSON output
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/schema.py views list --base-id appXXX --table "Contacts" --json
Create, read, update, delete, and query records.
# List records (default limit applies)
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py list --base-id appXXX --table "Contacts"
# List with field selection and limit
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py list --base-id appXXX --table "Contacts" \
--fields "Name,Email,Company" --max-records 10
# List with sorting
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py list --base-id appXXX --table "Contacts" --sort "Name"
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py list --base-id appXXX --table "Contacts" --sort "Name:desc"
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py list --base-id appXXX --table "Contacts" --sort "Status,Name:desc"
# List records from a specific view (applies the view's filters, sorts, and field visibility)
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py list --base-id appXXX --table "Contacts" --view "Active Contacts"
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py list --base-id appXXX --table "Contacts" --view "Active Contacts" --max-records 10
# Get a specific record
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py get --base-id appXXX --table "Contacts" --record-id recXXX
# Query with Airtable formula
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py query --base-id appXXX --table "Contacts" \
--formula "{Status}='Active'"
# Query with match criteria (equality matching)
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py query --base-id appXXX --table "Contacts" \
--match '{"Status": "Active", "Company": "Acme Corp"}'
# Query within a specific view
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py query --base-id appXXX --table "Contacts" \
--formula "{Status}='Active'" --view "Active Contacts"
# Create a record
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py create --base-id appXXX --table "Contacts" \
--fields '{"Name": "John Doe", "Email": "[email protected]"}'
# Update a record
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py update --base-id appXXX --table "Contacts" \
--record-id recXXX --fields '{"Status": "Inactive"}'
# Delete a record
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py delete --base-id appXXX --table "Contacts" \
--record-id recXXX
# List comments on a record
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py comments --base-id appXXX --table "Contacts" \
--record-id recXXX
# Add a comment to a record
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py add-comment --base-id appXXX --table "Contacts" \
--record-id recXXX --text "Followed up via email"
# Delete a comment from a record
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py delete-comment --base-id appXXX --table "Contacts" \
--record-id recXXX --comment-id comXXX
# JSON output
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py list --base-id appXXX --table "Contacts" --json
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py get --base-id appXXX --table "Contacts" --record-id recXXX --json
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py query --base-id appXXX --table "Contacts" --formula "{Status}='Active'" --json
Formula examples:
# Basic comparisons
--formula "{Status}='Active'"
--formula "{Score}>20"
# Lookup fields (from linked tables)
--formula "{Company Name (from Company)}='Acme'"
# Rollup aggregations
--formula "{Total Amount}>1000"
# Text search in fields
--formula "FIND('Active',{Status (from Projects)})"
--formula "SEARCH('smith',LOWER({Contact Name}))"
# Combined conditions
--formula "AND({Status}='Active',{Total Amount}>1000)"
--formula "OR({Priority}='High',{Due Date}<TODAY())"
Efficient batch create, update, upsert, and delete.
# Batch create records
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/batch.py create --base-id appXXX --table "Contacts" \
--records '[{"Name": "Alice"}, {"Name": "Bob"}, {"Name": "Charlie"}]'
# Batch update records
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/batch.py update --base-id appXXX --table "Contacts" \
--records '[{"id": "recXXX", "fields": {"Status": "Active"}}, {"id": "recYYY", "fields": {"Status": "Inactive"}}]'
# Upsert records (create or update based on key fields)
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/batch.py upsert --base-id appXXX --table "Contacts" \
--records '[{"Email": "[email protected]", "Name": "Alice Updated"}]' \
--key-fields "Email"
# Batch delete records
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/batch.py delete --base-id appXXX --table "Contacts" \
--record-ids "recXXX,recYYY,recZZZ"
# JSON output
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/batch.py create --base-id appXXX --table "Contacts" --records '[...]' --json
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/batch.py upsert --base-id appXXX --table "Contacts" --records '[...]' --key-fields "Email" --json
Create and manage webhooks for change notifications.
# List all webhooks
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/webhooks.py list --base-id appXXX
# Get webhook details
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/webhooks.py get --base-id appXXX --webhook-id whXXX
# Create a webhook (watch all table data)
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/webhooks.py create --base-id appXXX \
--url "https://example.com/webhook" \
--spec '{"options": {"filters": {"dataTypes": ["tableData"]}}}'
# Create webhook for specific table
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/webhooks.py create --base-id appXXX \
--url "https://example.com/webhook" \
--spec '{"options": {"filters": {"dataTypes": ["tableData"], "recordChangeScope": "tblXXX"}}}'
# Get webhook payloads
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/webhooks.py payloads --base-id appXXX --webhook-id whXXX
# Get payloads with cursor (pagination)
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/webhooks.py payloads --base-id appXXX --webhook-id whXXX --cursor 123
# Delete a webhook
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/webhooks.py delete --base-id appXXX --webhook-id whXXX
# JSON output
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/webhooks.py list --base-id appXXX --json
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/webhooks.py payloads --base-id appXXX --webhook-id whXXX --json
# 1. Test connection
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/connection.py test
# 2. List available bases
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/connection.py bases
# 3. List tables in the base
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/schema.py tables list --base-id appXXX
# 4. Describe table structure
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/schema.py tables describe --base-id appXXX --table "Tasks"
# 5. Preview records
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py list --base-id appXXX --table "Tasks" --max-records 5
# 1. Create a new table with initial fields
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/schema.py tables create --base-id appXXX --name "Invoices" \
--fields '[
{"name": "Invoice ID", "type": "singleLineText"},
{"name": "Amount", "type": "currency", "options": {"precision": 2, "symbol": "$"}},
{"name": "Date", "type": "date"},
{"name": "Status", "type": "singleSelect", "options": {"choices": [{"name": "Pending"}, {"name": "Paid"}, {"name": "Overdue"}]}}
]'
# 2. Add records in batch
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/batch.py create --base-id appXXX --table "Invoices" \
--records '[
{"Invoice ID": "INV-001", "Amount": 1500, "Date": "2024-01-15", "Status": "Paid"},
{"Invoice ID": "INV-002", "Amount": 1500, "Date": "2024-02-15", "Status": "Pending"}
]'
# 3. Query to verify
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py list --base-id appXXX --table "Invoices"
# 1. Query with a formula
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py query --base-id appXXX --table "Tasks" \
--formula "IS_BEFORE({Due Date}, TODAY())"
# 2. Update matching records (one at a time or batch)
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py update --base-id appXXX --table "Tasks" \
--record-id recXXX --fields '{"Status": "Overdue"}'
# Find contacts needing follow-up
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py query --base-id appXXX --table "Contacts" \
--formula "IS_BEFORE({Last Contacted}, DATEADD(TODAY(), -30, 'days'))"
# Find high-value leads
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py query --base-id appXXX --table "Contacts" \
--formula "AND({Status}='Lead', {Deal Value}>5000)"
# Find overdue tasks
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py query --base-id appXXX --table "Tasks" \
--formula "AND(IS_BEFORE({Due Date}, TODAY()), {Status}!='Done')"
# Find tasks assigned to a team member across linked projects
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py query --base-id appXXX --table "Tasks" \
--formula "AND({Assignee}='Alice', {Project Status (from Project)}='Active')"
# Find items below reorder threshold
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py query --base-id appXXX --table "Inventory" \
--formula "{Quantity}<{Reorder Level}"
# Find items expiring in next 30 days
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py query --base-id appXXX --table "Inventory" \
--formula "AND({Expiry Date}, IS_BEFORE({Expiry Date}, DATEADD(TODAY(), 30, 'days')))"
All scripts support --json for machine-readable output:
| Script | Commands with --json |
|---|---|
| connection.py | bases --json |
| schema.py | tables list --json, tables describe --json, tables create --json, fields create --json, views list --json |
| records.py | list --json, get --json, query --json, create --json, update --json, comments --json |
| batch.py | create --json, update --json, upsert --json, delete --json |
| webhooks.py | list --json, get --json, create --json, payloads --json |
Important: When parsing script output programmatically (e.g., in migration scripts or automation), always use the --json flag. The human-readable output is not designed for machine parsing and may cause incorrect results.
JSON output is useful for:
jq for further processingExample with jq:
# Count active records
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py query --base-id appXXX --table "Contacts" \
--formula "{Status}='Active'" --json | jq 'length'
# Extract specific field from records
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py list --base-id appXXX --table "Contacts" --json \
| jq '.[].fields.Email'
# Get record IDs only
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py list --base-id appXXX --table "Contacts" --json \
| jq '.[].id'
Scripts provide clear error messages without exposing sensitive data:
| Error | Message |
|---|---|
| Missing token | AIRTABLE_API_TOKEN environment variable is not set |
| Invalid token | Authentication failed. Verify your AIRTABLE_API_TOKEN is valid. |
| Base not found | Base not found. Check the base ID and your token's permissions. |
| Table not found | Table 'X' not found in base. |
| Permission denied | Permission denied. Your token may not have access to this base. |
| Task | Command |
|---|---|
| Test connection | uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/connection.py test |
| List bases | uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/connection.py bases |
| List tables | uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/schema.py tables list --base-id appXXX |
| Describe table | uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/schema.py tables describe --base-id appXXX --table "Name" |
| List views | uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/schema.py views list --base-id appXXX --table "Name" |
| List records | uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py list --base-id appXXX --table "Name" |
| Query records | uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py query --base-id appXXX --table "Name" --formula "..." |
| Create record | uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py create --base-id appXXX --table "Name" --fields '{...}' |
| Batch create | uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/batch.py create --base-id appXXX --table "Name" --records '[...]' |
| List webhooks | uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/webhooks.py list --base-id appXXX |
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub garyj/airtable-skill --plugin airtable