Guide

Detect Calendar Conflicts from the CLI

Spot double-booked meetings and overlapping events from the terminal. AI conflict detection and jq scripts catch calendar conflicts before they derail your day.

Written by Prem Keshari Senior SRE

VerifiedCLI 3.1.22 · Google Calendar · last tested June 19, 2026

According to Atlassian’s workplace productivity research, the average knowledge worker loses 31 hours per month to unproductive meetings — and double-bookings are among the most disruptive contributors. You show up to one meeting, miss another, and spend 20 minutes apologizing to both sides. The problem compounds on distributed teams where time zone math disguises a 10 AM slot in London as a 6 AM slot that is also blocked by an early standup in New York.

Conflict detection splits into two distinct jobs, and the CLI has a separate tool for each. Checking whether a proposed meeting collides with your schedule is a forward-looking question answered by nylas calendar ai conflicts check. Finding overlaps among events that already exist on your calendar is a deterministic scan you build with events list piped through jq. Mixing the two up is the most common mistake; this guide keeps them separate.

How do I check a proposed meeting for conflicts?

The nylas calendar ai conflicts check command tests one proposed meeting against your existing schedule before you send the invite. It separates hard conflicts (overlapping events) from soft conflicts (back-to-back stacking, focus-time interruptions, meeting overload) and scores alternative times so you pick the least disruptive slot. It evaluates a single candidate meeting; it does not scan a window of existing events.

The command takes --title and --start (both required, with --start in RFC3339 format), plus --duration in minutes (default 60) and an optional comma-separated --participants list. It reads events from your connected grant, so authenticate first. If you haven’t connected a calendar account yet, run nylas auth login and follow the OAuth prompt. The tool works with Google Calendar, Outlook, Exchange, Yahoo, iCloud, and IMAP providers.

# Check whether a proposed meeting collides with your schedule
nylas calendar ai conflicts check \
  --title "Product Review" \
  --start "2026-06-22T14:00:00Z" \
  --duration 60 \
  --participants team@company.com

# Let the assistant pick the best alternative automatically
nylas calendar ai conflicts check \
  --title "Team Sync" \
  --start "2026-06-23T10:00:00Z" \
  --duration 30 \
  --auto-resolve

The output groups conflicts into hard and soft severity and lists scored alternative times. Add --auto-resolve to skip the prompt and book the highest-scoring slot. Once you know a slot is clear, pair this with reschedule a meeting from the terminal to move a conflicted event into it without leaving the terminal.

How do you write a jq overlap checker?

A jq overlap check is the deterministic way to find conflicts among events that already exist, complementing the proposed-meeting check above. It works purely on timestamps: two events overlap when one starts before the other ends. This makes the script predictable and auditable — you can read every condition and trace exactly which pair triggered the flag. The approach is reliable for CI jobs and daily cron reports where you want the same logic to produce the same output every run.

The script below fetches the next 14 days of events, extracts each event’s start and end as epoch integers, and then checks every pair for overlap. Events with identical IDs are skipped so an event doesn’t flag itself. The output is a list of overlapping pairs with their titles and times.

nylas calendar events list --days 14 --json | jq '
  # Build a flat list with integer timestamps for comparison
  [.[] | {
    id: .id,
    title: .title,
    start: (.when.start_time | tonumber),
    end:   (.when.end_time   | tonumber)
  }] as $events
  |
  # Compare every pair once (i < j to avoid duplicate pairs)
  [ range($events | length) as $i
  | range($events | length) as $j
  | select($i < $j)
  | $events[$i] as $a
  | $events[$j] as $b
  | select($a.start < $b.end and $b.start < $a.end)
  | {
      conflict: "overlap",
      event_a: { id: $a.id, title: $a.title, start: $a.start, end: $a.end },
      event_b: { id: $b.id, title: $b.title, start: $b.start, end: $b.end }
    }
  ]'

An empty array means no overlaps in the next 14 days. A non-empty array means at least one pair of events shares a time window. Pipe the result to jq length for a quick count or jq -e ". == []" to exit non-zero when conflicts exist — useful as a CI gate.

How do you run a daily conflict check?

A daily conflict check that emails you the results is a straightforward cron pattern. The script below runs the jq overlap audit against the next 14 days of existing events, counts overlapping pairs, and lists each one. It fires at 7 AM every weekday and sends a summary to your inbox using nylas email send. Setting this up takes about 5 minutes and replaces manual morning calendar review.

Save the script, make it executable, then add a crontab entry. The script writes output to a temp file so the email body can capture both the overlap count and the detail of each conflicting pair. Authentication uses environment variables so no interactive prompt appears during the cron run — see the getting started guide for headless auth setup with NYLAS_API_KEY and NYLAS_GRANT_ID.

#!/usr/bin/env bash
# conflict-check.sh — daily calendar conflict report
set -euo pipefail

REPORT=$(mktemp)
EVENTS=$(nylas calendar events list --days 14 --json)

echo "=== Overlapping event pairs (next 14 days) ===" >> "$REPORT"
echo "$EVENTS" | jq -r '
  [.[] | { id: .id, title: .title, start: (.when.start_time | tonumber), end: (.when.end_time | tonumber) }] as $e
  | [range($e|length) as $i | range($e|length) as $j | select($i < $j)
     | $e[$i] as $a | $e[$j] as $b
     | select($a.start < $b.end and $b.start < $a.end)
     | "\($a.title) overlaps \($b.title)"]
  | .[]' >> "$REPORT"

