gooutside
An agent that finds in-person events near you and keeps them in your calendar. Updated every day.
gooutside.monadically.com · version 2 · 2 steps
find
agent · gemini/gemini-3-flash-preview · tools: geo.zip_lookup, geo.distances_from_zip, firecrawl.web_search, agent:event-page, agent:source-19hz · up to 25 turns
Find in-person events for the next 14 days (today through today + 13 days) within the input number of miles of the input zip code.
If the input has interests, keep only events that match them, and follow every exclusion in them. With no interests, keep a broad mix.
How to work:
1. zip_lookup the zip code to learn the town and state.
2. Find the best local event listing pages: web_search for event calendars, listings, and venue calendars of that town and nearby towns, including ones for the interests. Prefer pages that list many dated events.
3. Read sources with sub-agents. Call agent_event_page once for each promising listing page (up to 8 pages). Call several in the same turn: they run in parallel.
If the town is near a 19hz.info region (for example BayArea, LosAngeles, Seattle, Texas), also call agent_source_19hz for that region.
4. Call distances_from_zip once with the places of the events you are keeping ("Venue, City, ST" or an address). Drop events farther than the input miles. Keep an event with an unknown distance only if its city is clearly inside the radius.
5. Remove duplicates of the same event from different sources.
6. finish with the events, each with its distance in miles when known. Aim for quality over count; up to 150 events.Output schema
{
"type": "object",
"properties": {
"events": {
"type": "array",
"items": {
"type": "object",
"properties": {
"title": {
"type": "string"
},
"start": {
"type": "string",
"description": "Local start: 2026-10-05T19:00, or 2026-10-05 when no time is given"
},
"end": {
"type": "string"
},
"venue": {
"type": "string"
},
"address": {
"type": "string"
},
"city": {
"type": "string"
},
"url": {
"type": "string",
"description": "Link to the event page"
},
"price": {
"type": "string"
},
"tags": {
"type": "string",
"description": "Kind of event, genre, or short description"
},
"miles": {
"type": "number",
"description": "Miles from the zip code, from distances_from_zip"
},
"why": {
"type": "string",
"description": "Few words: why it matches the interests"
}
},
"required": [
"title",
"start",
"url"
]
}
}
},
"required": [
"events"
]
}
calendar
timeout 1m, 2 retries
// Turn the agent's events into calendar entries, in date order.
const day = s => { const m = String(s || '').match(/^(\d{4}-\d{2}-\d{2})(?:T(\d{2}:\d{2}))?/); return m ? (m[2] && m[2] !== '00:00' ? m[1] + 'T' + m[2] : m[1]) : null; };
const events = [];
for (const e of results.find.events || []) {
const start = day(e.start);
if (!e.title || !start) continue;
const end = day(e.end);
events.push({
uid: (await ctx.hash(e.title + '|' + start)).slice(0, 16) + '@gooutside.monadically.com',
title: e.title,
start,
end: end && end > start ? end : undefined,
location: [e.venue, e.address || e.city].filter(Boolean).join(', '),
url: e.url,
detail: [e.miles != null ? (e.miles < 1 ? '<1' : Math.round(e.miles)) + ' mi' : e.city, e.price, e.why].filter(Boolean).join(' · '),
description: [e.tags, e.price, e.url].filter(Boolean).join('\n'),
});
}
events.sort((a, b) => a.start.localeCompare(b.start));
return { events };