Platform
Provider Strategy
Provider Strategy
Every ladder declares an allowedTargets policy that controls which LLM providers and models it can run against. Universal lets the platform route to any configured provider. Constrained pins to an explicit allowlist. The policy is a top-level required field, not an optional optimization. It exists so callers know what they're paying for, so authors can guarantee behavior, and so the platform can route efficiently.
Why allowedTargets is required
Every ladder invokes LLMs. Those LLMs come from providers (OpenAI, Anthropic, Google, DeepInfra, OpenRouter, custom). The platform supports a wide catalog and lets callers connect their own provider API keys. So whose model does a published ladder actually use?
Three bad answers:
- The author's. Requires the author to share their API keys with every caller. Insecure.
- The caller's, with no constraint. The ladder runs against whatever the caller has configured. If the caller connects a low-quality provider, the ladder produces bad output and the author gets blamed.
- Fixed at platform boot. Every ladder uses the same provider. Inflexible.
LADR's answer is the allowedTargets policy (documented as a required top-level field in Top-Level Config). The author declares which providers and models are acceptable. The caller's request is routed only to providers that match. If the caller has no matching provider, the request fails with a clear error.
This makes the contract explicit:
- The author commits to "this ladder produces good output on these models."
- The caller commits to "I have API access to at least one of those models."
- The platform routes accordingly.
The field is required because every ladder needs this contract. There's no useful default.
The two strategies
Two strategies are accepted.
universal
The ladder runs against any provider the platform supports. The platform picks the best available provider based on the caller's connections, the provider's pricing, and the platform's routing heuristics.
allowedTargets: { strategy: universal }Use universal when:
- The ladder works well across many models (most reasoning strategies are model-agnostic).
- You want maximum reach (callers without specific provider connections can still invoke).
- You're publishing a public ladder and don't want to lock callers into one vendor.
constrained
The ladder is pinned to an explicit allowlist of providers and models. Only those can run it.
allowedTargets:
strategy: constrained
providers: [openai, anthropic]
models: [gpt-4o, gpt-4o-mini, claude-sonnet-4-20250514]Use constrained when:
- The ladder depends on a specific model's behavior (e.g. requires strong JSON-mode support).
- The author has benchmarked on specific models and cannot vouch for others.
- The ladder uses a custom or self-hosted model that the caller must connect explicitly.
Wildcard * is accepted in either list, but cannot combine with explicit entries:
# All providers, any model.
allowedTargets:
strategy: constrained
providers: ["*"]
models: ["*"]
# INVALID: cannot combine * with explicit entries.
allowedTargets:
strategy: constrained
providers: ["*", openai] # fails validationValidation
allowedTargets is validated at config load time.
strategymust beuniversalorconstrained. Anything else fails:allowedTargets.strategy must be "universal" or "constrained".- For
constrained:providersmust be a non-empty array of non-empty strings.modelsmust be a non-empty array of non-empty strings.- Wildcard
*cannot combine with explicit entries in either list.
Errors look like:
allowedTargets.strategy must be "universal" or "constrained"
allowedTargets.providers must include at least one entry for strategy "constrained"
allowedTargets.providers cannot combine "*" with explicit providers
allowedTargets.models entries must be non-empty stringsModel and provider names are not validated against a fixed catalog. New providers and models can be added without a grammar change. The platform maintains its own catalog and rejects runtime requests for unknown entries.
Runtime routing
At execution time, the platform resolves the actual provider and model to use for each LLM call. The resolution takes into account:
- The ladder's
allowedTargets. The set of acceptable providers and models. - The caller's connected providers. Which API keys the caller has configured.
- The caller's request. The
modelfield in the request body (if specified). - Provider availability. Which providers are currently up and not rate-limited.
- Fallback chains. The platform's per-ladder fallback order if the primary provider fails.
For strategy: universal:
- The caller's
modelfield is matched against the connected providers' catalogs. - The first available matching provider is used.
- If the primary provider fails (rate limit, network error, malformed response), the platform falls back to the next available provider that supports the model.
For strategy: constrained:
- The caller's
modelfield must be in the ladder'smodelsallowlist. Otherwise the request is rejected with a clear error. - The caller's connected providers must include at least one of the ladder's
providers(or a wildcard match). - Fallback happens only within the allowlist.
What happens if the caller has no matching provider. The request fails with invalid_request_error and a message identifying what's missing:
Ladder "@alice/researcher" requires providers [openai, anthropic] but your account has none of these connected.This is the explicit-contract benefit: the caller knows immediately what's wrong, instead of getting a generic execution error mid-pipeline.
Common patterns
Universal with a model hint. Let the platform route; have the caller suggest a model.
allowedTargets: { strategy: universal }POST /v1/{author}/{ladder}/chat/completions
{
"model": "gpt-4o-mini",
"messages": [...]
}The ladder runs on whatever the caller's highest-priority provider for gpt-4o-mini is. The platform's fallback chain handles provider failures.
Pinned to a single model for reproducibility.
allowedTargets:
strategy: constrained
providers: [openai]
models: [gpt-4o-2024-08-06] # pinned model versionThe ladder runs only on this exact model. Useful for benchmark submissions and papers where reproducibility matters.
Multi-provider for redundancy.
allowedTargets:
strategy: constrained
providers: [openai, anthropic, openrouter]
models: [gpt-4o, claude-sonnet-4-20250514]The caller can connect any of the three providers. The platform routes based on availability and falls back across providers. Useful for production ladders that need high uptime.
Multi-tier quality.
allowedTargets:
strategy: constrained
providers: [openai, anthropic]
models: [gpt-4o, gpt-4o-mini, claude-sonnet-4-20250514, claude-haiku-4]The ladder works on premium (gpt-4o, sonnet) and budget (mini, haiku) models. The caller picks the trade-off. Pair with knobs (knobs.branches, knobs.iterations) so callers can dial cost versus quality per call.
Enterprise-only provider.
allowedTargets:
strategy: constrained
providers: [custom-enterprise-gateway]
models: [internal-model-v2]The ladder runs only against the caller's internal provider. Useful for compliance scenarios where data cannot leave the corporate network.
Common pitfalls
Forgetting that allowedTargets is required. The parser rejects configs without it. Always declare it, even if just { strategy: universal }.
Listing models you haven't benchmarked. If your ladder's models list includes models you've never tested, callers may get unexpected behavior. Test on every model in the list.
Locking to one provider for portability reasons. A ladder that requires providers: [openai] excludes callers who only have Anthropic configured. Use universal unless you have a specific reason to constrain. The constraint should reflect real model dependencies, not author comfort.
Combining * with explicit entries. Fails validation. * means "any"; combining it with explicit entries is contradictory. Use * alone or list explicit entries alone.
Forgetting that the constraint applies per call. A constrained ladder does not remember which provider it used last call. Each call resolves the provider fresh. If the caller disconnects a provider between calls, the next call routes to a different one (or fails if no match).
Expecting allowedTargets to enforce spend limits. It doesn't. Use executionBudget.maxSpend for cost control. allowedTargets controls which providers can run; executionBudget controls how much they can cost.