mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-07 02:51:50 +00:00
Convert the airtable skill from 'skills.config.airtable.api_key' (config.yaml, wrong bucket for a secret) to 'prerequisites.env_vars: [AIRTABLE_API_KEY]' (~/.hermes/.env), matching every other bundled skill that authenticates with an API token. Why the original shape was wrong: - metadata.hermes.config is for non-secret skill settings (paths, preferences) per references/skill-config-interface.md. Storing a bearer token under skills.config.* also triggered the documented 'hermes config migrate' nag-on-every-run problem. - The Quick Reference's 'AIRTABLE_API_KEY=...' bash line couldn't read skills.config.airtable.api_key anyway — it's a yaml path, not an env var. Follow-up polish on the same pass: - Added version/author/license frontmatter to match notion/linear. - Added prerequisites.commands: [curl]. - Setup section now specifies the PAT format (pat...) that replaced legacy 'key...' API keys in Feb 2024, plus the three required scopes (data.records:read/write, schema.bases:read) and the per-base Access list requirement. - Clarified PATCH vs PUT and pagination (100 records/page cap). - Swapped verification from 'hermes -q ...' (non-deterministic) to a curl /v0/meta/bases call that returns a verifiable HTTP status code.
4.7 KiB
4.7 KiB
| name | description | version | author | license | prerequisites | metadata | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| airtable | Read/write Airtable bases via REST API using curl. List bases, tables, and records; create, update, and delete records. No dependencies beyond curl. | 1.0.0 | community | MIT |
|
|
Airtable REST API
Use Airtable's REST API via curl to list bases, inspect schemas, and run CRUD against records. No extra packages — curl plus Python stdlib for URL encoding is enough.
Setup
- Create a personal access token (PAT) at https://airtable.com/create/tokens
- Grant these scopes (minimum):
data.records:read— read rowsdata.records:write— create / update / delete rowsschema.bases:read— list bases and tables (step 2–3 of the procedure below)
- Add to
~/.hermes/.env(or set viahermes setup):AIRTABLE_API_KEY=pat_your_token_here - In the PAT UI, also add each base you want to access to the token's "Access" list. Tokens are scoped per-base.
Note: legacy
key...API keys were deprecated in Feb 2024. PATs (starting withpat) are the only supported format.
API Basics
- Base URL:
https://api.airtable.com/v0 - Auth header:
Authorization: Bearer $AIRTABLE_API_KEY - Object IDs: bases
app..., tablestbl..., recordsrec.... Prefer IDs over names when table names have spaces or may change. - Rate limit: 5 requests/sec/base. On
429, back off and avoid parallel mutations into the same base.
Quick Reference
AUTH="Authorization: Bearer $AIRTABLE_API_KEY"
BASE_ID=appXXXXXXXXXXXXXX
TABLE=Tasks # or tblXXXXXXXXXXXXXX
List records (first 10):
curl -s "https://api.airtable.com/v0/$BASE_ID/$TABLE?maxRecords=10" -H "$AUTH"
Create a record:
curl -s -X POST "https://api.airtable.com/v0/$BASE_ID/$TABLE" \
-H "$AUTH" -H "Content-Type: application/json" \
-d '{"fields":{"Name":"New task","Status":"Todo"}}'
Update a record (partial — PATCH preserves other fields):
curl -s -X PATCH "https://api.airtable.com/v0/$BASE_ID/$TABLE/$RECORD_ID" \
-H "$AUTH" -H "Content-Type: application/json" \
-d '{"fields":{"Status":"Done"}}'
Delete a record:
curl -s -X DELETE "https://api.airtable.com/v0/$BASE_ID/$TABLE/$RECORD_ID" -H "$AUTH"
Procedure
- Authenticate. Confirm
AIRTABLE_API_KEYis set. If empty, stop and ask the user to add it to~/.hermes/.env. - Find the base. List all bases the token can see:
Requirescurl -s "https://api.airtable.com/v0/meta/bases" -H "$AUTH"schema.bases:read. If the token lacks that scope, ask the user for the base ID directly. - Inspect the schema. List tables and fields for the chosen base:
Use this to confirm table names, IDs, and field names before mutating data.curl -s "https://api.airtable.com/v0/meta/bases/$BASE_ID/tables" -H "$AUTH" - CRUD against the target table.
- Read:
GET /v0/$BASE_ID/$TABLE - Create:
POST /v0/$BASE_ID/$TABLEwith{"fields": {...}} - Update:
PATCH /v0/$BASE_ID/$TABLE/$RECORD_IDwith only the fields to change (usePUTfor full replacement) - Delete:
DELETE /v0/$BASE_ID/$TABLE/$RECORD_ID
- Read:
- Paginate long lists. The list endpoint caps at 100 records per page. If the response includes
"offset": "...", pass it back as?offset=<value>on the next call and repeat until the field is absent.
Pitfalls
filterByFormulamust be URL-encoded. Use Python stdlib — no extra packages:ENC=$(python3 -c "import urllib.parse, sys; print(urllib.parse.quote(sys.argv[1], safe=''))" "{Status}='Todo'") curl -s "https://api.airtable.com/v0/$BASE_ID/$TABLE?filterByFormula=$ENC" -H "$AUTH"- Empty fields are omitted from responses. If a record looks like it's missing fields, inspect the table schema (step 3) before concluding the field doesn't exist.
- Tokens are per-base. The PAT UI requires adding each base to the token's Access list. A 403 on a specific base usually means the base wasn't granted, not that the token is wrong.
- PATCH vs PUT.
PATCHmerges the supplied fields into the existing record;PUTreplaces the record entirely, wiping any fields you didn't include. Default toPATCHunless you genuinely want to clear other fields.
Verification
curl -s -o /dev/null -w "%{http_code}\n" "https://api.airtable.com/v0/meta/bases" \
-H "Authorization: Bearer $AIRTABLE_API_KEY"
Expect 200 with a bases array. 401 means the key is wrong; 403 means the token is valid but lacks schema.bases:read (use step 2 workaround).