algoritmo de priorização de tarefas em python puro

Priority Decay em Python Puro: O Algoritmo Que Reorganiza Sua Lista de Tarefas Automaticamente Baseado em Urgência, Energia e Prazo (Sem Notion, Sem Todoist)

Você já teve aquela sensação de que sua lista de tarefas tá viva? Tipo, você acorda com 5 coisas urgentes, vai pro café, volta e agora são 12 urgentes — e nenhuma delas parece mais importante que a outra?

Eu vivi isso por anos. Testei Todoist, Notion, Trello, ClickUp, Monday, e mais uma dúzia de apps que prometem “organizar sua vida”. O resultado? Eu gastava mais tempo organizando as tarefas do que executando elas. Era produtividade de fachada.

Aí eu pensei: e se a priorização não fosse estática? E se cada tarefa tivesse uma “urgência” que decai com o tempo, um “custo energético” que varia conforme seu estado mental, e um “peso de deadline” que aumenta exponencialmente conforme o prazo se aproxima?

Foi aí que nasceu o Priority Decay: um algoritmo em Python puro que recalcula a prioridade de cada tarefa em tempo real, baseado em três variáveis dinâmicas. Sem apps pagos, sem SaaS, sem dependências externas. Só você, seu terminal, e um pouco de matemática aplicada.

O Problema da Priorização Estática

A maioria dos sistemas de produtividade trata prioridade como um número fixo: “essa tarefa é prioridade 1, essa é prioridade 2”. Mas isso ignora uma realidade fundamental: urgência não é constante.

Uma tarefa que era urgente ontem pode ser irrelevante hoje. Uma tarefa que parecia tranquila pode virar uma bomba se o deadline se aproximar. E uma tarefa que exige foco total às 9h da manhã pode ser impossível de executar às 16h, quando seu cérebro já fritou.

As Três Variáveis do Priority Decay

O algoritmo funciona com três componentes que se multiplicam:

  • Urgência Decrescente (U): começa alta e decai exponencialmente com o tempo
  • Energia Necessária (E): custo cognitivo da tarefa (1-10), comparado com seu nível atual de energia
  • Peso do Deadline (D): aumenta não-linearmente conforme o prazo se aproxima

A fórmula final é: Prioridade = U × E × D

Implementando a Classe Task

Vamos começar com a estrutura básica de uma tarefa:

from datetime import datetime, timedelta
import math

class Task:
    def __init__(self, name, urgency, energy_cost, deadline, created_at=None):
        self.name = name
        self.urgency = urgency  # 1-10, urgência inicial
        self.energy_cost = energy_cost  # 1-10, custo cognitivo
        self.deadline = deadline  # datetime
        self.created_at = created_at or datetime.now()
        self.last_updated = datetime.now()
    
    def __repr__(self):
        return f"Task('{self.name}', urgency={self.urgency}, energy={self.energy_cost})"

Simples, direto, sem ORM, sem framework. Cada tarefa sabe quando foi criada, qual seu custo energético e quando é o deadline.

Calculando o Decaimento de Urgência

A urgência decai exponencialmente com o tempo. A fórmula é:

U(t) = U₀ × e^(-λt)

Onde U₀ é a urgência inicial, λ é a taxa de decaimento, e t é o tempo em horas desde a criação.

def calculate_urgency_decay(self, current_time=None, decay_rate=0.05):
    """
    Calcula urgência atual com decaimento exponencial.
    decay_rate=0.05 significa que a urgência cai ~5% por hora.
    """
    current_time = current_time or datetime.now()
    hours_elapsed = (current_time - self.created_at).total_seconds() / 3600
    
    # Decaimento exponencial
    current_urgency = self.urgency * math.exp(-decay_rate * hours_elapsed)
    
    return max(1, current_urgency)  # Mínimo de 1 para não zerar

Eu escolhi decay_rate=0.05 porque, empiricamente, tarefas que eram urgentes há 24h geralmente perderam ~70% da urgência inicial. Você pode ajustar esse valor conforme seu contexto.

O Fator Energia: Matching Cognitivo

Aqui é onde a maioria dos sistemas falha. Eles ignoram que você não é uma máquina de estado constante. Às 9h da manhã, você consegue escrever código complexo. Às 16h, talvez só consiga responder emails.

