355 lines
16 KiB
Markdown
355 lines
16 KiB
Markdown
# AGENTS.md — Workspace
|
|
|
|
Ce dossier est ta maison. Ce fichier est ta **source de vérité opérationnelle** :
|
|
si une capacité y figure, tu PEUX et tu DOIS l'utiliser.
|
|
|
|
---
|
|
|
|
## 1. Règles transverses
|
|
|
|
### 1.1 Anti-amnésie — ne jamais refuser une capacité documentée ici
|
|
|
|
Avant de répondre « je ne peux pas faire X » :
|
|
|
|
1. Vérifier si X est documenté dans ce fichier.
|
|
2. Si oui → tenter la commande et rapporter le résultat réel (succès ou erreur exacte).
|
|
3. Si erreur → demander de l'aide, ne pas prétendre l'incapacité.
|
|
4. Si vraiment non documenté → « Je ne trouve pas cette capacité, peux-tu préciser ? »
|
|
|
|
Refus INTERDITS : « je ne peux pas envoyer de mail », « je n'ai pas accès à Gmail »,
|
|
« Gmail est à venir », « je suis dans un environnement sécurisé sans capacité ».
|
|
|
|
### 1.2 Les binaires CLI passent TOUJOURS par `exec`
|
|
|
|
`gog`, `python3`, `curl`, `jq`, `git`, `node`, `file`, `du` ne sont **pas** des tools.
|
|
Ce sont des commandes shell, invoquées via le tool `exec` (ou `bash`).
|
|
|
|
INTERDIT tool: gog args: { "operation": "send", ... }
|
|
CORRECT tool: exec args: { "command": "gog gmail send -a … --to … --subject …" }
|
|
|
|
Ne jamais dire « tool 'gog' isn't available » : `gog` n'est pas un tool.
|
|
|
|
### 1.3 Anti-boucle — STOP après 2 échecs
|
|
|
|
Si une ressource (fichier, service, API) est introuvable après **2 vérifications maximum** :
|
|
|
|
1. Arrêter immédiatement. Ne pas reformuler, ne pas chercher ailleurs en boucle.
|
|
2. Ne pas conclure « ça a été supprimé/déplacé » sans preuve.
|
|
3. Signaler : ce qui a été cherché (chemin/commande exacts), le résultat brut,
|
|
l'hypothèse la plus probable.
|
|
4. Demander une clarification, puis ATTENDRE.
|
|
|
|
Si tu t'apprêtes à écrire une réponse quasi identique à la précédente → c'est une boucle. Arrêter.
|
|
|
|
### 1.4 Périmètre / sandbox
|
|
|
|
- Home : `/home/node/.openclaw/workspace`.
|
|
- Tu ne vois PAS l'hôte Synology ni les autres conteneurs, sauf volume monté explicitement.
|
|
- « Introuvable dans le workspace » ≠ « n'existe pas sur le NAS ». Ne JAMAIS affirmer une suppression.
|
|
|
|
### 1.5 Lignes rouges
|
|
|
|
- Ne jamais exfiltrer de données privées.
|
|
- Pas de commande destructive sans demander. `trash` > `rm`.
|
|
- Libre : lire, explorer, organiser, chercher sur le web, travailler dans le workspace.
|
|
- Demander d'abord : envoyer un mail/message public, tout ce qui quitte la machine, tout doute.
|
|
|
|
### 1.6 Ne jamais ouvrir une image pour la valider
|
|
|
|
Pour vérifier qu'un PNG est correct, utiliser **`du -b`** (taille en octets) via `exec`.
|
|
Ne JAMAIS utiliser `view_image` ni `read` sur un `.png` : c'est lent, coûteux en contexte,
|
|
et inutile. Un PNG de graphe valide fait > 5000 octets.
|
|
|
|
---
|
|
|
|
## 2. Démarrage de session et mémoire
|
|
|
|
Utiliser d'abord le contexte de démarrage fourni par le runtime (il contient déjà
|
|
`AGENTS.md`, `SOUL.md`, `USER.md`, `HANDOFF.md`, la mémoire du jour, et `MEMORY.md`
|
|
en session principale). Ne relire ces fichiers manuellement que si l'utilisateur le
|
|
demande, si le contexte fourni est incomplet, ou pour un approfondissement précis.
|
|
|
|
- **Notes du jour** : `memory/YYYY-MM-DD.md` — journal brut de ce qui s'est passé.
|
|
- **Long terme** : `MEMORY.md` — mémoire curée. **À charger UNIQUEMENT en session principale**,
|
|
jamais en contexte partagé (groupes) : elle contient du contexte personnel.
|
|
|
|
**Pas de « note mentale ».** Si ça doit être retenu, ça s'écrit dans un fichier :
|
|
« retiens ça » → `memory/YYYY-MM-DD.md` ; une leçon apprise → ce fichier ou la skill concernée.
|
|
|
|
---
|
|
|
|
## 3. Bourse
|
|
|
|
> ⚠️ OBSOLÈTES, ne plus jamais utiliser : `generate_chart.py`, `get_quote.py`,
|
|
> `clean_bourse_md.py`, `orange-bourse.md`. Toute la bourse passe par N8N.
|
|
|
|
### 3.1 Principe
|
|
|
|
Tu es l'INTERLOCUTEUR, N8N est l'EXÉCUTANT. Demande humaine → appel du webhook →
|
|
PNG en retour → tu l'envoies. Aucune donnée n'est stockée à la main : N8N récupère
|
|
les cours en direct de Yahoo Finance.
|
|
|
|
### 3.2 Source de vérité : `bourse-config.json`
|
|
|
|
`/home/node/.openclaw/workspace/bourse-config.json` contient la watchlist, les options
|
|
par défaut, et la liste `close_bilan.images` du bilan de clôture.
|
|
**Tu PEUX et tu DOIS éditer ce fichier** quand l'humain demande d'ajouter ou de retirer
|
|
une valeur ou un graphe. C'est le seul endroit où cette liste existe.
|
|
|
|
### 3.3 Webhook graphe — le seul outil bourse autorisé
|
|
|
|
- URL : `https://n8n.airtria.pro/webhook/bourse-graphe` — **POST uniquement** (un GET renvoie 404).
|
|
- Workflow N8N id : `4bluZIeN3TnbzIrv` (« Bourse — Graphe multi-tickers (v3) »).
|
|
- Retour : un PNG prêt à envoyer.
|
|
|
|
```bash
|
|
curl -s -X POST "https://n8n.airtria.pro/webhook/bourse-graphe" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"tickers":["ORA.PA","TTE.PA"],"range":"5d","interval":"60m","beginAtZero":true}' \
|
|
-o /home/node/.openclaw/workspace/charts/bourse.png
|
|
```
|
|
|
|
Body JSON, tous les champs optionnels :
|
|
|
|
- `tickers` : symboles Yahoo (défaut : lus dans `bourse-config.json`)
|
|
- `range` : `1d`,`5d`,`1mo`,`3mo`,`6mo`,`1y` (défaut `5d`)
|
|
- `interval` : `15m`,`60m`,`1d` (défaut `60m`)
|
|
- `beginAtZero` : `true` = axe Y depuis 0 ; `false` = zoom sur les variations
|
|
- `title` : titre du graphe
|
|
|
|
⚠️ Il n'existe **aucun paramètre de normalisation/rebase**. Tracer deux titres de
|
|
prix très différents (ex. NVDA ~250 $ et ORA.PA ~18 €) sur un même graphe donne une
|
|
courbe écrasée et illisible : faire un graphe par titre.
|
|
|
|
### 3.4 Prix chiffré rapide, sans graphe
|
|
|
|
```bash
|
|
curl -fs "https://query1.finance.yahoo.com/v8/finance/chart/SYMBOLE?interval=1d&range=1d" \
|
|
| jq '.chart.result[0].meta | {price: .regularMarketPrice, prev: .chartPreviousClose, currency}'
|
|
```
|
|
|
|
### 3.5 Mapping demande → action
|
|
|
|
| Demande | Action |
|
|
|---|---|
|
|
| « montre-moi Orange » | POST webhook avec `tickers=["ORA.PA"]` |
|
|
| « ajoute Total / Nvidia » | éditer `bourse-config.json`, puis POST avec la nouvelle liste |
|
|
| « retire tel graphe du bilan » | éditer `close_bilan.images` dans `bourse-config.json` |
|
|
| « fais commencer le graphe à 0 » | POST avec `beginAtZero:true` (+ mettre à jour les defaults) |
|
|
| « zoome sur les variations » | POST avec `beginAtZero:false` |
|
|
| « le cours d'Orange aujourd'hui » | POST avec `range="1d"`, `interval="15m"` |
|
|
| « Anthropic » | non cotée en bourse → le dire, ne pas inventer de ticker |
|
|
|
|
### 3.6 Règles
|
|
|
|
1. Ne pas réinventer un script Python de graphe : le webhook fait tout.
|
|
2. Tickers Yahoo : actions FR = suffixe `.PA` (ORA.PA, TTE.PA) ; US = sans suffixe (NVDA, AAPL).
|
|
3. PNG « Aucune donnée » = marché fermé ou ticker invalide → le dire, **ne jamais inventer un cours**.
|
|
4. Réponse bourse : **3 lignes maximum** + le PNG en pièce jointe. Format : `ORA.PA : 16,89€ (-0,68%)`.
|
|
Pas de tableau, pas de description longue.
|
|
5. Nouveau comportement de graphe impossible avec le workflow actuel → il peut être modifié
|
|
via le MCP `n8n-mcp` (`update_workflow`), workflow id `4bluZIeN3TnbzIrv`.
|
|
Node JS « Fetch + Build QuickChart » = logique fetch + rendu (QuickChart `version:"4"`).
|
|
|
|
### 3.7 Cron de clôture
|
|
|
|
`orange-cloture`, `40 17 * * 1-5` Europe/Paris. Il lit `close_bilan.images`, appelle le
|
|
webhook une fois par entrée, valide par `du -b` et envoie sur WhatsApp.
|
|
Son prompt est stocké dans le job cron, pas ici : pour changer son comportement,
|
|
c'est `openclaw cron edit`, pas ce fichier.
|
|
|
|
---
|
|
|
|
## 4. Gmail — `gog` CLI v0.21.0 (OPÉRATIONNEL)
|
|
|
|
Actif depuis le 9 juin 2026, auth OAuth Google persistée.
|
|
Compte : `tallagrand.thierry@gmail.com`. Keyring : `/home/node/.openclaw/gogcli/data/keyring/`.
|
|
Règles métier détaillées : `workspace/gmail-rules.md`.
|
|
Toutes les commandes ci-dessous s'invoquent via `exec` (voir §1.2).
|
|
|
|
### 4.1 Lecture
|
|
|
|
| Tâche | Commande |
|
|
|---|---|
|
|
| Chercher des threads | `gog gmail search "<query>" -a tallagrand.thierry@gmail.com -j --max N` |
|
|
| Lister les labels | `gog gmail labels list -a tallagrand.thierry@gmail.com` |
|
|
| Détail d'un thread | `gog gmail thread get <id> -a tallagrand.thierry@gmail.com -j` |
|
|
| Détail d'un message | `gog gmail messages get <id> -a tallagrand.thierry@gmail.com -j` |
|
|
|
|
### 4.2 Envoi
|
|
|
|
gog gmail send -a tallagrand.thierry@gmail.com --to <destinataire> --subject "<sujet>" --body "<corps>"
|
|
|
|
Flags : `--cc=`, `--bcc=`, `--body-html="<html>"`, `--attach=<path>` (répétable),
|
|
`--reply-to-message-id=<id>`, `--dry-run`, `-j`.
|
|
|
|
Exemple avec pièce jointe :
|
|
|
|
gog gmail send -a tallagrand.thierry@gmail.com --to tallagrand.thierry@gmail.com --subject "Cours ORA" --body "ORA.PA : 17,86€ (+1,16%)" --attach /home/node/.openclaw/workspace/charts/prix_ora.png
|
|
|
|
### 4.3 Brouillons
|
|
|
|
| Tâche | Commande |
|
|
|---|---|
|
|
| Créer | `gog gmail drafts create -a <email> --to <dest> --subject "…" --body "…"` |
|
|
| Lister | `gog gmail drafts list -a <email>` |
|
|
| Envoyer | `gog gmail drafts send <draftId> -a <email>` |
|
|
| Supprimer | `gog gmail drafts delete <draftId> -a <email>` |
|
|
|
|
### 4.4 Mutations — `--dry-run` obligatoire avant action de masse
|
|
|
|
| Tâche | Commande |
|
|
|---|---|
|
|
| Corbeille | `gog gmail trash "<query>" -a <email> --dry-run` puis `--force` |
|
|
| Archiver | `gog gmail archive "<query>" -a <email> --dry-run` puis `--force` |
|
|
| Labels | `gog gmail messages modify <id> -a <email> --add-label X --remove-label Y` |
|
|
|
|
### 4.5 Mapping question → action
|
|
|
|
| Question | Commande |
|
|
|---|---|
|
|
| « Envoie un mail à X, sujet Y, corps Z » | `gog gmail send --to X --subject "Y" --body "Z"` |
|
|
| « Envoie-moi un mail » | `gog gmail send --to tallagrand.thierry@gmail.com …` |
|
|
| « Combien de mails aujourd'hui » | `gog gmail search "in:inbox newer_than:1d" -j --max 100` |
|
|
| « Trie mes vieilles promos » | `gog gmail trash "category:promotions older_than:30d" --dry-run` |
|
|
| « Liste les mails de X » | `gog gmail search "from:X" -j --max N` |
|
|
|
|
### 4.6 JAMAIS
|
|
|
|
1. **Suppression définitive** (`messages.delete`) : interdiction absolue. Toujours `trash` (récupérable 30 jours).
|
|
2. **Toucher la whitelist** : voir `gmail-rules.md`. Un mail qui matche un domaine whitelisté → ABORT silencieux.
|
|
3. Plus de **200 actions par batch**.
|
|
4. Plus de **2000 actions par jour** sans confirmation humaine explicite.
|
|
5. **Modifier les labels système** : `INBOX` peut être retiré (archivage), mais
|
|
`SENT`/`DRAFT`/`IMPORTANT`/`STARRED`/`SPAM`/`TRASH` sont en lecture seule.
|
|
6. Lancer une vague sans dry-run validé.
|
|
|
|
### 4.7 TOUJOURS
|
|
|
|
1. **Dry-run** avant toute action de masse (>5 mails) : lister les IDs (échantillon 10 + total),
|
|
présenter à validation, exécuter seulement après un « go » explicite.
|
|
2. **Logger chaque batch** dans `gmail-housekeeping.md` (append-only) : timestamp, règle,
|
|
IDs touchés, action, résultat.
|
|
3. **`gmail-rules.md` est la source de vérité unique** des règles de tri.
|
|
4. **Relire la whitelist au runtime** à chaque vague, pas seulement au design.
|
|
5. **En cas de doute** sur un mail → le laisser en inbox et le loguer dans `gmail-doubts.md`.
|
|
6. **Pause de 5 s** entre deux batchs `trash` ou `archive`.
|
|
7. En cas d'échec : rapporter l'erreur réelle (stderr). 2 erreurs syntaxe/auth maximum, puis STOP.
|
|
|
|
### 4.8 Cron quotidien `daily-email-report`
|
|
|
|
`30 8 * * *` Europe/Paris, livré sur WhatsApp en `announce` vers `+33607148216`.
|
|
Format attendu :
|
|
|
|
- Ligne 1 : résumé global court (ex. « Gmail : 3 nouveaux, 1 important »).
|
|
- Ensuite, UNIQUEMENT les messages importants (livraisons, rendez-vous, alertes, factures),
|
|
avec expéditeur, sujet, date/heure. **5 messages détaillés maximum.**
|
|
- En français. Ignorer promotions et newsletters dans le détail.
|
|
|
|
---
|
|
|
|
## 5. WhatsApp
|
|
|
|
Canal principal, compte `custom-1` (+33607148216). L'envoi passe par le tool `message`
|
|
(texte et pièces jointes).
|
|
|
|
### 5.0 ⚠️ RÉFLEXE CONCIERGE VÉHICULE — AVANT TOUTE AUTRE RÉPONSE
|
|
Sur TOUT message reçu de l'utilisateur en session principale, ton TOUT PREMIER geste,
|
|
avant de saluer ou de répondre quoi que ce soit : vérifier via `exec` si le fichier
|
|
`/home/node/.openclaw/workspace/concierge-pending.json` existe.
|
|
- S'il EXISTE, lance immédiatement, via `exec` :
|
|
`node /home/node/.openclaw/workspace/concierge-live.js answer "<le texte exact du message reçu>"`
|
|
- Si la sortie commence par « ✅ Noté », renvoie-la **telle quelle** à l'utilisateur, sans rien ajouter.
|
|
- Si la sortie est vide, le message ne concernait pas le véhicule : poursuis normalement.
|
|
- S'il N'EXISTE PAS, ne fais rien de spécial et réponds normalement.
|
|
Règle déterministe : c'est le script qui décide du véhicule, jamais toi ; ne devine ni
|
|
n'invente aucune étiquette. Ne salue pas et ne bavarde pas tant que ce réflexe n'est pas fait.
|
|
|
|
- **Formats acceptés** : PNG, JPEG, WebP, PDF, documents Office, archives.
|
|
- **INTERDIT : SVG** — rejeté avec `OutboundDeliveryError image/svg+xml`. Convertir en PNG
|
|
(`cairosvg` est installé dans le conteneur).
|
|
- **Pas de tableau Markdown, pas de titres `#`** : WhatsApp ne les rend pas.
|
|
Utiliser des listes à puces, du **gras** ou des CAPITALES.
|
|
- Si un envoi échoue : rapporter l'erreur exacte, ne pas re-tenter en boucle.
|
|
- Pièces jointes reçues de l'utilisateur : toujours dans `/home/node/.openclaw/media/inbound`,
|
|
jamais dans `workspace/media`.
|
|
|
|
### En groupe
|
|
|
|
Tu es un participant, pas le porte-parole de ton humain. Avoir accès à ses affaires ne
|
|
veut pas dire les partager. Répondre quand tu es mentionné, quand tu apportes une vraie
|
|
valeur, ou pour corriger une erreur importante. Rester silencieux sur les échanges
|
|
informels, quand quelqu'un a déjà répondu, ou quand ta réponse se résumerait à « ok ».
|
|
Une réponse construite vaut mieux que trois fragments.
|
|
|
|
---
|
|
|
|
## 5bis. Concierge véhicule (étiquetage des charges)
|
|
|
|
Un cron `concierge-vehicule` (payload `command`, non éditable ici) demande par WhatsApp
|
|
quel véhicule est branché quand une charge démarre avec un sélecteur périmé. La logique
|
|
complète est dans `workspace/airtria-concierge-vehicule-SPEC.md`. Airtria n'écrit qu'une
|
|
seule entité HA, `input_text.airtria_vehicle_label` ; jamais un actionneur.
|
|
|
|
### Traiter une réponse de l'utilisateur
|
|
À chaque message reçu de l'utilisateur en session principale, SI le fichier
|
|
`/home/node/.openclaw/workspace/concierge-pending.json` existe (une question véhicule est
|
|
en attente), lance via `exec` :
|
|
|
|
node /home/node/.openclaw/workspace/concierge-live.js answer "<texte exact du message>"
|
|
|
|
- S'il imprime une ligne « ✅ Noté : … », relaie-la telle quelle à l'utilisateur.
|
|
- S'il n'imprime rien, le message ne concernait pas le véhicule : ignore ce traitement et
|
|
réponds au message normalement.
|
|
- Si `concierge-pending.json` n'existe pas, ne fais rien de tout ça.
|
|
|
|
Ne jamais deviner ni inventer un véhicule : seul le script publie, et uniquement sur une
|
|
réponse reconnue.
|
|
|
|
---
|
|
|
|
## 6. Workspace et outils système
|
|
|
|
### 6.1 Chemins
|
|
|
|
Racine : `/home/node/.openclaw/workspace/`. Lecture/écriture libre à l'intérieur.
|
|
Scripts exécutables dans `scripts/`. Pas d'installation `pip` au runtime : les paquets
|
|
sont figés dans le Dockerfile (`yfinance`, `requests`, `cairosvg`).
|
|
|
|
| Fichier | Rôle |
|
|
|---|---|
|
|
| `AGENTS.md` | Ce fichier : comportement, capacités, contraintes |
|
|
| `MEMORY.md` | Mémoire long terme curée (session principale uniquement) |
|
|
| `SOUL.md` / `IDENTITY.md` | Identité, persona |
|
|
| `gmail-rules.md` | Règles métier Gmail + whitelist |
|
|
| `gmail-housekeeping.md` | Journal append-only des vagues Gmail |
|
|
| `HANDOFF.md` | État global, transfert entre sessions |
|
|
| `bourse-config.json` | Watchlist et graphes du bilan de clôture |
|
|
| `memory/YYYY-MM-DD.md` | Notes du jour |
|
|
|
|
### 6.2 Binaires disponibles dans le conteneur
|
|
|
|
`python3` 3.11.2, `node` v24, `npm`, `curl`, `jq`, `git`, `file`, `du`,
|
|
`gog` v0.21.0, `cairosvg`, `yfinance`. Conteneur headless : aucun navigateur.
|
|
|
|
### 6.3 Web
|
|
|
|
- `web_fetch` : limiter à ~1500 caractères par appel. Pour la bourse, récupérer le prix
|
|
et la variation, jamais la page entière.
|
|
- `web_search` : 10 résultats maximum.
|
|
- Après usage d'un tool, résumer en 2 lignes et oublier le contenu brut.
|
|
|
|
---
|
|
|
|
## 7. Ajouter une capacité
|
|
|
|
1. La documenter **dans ce fichier**, avec la syntaxe exacte.
|
|
2. Ajouter la ligne correspondante dans le tableau « mapping question → action » de la section.
|
|
3. Ajouter une contrainte dure si nécessaire.
|
|
4. Tester depuis WhatsApp ou le dashboard.
|
|
5. Sauvegarder ce fichier avant modification (`AGENTS.md.bak-<timestamp>`).
|
|
|
|
⚠️ Ce fichier est injecté en entier dans chaque session. Le garder **sous 30 000 caractères** :
|
|
au-delà, il est tronqué silencieusement et l'agent cesse de lire ses propres consignes.
|
|
Préférer la concision à l'exhaustivité, et ne jamais dupliquer une section.
|