← Blog·March 25, 2026·11 min read·Engineering

Multi-Person Scheduling Is a Consensus Problem. Here's How We Solved It.

Scheduling a meeting between two people is a search problem: find a slot where both are free. Scheduling a meeting between five people across three time zones is a consensus problem: find a slot that's acceptable to everyone, weighted by constraints that aren't always explicit.

Most tools treat multi-person scheduling as a harder version of the two-person problem. Just check more calendars, find the intersection, done. This breaks down immediately when you account for:

  • People who share calendars selectively (or not at all)
  • Preferences that aren't in the calendar (no meetings before coffee, avoid back-to-back afternoons)
  • Asymmetric importance (the VP's time matters more than the intern's for a skip-level, but not for a team lunch)
  • Attendees in different orgs with no shared calendar infrastructure
  • The social dynamics of who proposes, who concedes, and who gets the last word

We built Planck's multi-person scheduling as a negotiation protocol, not a lookup algorithm. Here's why, and how it works.

Why intersection-based scheduling fails

The naive approach: query every attendee's calendar, compute the intersection of free slots, present the options.

This works when:

  • All attendees share calendars with the organizer
  • "Free" on the calendar actually means "available" (not "blocked for focus time" or "tentatively holding for something else")
  • The number of attendees is small (2-3)
  • Everyone is in the same or adjacent time zones

It fails when any of these assumptions break. And in practice, they break constantly.

The visibility problem. In many organizations, you can see that a colleague is "busy" from 2-3pm but not what the event is. Is it a client call they absolutely can't move? Or a recurring team sync they'd happily skip? Without context, the scheduling algorithm treats all busy blocks equally.

The preference problem. A CEO's calendar might show 3pm as free, but their EA knows they never take meetings after 2:30pm on Fridays. This preference exists in a human's head, not in calendar data. Intersection-based systems can't account for it.

The combinatorial explosion. With 5 attendees, each with ~20 hours of meetings per week, the number of possible free-slot intersections shrinks rapidly. Add time zone constraints (no meetings before 9am local time for anyone) and the feasible set often drops to 1-2 options. Or zero. At which point the algorithm shrugs and says "no available times found," leaving the human to negotiate manually.

The negotiation model

Planck treats multi-person scheduling as a multi-round negotiation with proposals, responses, and convergence.

How it works

Round 1: Initial proposals

When a user says "schedule a 30-minute sync with Alex, Sam, and Jordan this week," the agent:

  1. Creates a negotiation record with the initiator, attendees, and constraints (duration, date range)
  2. Queries availability for all attendees it has access to (via shared calendars, scheduling links, or previous interaction history)
  3. For attendees without visible calendars, uses heuristics (standard working hours in their time zone, known preferences from past negotiations)
  4. Generates 3 time proposals, ranked by a scoring function

The scoring function considers:

  • Overlap quality: How cleanly does this slot fit in everyone's schedule? A slot with 30 minutes of buffer on all sides scores higher than one wedged between meetings.
  • Time zone fairness: Avoid proposals that fall at 8am for one person and 5pm for another. Distribute the inconvenience.
  • Preference alignment: If the agent knows Sam prefers afternoons, weight afternoon slots higher.
  • Focus time impact: Proposals that would break a contiguous focus block for any attendee are penalized.
  • Recency and freshness: Slots earlier in the week score slightly higher (gets the meeting done sooner).

Round 2: Responses

Proposals are sent to attendees. Each attendee can:

  • Accept a proposed time
  • Decline with or without a reason
  • Counter-propose with alternative times

The agent collects responses and evaluates whether consensus has been reached. Consensus doesn't require unanimity on a single slot. It requires one slot that enough attendees have accepted (configurable: strict = all must accept, flexible = majority + organizer approval).

Round 3+: Re-proposals

If no consensus emerges in Round 1, the agent re-proposes based on the feedback:

  • If attendees declined with reasons ("I can't do mornings"), the agent excludes those constraints
  • If attendees counter-proposed, the agent checks whether any counter-proposals have universal availability
  • If the feasible set is shrinking, the agent widens the date range or suggests async alternatives ("Could this be an email instead?")

Maximum 3 rounds. If consensus isn't reached after 3 rounds, the agent escalates to the organizer with a summary of what was tried and why it didn't converge.

The database model

negotiations
  negotiation_id    UUID
  initiator_id      UUID (FK → users)
  attendees         TEXT[] (emails)
  duration_minutes  INT
  date_range_start  TIMESTAMP
  date_range_end    TIMESTAMP
  status            ENUM (active, consensus_reached, failed, cancelled)
  created_at        TIMESTAMP

