Update and label events in the Estonia IT Events Coda database. Use when labeling events, adding missing links, or cleaning up the Coda table.
Update event labels and links in the Estonia IT Events Coda table.
ALWAYS load environment variables first:
Note: Use set -a && source ... && set +a instead of export $(grep ... | xargs) because some env vars contain paths with spaces.
set -a && source "${SKILLS_DIR:-$HOME/.claude/skills}/.env" && set +a
Note: Uses $SKILLS_DIR env var (set in .env) with a fallback to $HOME/.claude/skills. Change SKILLS_DIR in .env to use with other AI tools (e.g. Cursor).
Required env vars:
$CODA_API_TOKEN - Coda API authentication token$CODA_DOC_ID - Document ID$CODA_TABLE_ID - Table IDThe Coda table syncs from Google Calendar, but it does not auto-refresh. You must manually trigger a sync before working with the data.
browser_navigate to: https://coda.io/d/Estonia-IT-events_dzkj730WT5a/
Note: There is no API-based way to trigger this sync — the browser click is the only option.
Automatically mark past events as archived to keep the working set small:
# Get all non-archived events
QUERY=$(printf '"Archived":false' | jq -sRr @uri)
curl -s -H "Authorization: Bearer $CODA_API_TOKEN" \
"https://coda.io/apis/v1/docs/$CODA_DOC_ID/tables/$CODA_TABLE_ID/rows?useColumnNames=true&query=$QUERY" \
| jq -r '
.items[]
| select(.values.End < "'$(date -I)'")
| {
id: .id,
name: .values.Name,
end: .values.End
}
' | jq -s '. | length as $count | if $count > 0 then ("Found " + ($count | tostring) + " past events to archive") else "No past events to archive" end'
For each past event, set Archived=true:
EVENT_ID="i-xxxxx..."
curl -s -X PUT \
-H "Authorization: Bearer $CODA_API_TOKEN" \
-H "Content-Type: application/json" \
"https://coda.io/apis/v1/docs/$CODA_DOC_ID/tables/$CODA_TABLE_ID/rows/$EVENT_ID" \
-d '{
"row": {
"cells": [
{"column": "Archived", "value": true}
]
}
}' | jq '.'
Note: This keeps the API response small by filtering archived events server-side.
Get non-archived events that are missing either Labels OR Links:
# Server-side filter: only non-archived events
QUERY=$(printf '"Archived":false' | jq -sRr @uri)
curl -s -H "Authorization: Bearer $CODA_API_TOKEN" \
"https://coda.io/apis/v1/docs/$CODA_DOC_ID/tables/$CODA_TABLE_ID/rows?useColumnNames=true&query=$QUERY" \
| jq -r '
.items[]
| select(
((.values.Labels == "" or .values.Labels == null) or
(.values.Link == "" or .values.Link == null))
)
| .values.Description as $desc
| ($desc | split("\n")[0]) as $firstLine
| {
id: .id,
name: .values.Name,
start: .values.Start,
end: .values.End,
labels: (.values.Labels // "❌ MISSING"),
link: (.values.Link // "❌ MISSING"),
url_in_description: (if ($firstLine | test("^https?://")) then $firstLine else "No URL" end),
location: .values.Location,
description: $desc
}
' | jq -s '.'
Server-side filtering: Uses "Archived":false query to fetch only non-archived events, keeping the payload small.
Pro tip: Most events have the URL as the first line of description - extract and populate the Link field from there!
Get the current list of valid labels from Coda:
curl -s -H "Authorization: Bearer $CODA_API_TOKEN" \
"https://coda.io/apis/v1/docs/$CODA_DOC_ID/tables/$CODA_TABLE_ID/columns" \
| jq -r '.items[] | select(.name == "Labels") | .format.options[] | .name' | sort
Remove "🔥 New" from events that were previously labeled (this cleans up old labels):
QUERY=$(printf '"Archived":false' | jq -sRr @uri)
# Find events with "New" in labels
curl -s -H "Authorization: Bearer $CODA_API_TOKEN" \
"https://coda.io/apis/v1/docs/$CODA_DOC_ID/tables/$CODA_TABLE_ID/rows?useColumnNames=true&query=$QUERY" \
| jq -r '
.items[]
| select(.values.Labels | contains("New"))
| {
id: .id,
name: .values.Name,
labels: .values.Labels
}
' | jq -s '.'
For each event found, remove "🔥 New" from the labels (keep other labels):
EVENT_ID="i-xxxxx..."
# Example: if labels are "🔥 New,GameDev,Hackathon", set to "GameDev,Hackathon"
NEW_LABELS="GameDev,Hackathon"
curl -s -X PUT \
-H "Authorization: Bearer $CODA_API_TOKEN" \
-H "Content-Type: application/json" \
"https://coda.io/apis/v1/docs/$CODA_DOC_ID/tables/$CODA_TABLE_ID/rows/$EVENT_ID" \
-d "{
\"row\": {
\"cells\": [
{\"column\": \"Labels\", \"value\": \"$NEW_LABELS\"}
]
}
}"
Note: This step runs EVERY time to clean up "🔥 New" labels from previous runs. Only newly labeled events in step 4 get "🔥 New" added back.
⚠️ Important:
Check the url_in_description field from step 1. If present, use it to populate the Link field.
Update both Labels and Link fields:
# Example variables
EVENT_ID="i-xxxxx..."
LABELS="🔥 New,Startups,Hackathon" # ALWAYS add "🔥 New" for newly labeled events
LINK="https://example.com/event"
curl -X PUT \
-H "Authorization: Bearer $CODA_API_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"row\": {
\"cells\": [
{\"column\": \"Labels\", \"value\": \"$LABELS\"},
{\"column\": \"Link\", \"value\": \"$LINK\"}
]
}
}" \
"https://coda.io/apis/v1/docs/$CODA_DOC_ID/tables/$CODA_TABLE_ID/rows/$EVENT_ID"
Label format:
"🔥 New,Dev,Students,Hackathon"Rate limiting:
Before updating events:
❌ Not triggering Google Calendar sync before starting (data will be stale) ❌ Forgetting to run auto-archive step first ❌ Missing "Archived" column in Coda table ❌ Using keyword matching instead of reading descriptions ❌ Forgetting to add "🔥 New" to newly labeled events ❌ Wrong label format (spaces after commas) ❌ Not extracting URLs from description first lines ❌ API rate limiting (going too fast) ❌ Hardcoding IDs instead of using env vars