CRITICAL: This skill has MANDATORY step-by-step workflows for both event creation and event validation. You MUST follow the exact steps in order. Do NOT skip steps. Do NOT ask your own questions. Do NOT improvise. The workflow tells you exactly what to run and what to ask at each step.
When this skill is invoked (user says anything like "create events", "kyndlo-events", "generate events", etc.):
If the user says "validate events", "check events", "review events", or "validation" — skip directly to the Event Validation Workflow section below.
For event creation:
Events are created from campaign tasks stored in the Kyndlo database, not from user-provided descriptions. The system tells you what events to create. Your job is to follow the workflow.
bash
npm install -g gokyn
export KYNDLO_API_TOKEN="kyndlo_..."
export GOOGLE_PLACES_API_KEY="..." # Required for venue discovery via goplaces
All gokyn commands accept --token <token> if the env var is not set.
Add --json to any command for machine-readable output.
goplaces is used for venue discovery (Google Places API). It must be installed and configured separately.
Action: Run this command immediately — do not ask the user anything first.
bash
gokyn whoami --json
Confirm the token is valid. If it fails, help the user set KYNDLO_API_TOKEN.
Action: Run this command:
bash
gokyn task campaigns
Then say to the user:
"Here are the available campaigns: [show the list with name, state, progress, pending tasks]. Which campaign would you like to work on?"
STOP and wait for the user's reply. Extract the campaign name and state from their choice.
Action: Run this command using the state from the campaign they chose:
bash
gokyn task cities --state "<state>"
Then say to the user:
"Here are the cities in [state]: [show city list with populations]. Which city would you like to prioritize? Say a city name, or 'any' to work through all cities."
STOP and wait for the user's reply. Handle:
Say to the user:
"Would you like to focus on a specific county, or work through all of them? (By default, I'll focus on major city counties and skip rural counties. Say 'include rural' if you want those too.)"
STOP and wait for the user's reply. Handle:
--city "Rural". Skip the "Rural" entry when rotating. This is the default.--county <county> filter.Say to the user:
"How many events should I create before pausing to report results? (e.g. 5, 10, 20)"
STOP and wait for the user's reply. Store this as the batch size.
Action: Run this command:
bash
gokyn task rules
Read the full output and internalize every rule. These rules come from the Kyndlo admin dashboard and govern venue selection, descriptions, formatting, images, and quality. You must follow them strictly for every event.
Say to the user:
"Ready to start. Here's your configuration:
- Campaign: [name]
- State: [state]
- City: [specific city / rotating through all]
- County filter: [ignore rural (default) / include rural / specific county]
- Batch size: [N] events per batch
- Rules: Loaded
Shall I begin?"
STOP and wait for confirmation. Only proceed to the Autonomous Loop after the user says yes.
Task activityCategory values sometimes differ from activity titles in the database. Use this table when searching for the activity ID:
Task activityCategorySearch Term for gokyn activity list --searchSpecialty Niche MuseumsSpecialty & Niche MuseumsYoga ClassesWellness centersRestaurant/Cafes with Animal EncountersCoffee with animal encountersCommunity TheatersTheater loungesCraft CafesCraft cafésBeach/BoardwalksBeach BoardwalksFood TrucksFood truck parksPlanetariumsPlanetarium
If the task category is not in this table, use it as-is for the search.
When setting --recurrence-days, use these day numbers:
DayNumberSunday0Monday1Tuesday2Wednesday3Thursday4Friday5Saturday6
Include a day ONLY if the venue is open that day. Omit closed days entirely.
StateTimezoneColoradoAmerica/DenverFloridaAmerica/New_YorkNew YorkAmerica/New_York
Process tasks in batches. Each batch creates up to N events (the batch size from onboarding), then pauses to report results and ask the user whether to continue.
Important: If the loop exits early for any reason, run the Cleanup step to release any uncompleted tasks.
At the start of every batch (including the first), fetch the latest rules:
bash
gokyn task rules
Re-read and internalize. Rules may have been updated by the Kyndlo admin between batches.
Track the current city. When task next returns "count": 0 for the current city:
gokyn task cities --state "<state>" --jsongokyn task context --campaign <campaign> --city "<city>" --jsonWhen the user chose "ignore rural counties":
--city "Rural" to any commandbash
gokyn task next --campaign <campaign> --city <city> --assign --name "<agent-name>" --json
Apply filters based on onboarding preferences:
--county <county>--name (e.g. Sugar). Do NOT pass --priority — the server returns tasks in priority order automatically.If "count": 0:
"diagnostic" field, report it to the userExtract from tasks[0]: _id (taskId), county, activityCategory, cluster, state.
Check the Category Name Mapping table above. If the activityCategory matches a left-column entry, use the corresponding right-column search term. Otherwise use the category as-is.
bash
gokyn activity list --search "<mapped-category>" --json
Extract the activity _id from the first matching result. If no results, try shorter/partial search terms. If still no match, skip the task with reason "Activity not found for category: ".
Find a real venue matching the task's activityCategory in county, state. Use goplaces (Google Places API) as the primary discovery tool.
bash
goplaces search "<category> in <county> County, <state>" --json --limit 5 --region US
This returns up to 5 venues with place_id, name, address, rating, and open_now.
bash
goplaces details <place_id> --json
Extract from the response:
--booking-url)Before using a venue, verify ALL of these:
regular_opening_hours must be present. If None or missing, reject the venue.Convert hours to open day numbers (0=Sun through 6=Sat). Include a day ONLY if the venue is open that day.
If goplaces returns no results or all candidates fail validation:
Collect for the chosen venue:
Before creating an event, you MUST check if a venue already exists as an event:
bash
gokyn event list --search "<venue name>" --json
Duplicate detection rules:
gokyn task skip <taskId> --reason "All qualifying venues already have events"If you searched 5 candidates and all were duplicates, do NOT continue searching indefinitely — skip the task.
Look up the timezone from the State Timezone Reference table. Format open days as comma-separated numbers for --recurrence-days.
bash
gokyn event create \
--title "<venue name>" \
--description "<2-3 sentence description per rules>" \
--activity <activityId>:1 \
--start-date-time "2027-01-01T09:00:00Z" \
--end-date-time "2028-01-01T23:59:00Z" \
--timezone "<timezone>" \
--location-type physical \
--location-place "<venue name>" \
--location-address "<address>" \
--location-lat <latitude> \
--location-lng="<longitude>" \
--recurring \
--recurrence-frequency weekly \
--recurrence-interval 1 \
--recurrence-days "<open days>" \
--is-public=false \
--is-premium-only \
--is-active=false \
--price <price> \
--price-currency USD \
--booking-url "<venue website URL>" \
--json
CLI syntax notes:
= syntax: --location-lng="-104.99"=: --is-public=false2028-01-01T23:59:00Z (one year window for recurring events)Extract the eventId from the JSON response.
Every event must have an image. Use one of the following methods:
bash
gokyn image generate \
--prompt "A welcoming <venue-type> with <atmosphere details>, inviting for casual social meetups. Inspired by <venue name> in <city>, <state>." \
--event-id <eventId>
This generates an image using the AI provider configured in the Kyndlo dashboard (e.g. Gemini, OpenAI), optimizes it, uploads to R2, and attaches it to the event — all in one step.
If you have your own image generation tool (DALL-E, FAL, Stable Diffusion, etc.), generate the image yourself, then upload:
bash
gokyn image upload --file /tmp/venue-image.jpg --event-id <eventId>
# or from base64:
gokyn image upload --base64 "<base64-data>" --mime-type image/png --event-id <eventId>
If generation or upload fails, log the error and continue — the event is still valid without an image.
bash
gokyn task complete <taskId> --event-id <eventId> --venue "<venue name>"
Increment the batch counter. Log:
text
[Batch B, Task T/N] COMPLETED: <venue name> in <county> County (<cluster>/<category>) — Event ID: <eventId>
If the task was skipped:
text
[Batch B, Task T/N] SKIPPED: <county> County / <category> — Reason: <reason>
If the batch counter has reached the batch size ( N), go to Batch Report. Otherwise, loop back to Step 1.
After completing each batch of N events, present a report to the user:
text
=== Batch <B> Report ===
Campaign: <campaign-name>
City: <current-city>
Batch size: <N>
Created: <count>
Skipped: <count>
Failed: <count>
Events Created:
- <venue name> in <county> (<category>) — Event ID: <id>
- ...
Skipped Tasks:
- <county> / <category> — <reason>
- ...
Cumulative Totals (all batches):
Created: <total-created> | Skipped: <total-skipped> | Failed: <total-failed>
Then check remaining work:
bash
gokyn task context --campaign <campaign> --city "<current-city>" --json
Report how many tasks remain in the current scope. Then ask:
"Batch complete. tasks remaining in . Continue with the next batch?"
Wait for the user's response.
- If yes — reset the batch counter, refresh rules, and resume the loop - If no or stop — run Cleanup, then print the Final Summary - If the user changes preferences (different city, county, batch size) — update the configuration and resume
## Error Recovery
ErrorRecoveryNo tasks returned (count: 0)If diagnostic field present, report it to the user — it may indicate stale in-progress tasks that need releasing. If city="any", rotate to next city. Otherwise stop the loop.Diagnostic says tasks are "in_progress (possibly stale)"Run gokyn task release-stale --minutes 60 to release stuck tasks, then retry.Duplicate event foundSkip venue, try next candidate. If all candidates are duplicates, skip the task with reason "All qualifying venues already have events".No venues foundTry broader search terms. If still none, skip task.No venues with determinable hoursSkip task with reason "No venues with published hours".Activity ID not foundTry partial/shorter search terms. If still not found, skip task.Event creation failsLog the error. Release the task: gokyn task release <taskId>. Continue.Photo download/upload failsContinue without photo. Still complete the task.gokyn task complete failsLog the error. Release the task: gokyn task release <taskId>. Report the event ID.Agent interrupted or unexpected errorRelease all claimed-but-uncompleted tasks. See Cleanup.
## Cleanup
Before exiting — whether normally or due to an error — release any task that was claimed but not completed or skipped. bash
```bash gokyn task release
```
If you have multiple uncompleted tasks, or if previous agents left stale tasks behind, use the bulk release command: bash
```bash gokyn task release-stale --minutes 60
```
This releases all in_progress tasks that were assigned more than 60 minutes ago back to pending.
Rule: A task must NEVER be left in in_progress status when the agent exits. Every claimed task must end in one of three states:
- completed — event created successfully - skipped — permanent failure (no venues, category not found) - released (back to pending) — transient failure (API error, timeout)
Use skip for permanent failures. Use release for transient failures.
## Final Summary
After all batches are done (or the user stops), print a final session summary: text
``` === Event Creation Session Summary === Campaign: State: Cities worked: Total batches: Total created: Total skipped: Total failed:
All Created Events: - in () — Event ID: - ...
All Skipped Tasks: - / — - ...
All Failed Tasks: - / — - ...
```
## Skipping a Task
bash
```bash gokyn task skip --reason "No qualifying venue found in County for "
```
Always provide a specific reason.
## Releasing a Task
bash
```bash # Release a single task gokyn task release
# Release all stale tasks (assigned more than N minutes ago) gokyn task release-stale --minutes 60
```
## Starting a New State
When a campaign needs to cover a new US state: bash
```bash # 1. Register the state with its counties *gokyn task register-state --state "New York" * --counties "New York,Kings,Queens,Bronx,Richmond,Nassau,Suffolk"
# 2. Check city/metro areas gokyn task cities --state "New York"
# 3. Seed the campaign *gokyn task seed --campaign "newyork-2027" --state "New York" * *--counties "New York,Kings,Queens,Bronx,Richmond" * --clusters-json '{ "intellectual": ["History Museums", "Bookstore Cafes"], "visionary": ["Escape Rooms", "Comedy Clubs"], "protector": ["Yoga Classes", "Botanic Gardens"], "creator": ["Art Museums", "Pottery Painting Studios"] }'
# 4. Verify gokyn task campaigns gokyn task context --campaign "newyork-2027"
```
## Event Validation Workflow
CRITICAL: This is a MANDATORY step-by-step workflow for validating events. Follow each step in order.
Validations are periodic re-checks of existing events to ensure venue data (hours, price, address, website, status) is still accurate. Events go stale over time — venues close, change hours, raise prices, or move. Your job is to verify each event against current real-world data and report issues.
### Validation Step 1: Check validation stats
bash
```bash gokyn validation summary
```
Report the summary to the user:
> "Validation queue: [total] total — [pending] pending, [valid] valid, [invalid] invalid, [needsUpdate] needs update, [overdue] overdue. Ready to start validating?"
STOP and wait for the user's reply.
### Validation Step 2: Ask preferences
Say to the user:
> "How many validations should I process before pausing to report? (e.g. 5, 10, 20). Would you like to filter by state or county?"
STOP and wait for the user's reply. Store batch size and optional filters.
### Validation Step 3: Claim next validation
bash
```bash gokyn validation next --assign --json
```
Add filters if specified: --state <state> and/or --county <county>.
If no validations returned, report to the user and stop.
Extract from the response:
- _id (validationId)
- eventId
- eventTitle
- county, state
- status, priority
- lastValidatedAt (when it was last checked)
### Validation Step 4: Fetch the event details
bash
```bash gokyn event get --json
```
Extract the current event data:
- title — venue name - description - location.address — street address - location.place — venue name at the location - location.coordinates — lat/lng - price — listed price - bookingUrl — venue website - recurrence.daysOfWeek — which days the event recurs - startDateTime / endDateTime - activities — linked activity categories
### Validation Step 5: Verify against real-world data
Use goplaces to look up the venue and compare: bash
```bash goplaces search " in County, " --json --limit 3 --region US
```
Find the matching venue, then get full details: bash
```bash goplaces details <place_id> --json
```
#### What to check:
FieldHow to verifyIssue fieldStill openCheck if the place is marked permanently_closed or not foundotherAddressCompare goplaces address with event location.address``location.addressHoursCompare regular_opening_hours.weekday_descriptions with event recurrence.daysOfWeek``recurrence.daysOfWeekPriceCheck if entry fee has changed (from website if needed)priceWebsiteVerify bookingUrl is still valid and points to the right venuebookingUrlNameCheck if the venue has been renamedother
#### Severity guidelines:
- error — Venue permanently closed, wrong address, completely wrong hours, broken/unrelated website
- warning — Minor hour changes (e.g. one day different), price changed slightly, website redirects but still works
### Validation Step 6: Submit the result
Based on your findings, submit one of three statuses:
#### If everything checks out:
bash
```bash gokyn validation submit --status valid
```
#### If there are issues that make the event inaccurate:
bash
```bash *gokyn validation submit --status invalid * --issues-json '[{"field":"","severity":"<error|warning>","description":"","currentValue":"","expectedValue":""}]'
```
Multiple issues can be reported in the array: bash
```bash *gokyn validation submit --status invalid * --issues-json '[ {"field":"recurrence.daysOfWeek","severity":"error","description":"Venue now closed on Mondays","currentValue":"0,1,2,3,4,5,6","expectedValue":"0,2,3,4,5,6"}, {"field":"price","severity":"warning","description":"Entry fee increased","currentValue":"$0","expectedValue":"$10"} ]'
```
#### If minor updates are needed but the event is mostly correct:
bash
```bash *gokyn validation submit --status needs_update * --notes "Hours changed for summer season — now opens at 10am instead of 9am"
```
### Validation Step 7: Track progress
Log each result: text
``` [Batch B, V/N] VALID: in County — no issues [Batch B, V/N] INVALID: in County — issues found [Batch B, V/N] NEEDS_UPDATE: in County —
```
If the venue was not found on goplaces at all: bash
```bash *gokyn validation submit --status invalid * --issues-json '[{"field":"other","severity":"error","description":"Venue not found on Google Places — may be permanently closed"}]'
```
### Validation Step 8: Check batch completion
If the batch counter has reached the batch size, go to Validation Batch Report. Otherwise loop back to Validation Step 3.
### Validation Batch Report
After each batch, present: text
``` === Validation Batch Report === Processed: Valid: Invalid: Needs Update:
Results: - () — VALID - () — INVALID: - ...
Cumulative Totals (all batches): Valid: | Invalid: | Needs Update:
```
Then check remaining: bash
```bash gokyn validation summary
```
> "Batch complete. validations remaining. Continue?"
Wait for the user's response.
## Browsing Activities and Events
bash
```bash gokyn activity list --search "yoga" --limit 10 gokyn activity list --category "wellness" --json gokyn activity get gokyn activity categories
gokyn event list --limit 10 gokyn event list --search "garden" --is-active --json gokyn event get
```
## Updating and Deleting Events
bash
```bash gokyn event update --title "New Title" gokyn event update --is-active=false gokyn event update --price 25 --price-currency USD gokyn event update --activity :1 --activity :2 *gokyn event update * *--location-type physical * *--location-place "New Venue" * *--location-address "123 Main St" * *--location-lat 40.7 * --location-lng="-74.0" gokyn event delete
```
## Geographic Queries
bash
```bash gokyn task states # List registered US states gokyn task counties --state "Colorado" # List counties in a state gokyn task cities --state "Colorado" # List metro areas + rural breakdown
```
## Command Quick Reference
CommandPurposegokyn whoamiVerify token and permissionsgokyn task rulesRead event creation rules (MANDATORY before each batch)gokyn task campaignsList campaigns with progressgokyn task context --campaign <id>Campaign progress, next countygokyn task summary --campaign <id>Detailed stats by city and countygokyn task cities --state <s>Metro areas and county mappingsgokyn task next --campaign <id> --city <c> --assign --name <n>Claim next taskgokyn task complete <id> --event-id <eid>Mark task donegokyn task skip <id> --reason <r>Skip impossible taskgokyn task release <id>Unclaim a taskgokyn task release-stale --minutes 60Release all stale in-progress tasksgokyn task seed --campaign <id> ...Seed tasks for countiesgokyn activity list / get / categoriesBrowse activitiesgoplaces search "<query>" --json --limit 5 --region USSearch venues by category and locationgoplaces details <place_id> --jsonGet venue hours, address, coordinatesgokyn event list / get / create / update / deleteManage eventsgokyn image generate --prompt <p> --event-id <eid>Generate AI image and attach to eventgokyn image upload --file <f> --event-id <eid>Upload venue photo from filegokyn validation next / submit / summaryEvent validation
## Global Flags
FlagEnvDescription--token <token>``KYNDLO_API_TOKENAPI token (required)--base-url <url>``KYNDLO_API_URLAPI base URL (default: https://api.kyndlo.com)--jsonMachine-readable JSON output--timeout <ms>HTTP timeout in ms (default: 30000)--no-color``NO_COLORDisable ANSI colors
## Tips
- Always use --json when parsing output programmatically
- Always pass --name with --assign to track who claimed a task
- Use --city to focus on a metro area: --city "Denver" or --city "Rural"
- Negative numbers need = syntax: --location-lng="-104.99"
- Boolean flags: --is-public = true, --is-public=false = false
- IDs are 24-character hex strings (MongoDB ObjectId)
- Dates are ISO 8601: 2027-01-01T09:00:00Z