A keyboard-driven terminal app (TUI) for viewing Google Calendar. Launch it, leave it open, and read your week at a glance — a week grid with per-calendar colors and RSVP status, a free-slot finder that copies shareable availability to your clipboard, multiple Google accounts, and a multi-timezone gutter. It is read-only: it never modifies your calendars.
Repository: github.com/<you>/gcal_cli
- Week grid with per-calendar colors and per-event RSVP status (accepted / tentative / declined / needs-action).
- Free-slot finder — scans your visible "mine" calendars within working hours and lists open slots; select slots and copy a grouped-by-day, timezone-labelled availability block ("when can we meet") to the clipboard.
- Multiple accounts — connect several Google accounts; events merge into one view.
- Multi-timezone gutter — show the time column in several IANA zones side by side.
- Calendar toggles — flip a calendar's grid visibility, and mark which calendars are "mine" (count toward your free/busy) vs. colleagues' (shown but not blocking).
- Duplicate-event collapsing — the same meeting on several calendars collapses to one block, with participants listed.
- Local cache — last-fetched events load instantly on start, refreshing in the background.
- Read-only scopes —
calendar.readonly+tasks.readonlyonly.
| Key | Action |
|---|---|
tab |
Cycle panes: free slots → week grid → calendars |
↑ / ↓ (j / k) |
Move cursor (slot list / grid slot-row / calendar list) |
space |
Select slot (slots pane) · show/hide calendar (calendars pane) |
enter / space |
Expand a grid slot to all that week's meetings (grid pane) |
↓ at last slot |
Expand the next week in the free-slots panel |
backspace (or -) |
Collapse the last expanded week (free-slots panel) |
esc |
Collapse an expanded grid slot |
m |
Mark a calendar mine / not-mine (calendars pane) |
y |
Copy the current free-slot selection to the clipboard |
← / → (h / l) |
Previous / next week (moves both panes, collapses expansion) |
r |
Refresh both panes |
? |
Toggle the expanded help |
q |
Quit |
- macOS (v1 only): clipboard copy uses
pbcopy, OAuth tokens are stored in the macOS Keychain. - Go 1.25+ to build.
- A Google account (Workspace or personal Gmail).
git clone https://github.com/<you>/gcal_cli.git
cd gcal_cli
make build # produces ./bin/gcal_cli
cp bin/gcal_cli /usr/local/bin/ # or anywhere on your PATHOr with the Go toolchain:
go install github.com/<you>/gcal_cli@latestgcal_cli does not ship a shared OAuth client — you create your own in the
Google Cloud console and point the app at it. This keeps your data flowing only
between your machine and Google. Steps below are accurate as of 2026.
-
Create a project at https://console.cloud.google.com/ (or reuse one).
-
Enable APIs — in APIs & Services → Library, enable both:
- Google Calendar API
- Google Tasks API
-
Configure the OAuth consent screen (APIs & Services → OAuth consent screen):
- Workspace users: choose Internal. No app verification is required, and refresh tokens do not expire after 7 days.
- Personal Gmail: you can only choose External. Leave the app in
Testing and add your address as a test user. Caveat: in Testing mode a
personal-account refresh token expires after 7 days, so you will need to
re-run
gcal_cli auth addabout once a week.
-
Add scopes — request exactly:
https://www.googleapis.com/auth/calendar.readonlyhttps://www.googleapis.com/auth/tasks.readonly
-
Create the OAuth client (APIs & Services → Credentials → Create credentials → OAuth client ID): application type Desktop app.
-
Download the client JSON and install it:
mkdir -p ~/.config/gcal_cli mv ~/Downloads/client_secret_*.json ~/.config/gcal_cli/oauth_client.json chmod 600 ~/.config/gcal_cli/oauth_client.json
gcal_clireads this file and never writes to it.
gcal_cli auth add # opens the browser for consent; token → Keychain
gcal_cli calendars sync # discovers your calendars into config.toml
gcal_cli # launches the TUIIn the TUI, tab to the calendars pane, then:
spaceto toggle a calendar's visibility in the grid,mto mark a calendar as mine (so its events count toward free/busy).
Run gcal_cli auth add again for each additional account.
Config lives at ~/.config/gcal_cli/config.toml (or
$XDG_CONFIG_HOME/gcal_cli/config.toml). gcal_cli calendars sync populates the
[[calendars]] entries; you can hand-edit everything. Built-in defaults:
09:00–18:00 working hours Mon–Fri, 30-minute minimum free slot, 5-minute
background sync, a 30-days-back / 90-days-forward window.
Precedence: an explicit per-weekday working_hours override beats the default;
absent any config file, the built-in defaults apply.
[[accounts]]
email = "you@example.com"
label = "Work"
[[calendars]]
account = "you@example.com"
id = "you@example.com"
summary = "You"
visible = true
mine = true
color = "#4285F4"
[[calendars]]
account = "you@example.com"
id = "team@example.com"
summary = "Team"
visible = true
mine = false # shown in the grid, but does not block your free/busy
[working_hours]
[working_hours.default]
start = "09:00"
end = "18:00"
[working_hours.fri] # per-weekday override
start = "09:00"
end = "14:00"
min_slot_length = "30m"
sync_interval = "5m"
[window]
back_days = 30
forward_days = 90
[[timezones]]
name = "Europe/Berlin"
[[timezones]]
name = "America/New_York"- With the free-slots pane focused, the app lists open slots within your working hours across your visible "mine" calendars.
spaceselects slots. Need more range?↓at the last slot expands the next week;backspace(or-) collapses the last expanded week.ycopies your selection as a grouped-by-day, timezone-labelled text block — paste it straight into chat or email.
- Read-only OAuth scopes (
calendar.readonly,tasks.readonly); the app cannot change your calendars. - OAuth tokens are stored in the macOS Keychain (service
gcal_cli), never in plaintext config or the cache. - Your OAuth client JSON and the local event cache stay under
~/.config/gcal_cli/. No data leaves your machine except the API calls to Google.
Released under the PostgreSQL License — a liberal open-source license similar to MIT.