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/hydrobiont/gcal_cli
- Week grid with per-calendar colors and per-event RSVP status (accepted /
tentative / declined / needs-action). Today's column and day are marked
(today), and
tjumps back to the current week from anywhere. - Free-slot finder — scans your "mine" calendars within working hours and
lists open slots. Mark slots across as many weeks as you like (scroll with
←/→); the selection persists, andycopies 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.
- Live view — while open, the app follows the wall clock: it refreshes
events in the background every
sync_interval, and when left open across a week boundary it automatically advances to the new current week — keeping any free slots you'd marked. - 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 / unselect a free slot — accumulates across weeks (slots pane) · show/hide calendar (calendars pane) |
enter / space |
Expand a grid slot to all that week's meetings (grid pane) |
esc |
Collapse an expanded grid slot |
m |
Mark a calendar mine / not-mine (calendars pane) |
y |
Copy the free-slot selection — all weeks, kept after copy (slots pane) |
c |
Clear the whole free-slot selection (slots pane) |
← / → (h / l) |
Previous / next week — moves both panes; selection persists |
t |
Jump back to the current week |
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/hydrobiont/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/hydrobiont/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.
spacemarks slots. To pick across multiple weeks, scroll with←/→and keep marking — the selection accumulates across every week you visit.cclears the whole selection;tjumps back to the current week.ycopies your selection (across all weeks) as a grouped-by-day, timezone-labelled text block — paste it straight into chat or email. The selection is kept after copying, so you can refine and copy again.
- 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.