From c997183f535289e24ce43e4f24c656b39ceae63f Mon Sep 17 00:00:00 2001 From: Sonoyunchu Date: Sun, 26 Apr 2026 04:30:18 +0300 Subject: [PATCH] feat(skills): add bundled Airtable productivity skill --- skills/productivity/airtable/SKILL.md | 105 ++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 skills/productivity/airtable/SKILL.md diff --git a/skills/productivity/airtable/SKILL.md b/skills/productivity/airtable/SKILL.md new file mode 100644 index 0000000000..b66c4d987d --- /dev/null +++ b/skills/productivity/airtable/SKILL.md @@ -0,0 +1,105 @@ +--- +name: airtable +description: Read/write Airtable bases via REST API +metadata: + hermes: + tags: [Productivity, Database, API] + config: + - key: airtable.api_key + description: Airtable personal access token or API key for REST API calls + prompt: Airtable API key +--- + +# Airtable REST API + +Use Airtable's REST API with `curl` and Python stdlib only. Do not add third-party Python packages for this skill. + +## When to Use + +- Load this skill when the user mentions an Airtable base, table, or record. +- Use it for listing bases and tables, reading records, filtering records, and creating, updating, or deleting records. +- Prefer the REST API over browser/UI automation for routine Airtable data work. + +## Quick Reference + +Use a token header on every request: + +```bash +AIRTABLE_API_KEY="..." # from skills.config.airtable.api_key +AUTH_HEADER="Authorization: Bearer $AIRTABLE_API_KEY" +``` + +List records: + +```bash +curl -s "https://api.airtable.com/v0/$BASE_ID/$TABLE?maxRecords=10" \ + -H "$AUTH_HEADER" +``` + +Create a record: + +```bash +curl -s -X POST "https://api.airtable.com/v0/$BASE_ID/$TABLE" \ + -H "$AUTH_HEADER" \ + -H "Content-Type: application/json" \ + -d '{"fields":{"Name":"New task","Status":"Todo"}}' +``` + +Update a record: + +```bash +curl -s -X PATCH "https://api.airtable.com/v0/$BASE_ID/$TABLE/$RECORD_ID" \ + -H "$AUTH_HEADER" \ + -H "Content-Type: application/json" \ + -d '{"fields":{"Status":"Done"}}' +``` + +Delete a record: + +```bash +curl -s -X DELETE "https://api.airtable.com/v0/$BASE_ID/$TABLE/$RECORD_ID" \ + -H "$AUTH_HEADER" +``` + +## Procedure + +1. Authenticate first. Read `airtable.api_key` from skill config and use it as the bearer token for every request. If the credential is missing or invalid, stop and ask the user to configure it before continuing. +2. List bases to find the right `baseId`. Prefer: + ```bash + curl -s "https://api.airtable.com/v0/meta/bases" \ + -H "$AUTH_HEADER" + ``` + If this fails because the token lacks metadata scopes, ask the user for the base ID directly or ask them to provide a token with base schema access. +3. List tables for the chosen base: + ```bash + curl -s "https://api.airtable.com/v0/meta/bases/$BASE_ID/tables" \ + -H "$AUTH_HEADER" + ``` + Use this to confirm table names, table IDs, and field names before mutating data. +4. Perform CRUD against the target table: + - Read records with `GET /v0/$BASE_ID/$TABLE`. + - Create with `POST /v0/$BASE_ID/$TABLE` and a JSON body shaped like `{"fields": {...}}`. + - Update with `PATCH /v0/$BASE_ID/$TABLE/$RECORD_ID` and only the fields that should change. + - Delete with `DELETE /v0/$BASE_ID/$TABLE/$RECORD_ID`. +5. For tables with many records, follow Airtable pagination. Keep requesting the same list endpoint with the returned `offset` value until the response stops including `offset`. +6. Prefer stable IDs (`app...`, `tbl...`, `rec...`) over human-readable names when the base is large, table names contain spaces, or the user may rename objects while the session is active. + +## Pitfalls + +- Airtable's Web API rate limit is `5 req/sec/base`. If you hit HTTP `429`, slow down, retry with backoff, and avoid firing parallel mutations into the same base. +- `filterByFormula` must be URL-encoded when you are using raw `curl`. Use Python stdlib instead of extra packages: + ```bash + python -c "import urllib.parse; print(urllib.parse.quote(\"{Status}='Todo'\", safe=''))" + ``` + Then pass the encoded value as `filterByFormula=...`. +- List-record responses can omit empty fields. If field names look incomplete, inspect the table schema first instead of assuming the field does not exist. + +## Verification + +Run: + +```bash +hermes -q "List records in my Airtable base X" +``` + +Successful verification means Hermes identifies the right base and table, authenticates, and returns records through the REST API instead of asking for extra dependencies.