COUNT=$(echo "$EVENTS" | jq '
  [.[] | { start: (.when.start_time | tonumber), end: (.when.end_time | tonumber) }] as $e
  | [range($e|length) as $i | range($e|length) as $j | select($i < $j)
     | $e[$i] as $a | $e[$j] as $b
     | select($a.start < $b.end and $b.start < $a.end)] | length')
echo "" >> "$REPORT"
echo "Total overlapping pairs: $COUNT" >> "$REPORT"

nylas email send \
  --to "${NOTIFY_EMAIL}" \
  --subject "Calendar conflict report: $(date +%Y-%m-%d)" \
  --body "$(cat "$REPORT")"

rm -f "$REPORT"
# Add to crontab: 7 AM on weekdays
# crontab -e, then add:
0 7 * * 1-5 NYLAS_API_KEY=your_key NYLAS_GRANT_ID=your_grant NOTIFY_EMAIL=you@example.com /path/to/conflict-check.sh

Replace the inline environment variables with references to a secrets file (e.g. source ~/.config/nylas/env) if your cron daemon doesn’t inherit your shell environment. Never hard-code API keys in scripts checked into version control.

How do you investigate a flagged conflict?

Once a conflict is flagged, you need the full event details to decide whether to reschedule, decline, or send a note. The nylas calendar events show command returns the complete event record including title, attendees, conferencing links, and recurrence rules. Reviewing this takes about 10 seconds per conflict, versus 2-3 minutes of clicking through a calendar UI to find and compare two overlapping events.

Pipe the output through jq to extract only the fields you care about. The example below pulls title, start, end, and attendee emails for a quick triage view.

# Inspect a specific event by ID (get IDs from the overlap script output)
nylas calendar events show EVENT_ID_HERE --json | jq '{
  title: .title,
  start: .when.start_time,
  end:   .when.end_time,
  attendees: [.participants[].email]
}'

If the conflict involves a recurring event, the recurrence field in the output tells you the RRULE. Modifying only the conflicted instance without touching the series requires the event’s master ID and instance ID — both appear in the --json output from calendar events show.

How do you use conflict detection as a CI gate?

A conflict detection CI gate is a job step that blocks a deployment when the calendar already holds overlapping events in the next 2 days. Many engineering teams have a policy of not releasing during a scheduled incident review, all-hands, or known maintenance window — this check enforces that policy automatically. It adds under 5 seconds to a pipeline and requires no external scheduling service.

The gate below lists the next 2 days of events with nylas calendar events list --days 2 --json, runs the same jq overlap logic, and exits with code 1 when any pair overlaps. Add it as a step before your deployment step in GitHub Actions, CircleCI, or any CI system that respects exit codes. According to Nylas Calendar API docs, each event carries an id, a title, and a when object with start_time and end_time epoch fields, which is all the overlap test needs.

#!/usr/bin/env bash
# ci-calendar-gate.sh — block deploy when events overlap
set -euo pipefail

OVERLAPS=$(nylas calendar events list --days 2 --json | jq '
  [.[] | { id: .id, title: .title, start: (.when.start_time | tonumber), end: (.when.end_time | tonumber) }] as $e
  | [range($e|length) as $i | range($e|length) as $j | select($i < $j)
     | $e[$i] as $a | $e[$j] as $b
     | select($a.start < $b.end and $b.start < $a.end)
     | { event_a: $a.title, event_b: $b.title }]')

COUNT=$(echo "$OVERLAPS" | jq 'length')

if [ "$COUNT" -gt 0 ]; then
  echo "Deployment blocked: $COUNT overlapping event pair(s) in the next 2 days."
  echo "$OVERLAPS" | jq '.'
  exit 1
fi

echo "No overlaps. Safe to deploy."
exit 0

To gate on a proposed change window instead of existing events, swap the audit for nylas calendar ai conflicts check --title "Deploy window" --start "..." --duration 30 and fail the step when it reports a hard conflict. That variant tests one candidate slot rather than scanning the calendar.

What if the overlap audit returns no results?

An empty array from the jq overlap audit means either there are no overlapping events or the audit is reading the wrong calendar. The first thing to verify is which grant is active. Run nylas calendar events list --days 1 and confirm the events listed match what you expect to see. If events are missing, the connected grant may be pointing at a secondary calendar rather than the primary one that holds your meetings.

A second cause is the look-ahead window. The events list default is 7 days. If your double-booking is on day 8 or later, pass --days 14 or --days 30 to extend the scan. The events list command also caps results at 10 by default and auto-paginates only above 200, so add --limit 200 on busy calendars to be sure every event is fetched before the overlap test runs.

If events are present but no overlap appears despite a visible double-booking, verify the event timestamps. All-day events use a date field instead of start_time and end_time. The jq overlap script reads when.start_time and when.end_time, which are only set on timed events, so all-day events are excluded from the audit by design. The proposed-meeting check (ai conflicts check) is the right tool when you need a meeting evaluated against your full schedule rather than a raw timestamp comparison.

Tested on Nylas CLI 3.1.22 with Google Calendar. Provider-side behavior for Outlook, Exchange, Yahoo, iCloud, and IMAP is documented by Nylas but not verified end-to-end against each backend — test locally before deploying provider-specific rules.

References

Next steps