litellm-rust/crates/CODING_STANDARDS/PROVIDER_CODING_STANDARDS.md
Rules for adding or changing an LLM provider/route in litellm-rust. messages (core/src/messages, ANTHROPIC_MESSAGES_CONFIG) is the reference: a route is a core module with a public entrypoint that makes the call and returns a typed response.
get_custom_llm_provider (core/src/routing_utils/provider.rs). Nothing downstream may branch on a raw model string.prepare.rs, and passed down as typed fields. Don't re-resolve or re-parse it in transforms or handlers.transform_request + transform_response (+ complete_url, supported_params), living in core/src/<route>/transformation.rs (e.g. AnthropicMessagesProviderConfig, mirroring OcrProviderConfig).const <PROVIDER>_<ROUTE>_CONFIG in core/src/providers/<provider>/<route>/transformation.rs, mirroring the Python provider tree.core = the call itself (entrypoint, types, transforms, provider resolution, auth headers, provider HTTP, lifecycle hooks); ai-gateway = serving HTTP/WS (routing, extractors, auth of our callers, streaming to the client); python-bridge = thin PyO3 adapter. Hosts call the core entrypoint; they never build a provider request.core/src/providers/<provider>/<route>/; a route is a module, never a new crate.core::<route>::<route>() -> prepare_* -> handler (or CallLifecycle::run_request, which owns the pre_call -> during_call -> provider call -> success/failure order and phase timing). Axum handlers validate and delegate to a service that calls the entrypoint; no business logic in them.constants.rs, never inline. Config-shaped env reads happen at the host/config layer with the DEFAULT_* fallback defined in constants.rs; the only env read in core is the credential fallback in a route's prepare.rs.serde_json::Value / String / Vec<String> as a transform input or output. Parse wire bytes into typed structs/enums at the host edge; a type discriminator is a typed field, not a raw string.CoreError, don't panic. No unwrap/expect/panic! on user or provider input.collect), prefer immutable bindings and owned typed structs over seeding-and-mutating.null for parity, keep it and pin it with a test.*_match_python fixture parity.litellm/main.py. A route's provider dispatch lives in a thin dispatch class under litellm/llms/<provider>/<route>/ that calls the Rust bridge; main.py only instantiates it and calls its sync/async method.use_litellm_rust); never introduce a per-route env flag such as LITELLM_USE_RUST_<ROUTE>.cd litellm-rust
cargo fmt --check
cargo clippy -p litellm-ai-gateway --all-targets --features server -- -D warnings
cargo clippy -p litellm-core -p litellm-python-bridge --all-targets -- -D warnings
cargo test --workspace