How the Spend Tier System Routes Evaluations Across AI Providers in career-ops
The spend tier system reads your spend_tier setting from config/profile.yml and translates it into a specific Claude model identifier via the spend_tier_to_model helper, automatically routing evaluations to budget-appropriate AI providers while allowing CLI overrides.
The career-ops open-source framework simplifies AI-driven job offer evaluations by abstracting provider complexity into a declarative spend tier setting. Instead of manually selecting model names or managing provider-specific API configurations, you define your budget preference in a single YAML key. The system then automatically routes inference requests to the appropriate model across pipeline, batch, and CLI execution modes.
How Spend Tier Routing Works
The routing mechanism operates through a four-stage pipeline that transforms a user-friendly configuration value into a concrete provider API call. This process is centralized in the batch runner and shared across all execution modes.
Reading the Configuration
At the start of any evaluation run—whether in pipeline, batch, or CLI mode—the system invokes a configuration helper to parse config/profile.yml. According to the shared mode documentation in modes/_shared.md, the helper searches for the spend_tier key. If the key is absent, the system defaults to standard.
In batch/batch-runner.sh (lines 351–409), the read_spend_tier function extracts this value once per run and exports it for downstream use. This ensures consistent model selection across an entire batch job, preventing mixed-tier evaluations within a single execution context.
Validation and Fallback Logic
The system enforces a strict allowlist of tier values. As implemented in batch/batch-runner.sh (line 385), only three strings are accepted:
economystandardpremium
If the configuration contains an invalid value, the runner emits a warning and falls back to standard. This validation prevents provider errors from typos or unsupported tier names.
Mapping Tiers to Provider Models
Once validated, the tier string passes through the spend_tier_to_model helper function defined in batch/batch-runner.sh (lines 392–408). This function maps abstract budget tiers to concrete model identifiers:
spend_tier |
Resolved Model |
|---|---|
economy |
claude-haiku-4-5 |
standard |
claude-sonnet-5 |
premium |
claude-opus-5 |
This mapping provides a provider-agnostic interface; the user thinks in terms of cost ("economy"), while the system manages the specific Claude model name required by the API.
Applying Models to Evaluation Scripts
The resolved model identifier becomes the --model argument passed to evaluation scripts (e.g., node evaluate.mjs --model $RESOLVED_MODEL). However, explicit CLI flags take precedence over tier-derived values. As verified in test-all.mjs (lines 12948–13037), if you provide --model claude-opus-5 on the command line while your profile specifies economy, the CLI flag wins.
Batch-Specific Pre-Screening
In batch mode, the spend tier gates an additional optimization step. As noted in test-all.mjs (line 12948), the system runs a cheap pre-screen using the tier-appropriate model to discard low-quality offers before spending credits on full evaluations. This ensures high-volume runs remain cost-effective even when processing thousands of job descriptions.
Configuration and Usage Examples
Set your preferred tier in the profile configuration:
# config/profile.yml
spend_tier: economy # Uses claude-haiku-4-5 for high-volume, low-cost scanning
# spend_tier: standard # Default: claude-sonnet-5 for balanced performance
# spend_tier: premium # Uses claude-opus-5 for maximum evaluation depth
Run a standard evaluation—the tier determines the model automatically:
career-ops evaluate --job ./jds/example-job.md
# Verbose output confirms: Model: claude-haiku-4-5 (spend_tier=economy)
Override the tier for a single evaluation using the explicit model flag:
career-ops evaluate --job ./jds/example-job.md --model claude-opus-5
# Output shows: Model: claude-opus-5 (spend_tier=economy) # CLI flag takes precedence
Execute a batch run where the runner reads the tier once and applies it to every job:
career-ops batch run ./batch/jobs/
# Internally executes: RESOLVED_MODEL=$(spend_tier_to_model $(read_spend_tier))
Summary
- The spend tier is defined in
config/profile.ymland defaults tostandardif omitted. - Valid tiers are
economy,standard, andpremium, mapping toclaude-haiku-4-5,claude-sonnet-5, andclaude-opus-5respectively. - The
batch/batch-runner.shscript handles validation, mapping, and application of the model identifier via thespend_tier_to_modelhelper. - Explicit
--modelCLI arguments override the tier-derived model, as confirmed by the test suite intest-all.mjs. - Batch mode uses the tier to gate a pre-screen step that filters low-quality offers before incurring full evaluation costs.
Frequently Asked Questions
What happens if I don't define a spend_tier in my profile?
If the spend_tier key is missing from config/profile.yml, the system defaults to standard, which resolves to the claude-sonnet-5 model. This fallback logic is documented in modes/_shared.md and implemented in batch/batch-runner.sh.
Can I use a different model for a single evaluation without changing my profile?
Yes. You can override the tier-derived model by passing the --model flag directly to the CLI command (e.g., --model claude-opus-5). This explicit flag takes precedence over the spend_tier configuration for that specific execution.
How do the three spend tiers differ in practice?
The economy tier uses claude-haiku-4-5 for fast, low-cost scanning suitable for high-volume batches. The standard tier uses claude-sonnet-5 for balanced speed and reasoning quality. The premium tier uses claude-opus-5 for maximum capability when evaluating complex compensation packages or critical offers.
Does the spend tier affect batch processing costs beyond the model choice?
Yes. In batch mode, the tier also controls a pre-screening step that evaluates offers with a cheaper model pass before committing to full evaluations. This additional gate, referenced in test-all.mjs, prevents wasting premium model credits on obviously low-quality job descriptions.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →