May 19, 2026 · agentdraft.io

Why AI scheduling agents collide

Every AI scheduling agent builds its own private view of availability, then commits in isolation. That's the bug. Here's the protocol-layer fix.


TL;DR. Every scheduling agent in the market today reads availability, reasons in private, and commits a booking on its own. When two agents share a human, they collide. The fix is not "build a smarter agent." The fix is a coordination layer that every agent calls before it books — a single source of truth for what's held, what's committed, and who wins when two agents reach for the same slot in the same millisecond.

This post explains the problem, the four collision patterns we keep seeing, and the shape of the protocol-layer fix.

The pattern, in one paragraph

A human installs three scheduling assistants. Sales-bot to book demos. Recruit-bot to book interviews. A personal assistant for everything else. Each one is fine on its own. Each one has a perfectly reasonable view of the human's calendar through some combination of Google Calendar reads, caches, and webhooks. By Wednesday afternoon two of them have booked into the same 16:00 slot, neither one knows the other tried, and the human is the load-balancer.

This is not a bug in any individual agent. It is the predictable behaviour of three rational systems operating on a shared resource without a coordination layer between them.

Why "just read the calendar" doesn't fix it

The intuitive answer is: each agent should re-read the calendar right before it writes. If it's still free, write. If not, back off.

That works for one agent. It fails for two, for the same reason optimistic locking fails without a compare-and-swap primitive:

  1. Agent A reads the calendar. 16:00 is free.
  2. Agent B reads the calendar. 16:00 is free.
  3. Agent A writes 16:00.
  4. Agent B writes 16:00 — and the underlying store still accepts the write, because Google Calendar (and every other consumer calendar API) has no notion of "the other agent that was about to write here."
  5. Both agents return success to their respective users.

You cannot solve this in application code on top of a calendar API that doesn't speak conflict. The agent's check and the agent's write are separated by the network — by enough time for another agent to slip in between them. You need the check and the write to be one atomic operation, enforced at the storage layer. Calendars don't expose that primitive. Something else has to.

The four collision patterns we see in pilot

Once you instrument the problem, the failure modes are not random. They sort into four buckets:

1. Hold-vs-hold

Two agents both put a tentative hold on 16:00, neither commits, both emails go out asking the human to confirm. The human picks one. The other agent never gets told it lost; its calendar widget shows "pending" forever.

2. Hold-vs-commit-inside-bump

Agent A holds the slot. Agent B commits the slot a few seconds later. Whose booking is real? Today, the last write wins on the calendar — which is exactly backwards from the answer the human would give if you asked them which one mattered more.

3. Commit-vs-frozen

Both agents successfully commit a booking. Neither writes were rejected; both saw the slot as free. Now the calendar has two events at 16:00, both with the agents' own metadata, both believed to be canonical by their respective users. The double-booking is fully realised.

4. External-event-overlap

The human types a manual event onto their own calendar at 16:00. Sales-bot's hold for that slot is now invalidated, but sales-bot is not told. The next time it checks (in 90 seconds, via watch channels), it discovers the conflict — but by then it has already emailed the prospect with the proposed time.

The shape that connects all four: no party in the system knows the full set of pending writes against the resource at the moment of decision.

The coordination layer

The fix has a specific shape. It is not "a better calendar," and it is not "build everything inside one provider." It is an intermediate service that every booking-capable agent calls before it writes to a calendar:

  1. Availability: ask the coordination layer (not the calendar) whether a slot is free, given everyone's pending state.
  2. Hold: ask the coordination layer to reserve the slot tentatively with a TTL, with explicit priority.
  3. Commit: tell the coordination layer the booking is final. Only now does the booking flow downstream into the human's actual calendar — and only one agent gets a successful commit on a given slot.
  4. Audit: every step (availability check, hold, commit, eviction, failure) is recorded in an append-only log that any agent can read to explain what happened.

