On This Page
- 1. Read from a bookmark, and move it only when the batch has landed
- 2. Give every write a key that survives the crash
- 3. One run owns the sync, and proves it before each write
- 4. Retry what is passing, stop what is not
- 5. Treat silence as a finding
- 6. Decide what the sync may write once, and make every run prove it
- What is built, and what is not
On 8 October 2026 Lance Martin and CJ Avilla published a walkthrough of an agent that reads Slack and GitHub every morning and posts a brief to Slack. Nobody watches it run. Their most useful paragraph is about a failure that looks like success. When a source’s server is down or its token has expired, “the agent sees nothing from that source and reports ‘nothing new.’”
A Shopify-to-Brevo contact sync has the same failure. So does every scheduled sync between two SaaS tools. A read that fails quietly looks exactly like a store where nobody signed up today.
Their article ends on six rules for an agent that runs unattended. Read them as someone who runs syncs and each one is a reverse ETL rule. The worker died. The sync didn’t. follows one contact through a crash. This page is the checklist above it: six rules for an automated data sync, what Tajo’s runner does about each today, and where it falls short. The runner’s side is written up in Recover a stuck or failed sync.
1. Read from a bookmark, and move it only when the batch has landed
Their first rule: “Read each source from a bookmark, not a fixed time window.” A window of “the last 24 hours” leaves a gap when a run starts late and repeats records when it starts early.
A Tajo sync reads its source in batches from a saved cursor. The cursor moves at the end of a batch, and only when every record in that batch landed. A run that fails keeps the last clean position, so the next run reads the interrupted batch again instead of skipping it.
Orders get a bookmark of their own. A scheduled Shopify orders sync starts at its first scheduled run and sends what changed since the previous one. Past orders go only when a person runs the sync. Scheduled runs and runs a person starts keep separate cursors, so a history backfill or a test batch cannot rewind the scheduled one.
The cost is that an interrupted batch is read twice. Rule 2 is what makes that safe.
2. Give every write a key that survives the crash
Their fourth rule counts a post as sent “only when Slack confirms it”, and only then updates the bookmark and the ledger. A registered letter works this way. It is delivered when the signed receipt comes back, not when it leaves the counter.
Before Tajo writes a record, the record gets a delivery key. The key is a hash of the sync, the source, the page cursor, the position on the page and the record itself, so it holds no personal data. It is claimed before the destination is called and marked completed when the write succeeds. Completed keys are kept for seven days. A retry, or a later scheduled run, derives the same key for the same record, finds it completed and does not call the destination again.
Two costs come with it. After seven days the ledger forgets, and a replay from an older cursor can write again. And a write that times out leaves an honest doubt: the other system may have saved it without answering. Tajo tries that write again on a later attempt rather than recording it as failed for seven days. A connector that hands the destination an idempotency key of its own closes that doubt. One that cannot is left with the chance of one duplicate.
3. One run owns the sync, and proves it before each write
Their third rule: “Re-check every item right before posting.” For a sync, the thing most likely to have changed between the read and the write is who is allowed to write.
Each Tajo sync has one lease, with its own token and a 15-minute life renewed every five minutes. A run checks that it still holds the lease before it calls the destination, and again before it moves the cursor. A run that has lost it stops, and its page says “The run lost its slot part-way through and stopped to avoid writing twice.” A second run that collides with a live one ends instead of queuing behind it.
Records are checked as well. Between the read and the write, records pass the consent filter. A contact written to a marketing audience without provable consent is refused rather than guessed. In the help page’s words, the failure mode is “too careful”, never “over-sent”.
4. Retry what is passing, stop what is not
Their six rules say nothing about how often to try again. A sync needs that rule, because its most common failures are a rate limit and a vendor’s bad minute.
A queued Tajo run that fails gets five attempts. The waits between them are 60, 120, 240 and 480 seconds, about fifteen minutes in all. Some failures are never retried, because trying again cannot fix them. A run that collided with a run already in progress is not retried, and neither is a run whose published version or connections are no longer valid.
A streak is different from a blip. If the last five finished runs since the sync was last changed all failed, Tajo pauses the sync and shows the last error on its page. One success resets the count. Nothing restarts a paused sync by itself; a person fixes the cause and publishes it again. The worker-died article tells the incident that produced this rule.
5. Treat silence as a finding
“Report a failed read as unreadable, never as a quiet day.” This is the hardest of the six, and the one we meet only in part.
Where it holds: a read that errors fails the run. A refused token or a server that does not answer sends nothing to the destination, leaves the cursor where it was and counts toward the pause after five failed runs. And every hour, at 13 minutes past, Tajo checks every workspace with an active sync. It alerts its own team when there has been no successful run in the last 24 hours, including a workspace where no run was recorded at all. That is the hourly check.
Where it does not: the quiet read the authors describe is a read that answers “OK” with no records. Our runner counts that as a success. For sources such as Shopify customers, a separate check warns Tajo’s team after ten successful runs in a row with zero records, if the sync had produced records before. Shopify orders are read by update time, so an empty run is normal there and that check does not run. A source that returns some records, but fewer than it should, is not caught at all.
The objection goes like this: “Ten empty runs is two and a half hours on a 15-minute schedule. Why not alert on the first?” Contact syncs do run every 15 minutes by default. And a store with no new customers in a quarter of an hour is ordinary. An alert on the first empty run would fire every night, and an alert that always fires is one nobody reads. That line trades speed for being believed. It is still a guess about silence, not the authors’ rule.
6. Decide what the sync may write once, and make every run prove it
Their fifth rule keeps the agent’s preferences “from a store the agent can’t edit”. Their sixth gives the agent read-only access wherever it only reads, and caps what each run can spend. Both exist because the agent reads text other people wrote, and that text can try to give it orders.
A sync’s version of the preferences file is the published rule. Publishing a Tajo sync binds it to a digest of the exact rule that was previewed. Editing it returns it to draft, and it goes back through preview before it runs again. Every run checks, before it changes anything, that it is running that published version with the connections it was published with. A run that fails that check is not retried. The direction is fixed too: a sync rule writes one way and never back into Shopify.
The spending cap has no counterpart. Our sync runs have no per-run spend limit. The retry limit and the pause bound how long a failure can go on, not what a run costs.
What is built, and what is not
Built, as of this writing:
- A cursor that moves only after a batch in which every record landed, and a scheduled orders cursor that runs started by a person cannot rewind.
- A delivery key per record, checked against a ledger of completed writes kept for seven days.
- One lease per sync, checked before the write and before the cursor moves.
- Five attempts per run, waiting 60 seconds and then 120, 240 and 480, with no retry for a collision or an invalid publication.
- A pause after five runs in a row fail, shown on the sync’s page.
- An hourly alert when no run has succeeded in the last 24 hours.
- A consent filter at run time for contacts written to a marketing audience, and a check on every run that it is the published version.
Not built, and worth knowing before you rely on it:
- A read that succeeds with zero records is not reported as unreadable. The ten-run warning covers part of it. It does not cover Shopify orders or a source that returns too few records.
- The 24-hour alert reaches Tajo, not you, and so does the ten-run warning. The pause does show on the sync’s page.
- The hourly check watches the workspace, not each sync. One healthy sync hides a silent one beside it.
- No per-run spend cap.
- Nothing restarts a paused sync. A person does.
- The five-failure pause and the 24-hour check are set for the whole Tajo deployment, not per sync.
When one of these shows up on your own sync, Recover a stuck or failed sync says what you see and what to do.
The authors wrote six rules for a brief that a person reads every morning. A sync has no morning reader at all, which is why it needs them more. Rules one to four and rule six are code in our runner today. Rule five is half written: a sync that cannot read its source should say so.
Frequently Asked Questions
What does an automated data sync need to run safely when nobody is watching it?
Six things. A cursor that moves only after a whole batch landed. A delivery key per record that a retry derives again, checked against a ledger of completed writes. One run at a time per sync. A bounded number of retries, then a pause when runs keep failing. An alert when nothing succeeds for a day. And a published rule that every run must prove it is running.
Why should a sync not read a fixed time window such as the last 24 hours?
Because runs are not punctual. A run that starts late leaves a gap the window never covers, and a run that starts early reads records twice. A saved cursor starts each run exactly where the last clean batch ended, whenever the run starts.
How does Tajo stop a retried sync from writing the same record twice?
Each record gets a delivery key, a hash of the sync, the source, the page cursor, the position on the page and the record itself. The key is claimed before the destination is called and marked completed when the write succeeds, and completed keys are kept for seven days. A retry or a later run derives the same key and does not call the destination again.
Does Tajo notice when a source returns nothing because the read silently failed?
Only in part. A read that errors fails the run, and the run counts toward the pause after five failed runs in a row. A read that succeeds with zero records counts as a success. For sources such as Shopify customers, Tajo's team is warned after ten successful runs in a row with zero records, if the sync had produced records before. For Shopify orders, read by update time, that check does not run.