-
Notifications
You must be signed in to change notification settings - Fork 0
feat: skill-trigger evaluation + claude-cli provider (subprocess-based) #593
Description
Objective
Add first-class skill-trigger evaluation to AgentV, using a claude-cli provider that runs claude -p as a subprocess. claude becomes an alias for claude-cli (the new default); the existing SDK-based provider becomes claude-sdk.
Side effect: fixes #521 (SDK has its own internal timeout that fires at ~2 mins, overriding AgentV's timeout_seconds; direct subprocess control removes that layer).
Context
The current claude provider uses @anthropic-ai/claude-agent-sdk and exposes completed assistant messages with extracted tool calls. This is sufficient for execution-quality evaluation but misses two things skill-creator provides natively:
- Mid-stream trigger detection — skill-creator streams
--include-partial-messagesand exits early oncontent_block_startwhen it sees aSkillorReadtool call. Fast, low-cost binary signal without waiting for the full response. - Raw subprocess control —
claude -psubprocess is harness-consistent with the way skills are actually used interactively. The SDK adds abstraction that can hide behaviour visible to users in real sessions.
skill-creator's trigger detection pattern (reference implementation):
- Creates a temporary
.claude/commands/<skill>-<uuid>.mdfile before the run - Runs
claude -p <query> --output-format stream-json --include-partial-messages - Strips
CLAUDECODEenv var to allow nested sessions (AgentV already does this in the SDK provider) - Watches for
content_block_startwithSkill/Readtool name containing the injected skill name - Cleans up command file after run
Workspace setup for trigger evals uses the existing before_all hook pattern (npx allagents) — no new mechanism needed.
Proposed Design
Provider naming
| Provider name | Implementation | Notes |
|---|---|---|
claude |
alias for claude-cli |
default; existing configs continue to work |
claude-cli |
claude -p subprocess |
new default implementation |
claude-sdk |
@anthropic-ai/claude-agent-sdk |
explicit opt-in — note: already registered as an alias in PROVIDER_ALIASES pointing to the current SDK impl; this just formalises it |
Provider: claude-cli
- Spawns
claude -pas a subprocess - Passes workspace
cwd, model, system prompt, max turns via CLI flags - Streams
--output-format stream-json --include-partial-messagesfor event-level access - Returns
ProviderResponsein the same shape as the SDK provider (output, toolCalls, tokenUsage, costUsd) - Strips
CLAUDECODEenv var (same as current SDK provider)
Evaluator: trigger-judge
New evaluator type alongside tool-trajectory in eval-file.schema.ts:
- Checks whether the agent invoked the
Skilltool (orReadon a skill path) during the run - Takes a
skillparameter (skill name to check for) - Returns pass/fail with the triggering tool call as evidence
- Can detect early via stream events with
claude-cli, or post-hoc fromtoolCallswithclaude-sdk
evaluators:
- type: trigger-judge
skill: my-skill-nameKey Files
Track 1 — Provider (do first):
packages/core/src/evaluation/providers/claude.ts→ rename toclaude-sdk.ts(keep class, updatekind)packages/core/src/evaluation/providers/claude-cli.ts→ new file, subprocess implementationpackages/core/src/evaluation/providers/types.ts— addclaude-clitoAGENT_PROVIDER_KINDS;claude-sdkalready inPROVIDER_ALIASES, pointclaudealias toclaude-clipackages/core/src/evaluation/providers/index.ts— update registration (line 90:.register('claude', ...))packages/core/src/evaluation/providers/targets.ts— update provider resolution (line 789, case'claude')packages/core/src/evaluation/validation/targets-validator.ts— update validation (line 218)
Track 2 — Evaluator (parallel, no dependency on Track 1):
packages/core/src/evaluation/validation/eval-file.schema.ts— addtrigger-judgeschema alongsidetool-trajectory(line 140)- Evaluator runner (wherever
tool-trajectoryis evaluated — follow the same pattern)
Architecture Boundary
core-runtime — both tracks are in packages/core/.
Design Latitude
- Whether
claude-cliis a fully separate class or shares a base class withclaude-sdk - Whether mid-stream early-exit optimisation is implemented or deferred (post-hoc
toolCallscheck is correct and simpler; early-exit is a perf improvement) - Whether
trigger-judgeis a standalone evaluator or an extension totool-trajectory
Acceptance Signals
provider: claudein targets.yaml resolves toclaude-clibehaviourprovider: claude-sdkopts in to the previous SDK behaviourprovider: claude-cliworks explicitly- An eval with
type: trigger-judge, skill: my-skillcorrectly detects when Claude invokes the named skill claude-cliproduces equivalentProviderResponseasclaude-sdkfor execution-quality evals- Skill trigger eval runs end-to-end:
before_allinstalls skill → query → pass/fail trigger result - Tests cover trigger-judge evaluator logic and provider alias resolution
Non-Goals
- Trigger-description optimization loop (skill-creator's domain)
- Removing
claude-sdk— stays as explicit opt-in - Non-Claude harness trigger detection (Copilot, Gemini, etc. have no skills concept)
Related
- bug: claude provider times out after 2 mins #521 bug: claude provider times out after 2 mins — fixed as side effect
- tracking: Anthropic skill-creator eval framework alignment #569 tracking: Anthropic skill-creator eval framework alignment
- docs: separate execution quality from trigger quality in eval guidance #566 docs: separate execution quality from trigger quality (closed — this implements what docs: separate execution quality from trigger quality in eval guidance #566 deferred)
- Anthropic skill-creator
run_eval.py— reference implementation for trigger detection