This repository has no description
bez specs candidate-generation-claude-code-provider.md
3.2 kB


enabled: true touches: [crates/generation/src/model.rs, crates/generation/src/bin/absolute_real_model_run.rs, docs/model-first-cost.md, roadmap.md] depends-on: [] #

Candidate generation: a Claude Code subprocess provider #

Candidate generation has three sources today (crates/generation/src/model.rs): DirectoryCandidateSource (files on disk), RemoteCandidateSource (the rig's OpenAI-compatible gateway via HttpModelClient), and ClaudeCandidateSource (AnthropicClient, the metered Anthropic Messages API, selected by GENERA_PROVIDER=anthropic in absolute_real_model_run.rs). A batch run through that metered path has now cost noticeably more than docs/model-first-cost.md projected. This adds a fourth source that draws each candidate by running the claude CLI as a subprocess in headless mode, billed under the same interactive subscription the spec-watch tick and its writers already run on (~/.claude/bin/ spec-watch-tick.sh invokes claude ... -p '/spec-watch'; ~/.claude/commands/ spec-watch.md invokes claude --bg --model <model> --permission-mode acceptEdits '<brief>') rather than metered per-token.

Add ClaudeCliCandidateSource to model.rs, alongside the existing sources, same shape as ClaudeCandidateSource: one candidate per prompt, count drawn GENERA_CONCURRENCY at a time via the existing draw_concurrently. Where ClaudeCandidateSource calls AnthropicClient::complete (an HTTP POST), this spawns claude -p "<prompt>" (confirm the exact flags against claude --help — headless output needs to be just the completion text with no interactive chrome, which may mean --output-format text or json rather than the default; a model override, if wanted, is --model). Reuse extract_rust_source on the captured stdout the same way ClaudeCandidateSource does on a Messages API response, since the source is still Rust in a fenced block. Telemetry.prompt_tokens / completion_tokens have no equivalent from a CLI subprocess — leave them 0 rather than inventing a number; wall_clock_ms still times the subprocess call itself, the same way Telemetry is populated elsewhere in this file. stop_reason has no CLI equivalent either — leave it None.

Wire it into absolute_real_model_run.rs as a new GENERA_PROVIDER value (e.g. GENERA_PROVIDER=claude-code), alongside the existing GENERA_PROVIDER=anthropic branch and the rig-gateway default, following the same match shape the file already uses for provider selection.

Record the addition in docs/model-first-cost.md (a short section next to wherever the Anthropic-provider cost note already lives, naming this as the subscription-billed alternative) and in roadmap.md wherever the candidate-source options are listed.

This spec is implementation only — it adds the provider and switches nothing over by default. No real model batch runs as part of this work: cargo test --workspace and fragment_check --random (216/227, unchanged) are the gate. A follow-up spec decides whether absolute-batches-style work re-runs through this provider instead of the metered one; that decision is not this spec's to make.