A fast, native command-line interface for managing your macOS Calendar events. Built with EventKit integration, myCal lets you create, read, update, and delete calendar events directly from your terminal - with instant synchronization to Calendar.app.
- Native macOS Integration: Uses Apple's EventKit framework for seamless Calendar.app integration
- Instant Sync: Events appear in Calendar.app immediately - no manual sync required
- Flexible Date Parsing: Support for absolute dates (
2025-12-25), relative dates (tomorrow,next monday), and date math (+3,-2) - Multiple Calendars: Work with all your calendars (iCloud, Exchange, local)
- Simple Commands: Intuitive CLI with
create,list,edit,deleteoperations - No AppleScript: Direct EventKit access for reliability and speed
- macOS 10.14 (Mojave) or later
- Python 3.8 or later
- Calendar.app access permissions
# Clone or download the repository
cd /Users/cleytontioyama/Code/myCal
# Install dependencies
pip3 install -r requirements.txt
# Make the script executable
chmod +x myCal
# Add to your PATH (optional - choose one method)
# Method 1: Symlink to /usr/local/bin
sudo ln -s /Users/cleytontioyama/Code/myCal/myCal /usr/local/bin/myCal
# Method 2: Add to PATH in your shell profile (~/.zshrc or ~/.bash_profile)
echo 'export PATH="/Users/cleytontioyama/Code/myCal:$PATH"' >> ~/.zshrc
source ~/.zshrccd /Users/cleytontioyama/Code/myCal
pip3 install -e .pip3 install pyobjc-core pyobjc-framework-EventKit pyobjc-framework-CocoaThen run with: python3 /Users/cleytontioyama/Code/myCal/myCal
On first run, macOS will prompt you to grant Calendar access:
- Run any myCal command
- Click "OK" when prompted to grant Calendar access
- If you accidentally denied access, go to System Settings > Privacy & Security > Calendar and enable access for Terminal
# Create a basic event
myCal create "Team Meeting" --date 2025-12-25 --time 14:00
# With duration (in minutes)
myCal create "Lunch Break" --date tomorrow --time 12:30 --duration 90
# With description and location
myCal create "Client Meeting" --date "next monday" --time 10:00 \
--duration 120 --location "Conference Room A" \
--description "Quarterly review with stakeholders"
# Specify a calendar
myCal create "Dentist Appointment" --date tomorrow --time 15:00 \
--calendar "Personal"# List today's events
myCal list --date today
# List all events for a specific date
myCal list --date 2025-12-25
# List events in a date range
myCal list --date today --end +7
# List events from a specific calendar
myCal list --calendar "Work" --date today
# Verbose output with all details
myCal list --date today --verbose# Show full details for a specific event
myCal show <event-id># Change event title
myCal edit <event-id> --title "Updated Title"
# Change date and time
myCal edit <event-id> --date tomorrow --time 16:00
# Change duration
myCal edit <event-id> --duration 120
# Update multiple fields
myCal edit <event-id> --title "New Title" --date "next friday" \
--time 14:00 --location "New Location"# Delete with confirmation prompt
myCal delete <event-id>
# Delete without confirmation
myCal delete <event-id> --confirm# Show all available calendars
myCal calendarsmyCal supports flexible date input:
2025-12-25- ISO format (YYYY-MM-DD)12/25/2025- US format (MM/DD/YYYY)2025/12/25- Alternative format
today- Today's datetomorrow- Tomorrow's dateyesterday- Yesterday's date
monday,tuesday, etc. - Next occurrence of that weekdaynext monday- Explicitly next week's Mondaythis friday- This week's Friday
+3- 3 days from today-2- 2 days ago
14:00- 24-hour format2:00 PM- 12-hour format with AM/PM1400- Compact 24-hour format2 PM- Short 12-hour format
# Check today's schedule
myCal list --date today
# Add a quick meeting
myCal create "Quick Sync" --date today --time 15:00 --duration 30
# Check what's coming up this week
myCal list --date today --end +7# List all calendars
myCal calendars
# Create work event
myCal create "Sprint Planning" --date "next monday" --time 9:00 \
--calendar "Work" --duration 120
# Create personal event
myCal create "Gym" --date tomorrow --time 18:00 \
--calendar "Personal" --duration 60
# View only work calendar
myCal list --calendar "Work" --date today --end +7# Create an event
myCal create "Doctor Appointment" --date "next tuesday" --time 10:00 \
--location "Main Street Clinic" --duration 45
# List to find the event ID
myCal list --date "next tuesday"
# Edit the event (use the ID from list command)
myCal edit <event-id> --time 10:30 --duration 60
# Show full details
myCal show <event-id>
# Delete when no longer needed
myCal delete <event-id>myCal uses Apple's EventKit framework through PyObjC (Python-Objective-C bridge) to:
- Direct Database Access: Reads and writes directly to Calendar.app's database
- Immediate Sync: Changes appear instantly in Calendar.app (no polling or delays)
- Full Integration: Works with iCloud, Exchange, and local calendars
- Native Permissions: Uses macOS's standard calendar permission system
The architecture is simple:
eventkit_bridge.py- EventKit integration layerdate_parser.py- Flexible date/time parsingcli.py- Command-line interfacemyCal- Executable entry point
Problem: "Calendar access denied" error
Solution:
- Go to System Settings > Privacy & Security > Calendar
- Find your terminal app (Terminal.app, iTerm, etc.)
- Enable the checkbox
- Restart your terminal and try again
Problem: "Event with ID 'xxx' not found"
Solution: Event IDs can change if events are modified in Calendar.app. Use myCal list to get the current ID.
Problem: ImportError: No module named 'EventKit'
Solution:
pip3 install --upgrade pyobjc-core pyobjc-framework-EventKit pyobjc-framework-CocoaProblem: "Calendar 'Work' not found"
Solution: Run myCal calendars to see exact calendar names (case-sensitive).
#!/bin/bash
# Create daily standup meeting for next week
for day in monday tuesday wednesday thursday friday; do
myCal create "Daily Standup" --date "next $day" --time 9:00 \
--duration 15 --calendar "Work"
done# Use with jq for parsing (if you add JSON output in the future)
# Create event and capture ID
EVENT_ID=$(myCal create "Meeting" --date tomorrow --time 14:00 2>&1 | grep "Event ID:" | awk '{print $3}')
# Pipe dates from other commands
date -v+1d "+%Y-%m-%d" | xargs -I {} myCal list --date {}myCal/
├── src/
│ ├── __init__.py
│ ├── __main__.py
│ ├── cli.py # Command-line interface
│ ├── eventkit_bridge.py # EventKit integration
│ └── date_parser.py # Date/time parsing
├── myCal # Executable entry point
├── setup.py # Python package setup
├── requirements.txt # Dependencies
└── README.md # This file
# Test event creation
myCal create "Test Event" --date tomorrow --time 14:00
# Verify in Calendar.app
open -a Calendar
# Clean up
myCal list --date tomorrow
myCal delete <event-id> --confirm- macOS Only: Uses EventKit which is macOS-specific
- No Recurring Events: Current version doesn't support recurrence rules (planned for future)
- Event ID Stability: EventKit event IDs can change if events are modified externally
- No Reminders: Currently only supports calendar events, not reminders
- Recurring event support
- Reminders integration
- JSON output mode for scripting
- Interactive mode for event selection
- Event templates
- Natural language parsing ("meeting tomorrow at 2pm")
- Calendar subscriptions
- Bulk operations
MIT License - See LICENSE file for details
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Test thoroughly on macOS
- Submit a pull request
For issues, questions, or suggestions:
- Open an issue on GitHub
- Check existing issues for solutions
- Read the troubleshooting section above
- Built with PyObjC for Objective-C bridge
- Uses Apple's EventKit framework for calendar integration
- Inspired by the need for a fast, scriptable calendar interface