Discussion

Compétence d'explication de planification Cron

De Wikiprompt, l’encyclopédie libre de prompts

Fatih Kadir Akın

8 oct. 2026

Compétence d'explication de planification Cron Une compétence IA complète qui explique, valide et écrit des plannings cron. Comprend un script Python, des références de syntaxe, des guides sur les pièges courants, des modèles de révision et des exemples travaillés.

Contenu du PromptEnregistrer

🌐
--- name: cron-schedule-explainer description: Explique, valide et écrit des plannings cron - traduit une expression cron en anglais simple, liste les prochaines heures d'exécution et signale les pièges tels que la règle jour-du-mois OU jour-de-la-semaine, les dates qui n'arrivent jamais, les trous liés à l'heure d'été, la confusion de fuseau horaire, et les tâches qui se chevauchent ou sont trop fréquentes. À utiliser lorsqu'un utilisateur colle une ligne crontab, un CronJob Kubernetes, un planning GitHub Actions, ou demande "quand cela s'exécutera-t-il ?" ou "écris un cron pour chaque deuxième mardi". --- # Explicateur de Planning Cron Vous rendez les tâches planifiées prévisibles. Pour chaque planning, vous donnez une signification en anglais simple, les prochaines heures d'exécution concrètes et les risques qui surprendraient quelqu'un à 2 heures du matin. ## Fichiers dans cette compétence - `scripts/cron_explain.py` - analyseur, explicateur, calculateur de prochaine exécution et vérificateur de pièges (bibliothèque standard Python 3 uniquement) - `references/cron-syntax.md` - plages de champs, caractères spéciaux, macros et différences de plateforme - `references/scheduling-pitfalls.md` - erreurs courantes et comment les éviter - `templates/schedule-review.md` - format de revue - `examples/example-backup-review.md` - une revue travaillée de trois lignes crontab ## Flux de travail ### 1. Identifier la plateforme Le cron standard à 5 champs (Vixie cron, cronie, Kubernetes CronJob, GitHub Actions) est la valeur par défaut. Demandez ou vérifiez si l'utilisateur veut dire Quartz (6 ou 7 champs avec secondes et `?`), AWS EventBridge (6 champs avec année), ou les timers systemd ; voir `references/cron-syntax.md`. Notez le fuseau horaire : GitHub Actions utilise toujours UTC ; Kubernetes utilise le fuseau horaire du contrôleur sauf si `timeZone` est défini. ### 2. Exécuter le vérificateur ```bash python3 scripts/cron_explain.py "30 2 * * 1-5" python3 scripts/cron_explain.py "0 9 1 * MON" --count 8 --from "2026-10-08 10:00" python3 scripts/cron_explain.py --file crontab.txt ``` Il imprime une explication en anglais simple, les N prochaines heures d'exécution (heure locale naïve du serveur) et des avertissements. Le code de sortie est 1 lorsqu'une expression est invalide ou ne s'exécute jamais. Si vous ne pouvez pas exécuter le script, appliquez les mêmes règles manuellement et dites-le. ### 3. Expliquer Pour chaque planning, donnez : 1. Une phrase de signification en anglais simple. 2. Les 3 à 5 prochaines exécutions avec le fuseau horaire indiqué. 3. Les avertissements du script et de `references/scheduling-pitfalls.md` qui s'appliquent (chevauchement avec des tâches longues, heure d'été, UTC versus local, exécutions manquées pendant que la machine est éteinte). ### 4. Écrire ou corriger des plannings Lorsque l'utilisateur décrit un planning en mots, écrivez l'expression, puis passez-la au vérificateur pour confirmer que les prochaines exécutions correspondent à leur intention. Pour les choses que cron ne peut pas exprimer directement (chaque deuxième mardi, le dernier jour ouvrable du mois), donnez une expression cron plus une garde dans la commande, par exemple `[ "$(date +\%d)" -le 07 ] && run-job`, et expliquez pourquoi. ### 5. Rapporter Utilisez `templates/schedule-review.md`, comme dans `examples/example-backup-review.md`. ## Règles - Indiquez toujours le fuseau horaire que vous supposez. - Rappelez que `%` doit être échappé comme `\%` dans les champs de commande crontab. - Ne modifiez jamais une crontab en direct pour l'utilisateur ; montrez la ligne à ajouter et l'étape `crontab -e`. - Recommandez un verrou (par exemple `flock -n /tmp/job.lock cmd`) chaque fois qu'une tâche pourrait s'exécuter plus longtemps que son intervalle. FILE:references/cron-syntax.md # Référence de Syntaxe Cron (standard 5 champs) ``` +------------- minute (0-59) | +----------- heure (0-23) | | +--------- jour du mois (1-31) | | | +------- mois (1-12 ou JAN-DEC) | | | | +----- jour de la semaine (0-7 ou SUN-SAT ; 0 et 7 sont tous deux dimanche) | | | | | * * * * * commande ``` ## Caractères spéciaux | Symbole | Signification | Exemple | |---|---|---| | `*` | chaque valeur | `* * * * *` chaque minute | | `,` | liste | `0 8,12,18 * * *` à 08:00, 12:00, 18:00 | | `-` | plage | `0 9 * * 1-5` 09:00 du lundi au vendredi | | `/` | pas | `*/15 * * * *` toutes les 15 minutes ; `10-50/20` = 10, 30, 50 | Les noms sont insensibles à la casse. Les plages de noms (`MON-FRI`) fonctionnent dans la plupart des implémentations, les listes de noms fonctionnent partout. ## Macros | Macro | Équivalent | |---|---| | `@yearly` / `@annually` | `0 0 1 1 *` | | `@monthly` | `0 0 1 * *` | | `@weekly` | `0 0 * * 0` | | `@daily` / `@midnight` | `0 0 * * *` | | `@hourly` | `0 * * * *` | | `@reboot` | une fois au démarrage (pas basé sur le temps) | ## La règle du jour Si le jour du mois et le jour de la semaine sont tous deux restreints (ni l'un ni l'autre n'est `*`), la tâche s'exécute lorsque L'UN OU L'AUTRE correspond. `0 9 1 * MON` s'exécute le 1er de chaque mois ET chaque lundi. ## Différences de plateforme | Plateforme | Champs | Fuseau horaire | Notes | |---|---|---|---| | Cron Linux (cronie, Vixie) | 5 | heure locale système | `CRON_TZ=` supporté par cronie | | Kubernetes CronJob | 5 | fuseau horaire du contrôleur, ou `spec.timeZone` | utilisez `concurrencyPolicy: Forbid` pour empêcher les chevauchements | | `schedule` GitHub Actions | 5 | toujours UTC | les exécutions peuvent être retardées sous charge ; intervalle minimum 5 minutes | | Quartz (Java) | 6-7 (secondes en premier, année optionnelle) | configurable | `?` pour "aucune valeur spécifique", `L`, `W`, `#` supportés | | AWS EventBridge | 6 (avec année) | UTC sauf si un fuseau horaire de planificateur est défini | soit jour-du-mois soit jour-de-la-semaine doit être `?` | Le script de cette compétence supporte le standard à 5 champs plus les macros ci-dessus (sauf `@reboot`, qu'il signale comme non basé sur le temps). FILE:references/scheduling-pitfalls.md # Pièges de Planification ## 1. Jour du mois OU jour de la semaine `0 0 13 * 5` n'est PAS "vendredi 13". Il s'exécute chaque 13 et chaque vendredi. Utilisez `0 0 13 * *` plus une garde : `[ "$(date +\%u)" = 5 ] && cmd`. ## 2. Dates qui n'arrivent jamais ou rarement - `0 0 30 2 *` ne s'exécute jamais (février n'a pas de 30). - `0 0 31 * *` s'exécute seulement dans 7 mois de l'année. - `0 0 29 2 *` s'exécute seulement les années bissextiles. Pour "dernier jour du mois", utilisez `0 0 28-31 * *` avec une garde : `[ "$(date -d tomorrow +\%d)" = 01 ] && cmd`. ## 3. Heure d'été Dans les fuseaux horaires locaux avec heure d'été, les heures entre environ 01:00 et 03:00 peuvent être sautées (avance au printemps) ou s'exécuter deux fois (recul en automne), selon l'implémentation de cron. Planifiez les tâches critiques en dehors de cette fenêtre, ou exécutez cron en UTC. ## 4. UTC versus heure locale GitHub Actions et de nombreux planificateurs cloud utilisent UTC. "Chaque jour à 09:00" pour une équipe à Istanbul (UTC+3) est `0 6 * * *` en UTC. Écrivez toujours le fuseau horaire à côté de l'expression dans les documents et les commentaires de code. ## 5. Exécutions trop fréquentes ou chevauchantes - `* * * * *` s'exécute 1440 fois par jour. Assurez-vous que c'est intentionnel. - Un champ minute de `*` avec une heure fixe (`* 3 * * *`) s'exécute 60 fois entre 03:00 et 03:59 ; généralement `0 3 * * *` était voulu. - Si une tâche peut prendre plus longtemps que son intervalle, utilisez un verrou (`flock -n`) ou `concurrencyPolicy: Forbid`. ## 6. Les valeurs de pas ne s'enroulent pas uniformément `*/7` dans le champ minute s'exécute à 0, 7, ..., 56, puis à nouveau à 0 (un écart de 4 minutes). `*/25` s'exécute à 0, 25, 50. Les pas redémarrent chaque heure, jour ou mois. ## 7. Effet de troupeau De nombreuses équipes choisissent `0 0 * * *` ou `0 * * * *`. Déplacez les tâches vers une minute impaire (par exemple `17 2 * * *`) pour éviter les pics de charge sur les systèmes partagés et les API limitées en débit. ## 8. Environnement et sortie Cron s'exécute avec un PATH minimal et sans shell de connexion. Utilisez des chemins absolus, définissez les variables nécessaires dans la crontab et redirigez la sortie (`>> /var/log/job.log 2>&1`) pour que les échecs soient visibles. Échappez `%` comme `\%`. ## 9. Exécutions manquées Le cron simple ne rattrape pas les exécutions manquées pendant que la machine est éteinte. Utilisez anacron, les timers systemd avec `Persistent=true`, ou `startingDeadlineSeconds` de Kubernetes lorsqu'une exécution manquée compte. FILE:templates/schedule-review.md # Revue de Planning : {{system_or_repo}} **Plateforme :** {{cron Linux | CronJob Kubernetes | GitHub Actions | autre}} **Fuseau horaire supposé :** {{time_zone}} **Revu le :** {{date}} ## Résumé {{Une ou deux phrases : les plannings font-ils ce que l'équipe attend, et que faut-il changer.}} ## Plannings ### {{n}}. `{{expression}}` - {{nom de la tâche}} - **Signification :** {{explication en anglais simple}} - **Prochaines exécutions :** {{exécution 1}}, {{exécution 2}}, {{exécution 3}} - **Verdict :** {{OK | CORRIGER | CLARIFIER}} - **Avertissements :** - {{avertissement}} - **Ligne suggérée :** ``` {{ligne crontab corrigée}} ``` ## Questions - {{question pour l'équipe}} FILE:examples/example-backup-review.md # Revue de Planning : crontab du serveur ops **Plateforme :** cron Linux (cronie) **Fuseau horaire supposé :** Europe/Berlin (heure locale du serveur, a l'heure d'été) **Revu le :** 2026-10-08 ## Résumé Deux des trois lignes ne font pas ce que disent les commentaires. La sauvegarde s'exécute dans la fenêtre de l'heure d'été, et le rapport "vendredi 13" s'exécute en réalité chaque vendredi et chaque 13. ## Plannings ### 1. `30 2 * * *` - sauvegarde de base de données nocturne - **Signification :** À 02:30 chaque jour. - **Prochaines exécutions :** 2026-10-09 02:30, 2026-10-10 02:30, 2026-10-11 02:30 - **Verdict :** CORRIGER - **Avertissements :** - 02:30 est dans la fenêtre de changement d'heure d'été ; la nuit de l'avance au printemps, elle peut être sautée et en automne, elle peut s'exécuter deux fois. - La sauvegarde peut prendre plus d'une heure en fin de mois ; pas de verrou. - **Ligne suggérée :** ``` 17 4 * * * flock -n /tmp/db-backup.lock /opt/scripts/db-backup.sh >> /var/log/db-backup.log 2>&1 ``` ### 2. `0 9 13 * FRI` - rapport amusant "vendredi 13" - **Signification :** À 09:00 le jour 13 du mois OU chaque vendredi (règle du jour de cron). - **Prochaines exécutions :** 2026-10-09 09:00 (ven), 2026-10-13 09:00 (mar, le 13), 2026-10-16 09:00 (ven) - **Verdict :** CORRIGER - **Avertissements :** - Les deux champs de jour sont restreints, donc cron utilise OU, pas ET. - **Ligne suggérée :** ``` 0 9 13 * * [ "$(date +\%u)" = 5 ] && /opt/scripts/fun-report.sh ``` ### 3. `*/20 8-18 * * 1-5` - synchroniser les tickets du service d'assistance - **Signification :** Toutes les 20 minutes (à :00, :20, :40) de 08:00 à 18:59, du lundi au vendredi. - **Prochaines exécutions :** 2026-10-08 10:20, 2026-10-08 10:40, 2026-10-08 11:00 - **Verdict :** CLARIFIER - **Avertissements :** - La dernière exécution du jour est 18:40, pas 18:00. Utilisez `8-17` plus un `0 18 * * 1-5` séparé si la synchronisation doit s'arrêter à 18:00. ## Questions - Le serveur devrait-il exécuter cron en UTC pour éviter complètement les problèmes d'heure d'été ? FILE:scripts/cron_explain.py #!/usr/bin/env python3 """Explique, valide et prévisualise les expressions cron standard à 5 champs (bibliothèque standard uniquement). Utilisation : python3 cron_explain.py "EXPR" [--count N] [--from "YYYY-MM-DD HH:MM"] python3 cron_explain.py --file crontab.txt [--count N] [--from ...] Pour chaque expression : une explication en anglais simple, les N prochaines heures d'exécution (heure locale naïve du serveur, et avertissements de pièges. En mode --file, les lignes crontab sont lues ; les commentaires, lignes vides et lignes VAR=valeur sont sautés et les cinq premiers champs (ou une macro @ en tête) sont pris comme planning. Code de sortie : 0 = tout valide, 1 = une expression est invalide ou ne s'exécute jamais, 2 = utilisation. """ import argparse import calendar import datetime as dt import sys MONTHS = {m.lower(): i for i, m in enumerate(calendar.month_abbr) if m} DAYS = {"sun": 0, "mon": 1, "tue": 2, "wed": 3, "thu": 4, "fri": 5, "sat": 6} MACROS = { "@yearly": "0 0 1 1 *", "@annually": "0 0 1 1 *", "@monthly": "0 0 1 * *", "@weekly": "0 0 * * 0", "@daily": "0 0 * * *", "@midnight": "0 0 * * *", "@hourly": "0 * * * *", } FIELDS = [("minute", 0, 59, {}), ("heure", 0, 23, {}), ("jour du mois", 1, 31, {}), ("mois", 1, 12, MONTHS), ("jour de la semaine", 0, 7, DAYS)] DAY_NAMES = ["Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"] def compress(values, fmt=str): """[1,2,3,5] -> '1-3, 5' en utilisant fmt pour chaque nombre.""" vals, out, i = sorted(values), [], 0 while i < len(vals): j = i while j + 1 < len(vals) and vals[j + 1] == vals[j] + 1: j += 1 out.append(fmt(vals[i]) if j - i < 2 else f"{fmt(vals[i])}-{fmt(vals[j])}") if 0 < j - i < 2: out.append(fmt(vals[j])) i = j + 1 return ", ".join(out) class CronError(ValueError): pass def _num(token, lo, hi, names, field): t = token.lower() if t in names: return names[t] if not t.isdigit(): raise CronError(f"{field} : '{token}' n'est pas un nombre ou un nom connu") v = int(t) if not lo <= v <= hi: raise CronError(f"{field} : {v} est en dehors de {lo}-{hi}") return v def parse_field(text, lo, hi, names, field): values = set() for part in text.split(","): if not part: raise CronError(f"{field} : élément de liste vide dans '{text}'") step = 1 if "/" in part: part, step_s = part.split("/", 1) if not step_s.isdigit() or int(step_s) == 0: raise CronError(f"{field} : mauvais pas '/{step_s}'") step = int(step_s) if part == "*": start, end = lo, hi elif "-" in part: a, b = part.split("-", 1) start, end = _num(a, lo, hi, names, field), _num(b, lo, hi, names, field) if start > end: raise CronError(f"{field} : plage {a}-{b} inversée") else: start = _num(part, lo, hi, names, field) end = hi if step > 1 else start values.update(range(start, end + 1, step)) return values def parse(expr): expr = expr.strip() if expr.lower() == "@reboot": raise CronError("@reboot s'exécute une fois au démarrage et n'est pas basé sur le temps") expr = MACROS.get(expr.lower(), expr) parts = expr.split() if len(parts) != 5: hint = " (6-7 champs ressemblent à Quartz ou EventBridge ; voir references/cron-syntax.md)" if len(parts) in (6, 7) else "" raise CronError(f"5 champs attendus, {len(parts)} obtenus{hint}") for p in parts: bare = p.lower() for n in list(MONTHS) + list(DAYS): bare = bare.replace(n, "") if any(c in bare for c in "?lw#"): raise CronError(f"'{p}' : '?', 'L', 'W' et '#' sont des extensions Quartz, pas du cron standard") sets = [parse_field(p, lo, hi, names, name) for p, (name, lo, hi, names) in zip(parts, FIELDS)] if 7 in sets[4]: sets[4].discard(7) sets[4].add(0) return parts, sets def describe_set(values, lo, hi, field, raw): vals = sorted(values) if raw == "*": return None if field == "jour de la semaine": names = [DAY_NAMES[v] for v in vals] if vals == [1, 2, 3, 4, 5]: return "du lundi au vendredi" if vals == [0, 6]: return "le week-end" return ", ".join(names) if field == "mois": return ", ".join(calendar.month_name[v] for v in vals) return compress(vals) def explain(parts, sets): minute, hour, dom, month, dow = sets rm, rh, rdom, rmon, rdow = parts if rm == "*" and rh == "*": time_txt = "chaque minute" elif rm.startswith("*/") and rh == "*": time_txt = f"toutes les {rm[2:]} minutes" elif rm.startswith("*/"): time_txt = (f"toutes les {rm[2:]} minutes (à la minute " + ", ".join(str(m) for m in sorted(minute)) + ") pendant la/les heure(s) " + compress(hour, lambda h: f"{h:02d}")) elif rh == "*": time_txt = "à la minute " + ", ".join(str(m) for m in sorted(minute)) + " de chaque heure" elif rm == "*": time_txt = "chaque minute pendant la/les heure(s) " + compress(hour, lambda h: f"{h:02d}") elif len(minute) * len(hour) <= 6: time_txt = "à " + ", ".join(f"{h:02d}:{m:02d}" for h in sorted(hour) for m in sorted(minute)) else: time_txt = ("à la/aux minute(s) " + ", ".join(str(m) for m in sorted(minute)) + " après la/les heure(s) " + compress(hour, lambda h: f"{h:02d}")) day_txt = [] d_dom = describe_set(dom, 1, 31, "jour du mois", rdom) d_dow = describe_set(dow, 0, 6, "jour de la semaine", rdow) if d_dom and d_dow: day_txt.append(f"le(s) jour(s) {d_dom} du mois OU le {d_dow}") elif d_dom: day_txt.append(f"le(s) jour(s) {d_dom} du mois") elif d_dow: day_txt.append(d_dow if d_dow.startswith("le ") else f"le {d_dow}") else: day_txt.append("chaque jour") d_mon = describe_set(month, 1, 12, "mois", rmon) if d_mon: day_txt.append(f"en {d_mon}") text = f"{time_txt}, {' '.join(day_txt)}" return text[0].upper() + text[1:] + "." def day_matches(d, parts, sets): _, _, dom, month, dow = sets if d.month not in month: return False cron_dow = (d.weekday() + 1) % 7 dom_r, dow_r = parts[2] != "*", parts[4] != "*" if dom_r and dow_r: return d.day in dom or cron_dow in dow if dom_r: return d.day in dom if dow_r: return cron_dow in dow return True def next_runs(parts, sets, start, count, max_days=366 * 8): minute, hour = sorted(sets[0]), sorted(sets[1]) runs = [] day = start.date() for _ in range(max_days): if day_matches(day, parts, sets): for h in hour: for m in minute: t = dt.datetime(day.year, day.month, day.day, h, m) if t > start: runs.append(t) if len(runs) >= count: return runs day += dt.timedelta(days=1) return runs def warnings(parts, sets, runs): minute, hour, dom, month, dow = sets out = [] if parts[2] != "*" and parts[4] != "*": out.append("Le jour du mois ET le jour de la semaine sont tous deux définis : cron s'exécute lorsque L'UN OU L'AUTRE correspond (OU, pas ET).") if parts[2] != "*" and parts[4] == "*": max_days = {m: (29 if m == 2 else calendar.monthrange(2026, m)[1]) for m in month} if not any(d <= max_days[m] for m in month for d in dom): out.append("Ne s'exécute jamais : le(s) jour(s) du mois choisi(s) n'existent pas dans le(s) mois choisi(s).") elif any(d > 28 for d in dom): out.append("Certains jours choisis (29-31) n'existent pas chaque mois, donc certains mois sont sautés.") if parts[0] == "*" and parts[1] != "*": out.append("La minute est '*' : s'exécute chaque minute de la/des heure(s) choisie(s) ; vouliez-vous dire minute 0 ?") runs_per_day = len(minute) * len(hour) if runs_per_day >= 288: out.append(f"S'exécute {runs_per_day} fois par jour ; assurez-vous que c'est intentionnel et ajoutez un verrou contre le chevauchement.") if any(1 <= h <= 2 for h in hour) and parts[1] != "*": out.append("S'exécute entre 01:00 et 02:59 : dans les fuseaux horaires locaux avec heure d'été, cela peut être sauté ou s'exécuter deux fois.") for i, raw in ((0, parts[0]), (1, parts[1])): if "/" in raw: step = int(raw.split("/")[1]) span = 60 if i == 0 else 24 if span % step: out.append(f"Le pas /{step} ne divise pas {span} : l'écart est inégal là où {'l'heure' if i == 0 else 'le jour'} s'enroule.") if parts[0] == "0" and parts[1] in ("*", "0"): out.append("La minute 0 en haut de l'heure est un créneau populaire ; envisagez une minute impaire pour éviter les pics de charge.") return out def check(expr, start, count): print(f"Expression : {expr}") try: parts, sets = parse(expr) except CronError as e: print(f" INVALIDE : {e}\n") return False print(f" Signification : {explain(parts, sets)}") runs = next_runs(parts, sets, start, count) ok = True if runs: print(f" Prochaine(s) {len(runs)} exécution(s) après {start:%Y-%m-%d %H:%M} (heure locale du serveur :") for r in runs: print(f" {r:%Y-%m-%d %H:%M} {r:%a}") else: print(" Prochaines exécutions : aucune trouvée dans les 8 prochaines années") ok = False for w in warnings(parts, sets, runs): print(f" AVERTISSEMENT : {w}") print() return ok def crontab_schedules(path): with open(path, encoding="utf-8") as f: for line in f: s = line.strip() if not s or s.startswith("#"): continue first = s.split()[0] if "=" in first and not first.startswith("@"): continue yield first if first.startswith("@") else " ".join(s.split()[:5]) def main(argv=None): ap = argparse.ArgumentParser(description="Explique et valide les expressions cron.") ap.add_argument("expr", nargs="?", help='expression cron entre guillemets, ex. "*/15 9-17 * * 1-5"') ap.add_argument("--file", help="lit les plannings depuis un fichier crontab") ap.add_argument("--count", type=int, default=5, help="nombre de prochaines exécutions à afficher (défaut 5)") ap.add_argument("--from", dest="start", help='heure de début "YYYY-MM-DD HH:MM" (défaut : maintenant)') a = ap.parse_args(argv) if bool(a.expr) == bool(a.file): ap.print_usage(sys.stderr) print("erreur : donnez exactement un EXPR ou --file", file=sys.stderr) return 2 try: start = dt.datetime.strptime(a.start, "%Y-%m-%d %H:%M") if a.start else dt.datetime.now().replace(second=0, microsecond=0) except ValueError: print("erreur : --from doit ressembler à 2026-10-08 10:00", file=sys.stderr) return 2 exprs = list(crontab_schedules(a.file)) if a.file else [a.expr] results = [check(e, start, max(1, a.count)) for e in exprs] print(f"{sum(results)} sur {len(results)} planning(s) valide(s) et exécutable(s).") return 0 if all(results) else 1 if __name__ == "__main__": sys.exit(main())

Connectez-vous pour voir le prompt complet

Continuer avec:

En vous connectant, vous acceptez nos Conditions et Confidentialité

Utilisation

Ce prompt est conçu pour être utilisé avec productivity. Copiez le contenu ci-dessus et collez-le dans votre outil d’IA préféré.

Pour de meilleurs résultats, personnalisez les espaces réservés (indiqués par des crochets ou des majuscules) selon vos besoins.

Références

Catégories :productivity| prompts.chat| cron| scheduling

Discussion