Comparaison des données par outil
Objectif : Comparer les données disponibles dans les JSON/transcripts de chaque outil supporté par ai-footprint.
Mise à jour : Ce document est mis à jour à chaque nouvel outil ajouté.
Légende
| Symbole | Signification |
|---|---|
| ✅ | Disponible dans cet outil |
| ❌ | Non disponible |
| ⚠️ | Partiellement disponible (structure différente) |
Tableau comparatif
| Champ | Claude Code (JSONL) | Opencode (JSON) | Pi (JSONL) | Usage dans ai-footprint |
|---|---|---|---|---|
| Identifiants | ||||
sessionId |
✅ | ✅ session_id |
✅ header type:"session", id |
Clé de jointure avec sessions table |
uuid / id |
✅ msg_id |
✅ message.id |
✅ message.id (entrée type:"message") |
Clé unique par message |
| Modèle | ||||
model (string) |
✅ "claude-opus-4-8" |
⚠️ {providerID, modelID} |
✅ message.model |
Normalisé en provider + model dans InferenceEvent |
provider |
❌ (déduit de model) |
✅ model.providerID |
✅ message.provider |
Permet le lookup EcoLogits |
| Tokens | ||||
input_tokens |
✅ | ✅ tokens.input |
✅ message.usage.input |
Calcul d'impact |
output_tokens |
✅ | ✅ tokens.output |
✅ message.usage.output |
Calcul d'impact |
cache_creation_input_tokens |
✅ | ⚠️ tokens.cache.write |
✅ message.usage.cacheWrite |
Calcul d'impact (cache) |
cache_read_input_tokens |
✅ | ⚠️ tokens.cache.read |
✅ message.usage.cacheRead |
Calcul d'impact (cache) |
reasoning_tokens |
❌ | ✅ tokens.reasoning |
❌ | À valider avec EcoLogits |
| Temps | ||||
timestamp (ISO 8601) |
✅ | ⚠️ Unix timestamp ms | ✅ ISO 8601 natif | Converti en ISO 8601 UTC |
active_seconds (delta) |
✅ Calculé | ✅ time.completed - time.created |
✅ Calculé (delta entre timestamps successifs) | Mesure du temps actif |
| Coût | ||||
cost (USD) |
❌ (non lu par le collecteur) | ✅ cost (BD + exports) |
⚠️ message.usage.cost.total (présent mais non stocké) |
Non stocké — pas de champ cost dans InferenceEvent |
latency (ms) |
❌ (non lu par le collecteur) | ❌ | ❌ | Non exploité actuellement |
| Métadonnées session | ||||
title |
❌ | ✅ session.title |
❌ | Non stocké (note : à risquer) |
directory |
✅ cwd |
✅ session.directory |
✅ session.cwd |
Utilisé pour project (basename) |
slug |
❌ | ✅ session.slug |
❌ | Non stocké (note : à risquer) |
path |
❌ | ✅ session.path |
❌ | Non stocké (note : à risquer) |
| Statut | ||||
role (user/assistant) |
✅ | ✅ | ✅ message.role |
Filtrage (seuls les assistant comptent) |
error |
❌ | ✅ error.name, error.data |
❌ | Non stocké — pas de champ error dans InferenceEvent |
archived |
❌ | ✅ time_archived |
❌ | Non exploité actuellement |
| Collecte | ||||
| Format de stockage | JSONL (ligne par ligne) | SQLite (BDD locale) | JSONL (ligne par ligne) | Collecteurs spécifiques par outil |
| Déclencheur | hooks.Stop (fin de session) |
session.idle (plugin) |
session_shutdown (extension) |
Installation automatique |
| Backfilling | Lecture directe JSONL | Lecture directe SQLite | Lecture directe JSONL | Scripts de backfilling spécifiques |
Détails par outil
Claude Code
Sources disponibles :
- Transcripts de session :
~/.claude/projects/**/*.jsonl— seule source effectivement lue parClaudeCodeCollector(glob + parsing de tous les**/*.jsonl).
Structure d'un event (transcript) :
{
"type": "assistant",
"message": {
"model": "claude-opus-4-8",
"usage": {
"input_tokens": 8427,
"output_tokens": 287,
"cache_creation_input_tokens": 7052,
"cache_read_input_tokens": 8020
}
},
"sessionId": "sess-A",
"uuid": "u1",
"cwd": "/Users/me/DEV/projA",
"timestamp": "2026-06-27T10:08:45.619Z"
}
Collecteur : ClaudeCodeCollector (lecture directe JSONL)
Opencode
Sources disponibles :
- BDD locale :
~/.local/share/opencode/opencode.db(SQLite) - Exports plugin :
~/.ai-footprint/crush-exports/<sessionId>.json - SDK SSE :
event.subscribe()(temps réel)
Structure d'une session (table session) :
{
"id": "ses_120fa4dc7ffeSg6YofUeAPBX1P",
"title": "New session - 2026-06-19T08:35:53.016Z",
"directory": "/Users/renaudheluin/.agents",
"model": "{\"id\":\"Qwen3.6-35B-A3B-4bit\",\"providerID\":\"myprovider\"}",
"tokens_input": 145920,
"tokens_output": 11950,
"tokens_reasoning": 0,
"tokens_cache_read": 0,
"tokens_cache_write": 0,
"time_created": 1781858206763,
"time_updated": 1781858206763
}
Structure d'un message (table message) :
{
"id": "msg_edf05b24e001gD1yQMa8Rqwfpa",
"session_id": "ses_120fa4dc7ffeSg6YofUeAPBX1P",
"data": "{\"role\":\"assistant\",\"time\":{\"created\":1781858153054,\"completed\":1781858153428},\"model\":{\"providerID\":\"myprovider\",\"modelID\":\"Qwen3.6-35B-A3B-4bit\"},\"tokens\":{\"input\":0,\"output\":0,\"reasoning\":0,\"cache\":{\"read\":0,\"write\":0}},\"cost\":0}"
}
Structure d'un export (plugin) :
{
"info": {
"id": "sess-abc123",
"slug": "mon-projet",
"directory": "/home/user/project",
"model": { "id": "claude-sonnet-4-20250514", "providerID": "anthropic" },
"tokens": {
"input": 8427,
"output": 287,
"reasoning": 0,
"cache": { "read": 8020, "write": 7052 }
},
"time": { "created": 1719741600000, "updated": 1719742500000 }
},
"messages": [
{
"info": {
"id": "msg-1",
"role": "assistant",
"time": { "created": 1719741700000, "completed": 1719741800000 },
"model": {
"id": "claude-sonnet-4-20250514",
"providerID": "anthropic"
},
"tokens": {
"input": 8427,
"output": 287,
"reasoning": 0,
"cache": { "read": 8020, "write": 7052 }
},
"cost": 0.00123
}
}
]
}
Collecteur : CrushCollector (backfilling BDD + lecture exports plugin)
Pi
Sources disponibles :
- Transcripts de session :
~/.pi/agent/sessions/--<cwd>--/<timestamp>_<uuid>.jsonl
Structure d'un fichier de session (une entrée d'en-tête type:"session" puis des entrées type:"message") :
{"type":"session","id":"sess-A","timestamp":"2026-06-27T10:00:00.000Z","cwd":"/Users/me/DEV/projA"}
{"type":"message","id":"u1","timestamp":"2026-06-27T10:08:45.619Z","message":{"role":"assistant","provider":"anthropic","model":"claude-opus-4-8","usage":{"input":8427,"output":287,"cacheRead":8020,"cacheWrite":7052,"totalTokens":15786,"cost":{"total":0}}}}
Collecteur : PiCollector (lecture directe JSONL, root = répertoire ou fichier unique)
Notes pour les futurs outils
Quand un nouvel outil est ajouté, mettre à jour :
- Ce document (tableau comparatif)
- Le collecteur correspondant dans
ai_footprint/collectors/ - Les tests dans
tests/test_<outil>_collector.py
Champs obligatoires à mapper dans InferenceEvent :
provider(string)model(string)input_tokens(int)output_tokens(int)cache_creation_tokens(int)cache_read_tokens(int)timestamp(ISO 8601 UTC)project(string, basename du directory)session_id(string)msg_id(string)
Champs optionnels déjà mappés dans InferenceEvent :
active_seconds(float)client(string, identifie l'outil)
Champs pas encore mappés (présents chez au moins un outil, absents de
InferenceEvent — à ajouter si un besoin produit apparaît) :
reasoning_tokens(int)cost(float, USD)error(string)
Document créé le 2026-06-30, mis à jour le 2026-07-13. À mettre à jour à chaque nouvel outil ajouté.