cursor remembers where you left off, so each run fetches just the delta, in order, with nothing missed or double-counted.
The recipe
signals.list(sort="changed") is a change feed: signals ordered by when they last changed. You page it with a cursor, a bookmark you keep between runs, so you can poll on any cadence and always resume exactly where you left off.
1
Resume from your cursor
Pass your saved
cursor to signals.list(sort="changed"). The first run has no cursor, so it does a full initial sync; every run after is just the delta.2
Filter to your scope
The feed spans the whole corpus, so filter it to your scope: upsert each in-scope signal by
signal_id (newest wins, whole record), and drop any that no longer qualifies.3
Save the cursor for next time
Persist the updated store and the new cursor, ready for the next run.
gildea, set GILDEA_API_KEY, then (pure SDK, no model calls):
What you get
A local store of the signals in your scope, current to the last change. Each run writes the delta tosignals.jsonl and drops anything that fell out of scope, so your agent and Embed always read fresh, verified data without a full rebuild.