reminders-hassio-todo (also known as reminders-cli) is a comprehensive Swift-based solution for programmatic access to macOS Reminders. It consists of two main components:
- reminders - A command-line interface (CLI) tool for managing reminders from the terminal
- reminders-api - A REST API server built with Hummingbird that exposes reminders functionality over HTTP
The project uniquely leverages private macOS APIs to access features not available through the standard EventKit framework, including subtasks, URL attachments, and mail links.
- Full CRUD operations on reminders and lists
- Advanced search with complex filtering
- Real-time webhook notifications for reminder changes
- Private API access to subtasks, URL attachments, and mail links
- Optional token-based authentication
- n8n workflow integration nodes
- macOS service installation for background operation
/Users/bill/Dropbox/code/reminders-hassio-todo/
├── Sources/
│ ├── reminders/ # CLI application entry point
│ ├── reminders-api/ # REST API server entry point
│ └── RemindersLibrary/ # Shared business logic library
├── Tests/
│ └── RemindersTests/ # Test suite
├── .github/workflows/ # CI/CD automation
└── [Root configuration files]
Entry Points:
/Sources/reminders/main.swift- CLI application/Sources/reminders-api/main.swift- REST API server (1282 lines)
Core Library (RemindersLibrary/):
Reminders.swift- Core business logic, EventKit interactions (794 lines)EKReminder+PrivateAPI.swift- Private API access for subtasks/URLs (108 lines)EKReminder+Encodable.swift- JSON serialization for API responses (116 lines)WebhookManager.swift- Event detection and webhook delivery (515 lines)AuthManager.swift- Authentication and logging (303 lines)CLI.swift- Command-line parsing and commandsNaturalLanguage.swift- Date parsing utilitiesSort.swift- Sorting utilities
Configuration:
Package.swift- Swift Package Manager configurationMakefile- Build and packaging automation.github/workflows/swift.yml- CI/CD pipeline
Documentation:
README.md- User-facing documentation (962 lines)API_DOCUMENTATION.md- Comprehensive API reference (1374 lines)TAGS_IMPLEMENTATION_PLAN.md- Future feature planning
- Language: Swift 5.9+
- Platform: macOS 10.15+
- Build System: Swift Package Manager
- Architectures: Universal binary (ARM64 + x86_64)
From Package.swift:
.package(url: "https://github.com/apple/swift-argument-parser", .upToNextMinor(from: "1.3.1"))
.package(url: "https://github.com/hummingbird-project/hummingbird.git", .upToNextMinor(from: "1.8.2"))Key Libraries:
- ArgumentParser - CLI command parsing and help generation
- Hummingbird - Lightweight HTTP server framework
- HummingbirdFoundation - Additional Hummingbird utilities
- EventKit - macOS framework for calendar/reminder access
- n8n - Workflow automation platform (custom nodes available)
- Webhooks - Real-time event notifications via HTTP POST
- macOS Reminders - Native integration via EventKit
Layered Architecture with Event-Driven Components:
┌─────────────────────────────────────────────┐
│ Entry Points (CLI/API) │
│ - reminders (CLI commands) │
│ - reminders-api (HTTP routes) │
└────────────────┬────────────────────────────┘
│
┌────────────────▼────────────────────────────┐
│ Business Logic Layer │
│ - Reminders (core operations) │
│ - AuthManager (authentication) │
│ - WebhookManager (event handling) │
└────────────────┬────────────────────────────┘
│
┌────────────────▼────────────────────────────┐
│ Data Access Layer │
│ - EventKit (public API) │
│ - Private APIs (via Objective-C runtime) │
└─────────────────────────────────────────────┘
CLI Flow:
- User invokes command (e.g.,
reminders show Work) - ArgumentParser parses command and flags
- Reminders class fetches data from EventKit
- Results formatted and displayed (JSON or plain text)
API Flow:
- HTTP request arrives at Hummingbird router
- Authentication middleware validates token (if required)
- Route handler calls Reminders service
- EventKit performs async data fetch
- Results encoded as JSON and returned
- Webhooks triggered for any data changes
Webhook Event Flow:
- EventKit sends
EKEventStoreChangednotification - WebhookManager compares current vs previous state
- Detects created/updated/deleted/completed/uncompleted events
- Filters reminders against webhook configurations
- Delivers HTTP POST to matching webhook URLs
Stateless Design:
- CLI: No persistent state between invocations
- API: Stateless HTTP handlers using async/await patterns
State Storage:
- Reminders data: Stored in macOS Reminders.app database (accessed via EventKit)
- Webhook configs: JSON file in
~/Library/Application Support/reminders-cli/webhooks.json - Auth config: JSON file in
~/Library/Application Support/reminders-cli/auth_config.json - Previous reminder state: In-memory cache in WebhookManager for change detection
CLI Error Handling:
- ArgumentParser validates inputs automatically
- Errors printed to stdout with
exit(1) - Semaphores used for synchronous EventKit operations
API Error Handling:
- HTTP status codes (400, 401, 404, 500)
- JSON error responses:
{"error": "message", "status": 400} - Logging at multiple levels (DEBUG, INFO, WARN, ERROR)
- Graceful degradation for optional features
Platform-Specific:
- macOS only - Relies on EventKit and private Reminders framework
- TCC Permissions Required - User must grant Reminders access
- LaunchAgent Complexity - Service mode requires careful permission handling
Private API Risks:
- API Stability - Private APIs may break across macOS versions
- App Store Restrictions - Cannot distribute via App Store
- Maintenance Burden - Requires testing on each macOS release
Concurrency:
- EventKit uses callback-based async API
- Wrapped in Swift async/await using continuations
- Semaphores used for CLI synchronous behavior
- Webhook delivery on background queue
Authentication Model:
- Optional by default (can be toggled to required)
- Single admin token (no multi-user support)
- Token stored in plaintext config file
- No token rotation or expiration
Webhook Limitations:
- No retry logic for failed deliveries
- 5-second timeout per delivery
- No rate limiting on webhook triggers
- No signature verification for security
EventKit Performance:
- Fetching all reminders can be slow (async callback pattern)
- No built-in pagination in EventKit API
- Search implemented client-side (filters in memory)
- Change detection requires full state comparison
Recommended Limits:
- Limit search results via
limitparameter - Use specific list filters to reduce data fetching
- Configure webhook filters narrowly to reduce event volume
Authentication:
- Bearer token authentication (optional)
- Tokens stored in user application support directory
- No HTTPS enforcement (localhost default)
- CORS enabled for all origins (development-friendly, production risk)
Private API Usage:
- Uses Objective-C runtime reflection (
NSSelectorFromString) - Accesses private backing objects (
backingObject,_reminder) - No sandboxing restrictions (macOS service context)
Data Access:
- Full access to all user reminders
- No row-level security or user isolation
- Webhook URLs receive sensitive reminder data
- No data encryption at rest
Core Functionality:
- ✅ CLI commands for all CRUD operations
- ✅ REST API with comprehensive endpoints
- ✅ Authentication (optional token-based)
- ✅ Webhook system with event filtering
- ✅ Private API access (subtasks, URLs, mail links)
- ✅ Search with advanced filtering
- ✅ JSON and plain text output formats
- ✅ macOS service installation
- ✅ n8n integration nodes
- ✅ Universal binary builds (ARM64 + x86_64)
Testing:
- ✅ Test suite exists in
/Tests/RemindersTests/ - ✅ GitHub Actions CI/CD workflow
- ✅ Multiple test files covering different components
From TAGS_IMPLEMENTATION_PLAN.md:
- Tags feature is planned but not fully implemented
- Command stubs exist (
ShowTags,FilterByTag,AddTag,RemoveTag) - Read-only tag access partially implemented
- Write operations for tags not completed
TCC Permission Challenges:
- LaunchAgent service may return empty results without proper permissions
- Binary must be granted Reminders access separately from Terminal
- Documentation includes extensive troubleshooting guide
Limitations:
- EventKit's
urlfield is typically null (documented Apple limitation) - URL attachment write operations not implemented
- Subtask creation not implemented (read-only)
Technical Debt:
-
Priority Mapping Inconsistency
- Recent commits mention fixing priority mapping (0-3 scale)
- May have legacy code using different scales
-
Error Handling
- Some functions use
exit(1)instead of throwing errors - Inconsistent error messages between CLI and API
- Some functions use
-
Testing Coverage
- Several test files are stubs (171 bytes suggests placeholder content)
- Need more comprehensive integration tests
-
Documentation
- Extensive documentation but may need updates after recent changes
- n8n nodes mentioned as "new in v1.1.0" but integration details sparse
Security Improvements:
- Add HTTPS support for production deployments
- Implement webhook signature verification
- Add token rotation capabilities
- Restrict CORS origins in production mode
Performance Optimizations:
- Implement caching layer for frequently accessed lists
- Add pagination support in API endpoints
- Optimize change detection in WebhookManager
- Consider database for webhook event history
From Git History:
3763e63 we already had nodes
8d65cff Add n8n nodes package for reminders-api
b398548 Fix priority mapping to use correct 0-3 scale
86d4a67 Enhance API with unified list/calendar filtering and improved priority mapping
bbbd415 Enhance search API with advanced filtering options
Key Recent Enhancements:
- n8n Integration - Added comprehensive n8n nodes package
- Priority Mapping Fix - Corrected priority scale to 0-3
- Advanced Search - Enhanced filtering with calendar/list exclusions
- Unified Filtering - Calendar and list parameters now accept names or UUIDs
File Naming:
- Swift files use PascalCase
- Extensions use pattern:
TypeName+Extension.swift - Test files mirror source files with
Testssuffix
Code Style:
- 4-space indentation
- Extensive inline comments explaining private API usage
- Descriptive variable names (prefer clarity over brevity)
- Functions returning values vs void based on side effects
Established Pattern (from EKReminder+PrivateAPI.swift):
1. Access backing object via `backingObject` selector
2. Call `_reminder` on backing object
3. Use `NSSelectorFromString` for private method calls
4. Handle `Unmanaged` values with `takeUnretainedValue()`
5. Provide computed properties as public interface
6. Document NOTE comments explaining private API usageExample:
var attachedUrl: URL? {
let attachmentsSelector = NSSelectorFromString("attachments")
guard let backingObj = reminderBackingObject,
let unmanagedAttachments = backingObj.perform(attachmentsSelector),
let attachments = unmanagedAttachments.takeUnretainedValue() as? [AnyObject] else {
return nil
}
// Process attachments...
}Endpoint Patterns:
- RESTful resource naming (e.g.,
/reminders,/lists,/webhooks) - UUID-based operations preferred over index-based
- Legacy endpoints maintained for backward compatibility
- Query parameters for filtering, not path segments
Response Formats:
- JSON with pretty printing and sorted keys
- ISO8601 dates with internet format
- UUIDs without
x-apple-reminder://prefix in API responses - Consistent error response structure
Test Organization:
- Unit tests for individual functions
- Integration tests for API endpoints
- Component-specific test files (Auth, Webhooks, etc.)
- Natural language parsing tests
Current Test Files:
APIEndpointTests.swift(131 bytes - likely stub)AuthManagerTests.swift(3804 bytes - substantive)NaturalLanguageTests.swift(5012 bytes - comprehensive)- Several stub files needing implementation
Makefile Targets:
build-release # Build CLI + API for production
build-api # Build only API server
run-api # Build and run API server
test # Run all tests
test-single # Run specific test
package # Create CLI distribution tarball
package-api # Create API distribution tarball
clean # Clean build artifactsCompiler Flags:
--arch arm64 --arch x86_64- Universal binaries-Xswiftc -enable-upcoming-feature -Xswiftc DisableSwift6Isolation- Future Swift features
Service Installation:
- LaunchAgent plist configuration
- Installation scripts with TCC permission handling
- Automatic startup on login
- Log files in
/tmp/reminders-api-service.{out,err}
Production Deployment:
deploy-production.shscript for remote servers- Token generation and configuration
- Service installation and verification
- SSH-based deployment
Question: How stable are the private APIs across macOS versions?
Context: The project uses NSSelectorFromString to access:
backingObject→_reminder→attachmentsparentReminderID→uuiduserActivity→storage
Risk: These selectors could change or be removed in future macOS releases.
Mitigation: Need to test on each new macOS version and potentially version-guard private API access.
Question: What is the current state of the n8n integration?
Evidence:
- API_DOCUMENTATION.md mentions "New in v1.1.0"
- Recent commit: "we already had nodes"
- Documentation shows comprehensive node types
Uncertainty:
- Are the n8n nodes published to npm?
- Where is the node source code located?
- Is there a separate package or embedded in this repo?
Need: Clarification on n8n node distribution and maintenance.
Question: What is the actual test coverage?
Observation: Several test files are extremely small (171 bytes), suggesting stubs.
Files needing investigation:
EKReminderEncodableTests.swiftRemindersAPITests.swiftRemindersTests.swiftSortTests.swiftTokenAuthMiddlewareTests.swift
Action needed: Expand test coverage or remove placeholder files.
Question: Is the priority system fully consistent after recent fixes?
Evidence:
- Commit b398548: "Fix priority mapping to use correct 0-3 scale"
- Code uses both raw values and
Priorityenum - API accepts string values ("none", "low", "medium", "high")
Potential issues:
- Legacy code may use old scale
- Documentation may reference incorrect values
- API validation may not be comprehensive
Question: Is the current authentication model sufficient for production?
Current state:
- Optional token authentication
- Single admin token
- No token rotation
- Plaintext storage
- No expiration
Considerations:
- Is multi-user support planned?
- Should tokens expire?
- Is HTTPS enforcement needed?
- Should webhook deliveries be signed?
Question: How should webhook delivery failures be handled?
Current behavior:
- No retry logic
- 5-second timeout
- Fire-and-forget delivery
- No delivery confirmation
Unknowns:
- Should failed deliveries be logged?
- Should there be a retry queue?
- Should webhooks be disabled after repeated failures?
- Should delivery history be persisted?
When resuming work on this project, consider investigating:
- n8n Node Package - Locate and document the n8n integration source
- Test Coverage - Run coverage analysis and expand stub tests
- Priority System Audit - Verify consistency across CLI, API, and documentation
- Tags Feature - Review TAGS_IMPLEMENTATION_PLAN.md and decide on implementation
- Security Hardening - Evaluate authentication and webhook security requirements
- Performance Profiling - Test with large reminder datasets
- macOS Version Compatibility - Test private APIs on latest macOS release
Context Documentation Created: 2025-10-16
Codebase Branch: reminders-hassio-todo (clean working tree)
Last Commit: 3763e63 "we already had nodes"
Total Lines Analyzed: ~8,000+ across 33 files