The recipe
sort=changed is a change feed: signals ordered by when they last changed. You page it with a cursor, and the cursor is a bookmark you keep between runs. Poll hourly, daily, or after a week away, and you always pick up exactly where you left off.
Resume from your cursor
Pass your saved
cursor to signals.list(sort="changed"). It returns everything that changed since that point. The first run has no cursor, so it does a full initial sync; every run after is just the delta.Upsert by signal id
Replace each changed signal in your store by its
signal_id: newest wins, wholesale. A signal’s entities can change over time as they’re merged or renamed, so you replace the whole record; merging would leave stale parts behind.Save the cursor for next time
Persist the updated store and the new cursor. Poll on any cadence (hourly, daily, after a week away) and your territory stays current, so Search and the rest of your loop always read fresh, verified data.
gildea, set GILDEA_API_KEY, then (pure SDK, no model calls):
What you get
A self-healing watch on your scope: poll on any cadence (hourly, daily, after a week off) and you always get exactly what changed since last time, with nothing missed or repeated. The cursor makes it incremental; the upsert keeps every record current. It writes to the samesignals.jsonl your other recipes read, so your context layer stays current without a full rebuild.