Skip to content

Jesuisleon/eval-agentic-tool

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

title Eval Runner - Guide utilisateur
type documentation
version 2.0
created 2026-03-30
updated 2026-03-30
domain tooling
tags
eval
claude-code
skills
hooks
e2e
trajectory
calibration
summary Guide d'installation, configuration et usage de l'Eval Runner, outil de calibration des skills, commands et hooks Claude Code via execution reelle (e2e) et analyse de trajectoire.

Eval Runner

License: MIT Bun Claude Code CI

Outil de calibration des skills, commands et hooks Claude Code par execution reelle.

Chaque eval lance Claude Code dans un environnement isole avec des fichiers de test (fixtures), capture la trajectoire complete (outils utilises, arguments, ordre), et verifie l'etat final des fichiers.

Inspire de la methodologie Anthropic "Demystifying Evals for AI Agents" :

  • Binary pass/fail
  • Grade outcomes, not paths (mais capture la trajectoire pour le debug)
  • Deux axes : trigger (routing) et e2e (execution reelle)

Prerequis

  • Bun >= 1.0
  • Claude Code CLI installe et authentifie (claude --version)

Installation

bun install

Aucune configuration supplementaire requise. Le runner utilise l'authentification Claude Code deja presente sur la machine.

Quickstart (30 seconds)

Pour voir le runner fonctionner rapidement, utilisez un eval de type hook — aucun appel LLM, execution quasi-instantanee.

  1. Creez un fichier _evals/hooks/demo.eval.yaml :
name: demo
type: hook
target: .claude/hooks/demo.sh

cases:
  - scenario: "Commande reussie, pas de contexte ajoute"
    input:
      tool_result:
        exit_code: 0
        stdout: "ok"
        stderr: ""
    expect:
      has_context: false
  1. Lancez le runner :
bun run eval demo

Vous devriez voir PASS demo en sortie console. Pour un eval skill/command complet avec fixtures et outcomes, voir la section Format YAML des test cases.

Configuration

Variable Defaut Description
EVAL_MODEL opus Modele Claude Code a utiliser (haiku, sonnet, opus)

Le modele peut aussi etre specifie par scenario dans le YAML (model: sonnet).

Usage CLI

# Executer tous les evals (trigger + e2e + hook)
bun run eval

# Filtrer par nom
bun run eval ts-fixer

# Un axe seulement
bun run eval --axis trigger
bun run eval --axis e2e

# Afficher les trajectoires et details
bun run eval --verbose

# Combiner les options
bun run eval ts-fixer --axis e2e --verbose

Options

Option Type Defaut Description
[name] positional - Filtre par nom exact de l'eval
--axis trigger | e2e tous Axe d'evaluation a executer
--trials 1-10 1 Nombre de repetitions par scenario
--verbose boolean false Affiche les trajectoires et outputs

Codes de sortie

Code Signification
0 Tous les evals passent
1 Au moins un eval echoue
2 Erreur CLI (option invalide)

Format YAML des test cases

Les fichiers d'eval sont dans _evals/ avec l'extension .eval.yaml.

_evals/
├── skills/
│   └── ts-fixer.eval.yaml
├── commands/
│   └── tdd.eval.yaml
├── hooks/
│   └── ts-fixer-hook.eval.yaml
└── results/
    └── 2026-03-30T14-30-00_ts-fixer.json

Schema Skill / Command

Les skills et commands partagent le meme schema avec deux sections : trigger et e2e.

name: mon-skill               # Identifiant unique
type: skill                    # "skill" ou "command"
target: .claude/skills/mon-skill/SKILL.md  # Fichier cible (lu pour trigger eval)

# ── Trigger eval ──
# Teste si la description du skill route correctement les requetes
trigger:
  positive:                    # Requetes qui DOIVENT matcher
    - query: "Fix the TypeScript errors"
      note: "Explication optionnelle"
  negative:                    # Requetes qui NE DOIVENT PAS matcher
    - query: "Fix the CSS styling"
      note: "CSS, pas TypeScript"

# ── E2E eval ──
# Lance Claude Code pour de vrai dans un dossier temp avec des fixtures
e2e:
  - scenario: "Fix type assignment error"
    fixture:                   # Fichiers crees dans le dossier temp
      src/app.ts: |
        const greeting: number = "hello world";
        console.log(greeting);
      tsconfig.json: |
        { "compilerOptions": { "strict": true, "noEmit": true } }
    prompt: "Fix the TypeScript errors in this project"
    model: haiku               # Optionnel (defaut: EVAL_MODEL ou opus)
    outcomes:                  # Verifications sur l'etat final des fichiers
      - type: file-not-contains
        file: src/app.ts
        value: "as any"
      - type: file-not-contains
        file: src/app.ts
        value: "@ts-ignore"
    workflow:                  # Verifications sur la trajectoire d'outils
      match_mode: superset
      expected_tools:
        - name: Read
          args_contain:
            file_path: "app.ts"
        - name: Edit
          args_contain:
            file_path: "app.ts"
          after: Read          # Edit doit venir APRES Read
      forbidden_tools:
        - Write                # Ne doit PAS reecrire le fichier entier

