# tock
**The fast terminal calendar. Written in Rust.**
   
Terminal calendar with week view, event management, astronomy, and weather. Built on [Crust](https://github.com/isene/crust). Feature clone of [Timely](https://github.com/isene/Timely) rewritten in Rust for speed and single-binary distribution.

## Features
- **5-pane TUI**: info bar, mini-month strip, week view grid, event details, status bar
- **Week view**: 7-column layout with half-hour time slots, all-day event rows, weather per day; events that overlap sit side by side in lanes
- **Mini-month calendars**: horizontal strip with event indicators, week numbers, today highlight
- **Calendar sources**: Google Calendar (OAuth2), Outlook/365 (device auth), CalDAV (iCloud, Fastmail, Nextcloud, Radicale), local events
- **ICS import**: parse and import .ics files with RRULE expansion for recurring events
- **Background sync**: automatic polling with configurable intervals
- **Ephemeris engine**: full planetary position calculator ported from [ruby-ephemeris](https://github.com/isene/ephemeris)
- Moon phase with emoji symbols, illumination percentage
- Moon rise/set times
- Sunrise/sunset times
- Visible planets (Mercury, Venus, Mars, Jupiter, Saturn) with rise/set
- Solstices, equinoxes, 11 meteor shower peaks
- **Weather**: 7-day forecast from Met.no (free, no API key)
- **Desktop notifications**: configurable alarms via notify-send
- **Event management**: create, edit, delete, accept invites (RSVP)
- **Preferences**: 15 configurable settings with inline color picker (256-color grid)
- **Calendar manager**: enable/disable calendars, change colors, remove
- **Kastrup integration**: reply to events via Kastrup (r key), jump to Kastrup (Z key)
- **Database**: [ferrite](https://github.com/isene/ferrite) in ~/.tock/tock.ferrite/, or SQLite with `database: sqlite` in the config
## Install
Download the prebuilt binary from [Releases](https://github.com/isene/tock/releases), or build from source:
```bash
cargo build --release
cp target/release/tock ~/.local/bin/
```
## Key Bindings
| Key | Action |
|-----|--------|
| d/RIGHT, D/LEFT | Next/prev day |
| w/W | Next/prev week |
| m/M | Next/prev month |
| y/Y | Next/prev year |
| UP/DOWN | Navigate time slots |
| PgUp/PgDn | Jump 10 slots |
| HOME/END | Top/bottom of day |
| j/k | Cycle events on day |
| e/E | Jump to next/prev event |
| t | Go to today |
| g | Go to date |
| n | New event |
| Enter | Edit event |
| x/DEL | Delete event |
| v | View event details |
| a | Accept invite (RSVP) |
| Ctrl+Y | Copy event to clipboard |
| Ctrl+A | A Claude session about the screen and the seven days from the selected one (`claude` on the PATH); `/exit` comes back |
| i | Import ICS file |
| G | Setup Google Calendar |
| K | Setup CalDAV (iCloud, Fastmail, Nextcloud, …) |
| O | Sign in to Outlook/365: opens the sign-in page in your browser with the code on the clipboard |
| S | Manual sync |
| C | Calendar manager |
| P | Preferences |
| Ctrl+R | Clear caches |
| Ctrl+L | Redraw |
| ? | Help |
| q | Quit |
## Configuration
Config file: `~/.tock/config.yml`
Settings include location (for astronomy/weather), work hours, calendar colors, sync intervals, and notification preferences.
tock keeps its calendars in [ferrite](https://github.com/isene/ferrite),
the Fe₂O₃ database that keeps its tables in memory. Every commit is forced
to the disk before it returns.
Coming from a tock that used SQLite? The first start copies everything out
of `tock.db` into `~/.tock/tock.ferrite/` and leaves the SQLite file as it
was. `database: sqlite` in the config takes you back to the data as of
that copy.
## Google Calendar
Google wants an OAuth client of your own, made once in Google Cloud Console:
1. Make a project, enable the Google Calendar API, and fill in the OAuth
consent screen. While it is in "Testing", add yourself as a test user.
2. Under Credentials, create an OAuth client ID of the type **Desktop app**
and download its JSON file.
Then press `G` in tock and give your Google email. tock offers the newest
`client_secret_*.json` in your download folder; Enter takes it, and a copy
goes into `~/.config/tock/credentials` (set by `google.safe_dir`), readable
by you alone. The browser opens on Google's sign-in. Allow tock, and the
page comes back to tock on a local port; nothing is pasted.
Every calendar of the account is added. The main one is on and syncs at
once; `C` turns on the others.
A web-type client works too. If it lists a return address on this machine
(`http://localhost:8080/`, say), tock listens there. If it lists one
elsewhere, tock asks you to paste the address the browser ends on, or just
the code.
A client still in "Testing" gets a sign-in that lapses after a week. Press
`G` again with the same email: tock signs in anew and leaves the calendars
as they are. Publishing the consent screen ends the weekly sign-in.
## CalDAV: iCloud, Fastmail, Nextcloud and more
Press `K` and give the server, your user name and a password:
| Service | Server | User name | Password |
|---|---|---|---|
| iCloud | `https://caldav.icloud.com` | your Apple ID | an app-specific password from account.apple.com |
| Fastmail | `https://caldav.fastmail.com` | your address | an app password |
| Nextcloud | `https:///remote.php/dav` | your user | your password or an app password |
| Radicale | `http://:5232` | your user | your password |
tock finds the account's calendars and adds every one that takes events,
all on; `C` turns any off. A task list is left out. The password is kept in
a file only you can read, beside the Google credentials.
Events come down with the rest of the sync. tock first asks the server
whether a calendar changed at all, and fetches its events only when it has,
or once a day. A repeating event arrives as its dates, each its own row.
Events you make or change in tock go up to the server, and so do the ones
dropped into `~/.tock/incoming/`. One date of a repeating series is changed
on the server, not in tock. If the password changes, press `K` again with
the same server and user.
Outlook needs none of this: `O` runs the whole device-code flow. A company
sign-in policy can expire that sign-in after some weeks; tock then shows a red
⚠ line in the status bar and `S` says which calendar it is. Press `O` and sign
in again; the calendar and its events stay as they are.
## Dependencies
Runtime: SQLite (bundled) or ferrite (built in). Optional: `notify-send` (notifications), `xclip` (clipboard).
## Part of the Rust Terminal Suite
See the [Fe₂O₃ suite overview](https://github.com/isene/fe2o3) and the [landing page](https://isene.org/fe2o3/) for the full list of projects.
| Tool | Clones | Description |
|------|--------|-------------|
| [rush](https://github.com/isene/rush) | [rsh](https://github.com/isene/rsh) | Shell |
| [crust](https://github.com/isene/crust) | [rcurses](https://github.com/isene/rcurses) | TUI library |
| [kastrup](https://github.com/isene/kastrup) | [Heathrow](https://github.com/isene/heathrow) | Messaging hub |
| [tock](https://github.com/isene/tock) | [Timely](https://github.com/isene/timely) | Calendar |
| [pointer](https://github.com/isene/pointer) | [RTFM](https://github.com/isene/RTFM) | File manager |
| [scroll](https://github.com/isene/scroll) | [brrowser](https://github.com/isene/brrowser) | Web browser |
| [crush](https://github.com/isene/crush) | - | Rush config helper |
## License
[Unlicense](https://unlicense.org/) - public domain.
## Credits
Created by Geir Isene (https://isene.org) with extensive pair-programming with Claude Code.