Source: https://cli.nylas.com/guides/block-focus-time-cli

# Block Focus Time on Your Calendar (CLI)

Create busy blocks from the terminal to protect deep-work windows before meetings can fill them. Find open mornings with availability check, then lock them with events create.

Written by [Qasim Muhammad](https://cli.nylas.com/authors/qasim-muhammad) Staff SRE

Updated June 9, 2026

> **TL;DR:** Run [`nylas calendar availability check`](https://cli.nylas.com/docs/commands/calendar-availability-check) to find open windows, then [`nylas calendar events create --busy`](https://cli.nylas.com/docs/commands/calendar-events-create) to create a busy block that shows you as unavailable. Run the script nightly to protect tomorrow's mornings before your colleagues fill them.

According to [Asana's research on context-switching](https://asana.com/resources/context-switching), a single interruption costs 23 minutes of recovery time before a developer returns to full focus. Most engineers lose 2 hours a day to meeting fragmentation alone. The fix isn't better discipline — it's blocking time before the invites arrive.

Nylas CLI gives you two commands to automate this. First, find open windows with `nylas calendar availability check`. Second, lock those windows with `nylas calendar events create --busy`. Combine them in a shell script and run it on a cron schedule each evening.

## Why automate focus blocks instead of adding them manually?

Manual focus blocks work until you forget to add one, or a recurring meeting moves and leaves a gap. Automated blocking runs every night and fills open windows before your colleagues can. It also removes the guilt of declining a meeting — your calendar already shows you busy. [Harvard Business Review's 2017 survey](https://hbr.org/2017/07/stop-the-meeting-madness) found that executives waste an average of 23 hours per week in unproductive meetings — and that the majority of those meetings could be eliminated without loss.

A typical developer calendar has 3 to 4 meetings before 10 AM on any given Monday. That fragmentation makes deep work nearly impossible before noon. Running a blocking script the night before creates a first-mover advantage: your focus window is reserved before anyone books a 9 AM status call.

Automation also makes the behavior consistent across vacations, holidays, and schedule changes. You write the script once, and it runs for months without manual intervention. If your schedule changes — say, you move to a later morning window — you update one variable in the script rather than rebooking dozens of calendar entries.

## How do you find open windows on your calendar?

Finding open windows means calling [`nylas calendar availability check`](https://cli.nylas.com/docs/commands/calendar-availability-check) against your own grant ID with a start and end window. The command returns free/busy data as JSON in under 2 seconds. You pass it a time range for the upcoming morning and parse the result to decide whether the window is still open.

The command below checks whether your calendar is free between 9 AM and 11 AM tomorrow morning. Pass your own email as the only participant to check your personal availability, not a group.

```bash
# Check if tomorrow 9-11 AM is free
TOMORROW=$(date -v+1d "+%Y-%m-%dT09:00:00Z" 2>/dev/null || date -d "tomorrow" "+%Y-%m-%dT09:00:00Z")
END=$(date -v+1d "+%Y-%m-%dT11:00:00Z" 2>/dev/null || date -d "tomorrow" "+%Y-%m-%dT11:00:00Z")

nylas calendar availability check "$NYLAS_GRANT_ID" \
  --emails "$YOUR_EMAIL" \
  --start "$TOMORROW" \
  --end "$END" \
  --json
```

Use UTC timestamps in scripts. That keeps cron jobs and local developer machines from disagreeing on timezone math — especially across daylight saving time transitions. Convert to display time only at the output step.

## How do you find the best open morning slot across several days?

When you want the best available morning across an entire week, use [`nylas calendar find-time`](https://cli.nylas.com/docs/commands/calendar-find-time). This command scores candidate slots against working hours, timezones, and holidays, returning a ranked list rather than a raw free/busy answer. It's more useful when you want to pick the earliest available 2-hour slot across the next 5 days.

The command below searches for a 120-minute open window across the next 5 days and returns results sorted by quality. Pipe the output to `jq` to extract the first suggested slot before passing it to the blocking step.

```bash
nylas calendar find-time \
  --participants "$YOUR_EMAIL" \
  --timezones America/Toronto \
  --duration 120m \
  --days 5 \
  --json | jq '.[0]'
```

## How do you create a busy block that prevents bookings?

A busy block is a calendar event with the `--busy` flag. This tells the provider — Google Calendar in this case — to show you as unavailable during that window so scheduling tools and colleagues can't book over it. An event created without `--busy` appears as free time and won't block incoming invites.

The [`nylas calendar events create`](https://cli.nylas.com/docs/commands/calendar-events-create) command requires three flags: `--title`, `--start`, and `--end`. Adding `--busy` marks the window as unavailable. The command completes in under 1 second and the block appears on your calendar immediately.

```bash
nylas calendar events create "$NYLAS_GRANT_ID" \
  --title "Focus Time" \
  --start "2026-06-10T09:00:00Z" \
  --end "2026-06-10T11:00:00Z" \
  --description "Deep work block. No meetings." \
  --busy
```

Give the block a consistent title across all your scripts, like `"Focus Time"` or `"Deep Work"`. That way you can grep your calendar with [`nylas calendar events list`](https://cli.nylas.com/docs/commands/calendar-events-list) to audit existing blocks before creating duplicates.

## How do you wire availability check and event creation into one script?

The full automation connects three steps: check tomorrow's availability window, skip the block if the window is already busy, then create the block if it's open. This script is safe to run nightly — it won't stack duplicate focus blocks because it checks first and exits early if the window is occupied.

The script below uses `set -euo pipefail` to fail loud on any error and parses the availability JSON with `jq`. Adjust `FOCUS_START_HOUR` and `FOCUS_END_HOUR` to match your preferred deep-work window — most engineers find 9 AM to 11 AM or 8 AM to 10 AM most effective before standup interrupts the morning.

```bash
#!/usr/bin/env bash
set -euo pipefail

# Configure these for your schedule
YOUR_EMAIL="you@example.com"
FOCUS_START_HOUR="09"
FOCUS_END_HOUR="11"
TITLE="Focus Time"

# Build tomorrow's window in UTC
# macOS uses -v+1d; Linux uses --date="tomorrow"
FMT_START="+%Y-%m-%dT$FOCUS_START_HOUR:00:00Z"
FMT_END="+%Y-%m-%dT$FOCUS_END_HOUR:00:00Z"
TOMORROW_START=$(date -v+1d "$FMT_START" 2>/dev/null || date -d "tomorrow" "$FMT_START")
TOMORROW_END=$(date -v+1d "$FMT_END" 2>/dev/null || date -d "tomorrow" "$FMT_END")

echo "Checking availability: $TOMORROW_START -> $TOMORROW_END"

# Step 1: Check if the window is free
availability=$(nylas calendar availability check "$NYLAS_GRANT_ID" \
  --emails "$YOUR_EMAIL" \
  --start "$TOMORROW_START" \
  --end "$TOMORROW_END" \
  --json)

# Step 2: Exit if the window is already busy
busy=$(echo "$availability" | jq -r '.busy // false')
if [ "$busy" = "true" ]; then
  echo "Window is already busy — skipping focus block."
  exit 0
fi

# Step 3: Create the busy block
nylas calendar events create "$NYLAS_GRANT_ID" \
  --title "$TITLE" \
  --start "$TOMORROW_START" \
  --end "$TOMORROW_END" \
  --description "Deep work block. No meetings." \
  --busy

echo "Focus block created: $TOMORROW_START -> $TOMORROW_END"
```

## How do you run the blocking script every night automatically?

A cron job that runs at 8 PM each evening ensures your focus block is on the calendar before your colleagues start their morning planning sessions. Most calendar invite senders check your availability as they compose — a block that exists by 8 PM is protected for the next day.

Add the cron entry with `crontab -e`. The example below runs the script at 8 PM in your local timezone. Set `NYLAS_GRANT_ID` and `NYLAS_API_KEY` as environment variables in your shell profile or pass them directly in the crontab line.

```bash
# Edit your crontab
crontab -e

# Add this line to run the blocking script at 8 PM every weekday
0 20 * * 1-5 NYLAS_GRANT_ID=your_grant_id NYLAS_API_KEY=your_key /path/to/block-focus.sh >> /tmp/focus-block.log 2>&1
```

The script writes output to `/tmp/focus-block.log` so you can review yesterday's run with `tail /tmp/focus-block.log`. On macOS, you can also use a launchd plist; on Linux servers, systemd timers are a reliable alternative to cron for long-running pipelines.

## How do you check which focus blocks are already on your calendar?

Before creating new blocks, it helps to audit existing ones. Running [`nylas calendar events list`](https://cli.nylas.com/docs/commands/calendar-events-list) with `--json` and piping to `jq` filters for events matching your focus block title. This confirms which mornings already have protection and avoids creating duplicate events across the same window.

The command below lists the next 20 calendar events and filters for any titled "Focus Time". If you use a different block title in your script, update the`jq` filter to match.

```bash
nylas calendar events list "$NYLAS_GRANT_ID" \
  --limit 20 \
  --json | jq '[.[] | select(.title == "Focus Time")]'
```

## Verify

Tested on Nylas CLI 3.1.16 against Google Calendar. To confirm the full flow works end-to-end, run the availability check, create one focus block manually, then list events and verify the block appears with status `busy`. Provider-side availability behavior for Outlook and other calendars is described from documented provider behavior — verify locally before deploying to non-Google accounts.

```bash
# 1. Check availability for a test window
nylas calendar availability check "$NYLAS_GRANT_ID" \
  --emails "$YOUR_EMAIL" \
  --start "2026-06-10T09:00:00Z" \
  --end "2026-06-10T11:00:00Z" \
  --json

# 2. Create the test focus block
nylas calendar events create "$NYLAS_GRANT_ID" \
  --title "Focus Time" \
  --start "2026-06-10T09:00:00Z" \
  --end "2026-06-10T11:00:00Z" \
  --busy

# 3. Confirm the block is on your calendar
nylas calendar events list "$NYLAS_GRANT_ID" --json | jq '[.[] | select(.title == "Focus Time")]'
```

## References

- [Asana: The cost of context-switching](https://asana.com/resources/context-switching) — 23-minute recovery stat from Asana's workplace productivity research
- [Harvard Business Review: Stop the Meeting Madness (2017)](https://hbr.org/2017/07/stop-the-meeting-madness) — survey data on unproductive meeting hours per week
- [Google Calendar API: Events insert reference](https://developers.google.com/workspace/calendar/api/v3/reference/events/insert) — the underlying API field that controls free/busy status on events

## Next steps

- [Manage calendar events from the terminal](https://cli.nylas.com/guides/manage-calendar-from-terminal) — full event list, create, and timezone reference
- [Check calendar availability from the terminal](https://cli.nylas.com/guides/check-calendar-availability-cli) — deeper guide on free/busy checks, resource calendars, and booking flows
- [Schedule across time zones](https://cli.nylas.com/guides/schedule-across-timezones-cli) — handle DST and multi-region scheduling from the CLI
- [Calendar analytics from the CLI](https://cli.nylas.com/guides/calendar-analytics-cli) — measure how much focus time you actually have versus how much meetings consume
- [Command reference](https://cli.nylas.com/docs/commands) — every calendar flag and subcommand
