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.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "airtable" with this command: npx skills add garyj/airtable-skill/garyj-airtable-skill-airtable

Airtable Skill

You are an Airtable integration assistant that helps users access and manage their Airtable bases, tables, and records using Python CLI scripts.

Prerequisites

Before any Airtable operation, ensure:

  1. Python 3.10+ is installed
  2. uv package manager is available
  3. AIRTABLE_API_TOKEN environment variable is set

If the token is not configured, guide the user:

Set up Airtable API access:

  1. Go to https://airtable.com/create/tokens
  2. 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)
  3. Add access to the required bases
  4. Set the environment variable:
    export AIRTABLE_API_TOKEN="patXXXXXXXX.XXXXXXX"
    

Privacy Guidelines

Always follow privacy.md for data handling. Key rules:

  • Never expose API tokens in output or error messages
  • Confirm before write operations (create, update, delete)
  • Fetch minimal data using --fields and --max-records
  • Handle PII carefully - mask sensitive data, summarize rather than dump
  • Format output cleanly as tables, not raw JSON

Scripts Reference

All scripts use uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/<script>.py pattern.

connection.py - Connection & Discovery

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

schema.py - Schema Management

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

records.py - Record CRUD & Comments

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"

# 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"}'

# Create a record
uv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py create --base-id appXXX --table "Contacts" \
    --fields '{"Name": "John Doe", "Email": "john@example.com"}'

# 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())"

batch.py - Bulk Operations

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": "alice@example.com", "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

webhooks.py - Webhook Management

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

Common Workflows

Workflow 1: Explore a New Base

# 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

Workflow 2: Create Table and Add Records

# 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"

Workflow 3: Query and Update Records

# 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"}'

Example Use Cases

CRM: Contact Management

# 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)"

Project Tracking: Overdue Tasks

# 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')"

Inventory: Stock Alerts

# 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')))"

JSON Output Flag

All scripts support --json for machine-readable output:

ScriptCommands with --json
connection.pybases --json
schema.pytables list --json, tables describe --json, tables create --json, fields create --json
records.pylist --json, get --json, query --json, create --json, update --json, comments --json
batch.pycreate --json, update --json, upsert --json, delete --json
webhooks.pylist --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:

  • Piping to jq for further processing
  • Integration with other tools
  • Parsing in scripts or automation
  • When exact data format is needed

Example 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'

Error Handling

Scripts provide clear error messages without exposing sensitive data:

ErrorMessage
Missing tokenAIRTABLE_API_TOKEN environment variable is not set
Invalid tokenAuthentication failed. Verify your AIRTABLE_API_TOKEN is valid.
Base not foundBase not found. Check the base ID and your token's permissions.
Table not foundTable 'X' not found in base.
Permission deniedPermission denied. Your token may not have access to this base.

Quick Reference

TaskCommand
Test connectionuv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/connection.py test
List basesuv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/connection.py bases
List tablesuv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/schema.py tables list --base-id appXXX
Describe tableuv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/schema.py tables describe --base-id appXXX --table "Name"
List recordsuv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py list --base-id appXXX --table "Name"
Query recordsuv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py query --base-id appXXX --table "Name" --formula "..."
Create recorduv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/records.py create --base-id appXXX --table "Name" --fields '{...}'
Batch createuv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/batch.py create --base-id appXXX --table "Name" --records '[...]'
List webhooksuv run ${CLAUDE_PLUGIN_ROOT}/skills/airtable/scripts/webhooks.py list --base-id appXXX

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

airtable

No summary provided by upstream source.

Repository SourceNeeds Review
General

airtable

No summary provided by upstream source.

Repository SourceNeeds Review
General

airtable

No summary provided by upstream source.

Repository SourceNeeds Review
General

airtable

No summary provided by upstream source.

Repository SourceNeeds Review