Aller au contenu
Hermès Skills
← Retour au catalogue

suivi-taches-automatique

Pour chaque demande utilisateur, créer une entrée dans le Google Sheet de suivi avec statuts (planifiée, en cours, terminée, abandonnée) et code couleur

Quand l'utiliser (Trigger)

Déclenchement standard selon le contexte de l'écosystème Hermès.

Mode d'emploi (Usage)

Mode d'emploi standard via l'agent Hermès.

Suivi Automatique des Tâches

À charge pour chaque nouvelle demande utilisateur.

Prérequis

  • Google Sheet maître : 1ApgDSz7ZjlMj_1WeRt7EFkLf_fVSxgsWRGBUTEF2dRw
  • Sheet nommé ”📋 Tableau de Bord — Suivi des Tâches & Projets”
  • Onglets : Tâches, Projets, Stats
  • Raccourci GAPI : GAPI="python ~/.hermes/skills/productivity/google-workspace/scripts/google_api.py"

Workflow Obligatoire

Pour CHAQUE nouvelle tâche que l’utilisateur donne :

1. Créer l’entrée dans le Google Sheet

Lire d’abord l’onglet Tâches pour déterminer le prochain numéro et la liste existante :

# Lecture des tâches existantes (import google_api, build_service)
data = service.spreadsheets().values().get(
    spreadsheetId=SHEET_ID, range="Tâches!A:J"
).execute()
rows = data.get('values', [])
next_num = len(rows)  # après le header
existing_titles = {r[1].strip() for r in rows if len(r) >= 2}

Ajouter une ligne avec append API si le titre n’existe pas déjà.

Colonnes de l’onglet Tâches :

ColChampValeur
A#Prochain numéro auto
BTâcheNom de la tâche
CProjetCatégorie (DevOps, Emploi, Workflow, etc.)
DStatutPlanifiée / En cours / Terminée / Abandonnée
EPrioritéHaute / Moyenne / Basse
FDate créationAujourd’hui (YYYY-MM-DD)
GDernière MAJAujourd’hui
HLien Vikunja(facultatif — projet 19, buckets: Planifiée=55, En cours=56, Terminée=57, Abandonnée=62)
ITagsmots-clés séparés par virgule
JNotesDescription ou contexte

1b. Optionnel: Ajouter l’entrée dans Vikunja

Si Vikunja est accessible (https://vikunja.iatuto.com), synchroniser aussi la tâche dans le projet “Suivi des Tâches” (ID:19). Utiliser le JWT depuis le login API (curl, pas Python urllib — Cloudflare bloque SSL Python).

Méthode (via curl en subprocess):

import json, subprocess

# Login
r = subprocess.run(["curl","-sk",
  "https://vikunja.iatuto.com/api/v1/login","-X","POST",
  "-H","Content-Type: application/json",
  "-d",'{"username":"hermes-agent","password":"DwzBo77RmVlf02Cg"}'],
  capture_output=True, text=True, timeout=15)
token = json.loads(r.stdout)["token"]

# Create task - use PUT not POST, labels as objects not bare IDs
# IMPORTANT: avoid braces in f-strings for the auth header
# use %s or concat to prevent template interpretation
AUTH_HDR = "Authorization: Bearer %s" % token
cmd = ["curl","-sk",
  "https://vikunja.iatuto.com/api/v1/projects/19/tasks","-X","PUT",
  "-H","Content-Type: application/json",
  "-H", AUTH_HDR,
  "-d", json.dumps({
    "title": task_title,
    "description": desc,
    "priority": priority,
    "labels": [{"id": label_id}],  # objects, not bare ints
    "bucket_id": bucket_id  # 55=Planifiee, 56=En cours, 57=Terminee
  })]
r = subprocess.run(cmd, capture_output=True, text=True, timeout=15)

Config sauvegardée dans ~/.hermes/vikunja_config.json.

2. Appliquer le code couleur via batchUpdate

Obligatoire après chaque ajout ou modification de statut. Utiliser l’API batchUpdate de Sheets (pas via google_api.py — il faut un appel direct) :

colors = {
    "Terminée":   {"red": 0.78, "green": 0.92, "blue": 0.78},  # vert pâle
    "En cours":   {"red": 0.85, "green": 0.91, "blue": 0.98},  # bleu pâle
    "Planifiée":  {"red": 1.0,  "green": 0.96, "blue": 0.78},  # jaune pâle
    "Abandonnée": {"red": 0.92, "green": 0.92, "blue": 0.92},  # gris pâle
}

# 1) Trouver l'ID de l'onglet "Tâches"
meta = service.spreadsheets().get(spreadsheetId=SHEET_ID).execute()
tasks_sheet_id = None
for s in meta['sheets']:
    if s['properties']['title'] == 'Tâches':
        tasks_sheet_id = s['properties']['sheetId']

# 2) Colorer la cellule de statut (colonne D, gras)
requests.append({
    "repeatCell": {
        "range": {"sheetId": tasks_sheet_id, "startRowIndex": row_idx,
                  "endRowIndex": row_idx + 1, "startColumnIndex": 3, "endColumnIndex": 4},
        "cell": {"userEnteredFormat": {"backgroundColor": bg, "textFormat": {"bold": True}}},
        "fields": "userEnteredFormat.backgroundColor,userEnteredFormat.textFormat.bold"
    }
})

# 3) Colorer la ligne entière en version plus claire (optionnel mais recommandé)
light_bg = {k: v * 0.95 + 0.05 for k, v in bg.items()}
requests.append({
    "repeatCell": {
        "range": {"sheetId": tasks_sheet_id, "startRowIndex": row_idx,
                  "endRowIndex": row_idx + 1, "startColumnIndex": 0, "endColumnIndex": 10},
        "cell": {"userEnteredFormat": {"backgroundColor": light_bg}},
        "fields": "userEnteredFormat.backgroundColor"
    }
})

# Envoyer par batch de 100 max
BATCH_SIZE = 100
for start in range(0, len(requests), BATCH_SIZE):
    service.spreadsheets().batchUpdate(
        spreadsheetId=SHEET_ID,
        body={"requests": requests[start:start + BATCH_SIZE]}
    ).execute()

3. Mettre à jour les Stats

Toujours recalculer après chaque modification. Lire toutes les tâches et compter :

data = service.spreadsheets().values().get(
    spreadsheetId=SHEET_ID, range="Tâches!D:D").execute()
rows = data.get('values', [])
by_status = {}
for r in rows[1:]:
    s = r[0].strip() if r else '?'
    by_status[s] = by_status.get(s, 0) + 1

stats = [
    ['Tâches totales', str(len(rows) - 1), today, ''],
    ['En cours', str(by_status.get('En cours', 0)), today, ''],
    ['Planifiées', str(by_status.get('Planifiée', 0)), today, ''],
    ['Terminées', str(by_status.get('Terminée', 0)), today, ''],
    ['Abandonnées', str(by_status.get('Abandonnée', 0)), today, ''],
    ['Projets actifs', '3', today, ''],
]
service.spreadsheets().values().update(
    spreadsheetId=SHEET_ID, range="Stats!A2:D7",
    valueInputOption='USER_ENTERED',
    body={'values': stats}).execute()

4. Audit rétrospectif (import de tâches historiques)

Quand l’utilisateur demande un état des lieux complet, NE PAS se limiter aux tâches de la session en cours. Chercher dans l’historique des sessions avec session_search() pour identifier TOUTES les tâches passées, puis les ajouter au Sheet si absentes avec leur statut réel (En cours / Terminée / Abandonnée). Ne pas deviner — vérifier chaque statut en fonction du contexte réel.

5. Mettre à jour le Todo interne (Hermes)

Utiliser le tool todo() pour suivre l’avancement en temps réel dans la session.

Codes Statut & Couleurs

StatutCouleurEmojiSignification
Planifiée🟡 Jaune📋Identifiée, pas démarrée
En cours🔵 Bleu🔧Travail actif
Terminée🟢 VertComplétée
Abandonnée⚪ Gris🗑️Annulée ou remplacée

Pitfalls

  1. Ne pas ajouter deux fois la même tâche — lire existing_titles avant append.
  2. Ne pas oublier les stats — toujours recalculer après ajout/suppression.
  3. Code couleur post-ajout — l’append seul ne colore pas. Faire batchUpdate après.
  4. Vikunja via curl, pas Python urllib — Vikunja derrière Cloudflare, Python SSL handshake timeoute. Toujours utiliser subprocess.run(["curl",...]) depuis Python.
  5. batchUpdate limit 100 — diviser les requêtes par batch de 100 max.
  6. Vikunja labels = objets pas entiers{"labels": [{"id": 15}]} pas [15].
  7. Vikunja PUT pas POST — création tâche via -X PUT pas -X POST.
  8. Jamais {token} ou {jwt} dans les strings Python — les write_file les interprète comme templates. Utiliser AUTH_HDR=*** Bearer %s" % tok ou concat simple.

Références

  • references/color-coding-sheet.md — API calls complètes pour batchUpdate (repeatCell, backgroundColor)
  • references/vikunja-token-format.md — Structure des tokens hashés Vikunja + limitations API
  • Voir skill google-workspace pour l’API Google Sheets générique
  • Voir skill claude-code section “Usage as Fallback for Failed Hermes Tasks” pour utiliser Claude Code en fallback quand les outils Hermes échouent

Absorbed: Personal Organizer

references/personal-organizer.md — Monstre Organisateur: personal task management for users mentioning tasks, ideas, planning, overwhelm, procrastination, reminders, or daily priorities. Previously a standalone skill (personal-organizer).