Schema Hook

Les hooks sont testes par execution directe du script shell. Pas de Claude Code implique.

name: mon-hook
type: hook
target: .claude/hooks/mon-hook.sh

cases:
  - scenario: "Commande echouee avec erreurs TS"
    input:
      tool_result:
        exit_code: 1
        stdout: "error TS2322: Type 'string' is not assignable"
        stderr: ""
    expect:
      has_context: true
      context_contains: "TypeScript"

  - scenario: "Commande reussie"
    input:
      tool_result:
        exit_code: 0
        stdout: "Build successful"
        stderr: ""
    expect:
      has_context: false

Axes d'evaluation

Trigger Eval

Evalue la precision du routing : est-ce que la description du skill attire les bonnes requetes ?

Comment ca marche : Claude Code recoit un prompt "est-ce que cette requete devrait declencher ce skill ?", repond OUI/NON. Pas de tool use, pas de fichiers — juste du texte.

Metriques :

Metrique Formule Interpretation
Precision TP / (TP + FP) % des triggers qui sont corrects
Recall TP / (TP + FN) % des requetes pertinentes detectees
F1 2 * P * R / (P + R) Equilibre precision/recall

E2E Eval

Evalue le comportement reel de Claude Code : est-ce qu'il utilise les bons outils et produit le bon resultat ?

Comment ca marche :

1. Cree un dossier temp avec les fichiers de la fixture
2. Lance: claude -p "<prompt>" --bare --cwd /tmp/eval-xxx --model haiku
3. Claude Code lit les fichiers, fait des edits, lance des commandes...
4. Capture la trajectoire (sequence de tool calls)
5. Verifie l'etat final des fichiers (outcomes)
6. Verifie la trajectoire (workflow)
7. Nettoie le dossier temp

Types d'outcomes (verifications sur les fichiers apres execution) :

Type Description
file-contains Le fichier contient une sous-chaine
file-not-contains Le fichier NE contient PAS une sous-chaine
file-matches Le fichier matche une regex
file-exists Le fichier existe
file-not-exists Le fichier n'existe pas
bash-succeeds La commande bash retourne exit 0
bash-fails La commande bash retourne exit != 0
bash-output-contains La sortie de la commande contient une sous-chaine

Workflow — modes de matching (verifications sur la trajectoire d'outils) :

Mode Verifie Quand l'utiliser
strict Memes outils, meme ordre, memes args Workflow tres precis
unordered Memes outils dans n'importe quel ordre Quand l'ordre n'importe pas
subset L'agent n'utilise QUE les outils listes Verifier qu'il ne fait pas trop
superset L'agent utilise AU MOINS les outils listes Le minimum requis (recommande)

Workflow — contraintes d'ordre :

expected_tools:
  - name: Edit
    after: Read    # Edit doit apparaitre APRES Read dans la trajectoire

Workflow — outils interdits :

forbidden_tools:
  - Write          # Si Claude Code utilise Write au lieu de Edit, le test echoue

Hook Eval

Evalue les hooks shell par execution directe. Pas de Claude Code, pas de LLM.

Comment ca marche :

  1. Le script hook est execute avec mock JSON en stdin
  2. Le stdout est parse comme JSON
  3. Verification de additionalContext (presence + contenu)

Interpretation des resultats

Sortie console

━━━ ts-fixer (skill) ━━━

  Trigger Eval
    Positive: 3/3 (100%)
    Negative: 3/3 (100%)
    Precision: 100%  Recall: 100%  F1: 100%

  E2E Eval (cost: $0.0842)

    PASS Fix type assignment error (8523ms, $0.0521)
      Trajectory: Read → Read → Edit → Bash
      PASS [file-not-contains] src/app.ts not contains "as any"
      PASS [file-not-contains] src/app.ts not contains "@ts-ignore"
      PASS Workflow checks passed

    FAIL Fix missing property error (12341ms, $0.0321)
      Trajectory: Read → Write
      PASS [file-not-contains] src/user.ts not contains "as any"
      FAIL Forbidden: Write
      Pass rate: 50%

  Duration: 21000ms

═══ Summary ═══

  FAIL ts-fixer
  Total e2e cost: $0.0842

  0 passed, 1 failed

Resultats JSON

Chaque run produit un fichier horodate dans _evals/results/ :

{
  "name": "ts-fixer",
  "type": "skill",
  "timestamp": "2026-03-30T14:30:00.000Z",
  "config": { "model": "haiku", "trials": 1 },
  "trigger": {
    "positive": { "total": 3, "passed": 3, "rate": 1.0 },
    "negative": { "total": 3, "passed": 3, "rate": 1.0 },
    "precision": 1.0, "recall": 1.0, "f1": 1.0
  },
  "e2e": {
    "scenarios": [
      {
        "scenario": "Fix type assignment error",
        "trajectory": [
          { "tool_name": "Read", "tool_args": { "file_path": "/tmp/eval-xxx/src/app.ts" } },
          { "tool_name": "Edit", "tool_args": { "file_path": "/tmp/eval-xxx/src/app.ts", "..." : "..." } }
        ],
        "outcomes": [
          { "type": "file-not-contains", "description": "...", "passed": true }
        ],
        "workflow": {
          "tool_match": { "passed": true, "reason": "All required tools present" },
          "forbidden_check": { "passed": true, "violations": [] },
          "ordering_check": { "passed": true, "violations": [] }
        },
        "cost_usd": 0.0521,
        "duration_ms": 8523,
        "passed": true
      }
    ],
    "pass_rate": 1.0,
    "total_cost_usd": 0.0521
  },
  "duration_ms": 21000
}

Architecture

scripts/
├── eval-runner.ts           # Entry point CLI + orchestration
└── eval/
    ├── types.ts             # Types TypeScript + schemas Zod
    ├── config.ts            # Config (model, dirs)
    ├── claude-run.ts        # Helper claude -p (shared trigger/e2e)
    ├── loader.ts            # Discovery YAML + parsing + validation
    ├── trigger.ts           # Trigger eval via claude -p
    ├── e2e.ts               # E2E eval (fixtures, trajectoire, outcomes)
    ├── hooks.ts             # Hook eval (shell exec)
    └── report.ts            # Rendu console ANSI + ecriture JSON

Tout passe par claude -p (le CLI Claude Code en mode non-interactif). Aucune API externe, aucune cle API, aucun .env requis.

Troubleshooting

Symptome Cause probable Solution
claude: command not found CLI Claude Code non installe Installer Claude Code, puis verifier avec claude --version
claude auth status indique not logged in Session expiree ou absente Lancer claude auth login
bun: command not found Bun non installe curl -fsSL https://bun.sh/install | bash
Eval timeout / scenario bloque Depasse le timeout_ms de claudeRun Defaut 5 minutes (300000 ms). Ajuster le timeout_ms dans claude-run.ts ou reduire la taille de la fixture
Warning MCP dans le sandbox Voir e2e.ts:217 — le sous-processus Claude Code ne charge pas tous les MCP dans le dossier temp Generalement sans impact sur l'eval, peut etre ignore
Erreur de validation YAML (Zod) Le fichier .eval.yaml ne respecte pas le schema Consulter les sections Schema Skill / Command et Schema Hook plus haut
Runs e2e plus longs qu'attendu Modele Opus par defaut Passer EVAL_MODEL=haiku en variable d'env ou ajouter model: haiku dans le scenario

Ecrire un nouvel eval

  1. Creer un fichier _evals/skills/mon-skill.eval.yaml (ou commands/, hooks/)
  2. Remplir le schema YAML correspondant au type
  3. S'assurer que le target pointe vers un fichier existant (pour trigger eval)
  4. Pour les e2e : definir les fixtures (vrais fichiers de test)
  5. Lancer bun run eval mon-skill --verbose pour tester
  6. Ajuster les fixtures, outcomes et workflow selon les resultats

Bonnes pratiques

  • Fixtures minimalistes : le moins de fichiers possible pour reproduire le cas
  • Outcomes deterministes : preferer file-not-contains et bash-succeeds aux checks fragiles
  • superset par defaut : verifier le minimum requis, pas le chemin exact
  • after pour les contraintes d'ordre : Read avant Edit, pas de strict ordering global
  • forbidden_tools pour les anti-patterns : Write quand Edit suffit
  • 20-50 test cases par cible (recommandation Anthropic)
  • Equilibrer positifs et negatifs dans les triggers
  • Haiku pour le dev, Sonnet pour la CI : calibrer avec Haiku (rapide), valider avec Sonnet

Note sur cost_usd

Les resultats JSON contiennent un champ cost_usd (et total_cost_usd agrege). Cette valeur est calculee par Claude Code a partir des tarifs API et represente une consommation equivalente. Avec un abonnement Claude Pro ou Max, les runs sont couverts par l'abonnement — pas de facturation par eval. La valeur reste utile pour comparer l'intensite relative entre scenarios et modeles.

License

Released under the MIT License. See LICENSE.

About

Calibration tool for Claude Code skills, commands and hooks through real execution. Captures tool-use trajectories and verifies final file state.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors