I Built a Free macOS Task Manager in a Weekend Because I Was Tired of Paying for Todo Apps
A full Google Calendar sync, native macOS app, built with Tauri + Rust + React — zero subscription fees, forever.
The spark hit me when I opened Todoist and saw the paywall for Google Calendar sync. A $48/year subscription. For syncing a calendar. Something that should be a basic feature.
I'm a CEO. I live in task managers. I've tried Todoist, Things 3, TickTick, Notion, Linear. They're all great — and they all want $50-100/year for features that should be free.
So I decided to build my own.
The Stack: Why Tauri?
I chose Tauri over Electron because I didn't want a 200MB app that eats RAM. Tauri apps are native — they use the OS's webview and a Rust backend. The Daily Planner app is under 10MB.
Stack:
Tauri 2.0 — native macOS wrapper
Rust — backend logic, database, OAuth
React 18 + TypeScript — frontend UI
SQLite via SQLx — local-first data storage, no server required
Tailwind CSS — styling
Why this stack? Because I wanted something that:
Doesn't ship 200MB of Chromium
Feels native to macOS (dock icon, menu bar, native notifications)
Stores data locally (no cloud vendor lock-in)
Is fast and efficient
Can be built by one person in a weekend
Tauri + Rust hit all five.
The Architecture: Local-First
Most task apps store your data on their servers. Daily Planner stores everything locally in SQLite. Google Calendar sync is optional and additive — your data is yours.
The SQLite database lives at:
~/Library/Application Support/dev.inguva.daily-planner/daily-planner.db
You can back it up, copy it between machines, inspect it with any SQLite client. It's your data.
Why local-first?
Cloud sync is convenient, but it comes with vendor risk. If a SaaS company:
Gets acquired and shuts down
Changes pricing models
Has a data breach
Decides to pivot away from your use case
...your data is at risk or gone.
With local-first, I own my task history. If Daily Planner disappears tomorrow, my 5 years of task data is still on my machine.
The Google Calendar Sync: Secure OAuth Without a Backend
This was the fun part. I implemented a proper OAuth 2.0 PKCE flow — no server needed.
How it works:
User clicks "Connect Google Calendar"
App opens a local HTTP server on a random port (e.g.,
:59265)Browser opens to Google's OAuth consent page
User signs in and authorizes access to calendar
Google redirects to
http://127.0.0.1:59265/callback?code=xyzApp captures the code and exchanges it for access tokens
Tokens stored locally, sync runs in background
Browser tab closes automatically
PKCE (Proof Key for Code Exchange) is the secure standard for desktop apps. It's what mobile apps use. It doesn't require a backend server or any secrets transmitted over the internet.
No server. No database. No infrastructure costs. Completely free.
The Code
pub async fn start_flow(&self) -> Result<(String, String, u16), String> {
let code_verifier = Self::generate_code_verifier();
let code_challenge = Self::generate_code_challenge(&code_verifier);
// Start local HTTP server
let listener = TcpListener::bind("127.0.0.1:0").map_err(|e| e.to_string())?;
let port = listener.local_addr().map_err(|e| e.to_string())?.port();
// Build OAuth URL with PKCE challenge
let redirect_uri = format!("http://127.0.0.1:{}/callback", port);
let oauth_url = format!(
"{}?client_id={}&redirect_uri={}&response_type=code&code_challenge={}&code_challenge_method=S256&access_type=offline&prompt=consent",
GOOGLE_OAUTH_URL,
urlencoding::encode(&self.client_id),
urlencoding::encode(&redirect_uri),
code_challenge
);
// Open browser
open::that(&oauth_url)?;
// Wait for callback
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
if let Ok((stream, _)) = listener.accept() {
let _ = handle_callback(stream, &tx);
}
});
let auth_code = rx.recv_timeout(std::time::Duration::from_secs(300))?;
Ok((auth_code, code_verifier, port))
}
The entire flow is client-side. No backend. No webhook. Just a local server that lives for 5 seconds.
Priority → Calendar Color Mapping
One of my favorite features: task priority maps to Google Calendar event color.
P1 Urgent → Red (Tomato)
P2 High → Yellow (Banana)
P3 Medium → Green (Sage)
P4 Low → Purple (Lavender)
Your calendar becomes a visual priority map. Glance at your calendar and you immediately see what's urgent.
fn priority_to_calendar_color(priority: i32) -> &'static str {
match priority {
1 => "Tomato", // Red
2 => "Banana", // Yellow
3 => "Sage", // Green
_ => "Lavender", // Purple
}
}
What It Has (v0.1.0)
✅ Full task CRUD with priorities ✅ Due dates + times ✅ Recurring tasks (daily/weekly/monthly) ✅ Google Calendar two-way sync ✅ Tray icon for quick task entry ✅ Light/dark theme ✅ Keyboard shortcuts (⌘N for new task, ⌘K for search) ✅ Markdown support in task descriptions
What's Next
Phase 1 — Foundation Hardening (Week 2)
Token refresh (OAuth expires after 1 hour)
Pull from GCal (currently push-only)
Auto-sync every 15 minutes
Native macOS notifications
YEARLY recurrence support
Fix timezone handling
Phase 2 — Power User Features (Month 2)
Subtasks and projects
Natural language input ("Buy milk tomorrow at 5pm")
Drag & drop reordering
Keyboard-first navigation
Global hotkey for quick capture (⌘⇧Space)
Phase 3 — Smart Features (Month 3)
Focus mode / Pomodoro timer
Time tracking per task
AI-powered task prioritization
Weekly review summary
Smart scheduling suggestions
Phase 4 — Ecosystem (Month 4+)
Apple Reminders sync
Notion integration
Slack integration
GitHub Issues sync
iOS companion app
The Challenges
Challenge #1: Rust Learning Curve
I hadn't written Rust before this. The first 2 hours were painful. But the compiler errors are incredibly helpful. "You can't move this value because it doesn't implement Copy" is actually good feedback.
Rust forces you to think about ownership and memory. Once it clicks, you realize how many bugs this prevents.
Challenge #2: Tauri Build System
Bundling a native macOS app requires:
Signing with a developer certificate
Creating icons in 8 different sizes
Configuring the
tauri.conf.jsonmanifestLearning how Tauri's preload scripts work
Once it's working, though, shipping updates is as simple as npm run build. The app bundles itself into a .dmg file ready for distribution.
Challenge #3: OAuth Debugging
Getting PKCE right took trial and error. I had to:
Add the app to Google's OAuth consent screen
Add my test email as an authorized user
Debug the redirect URI (it must be
127.0.0.1, notlocalhost)Handle the authorization code properly
But once it worked, the rest was straightforward.
Key Takeaways
1. You don't need a backend for everything
OAuth PKCE is designed for desktop/mobile apps. You can authenticate users without running a server. Your app is the server for 5 seconds.
2. Local-first is underrated
Most indie developers assume they need to sync to the cloud. You don't. SQLite on your machine is powerful. Sync it manually, or add cloud backup without locking users in.
3. Tauri is a game-changer for indie developers
Electron dominates because it's easy. But Tauri is the better choice for native performance, small bundle size, and fast startup. The ecosystem is young but growing.
4. One weekend is enough
I built the MVP — tasks, due dates, priorities, GCal sync, native UI — in about 12 hours. Most of my time went to learning Tauri's architecture and OAuth, not coding.
How to Use It
Download the latest
.dmgfrom the Releases pageDrag
Daily Planner.appinto ApplicationsLaunch it (you may need to right-click and "Open" to bypass Gatekeeper)
Click "Connect Google Calendar" and authorize
Start adding tasks
All data stays on your machine. You own it.
Contributing
The codebase is open source. If you want to:
Fix a bug
Add a feature
Improve the UI
Optimize performance
...you're welcome to contribute. The tech stack is accessible: Rust isn't scary, and React/TypeScript is familiar to web developers.
What Would You Build?
If you're frustrated with subscription pricing on productivity tools, what feature would you want in your ideal task manager?
Drop a comment below, and if it resonates, I'll add it to the roadmap.
Daily Planner is free and always will be.
No ads. No tracking. No pricing tiers. No dark patterns. Just a task manager that syncs to your calendar and respects your data.