Systems Library / Operations & Admin / How to Create Automated Performance Review Reminders
Operations & Admin hr people

How to Create Automated Performance Review Reminders

Schedule and remind managers about performance reviews automatically.

Jay Banlasan

Jay Banlasan

The AI Systems Guy

Performance reviews slip because nobody has a system to track them. I built a system to automate performance review reminders that schedules reviews, sends escalating reminders to managers, and tracks completion rates. No review falls through the cracks.

The system handles the nagging so HR does not have to.

What You Need Before Starting

Step 1: Set Up the Review Schedule Database

import sqlite3
from datetime import datetime

def init_review_db(db_path="reviews.db"):
    conn = sqlite3.connect(db_path)
    conn.execute("""
        CREATE TABLE IF NOT EXISTS review_schedule (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            employee_name TEXT,
            employee_email TEXT,
            manager_name TEXT,
            manager_email TEXT,
            review_type TEXT,
            due_date TEXT,
            status TEXT DEFAULT 'scheduled',
            completed_at TEXT,
            reminders_sent INTEGER DEFAULT 0
        )
    """)
    conn.commit()
    return conn

Step 2: Generate Review Schedules

from datetime import timedelta

def schedule_reviews(conn, employees, review_type="quarterly"):
    cycles = {
        "quarterly": [("Q1", "03-31"), ("Q2", "06-30"), ("Q3", "09-30"), ("Q4", "12-31")],
        "annual": [("Annual", "12-15")],
        "semi_annual": [("H1", "06-30"), ("H2", "12-31")]
    }

    year = datetime.now().year
    for employee in employees:
        for label, date_str in cycles[review_type]:
            due = f"{year}-{date_str}"
            conn.execute(
                "INSERT INTO review_schedule (employee_name, employee_email, manager_name, manager_email, review_type, due_date) VALUES (?,?,?,?,?,?)",
                (employee["name"], employee["email"], employee["manager_name"],
                 employee["manager_email"], f"{label} {review_type.title()}", due)
            )
    conn.commit()

Step 3: Build the Reminder Engine

def get_pending_reminders(conn):
    today = datetime.now().strftime("%Y-%m-%d")
    reminders = []

    rows = conn.execute("""
        SELECT id, employee_name, manager_name, manager_email, review_type, due_date, reminders_sent
        FROM review_schedule
        WHERE status = 'scheduled'
    """).fetchall()

    for row in rows:
        review_id, emp_name, mgr_name, mgr_email, review_type, due_date, sent = row
        days_until = (datetime.strptime(due_date, "%Y-%m-%d") - datetime.now()).days

        if days_until <= 14 and sent == 0:
            reminders.append({"id": review_id, "type": "first", "days": days_until,
                            "manager_email": mgr_email, "employee": emp_name, "review_type": review_type})
        elif days_until <= 7 and sent <= 1:
            reminders.append({"id": review_id, "type": "second", "days": days_until,
                            "manager_email": mgr_email, "employee": emp_name, "review_type": review_type})
        elif days_until <= 0 and sent <= 2:
            reminders.append({"id": review_id, "type": "overdue", "days": abs(days_until),
                            "manager_email": mgr_email, "employee": emp_name, "review_type": review_type})

    return reminders

Step 4: Send Escalating Notifications

def send_reminder(reminder):
    templates = {
        "first": "Reminder: {employee}'s {review_type} review is due in {days} days.",
        "second": "Second reminder: {employee}'s {review_type} review is due in {days} days. Please schedule it.",
        "overdue": "OVERDUE: {employee}'s {review_type} review is {days} days past due. HR has been notified."
    }

    message = templates[reminder["type"]].format(**reminder)
    print(f"Sending to {reminder['manager_email']}: {message}")
    return message

Step 5: Track Completion and Report

def completion_report(conn):
    total = conn.execute("SELECT COUNT(*) FROM review_schedule").fetchone()[0]
    done = conn.execute("SELECT COUNT(*) FROM review_schedule WHERE status='complete'").fetchone()[0]
    overdue = conn.execute(
        "SELECT COUNT(*) FROM review_schedule WHERE status='scheduled' AND due_date < ?",
        (datetime.now().strftime("%Y-%m-%d"),)
    ).fetchone()[0]

    return {
        "total_scheduled": total,
        "completed": done,
        "completion_rate": round(done/total*100, 1) if total else 0,
        "overdue": overdue
    }

Schedule the reminder check to run daily:

0 9 * * * python3 /path/to/review_reminders.py

What to Build Next

Add self-review prompts that go to employees before the manager review. Include AI-generated talking points based on the employee's project history. The reminder system keeps reviews on schedule. The prep system makes them actually useful.

Related Reading

Want this system built for your business?

Get a free assessment. We will map every system your business needs and show you the ROI.

Get Your Free Assessment

Related Systems