What this gets you:

  • One source of truth for what is held and what is committed across every agent that uses the layer.
  • Deterministic conflict resolution — when two agents reach for the same slot, exactly one wins, by an explicit priority rule, in the same millisecond.
  • Typed failure for the losing agent. Not a timeout, not a "calendar said no" — a structured 409 with the winning agent's id, the priority comparison, and an audit reference. The losing agent can tell its user why it failed and who won.
  • No more "the bot booked over my standup" because the human's manually-typed event is a first-class participant in the same coordination layer.

What makes a coordination layer actually work

A few non-obvious requirements show up the moment you try to build one:

The check and the write must be the same operation. Anything that separates "is the slot free?" from "claim the slot" reintroduces the race the layer exists to prevent. Implementation-wise, this means storage-level conditional writes — not application-level locks, not "check, then write." We use DynamoDB TransactWriteItems with a ConditionExpression on every bucket row; the write is the check. (Engineering detail here.)

Priority is a parameter, not a policy. Different humans want different rules. Sales calls outrank personal blocks for an enterprise salesperson; personal blocks outrank everything for a consultant. The layer must accept a per-agent priority and resolve conflicts against that priority — but it must not bake a single global rule into the engine.

Holds must expire. A coordination layer with no TTL on holds turns into a denial-of-service surface: any agent can park a hold on every slot and starve every other agent. Holds must have an explicit, short TTL (we use 30 seconds by default) and the layer must enforce expiry even if the agent never returns to release the hold.

Commits must have a bump window. If a higher-priority agent shows up 0.5 seconds after a lower-priority commit, "first-write-wins" is the wrong answer — the human would prefer the higher-priority commit. After a short bump window (we use 30 seconds), commits become frozen and the priority comparison no longer applies. Inside the window, priority still does.

The audit log is a feature, not infrastructure. Every collision is a question — "why didn't I get the slot?" — and the audit log is the answer. It must be append-only, queryable by booking id and by agent id, and exposed to both the winning and losing agents. The audit log is what makes the coordination layer trustworthy across organisational boundaries.

What this is not

This isn't a calendar. We don't replace Google Calendar; we sit in front of it. Committed bookings flow into the calendar after the engine has resolved the conflict.

This isn't a meeting scheduler. Cal.com, Calendly, Motion, Reclaim — those are great products for scheduling between a human and a stranger. They don't solve the multi-agent collision problem because they don't know about each other. (If two of them are installed on the same calendar, they collide too.)

This isn't AGI-flavoured agent orchestration. The coordination layer is deliberately dumb. It enforces one rule: one slot, one winner, deterministically. The intelligence stays in the agents. The arbitration moves out.

Where this goes

Once a coordination layer exists, three things become possible that weren't before:

  • Cross-vendor interop. A sales bot from one vendor and a recruit bot from another can share a calendar without either one knowing the other exists, because both call the same coordination layer first.
  • Auditable agent behaviour. Every "the bot did the wrong thing" question has a deterministic answer in the log. Compliance teams care about this; so do the humans whose calendars are getting written to.
  • Priority routing as a product feature. Agents can be designed expecting a coordination layer, with smarter fallback behaviour when they lose — propose an alternate slot, escalate to the human, defer to tomorrow — instead of the current "best-effort, hope nothing goes wrong" pattern.

The market is going to have a coordination layer either way. The only question is whether it's an open protocol multiple vendors implement, or whether one calendar provider builds it as a moat and the agents have to integrate one-by-one. AgentDraft is a bet on the first outcome.

Try it

The protocol is documented at agentdraft.io/spec. The deterministic conflict engine that backs it is described in the race-engine post. The integration takes about five minutes — start at the quickstart. Cohort signups are open at agentdraft.io.

If you're building an agent that touches calendars, dive into the quickstart. If you're a human who's already living with the collision problem, we'd like to hear which of the four patterns above is the one ruining your week.

— agentdraft.io · v0.2


§ Field Notes

Liked this? One short note every other Tuesday.

Conflict-engine post-mortems, new endpoints, the rare opinion. No tracking pixels.

Double opt-in — you'll get a confirmation link. Unsubscribe in one click.