def calculate_energy_match(self, current_energy_level):
    """
    current_energy_level: 1-10, seu nível atual de energia mental
    Retorna um multiplicador: 1.0 se match perfeito, <1 se mismatch
    """
    # Se a tarefa exige mais energia que você tem agora, penaliza
    if self.energy_cost > current_energy_level:
        # Penalidade proporcional ao gap
        gap = self.energy_cost - current_energy_level
        penalty = 1 / (1 + gap * 0.3)  # Gap de 3 = ~0.5x prioridade
        return penalty
    else:
        # Se você tem energia sobrando, bônus pequeno
        surplus = current_energy_level - self.energy_cost
        bonus = 1 + (surplus * 0.1)  # Surplus de 3 = 1.3x
        return min(1.5, bonus)  # Cap em 1.5x

Esse cálculo cria um matching dinâmico: tarefas de alta energia só aparecem no topo quando você realmente tem energia pra elas. Senão, o algoritmo sugere coisas mais leves.

Peso do Deadline: A Curva Exponencial

Deadlines não são lineares. Uma tarefa com deadline em 7 dias não é “2x menos urgente” que uma com deadline em 3.5 dias. A pressão aumenta exponencialmente conforme o prazo se aproxima.

def calculate_deadline_weight(self, current_time=None):
    """
    Retorna um multiplicador baseado na proximidade do deadline.
    Deadline em 7 dias = ~1.0x
    Deadline em 1 dia = ~3.0x
    Deadline em 1 hora = ~10.0x
    """
    current_time = current_time or datetime.now()
    hours_until_deadline = (self.deadline - current_time).total_seconds() / 3600
    
    if hours_until_deadline <= 0:
        return 15.0  # Deadline passou, prioridade máxima
    
    # Curva inversa: quanto menos tempo, maior o peso
    # weight = 1 + (k / hours)
    k = 10  # Constante de ajuste
    weight = 1 + (k / hours_until_deadline)
    
    return min(15.0, weight)  # Cap em 15x

A constante k=10 foi calibrada empiricamente. Tarefas com deadline em 10h têm peso ~2x, em 1h têm peso ~11x. Ajuste conforme sua tolerância a pressão.

Juntando Tudo: O Cálculo de Prioridade

def calculate_priority(self, current_energy_level, current_time=None):
    """
    Calcula prioridade final combinando os três fatores.
    """
    current_time = current_time or datetime.now()
    
    urgency = self.calculate_urgency_decay(current_time)
    energy_match = self.calculate_energy_match(current_energy_level)
    deadline_weight = self.calculate_deadline_weight(current_time)
    
    priority = urgency * energy_match * deadline_weight
    
    return round(priority, 2)

Simples assim. Três variáveis dinâmicas, uma multiplicação, e você tem uma prioridade que se adapta em tempo real.

O Sistema de Reorganização Automática

Agora vamos criar uma classe que gerencia múltiplas tarefas e as reordena automaticamente:

class PriorityDecaySystem:
    def __init__(self):
        self.tasks = []
    
    def add_task(self, task):
        self.tasks.append(task)
    
    def get_prioritized_list(self, current_energy_level, current_time=None):
        """
        Retorna tarefas ordenadas por prioridade atual.
        """
        current_time = current_time or datetime.now()
        
        # Calcula prioridade de cada tarefa
        prioritized = []
        for task in self.tasks:
            priority = task.calculate_priority(current_energy_level, current_time)
            prioritized.append((task, priority))
        
        # Ordena por prioridade (maior primeiro)
        prioritized.sort(key=lambda x: x[1], reverse=True)
        
        return prioritized
    
    def display_list(self, current_energy_level):
        """
        Exibe lista formatada no terminal.
        """
        print(f"
{'='*60}")
        print(f"LISTA DE TAREFAS (Energia atual: {current_energy_level}/10)")
        print(f"{'='*60}
")
        
        prioritized = self.get_prioritized_list(current_energy_level)
        
        for i, (task, priority) in enumerate(prioritized, 1):
            hours_left = (task.deadline - datetime.now()).total_seconds() / 3600
            print(f"{i}. [{priority:6.2f}] {task.name}")
            print(f"   Urgência: {task.urgency}/10 | Energia: {task.energy_cost}/10 | Deadline: {hours_left:.1f}h")
            print()

Exemplo de Uso: Um Dia Real

Vamos simular um dia típico. São 9h da manhã, você tá com energia 8/10:

# Criando tarefas
system = PriorityDecaySystem()

system.add_task(Task(
    "Finalizar apresentação pro cliente",
    urgency=9,
    energy_cost=7,
    deadline=datetime.now() + timedelta(hours=4)
))

system.add_task(Task(
    "Revisar pull request do João",
    urgency=6,
    energy_cost=5,
    deadline=datetime.now() + timedelta(hours=8)
))

system.add_task(Task(
    "Responder emails não-urgentes",
    urgency=3,
    energy_cost=2,
    deadline=datetime.now() + timedelta(days=1)
))

system.add_task(Task(
    "Escrever documentação da API",
    urgency=5,
    energy_cost=8,
    deadline=datetime.now() + timedelta(days=3)
))

# 9h da manhã, energia alta
system.display_list(current_energy_level=8)

O resultado? A apresentação do cliente aparece em primeiro (deadline próximo + alta urgência), seguida pela documentação da API (energia alta disponível).

Agora simule as 15h, energia caiu pra 4/10:

# 15h, energia baixa
system.display_list(current_energy_level=4)

Agora "Responder emails" subiu na lista, porque exige pouca energia. A documentação da API despencou, porque você não tem energia pra ela.

Otimizações e Ajustes Finos

Depois de usar isso por 3 meses, descobri algumas coisas:

1. Decay Rate Variável

Nem toda tarefa decai na mesma velocidade. Tarefas de clientes externos decaem mais devagar (porque têm consequências reais). Tarefas internas decaem mais rápido.

def calculate_urgency_decay(self, current_time=None, decay_rate=None):
    if decay_rate is None:
        # Decay rate baseado no tipo de tarefa
        decay_rate = getattr(self, 'custom_decay_rate', 0.05)
    
    # ... resto do código

2. Persistência com JSON

Salvar tarefas em arquivo JSON pra não perder o estado:

import json

def save_tasks(self, filename='tasks.json'):
    data = []
    for task in self.tasks:
        data.append({
            'name': task.name,
            'urgency': task.urgency,
            'energy_cost': task.energy_cost,
            'deadline': task.deadline.isoformat(),
            'created_at': task.created_at.isoformat()
        })
    
    with open(filename, 'w') as f:
        json.dump(data, f, indent=2)

def load_tasks(self, filename='tasks.json'):
    with open(filename, 'r') as f:
        data = json.load(f)
    
    for item in data:
        task = Task(
            item['name'],
            item['urgency'],
            item['energy_cost'],
            datetime.fromisoformat(item['deadline']),
            datetime.fromisoformat(item['created_at'])
        )
        self.add_task(task)

3. Integração com Cron

Rodar automaticamente a cada hora e mandar notificação:

# Crontab: rodar a cada hora
0 * * * * /usr/bin/python3 /path/to/priority_decay.py --notify

Por Que Isso Funciona Melhor Que Apps Pagos

Apps como Todoist e Notion tratam prioridade como algo estático. Você marca "prioridade alta" e aquilo fica lá pra sempre, até você mudar manualmente.

O Priority Decay entende que prioridade é dinâmica. Ela muda conforme:

  • O tempo passa (urgência decai)
  • Sua energia varia ao longo do dia
  • O deadline se aproxima (pressão aumenta)

E faz isso sem você precisar mexer em nada. Você só olha a lista e ela já tá ordenada pelo que realmente importa agora.

Limitações e Próximos Passos

Óbvio que não é perfeito. Algumas coisas que ainda preciso melhorar:

  • Dependências entre tarefas: "Tarefa B só pode começar depois que A terminar"
  • Context switching cost: penalidade por trocar de projeto
  • Energy prediction: prever energia baseado em hora do dia e atividades anteriores

Mas pra uma v1 em Python puro, sem dependências externas, já resolve 80% do problema.

Conclusão: Produtividade Não É Sobre Apps, É Sobre Sistemas

A gente gasta tempo demais procurando o "app perfeito" e tempo de menos construindo sistemas que realmente funcionam pro nosso contexto.

O Priority Decay não é revolucionário. É só matemática básica aplicada a um problema real. Mas funciona porque:

  • É adaptativo (muda conforme você muda)
  • É transparente (você entende por que cada tarefa tá onde tá)
  • É seu (ninguém tá vendendo seus dados, ninguém tá te empurrando features premium)

Se você tá cansado de apps que prometem organizar sua vida mas só adicionam complexidade, talvez seja hora de voltar pro básico: um terminal, um script, e um pouco de matemática aplicada.

Agora me conta: qual automação de produtividade você queria ver implementada em Python puro? Manda aí nos comentários que eu transformo em código.

Posts Similares