negotiation_proposals
  proposal_id       UUID
  negotiation_id    UUID (FK → negotiations)
  round             INT
  proposed_times    JSONB[] ({start, end, score})
  responses         JSONB ({email: {status, counter_proposal?, reason?}})
  created_at        TIMESTAMP

This structure supports:

  • Tracking which round we're in
  • Storing per-attendee responses per proposal
  • Auditing the full negotiation history
  • Resuming interrupted negotiations

Handling attendees outside the system

The hardest part of multi-person scheduling is attendees who don't use your product. You can't query their calendar. You can't send them an in-app notification. You're reduced to email.

Planck handles this with a tiered approach:

Tier 1: In-system attendees. Full calendar access, real-time availability, instant responses. The agent can query their calendar and preferences directly.

Tier 2: Calendar-shared attendees. Attendees whose Google Calendar is visible to the organizer (via org-level sharing or explicit grants). The agent can see free/busy status but not event details or preferences.

Tier 3: External attendees. No calendar access. The agent falls back to:

  • Scheduling links (if the attendee has one on file)
  • Email proposals with clickable time options
  • Time zone-based heuristics (assume standard 9-5 in their timezone)

The agent adjusts its strategy based on the attendee mix. If all attendees are Tier 1, it can often resolve scheduling in a single round. If most are Tier 3, it sets expectations with the organizer ("This will likely take 1-2 days to coordinate").

The fallback system

Not every scheduling attempt succeeds. The fallback system handles degraded scenarios:

No overlapping availability: The agent suggests extending the date range, shortening the meeting duration, or splitting into multiple smaller meetings with subsets of attendees.

Attendee non-response: After 24 hours without response, the agent sends a reminder. After 48 hours, it proposes proceeding without the non-responsive attendee (with organizer approval).

Conflicting hard constraints: If two attendees have mutually exclusive availability ("only mornings" vs. "only afternoons" in overlapping time zones), the agent surfaces this explicitly rather than silently failing.

Calendar API failures: If a calendar sync fails during negotiation, the agent uses the last-known availability data and flags the staleness to the organizer.

Why this approach works better

It degrades gracefully

Intersection-based systems are binary: they find a slot or they don't. The negotiation model produces increasingly good approximations. Even if perfect consensus isn't reached, the output is "here are the best options and who has conflicts with each" rather than "no times available."

It captures implicit preferences

Through the response loop, the agent learns things that aren't in calendar data. If Sam consistently declines morning proposals and counter-proposes afternoons, the agent infers a preference and applies it to future negotiations involving Sam. These inferences are stored and refined over time.

It respects social dynamics

The organizer initiates and has final say. Attendees respond to proposals rather than being forced into a slot. Counter-proposals are welcome but not required. This mirrors how scheduling actually works between humans, with the added benefit of an agent handling the logistics.

It handles the long tail

Straightforward scheduling (2-3 people, shared calendars, same timezone) still resolves in one round, usually under 30 seconds. The negotiation model only adds complexity when complexity is genuinely needed. Simple cases stay simple.

Implementation notes

Start with 2-person scheduling

Before building the full negotiation system, get single-round, two-person scheduling working perfectly. This exercises the availability calculation, scoring function, and event creation pipeline without the complexity of multi-round negotiations.

Score, don't sort

Don't just rank available slots by time. Score them by quality. A slot at 10am with 1-hour buffers on both sides and no focus time impact is meaningfully better than a slot at 8am wedged between two other meetings. The scoring function is where your scheduling quality lives.

Keep proposals to 3

Offering too many options causes decision paralysis. Three proposals give enough variety without overwhelming. Present them in ranked order with a brief explanation of why each scored well.

Make round limits explicit

Tell users upfront: "I'll try up to 3 rounds of proposals." This sets expectations and prevents the agent from endlessly proposing and re-proposing. If 3 rounds don't converge, the problem likely needs a human decision, not more automation.

Store everything

Every proposal, response, counter-proposal, and final outcome should be stored. This data is valuable for:

  • Improving the scoring function (which proposals get accepted?)
  • Learning individual preferences (who always declines mornings?)
  • Auditing (why was this meeting scheduled at this specific time?)
  • Debugging (when scheduling goes wrong, you need the full trace)

Multi-person scheduling is messy because human coordination is messy. The goal isn't to eliminate the mess. It's to handle it systematically, with good defaults, graceful fallbacks, and a system that gets smarter with each negotiation.