Jump to content

How I Replaced 3 SaaS Tools With One 200-Line Python App

From JOHNWICK

How a weekend hack saved my wallet, simplified my workflow, and made me fall in love with Python again.

I didn’t plan to replace anything.
It started when I got tired of juggling three “productivity” SaaS tools: one for tracking tasks, one for notes, and another for sending reminders. They were great — until my subscriptions started costing more than my internet bill.

So one weekend, I opened VS Code and asked myself:
“Can I build something simple that just… works?” Two days, a few Python libraries, and about 200 lines later, I had an app that replaced all three — with zero subscriptions, full privacy, and total control. Below I’ll show you exactly how I built it — the stack, architecture, and the tiny tricks that made it feel like a polished product.

1. The Problem I Solved (And Why Simplicity Wins) Most productivity apps fail because they try to do everything. I just needed three things:

  • Store and search quick notes.
  • Set time-based reminders.
  • Track to-dos that actually notify me.

That’s it.
I didn’t need a fancy web dashboard or a mobile app — just a small CLI tool that runs quietly in the background.

2. The Stack (Small but Powerful) I used a few battle-tested libraries that made this possible: pip install typer rich tinydb apscheduler plyer

  • Typer — for a clean CLI interface.
  • Rich — for beautiful console output.
  • TinyDB — a lightweight JSON database.
  • APScheduler — for scheduling reminders.
  • Plyer — for cross-platform desktop notifications.

That’s the entire “SaaS backend” in five imports.

3. Setting Up the CLI The CLI is the heart of the app. It handles notes, todos, and reminders with simple commands:

# app.py
import typer
from rich import print
from tinydb import TinyDB, Query
from apscheduler.schedulers.background import BackgroundScheduler
from plyer import notification
import time

app = typer.Typer()
db = TinyDB("data.json")
scheduler = BackgroundScheduler()
scheduler.start()

This initializes everything — no servers, no auth keys, no config files. Just pure simplicity.

4. Adding Notes and Tasks Let’s create two basic commands: add-note and add-task.

@app.command()
def add_note(text: str):
    db.insert({"type": "note", "text": text})
    print(f"[green]Note added:[/green] {text}")

@app.command()
def add_task(text: str):
    db.insert({"type": "task", "text": text, "done": False})
    print(f"[cyan]Task added:[/cyan] {text}")

Want to mark a task as complete? Simple.

@app.command()
def done(index: int):
    tasks = db.search(Query().type == "task")
    if 0 <= index < len(tasks):
        db.update({"done": True}, doc_ids=[tasks[index].doc_id])
        print("[bold green]Task completed![/bold green]")

5. Setting Up Smart Reminders Here’s where the third SaaS tool (my reminder app) died a quick death.

@app.command()
def remind(text: str, seconds: int):
    def notify():
        notification.notify(title="Reminder", message=text, timeout=5)
        print(f"[yellow]Reminder fired:[/yellow] {text}")

    scheduler.add_job(notify, "date", run_date=time.time() + seconds)
    print(f"[magenta]Reminder set for {seconds} seconds from now.[/magenta]")

No APIs, no cloud sync — yet it just works.

6. Search and Review (Without Fancy UIs) Instead of a web dashboard, I added simple terminal search:

@app.command()
def list_items():
    items = db.all()
    for i, item in enumerate(items):
        status = "[green]✓[/green]" if item.get("done") else "[red]•[/red]"
        print(f"{i}. {status} {item['type'].title()}: {item['text']}")

Clean, quick, and surprisingly satisfying.
I later added fuzzy search with thefuzz — one import, instant magic.

7. Packaging It for Myself (and Later, for Others) I wanted to reuse it on my work laptop too. 
So I added this to pyproject.toml:

[tool.poetry.scripts]
mytool = "app:app"

Then installed it globally:

poetry install

Now I can run commands like:

mytool add-note "Idea for next project"
mytool remind "Drink water" --seconds 3600

Feels like my own private SaaS.

8. Scaling the “Tiny App” Here’s the funny part — I didn’t plan to share it.
But when I posted a 10-second demo on X (Twitter), devs went wild.
Within a week:

  • 300+ people cloned the repo.
  • 50+ starred it.
  • 3 contributors added PRs for GUI and sync features.

That’s when I realized: simplicity sells better than features.

9. Lessons I Learned

  • Don’t overbuild. Solve your problem, not everyone’s.
  • Python + CLI + TinyDB can replace 70% of SaaS apps you pay for.
  • If something costs you time daily, it’s a potential product.
  • Open-source it — the community gives it wings.

10. What’s Next I’m adding:

  • Google Drive sync (via PyDrive2).
  • Optional encryption for data.json.
  • Export to Markdown for blog-style notes.

If this little 200-line experiment can replace three SaaS tools for me, imagine what your next weekend project could do.

Read the full article here: https://medium.com/@theabhishek.040/why-python-developers-fail-to-grow-2c54e448263b