location
Location tracking, place recognition, visit history, and calendar attendance
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
Location tracking, place recognition, visit history, and calendar attendance
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
Calendar operations with CalDAV
Git repository management, GitLab merge requests, and GitHub pull requests
Persistent memory writes — USER.md (behavioral) and the knowledge graph (facts).
Accounting operations (ledger, invoicing, transactions, work log, investment portfolio) — runs in-process via the vendored money package
Send a push notification to the user's configured ntfy device(s). One-way (bot to phone), no reply channel.
Briefing formatting guidelines for chat messages
| name | location |
| triggers | ["location","gps","where","place","places","visit","visits","track","position","coordinates","attendance","reverse geocode","day summary","neighborhood","summary"] |
| description | Location tracking, place recognition, visit history, and calendar attendance |
| cli | true |
| env | [{"var":"LOCATION_DB_PATH","from":"setup_env"},{"var":"CALDAV_URL","from":"config","config_path":"caldav_url","when":"caldav_url","gate_has_discovered_calendars":true},{"var":"CALDAV_USERNAME","from":"config","config_path":"caldav_username","when":"caldav_url","gate_has_discovered_calendars":true},{"var":"CALDAV_PASSWORD","from":"config","config_path":"caldav_password","when":"caldav_url","gate_has_discovered_calendars":true,"sensitive":true}] |
GPS-based location tracking via the Overland iOS app. Tracks location pings, resolves named places, and records visits.
Places (named geofences) are stored in the database. Full CRUD via CLI:
places — list all saved places (includes id for each)learn — save current GPS position as a named placeupdate — modify an existing place (category, name, radius, coordinates, notes)delete — remove a place (also clears place assignment from historical pings)place-stats — visit count, first/last/longest visit, total time spent (derived from pings)Changes take effect on the next incoming GPS ping (no restart needed).
The web UI surfaces "discovered clusters" — recurring locations that aren't yet saved as named places. The same flow is available via CLI:
discover — find clusters of stationary pings not assigned to any place. Filters out clusters near existing places or inside dismissed zones.dismiss-cluster — record a lat/lon/radius zone so future discover calls skip it (use when the user doesn't want a place suggested again).list-dismissed — list dismissed cluster zones with their ids.restore-dismissed — un-dismiss a zone by id (so it can surface again).Run istota-skill location --help (or istota-skill location <subcommand> --help) to see the live argument list.
All commands output JSON. LOCATION_DB_PATH (the user's per-user location.db) is set automatically by the skill's setup_env hook. The reverse-geocode and day-summary subcommands also read ISTOTA_DB_PATH (the framework DB) for the cross-user reverse-geocode cache.
# Current location + place/visit info
istota-skill location current
# Recent pings (default: last 20; --date returns all pings for that day)
istota-skill location history
istota-skill location history --limit 50
istota-skill location history --date 2026-02-15
istota-skill location history --date 2026-02-15 --tz America/New_York
# List known places (each entry includes id, name, lat, lon, radius_meters, category, notes)
istota-skill location places
# Save current location as a named place (inserts into DB)
# Takes effect immediately on the next incoming ping
istota-skill location learn "coffee shop"
istota-skill location learn "gym" --category gym --radius 75
istota-skill location learn "office" --notes "side entrance, 4th floor"
# Update an existing place — identify by --name or --id
# Only specified fields are changed; others are left as-is
istota-skill location update --name "coffee shop" --category food
istota-skill location update --name "old name" --rename "new name"
istota-skill location update --id 42 --radius 200 --notes "back entrance"
istota-skill location update --id 42 --notes "" # clear notes
istota-skill location update --name "office" --lat 40.71 --lon -74.01
# Delete a place — identify by --name or --id
# Also removes the place assignment from historical pings
istota-skill location delete --name "coffee shop"
istota-skill location delete --id 42
# Check calendar attendance via GPS pings
# Requires CALDAV_URL, CALDAV_USERNAME, CALDAV_PASSWORD env vars
istota-skill location attendance
istota-skill location attendance --date 2026-02-15
istota-skill location attendance --event "dentist"
# Reverse geocode a single coordinate pair
istota-skill location reverse-geocode --lat 40.71 --lon -74.01
# Day summary: clusters pings into stops, resolves names via saved places
# or reverse geocoding, filters transit, merges consecutive same-location stops
istota-skill location day-summary --date 2026-03-08
istota-skill location day-summary --date 2026-03-08 --tz America/New_York
# Visit statistics for a place (by name or id)
istota-skill location place-stats --name "home"
istota-skill location place-stats --id 42
# Find unknown recurring clusters
istota-skill location discover
istota-skill location discover --min-pings 20
# Dismiss a cluster zone so it stops surfacing in discover
istota-skill location dismiss-cluster --lat 40.71 --lon -73.98 --radius 200
# List / un-dismiss
istota-skill location list-dismissed
istota-skill location restore-dismissed 7
Aliased as last (istota-skill location last).
{
"last_ping": {
"timestamp": "2026-02-20T10:30:00Z",
"lat": 40.71,
"lon": -73.98,
"accuracy": 5,
"activity_type": "stationary",
"place": "home"
},
"current_visit": {
"place_name": "home",
"entered_at": "2026-02-20T08:00:00Z",
"duration_minutes": 150,
"ping_count": 30
}
}
[
{
"timestamp": "2026-02-20T10:30:00Z",
"lat": 40.71,
"lon": -73.98,
"accuracy": 5,
"place": "home",
"activity_type": "stationary"
}
]
[
{
"id": 1,
"name": "home",
"lat": 40.71,
"lon": -73.98,
"radius_meters": 150,
"category": "home",
"notes": null
}
]
{
"status": "ok",
"place": "coffee shop",
"lat": 40.75,
"lon": -73.99,
"radius_meters": 100,
"message": "Saved 'coffee shop' at 40.7500, -73.9900"
}
{
"status": "ok",
"place": {
"id": 42,
"name": "coffee shop",
"lat": 40.75,
"lon": -73.99,
"radius_meters": 100,
"category": "food",
"notes": null
}
}
{
"status": "ok",
"deleted": "coffee shop"
}
{
"place_id": 42,
"total_visits": 12,
"first_visit": "2026-01-08T09:00:00Z",
"last_visit": "2026-04-22T18:30:00Z",
"avg_duration_min": 75,
"total_duration_min": 902,
"longest_visit_min": 210
}
{
"clusters": [
{
"lat": 40.7580,
"lon": -73.9855,
"total_pings": 38,
"first_seen": "2026-03-01T08:00:00Z",
"last_seen": "2026-04-25T17:30:00Z",
"radius_meters": 75
}
]
}
{
"dismissed": [
{
"id": 7,
"lat": 40.71,
"lon": -73.98,
"radius_meters": 100,
"dismissed_at": "2026-04-20T12:00:00Z"
}
]
}
{
"display_name": "123 Main St, New York, NY 10001, USA",
"neighborhood": "Downtown",
"suburb": "Central LA",
"road": "Main St",
"city": "New York",
"source": "nominatim"
}
Clusters the day's pings into stops. Resolves location names by: (1) direct place match from ping data, (2) proximity match against saved places (100m minimum radius), (3) reverse geocoding via Nominatim. Filters out transit clusters (1-2 pings without a place match). Merges consecutive stops at the same location.
{
"date": "2026-03-08",
"timezone": "America/Los_Angeles",
"ping_count": 120,
"transit_pings": 8,
"stops": [
{
"location": "home",
"location_source": "saved_place",
"arrived": "08:00",
"departed": "09:30",
"ping_count": 20,
"lat": 40.71,
"lon": -74.01
},
{
"location": "Magnolia Park",
"location_source": "nominatim",
"road": "Elm St",
"neighborhood": null,
"suburb": "Magnolia Park",
"arrived": "10:15",
"departed": "12:30",
"ping_count": 25,
"lat": 40.78,
"lon": -73.96
}
]
}
Cross-references calendar events with GPS pings to confirm attendance. Skips all-day events, events without a location, and virtual meetings. Resolves event locations by matching against known places first, then geocoding via Nominatim (results cached in DB). Uses a 30-minute buffer around event times and a default 200m radius (or the place's radius if matched).
{
"date": "2026-02-20",
"events": [
{
"summary": "Dentist",
"uid": "abc123",
"start": "2026-02-20T10:00:00-08:00",
"end": "2026-02-20T11:00:00-08:00",
"location": "123 Main St",
"location_resolved": true,
"resolution_source": "geocode",
"event_lat": 40.71,
"event_lon": -73.98,
"radius_meters": 200,
"attended": true,
"first_nearby_ping": "2026-02-20T09:45:00Z",
"last_nearby_ping": "2026-02-20T10:55:00Z",
"nearby_ping_count": 12
}
]
}