Skip to content

Jamoncillo22/mycal

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mycal

mycal is a private, local-first calendar, reminder manager, and Markdown note popup for Waybar. It runs natively on Wayland with GTK4 and gtk4-layer-shell.

View the project roadmap.

mycal calendar with synthetic events

The screenshot uses an isolated profile and synthetic events.

  • No account or cloud service
  • No Google credentials or OAuth setup
  • No telemetry or required network access
  • Local notes, reminders, settings, and attachments
  • Month and year views
  • Quick events and a full Markdown editor
  • Missed reminder delivery after the next login or system resume
  • 46 built-in interface languages
  • Matugen, Omarchy, pywal, TOML, and manual color support

The project is developed and tested on Arch Linux with niri. Other Wayland compositors that implement layer-shell may also work.

Privacy

At runtime, data stays on the local machine:

Path Contents
${XDG_DATA_HOME:-~/.local/share}/mycal/local.json Notes and schedules
${XDG_DATA_HOME:-~/.local/share}/mycal/settings.json Preferences and custom languages
${XDG_DATA_HOME:-~/.local/share}/mycal/images/ Pasted note images
${XDG_STATE_HOME:-~/.local/state}/mycal/fired.json Delivered reminder state
${XDG_CONFIG_HOME:-~/.config}/mycal/theme.toml Optional theme configuration
$XDG_RUNTIME_DIR/mycal/, or ${XDG_CACHE_HOME:-~/.cache}/mycal/ when unavailable PID and temporary Waybar cache

Local data is not application-level encrypted. Use normal filesystem permissions and disk encryption when the contents are sensitive.

Requirements

  • Linux and a Wayland compositor with layer-shell support
  • Python 3.11 or newer at /usr/bin/python3
  • GTK 4
  • gtk4-layer-shell
  • PyGObject and pycairo
  • Babel
  • Waybar
  • systemd --user
  • flock, pkill, readlink, and standard GNU userland tools
  • A notification daemon such as mako, swaync, or dunst
  • A Nerd Font or Font Awesome font is recommended for interface icons

Arch Linux

sudo pacman -S --needed \
  git python python-gobject python-cairo python-babel \
  gtk4 gtk4-layer-shell waybar procps-ng coreutils util-linux

Install and configure a notification daemon separately if the desktop does not already provide one.

For other distributions, install equivalent packages from the system package manager. PyGObject and gtk4-layer-shell should be installed as system packages, not from an isolated Python virtual environment.

Install

Clone this repository and run the per-user installer:

git clone https://github.com/Jamoncillo22/mycal.git
cd mycal
./install.sh

Do not run the installer with sudo.

install.sh first checks the interpreter, Python modules, GTK libraries, and required commands. It then calls the atomic deployment script, which:

  1. Stages and compiles a release.
  2. Installs code under $HOME/.local/share/mycal.
  3. Installs mycal.service under the user systemd configuration.
  4. Enables and starts the reminder daemon.
  5. Verifies the daemon PID and service state.
  6. Rolls back automatically if activation fails.
  7. Keeps the active release and one rollback release.

Notes and settings are never copied from the source checkout and are preserved during updates.

Migrating from waybar-ycal

The repository previously contained the Google Calendar-based waybar-ycal. When detected, install.sh disables and stops its user service or standalone popup before deploying mycal, preventing both daemons from running together.

The migration deliberately does not delete ~/.config/waybar-ycal, Google credentials, tokens, or package-manager files, and it does not import Google events into the local calendar. Replace the old Waybar commands with the fragment below. After verifying mycal, remove the old package and private directory manually if they are no longer needed.

Waybar Setup

Add the fragment below to the top-level object in ~/.config/waybar/config.jsonc:

"custom/ycal": {
  "exec": "\"$HOME/.local/share/mycal/bar.py\"",
  "on-click": "\"$HOME/.local/share/mycal/toggle.sh\"",
  "interval": 60,
  "signal": 10,
  "return-type": "json",
  "escape": true,
  "tooltip": true
}

Then place custom/ycal in one module list, for example:

"modules-center": ["custom/ycal"]

The installer normally copies the same fragment to:

~/.config/mycal/examples/waybar-module.jsonc

Optional neutral styling is available in waybar-style.css:

#custom-ycal {
  padding: 0 12px;
  margin: 4px 2px;
  background: rgba(0, 0, 0, 0.25);
  border-radius: 10px;
}

#custom-ycal.error {
  color: #ff6b6b;
}

After changing the Waybar configuration, reload or restart Waybar once.

First Use

Click the Waybar module to open or hide the calendar. The service remains in the background so reminders can be delivered while the popup is closed.

Action Result
Click the Waybar module Show or hide mycal
Click a day Select that day
Scroll over the calendar Change month or year
Click Quick note Open the compact event form
Click Add Open the complete Markdown editor
Click an event title Open the event viewer
Click the pencil Edit an event
Right-click an event Toggle completion
Press Escape Close the active window or popup

An event can be all-day, have one start time, or have a start and end time. End times at or before the start are treated as overnight events.

More Screenshots

Quick note Markdown editor Note preview
mycal quick-note form mycal Markdown event editor mycal note preview with tasks and a local image
General settings Language selection Appearance settings
mycal general settings mycal language selection mycal appearance settings

The screenshots contain demonstration data rather than a private calendar.

Notes and Attachments

The editor supports headings, lists, task lists, block quotes, fenced code, bold, italic, inline code, links, and local images. Raw HTML is escaped.

Use the image button to choose a local image, or paste an image with Ctrl+V. Managed images are stored under the mycal data directory. Remote images are not downloaded into Markdown previews.

Reminders

Reminders can be scheduled in seconds, minutes, hours, or days before an event. The daemon handles:

  • Duplicate delivery protection
  • Catch-up after login or resume
  • All-day and overnight events
  • Daylight-saving gaps and repeated hours
  • Completed-event exclusion

If the computer is off, asleep, or no graphical session is running when a reminder becomes due, mycal checks for missed reminders at the next login or resume and delivers the notification then. Catch-up remains valid until the event's explicit end, until the next midnight for an all-day event, or for up to 24 hours after a timed event without an end time.

Notifications use the standard org.freedesktop.Notifications D-Bus interface.

Settings

Open the native settings window from the calendar to configure:

  • Interface language
  • Monday or Sunday week start
  • Notification enable/disable
  • System or custom IANA time zone
  • Automatic or custom date format
  • 12-hour or 24-hour time
  • Font family and size
  • Interface scale
  • Theme colors
  • Custom language catalogs

The default settings example is normally copied to ~/.config/mycal/examples/settings.example.json.

Themes

mycal using a Matugen-generated palette

Matugen theme shown with the same synthetic calendar profile.

The default auto theme source checks providers in this order:

  1. Matugen
  2. Omarchy
  3. pywal
  4. Built-in defaults

When no generated provider is available, mycal uses this built-in fallback:

Role Color
Text #eee0d5
Background #18120c
Accent #f9ba72
Secondary accent #e0c1a3
Error #ffb4ab

Omarchy and pywal work without additional mycal configuration when their standard color files already exist.

Matugen needs a one-time output entry because mycal cannot safely edit an existing Matugen configuration. The installer places the input template at ~/.config/mycal/matugen-template.toml. Add this block to ~/.config/matugen/config.toml:

[templates.mycal]
input_path = "~/.config/mycal/matugen-template.toml"
output_path = "~/.cache/mycal/matugen.toml"

Then run the normal Matugen generation command used for the wallpaper. Once ~/.cache/mycal/matugen.toml exists, the default auto source selects it before Omarchy or pywal. The same block is normally copied to ~/.config/mycal/examples/matugen-config-snippet.toml.

Configuration examples are best-effort: deployment prints a warning instead of replacing an active release if the examples directory is not writable.

Applying Generated Colors

The installer copies templates but cannot generate a palette because it does not know which wallpaper or theme the user wants. Keep the default auto source, then regenerate colors with the provider whenever the wallpaper or desktop theme changes:

  • Matugen: run the normal Matugen command or wallpaper script, such as setwall, after adding the template block above.
  • Omarchy: apply the Omarchy theme normally so its colors.toml is updated.
  • pywal: run the normal wal command so ~/.cache/wal/colors.json is updated.

If ~/.config/mycal/theme.toml contains source = "manual", generated colors are intentionally ignored. Remove that file or change it to source = "auto" to follow Matugen, Omarchy, or pywal again.

mycal reads the generated files each time the popup opens. If it is already visible, close and reopen it from the Waybar module. Restarting the service is an equivalent fallback:

systemctl --user restart mycal.service

Waybar does not need to be reloaded just to update the popup colors. If the same theme command also changed Waybar's own CSS and did not reload it, reload Waybar separately:

pkill -SIGUSR2 -x waybar

To use a manual theme:

mkdir -p "${XDG_CONFIG_HOME:-$HOME/.config}/mycal"
cp \
  "${XDG_CONFIG_HOME:-$HOME/.config}/mycal/theme.example.toml" \
  "${XDG_CONFIG_HOME:-$HOME/.config}/mycal/theme.toml"

Edit the copied file and set source = "manual". Supported sources are auto, matugen, omarchy, pywal, manual, and file. Theme opacity and corner radius are configured in the same TOML file.

Update

These commands apply to an existing mycal installation. Users of the legacy Google Calendar version should follow Migrating from waybar-ycal first.

cd mycal
git pull --ff-only
./install.sh

Updates use the same validation, atomic activation, and rollback process as a first installation.

Uninstall

First remove custom/ycal from the Waybar configuration. Then uninstall the service and application code while preserving all notes and settings:

./uninstall.sh

To permanently delete the code and every local note, setting, pasted image, and reminder record:

./uninstall.sh --purge-data

The purge operation cannot be undone without a backup.

Troubleshooting

Check the service:

systemctl --user status mycal.service
journalctl --user-unit=mycal.service -n 50 --no-pager

Check the Waybar JSON producer directly:

"$HOME/.local/share/mycal/bar.py"

Toggle the popup directly:

"$HOME/.local/share/mycal/toggle.sh"

If the service cannot start, confirm that /usr/bin/python3 can import gi, babel, GTK4, and Gtk4LayerShell. Running ./install.sh repeats the same dependency check.

Development and Verification

Run every syntax check and test in isolated temporary XDG directories:

./verify.sh

The unittest modules live under tests/; application files remain at the repository root for direct deployment.

The verification script does not read or write the real calendar. Tests cover storage validation, bounded I/O, atomic writes, concurrency, reminders, DST, completion, Markdown safety, languages, themes, Waybar output, deployment rollback, and uninstall behavior.

Roadmap

Planned local-first features include handwritten notes with a mouse or stylus, user-controlled voice-note recording, and optional calendar synchronization. See docs/ROADMAP.md for scope, privacy requirements, and later ideas.

Architecture

File Responsibility
popup.py GTK windows, editor, settings, reminders, and D-Bus integration
bar.py Localized Waybar JSON and event indicator cache
mycal_core.py Event validation, storage transactions, schedules, and reminders
mycal_io.py Bounded regular-file reads
mycal_markdown.py Safe Markdown parsing, links, tasks, and local images
mycal_theme.py Theme discovery, parsing, and validation
i18n.py Languages, date/time formatting, and settings
launcher.py Stable launcher pinned to one release
deploy.sh Atomic deployment and rollback

Security Reports

See SECURITY.md. Do not attach real local.json, settings.json, images, notification contents, or reminder-state files to a public issue.

Credits

mycal began from the GTK popup concept in waybar-ycal by yagybaba. The upstream MIT notice is retained in LICENSE.

License

MIT. See LICENSE.

About

A local-first calendar and reminder popup for Waybar, with optional synchronization. Forked from waybar-ycal.

Resources

Security policy

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages