Step-by-step checklist for adding a new inference provider to openshell-image-builder, covering the trait implementation, agent wiring, unit tests, integration tests, and README
Instalação
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Step-by-step checklist for adding a new inference provider to openshell-image-builder, covering the trait implementation, agent wiring, unit tests, integration tests, and README
argument-hint
<provider-name>
Add Inference Provider
End-to-end checklist for making a new LLM backend available via --inference.
Description
Adding a new inference provider touches six layers: the inference module, main.rs, each agent that will support it, unit tests throughout, integration tests, and the README. The existing providers are the canonical reference:
anthropic — cloud, fixed default endpoint, supports --endpoint override, bakes env var into image for Claude.
policy_yaml returns a YAML fragment that is merged into the sandbox policy. It receives:
agent_binary — the absolute path to the agent binary (scope the policy to it).
base_url — the resolved endpoint URL when --endpoint was passed (and the provider supports it); None otherwise.
Follow the existing pattern closest to the new provider:
Cloud provider with --endpoint support (anthropic pattern): if base_url is Some, parse its host and port with super::parse_host_port and use them; otherwise use the provider's default hostnames.
Local provider (ollama pattern): call base_url.and_then(super::parse_host_port).unwrap_or_else(|| (DEFAULT_HOST, DEFAULT_PORT)). Export DEFAULT_BASE_URL as a pub(crate) const so main.rs can reference it for the localhost-rewrite logic.
The YAML shape must follow the existing structure — one network policy with name, endpoints, and binaries:
Unit tests to write in the same file (inside #[cfg(test)] mod tests):
policy_yaml_contains_<provider>_endpoint — default host appears in output.
policy_yaml_embeds_agent_binary — agent binary path appears in output.
policy_yaml_has_<provider>_name — name: myprovider appears in output.
If --endpoint is supported: policy_yaml_with_custom_endpoint_uses_proxy_host, policy_yaml_with_custom_endpoint_omits_default_host, policy_yaml_with_custom_endpoint_custom_port.
If endpoint is fixed: one test confirming base_url is ignored (pass a URL and assert the fixed host still appears).
Step 2 — register in src/inference/mod.rs
Four additions:
mod myprovider; // 1. declare the modulepub(crate) use myprovider::DEFAULT_BASE_URL as MYPROVIDER_DEFAULT_BASE_URL; // 2. re-export default URL (if local provider)#[cfg(test)]pubuse myprovider::MyProviderInference; // 3. export for test use// 4. add variant to the enum#[derive(Clone, PartialEq, ValueEnum)]pubenumInferenceKind {
Anthropic,
Ollama,
#[value(name = "vertexai")]
VertexAi,
MyProvider, // add here
}
// 5. add arm to from_kind()pubfnfrom_kind(kind: InferenceKind) ->Box<dyn Inference> {
match kind {
...
InferenceKind::MyProvider => Box::new(myprovider::MyProviderInference),
}
}
If the CLI value should differ from the Rust variant name (e.g. vertexai instead of VertexAi), add #[value(name = "myprovider")] above the variant.
Step 3 — wire into main.rs
resolve_base_url() — local providers only
If the new provider has a default local URL that needs localhost → host.openshell.internal rewriting, add a match arm following the Ollama pattern:
For cloud providers this is not needed — resolve_base_url should return None unless --endpoint is given (anthropic pattern) or always None (vertexai pattern).
Validation in run() — if --endpoint is unsupported
If the new provider has a proprietary fixed endpoint and must reject --endpoint, add an early check at the top of run():
if endpoint.is_some() && inference_kind == Some(inference::InferenceKind::MyProvider) {
returnErr("--endpoint is not supported for the myprovider inference provider".into());
}
Step 4 — update each agent that supports the new inference
For each agent that should work with the new provider:
set_inference() — if the provider requires agent config files
If using the new provider with a particular agent should write config files into the image (like Ollama writes .config/opencode/config.json for opencode), add an arm to set_inference():
The configure function lives in src/agent/opencode/myprovider.rs (a new submodule), following the structure of src/agent/opencode/anthropic.rs and src/agent/opencode/ollama.rs.
env_vars() — if the provider requires baked-in environment variables
If the new provider requires an env var baked into the image (like ANTHROPIC_BASE_URL for Claude + Anthropic), add a branch to env_vars():
If the new inference produces a distinguishable policy entry, add a check_myprovider_policy(image, expected) helper following check_anthropic_policy / check_ollama_policy.
Then add has_myprovider to the image_tests! macro — add the parameter, add a generated policy_has_myprovider_rules test inside the macro body, and update every existing image_tests! call to pass has_myprovider: false (or true for the new combinations).
Image singletons and accessors
Add one OnceLock + accessor per agent that supports the new inference, following the naming convention <base_image>_<agent>_<provider>_image. At minimum add ubuntu variants:
Add the new provider to the canonical reference list at the top of the Description section of this skill, following the same one-line format as the existing entries:
- **`myprovider`** — <cloud|local>, <endpoint behaviour>, <any special wiring>.
This keeps the reference list accurate and gives the next contributor a concrete example to follow for a similar provider.
Step 7 — update README.md
Intro layer list — if the new provider adds a new entry to the "Inference network rules" bullet, update the description.
"Configuring inference" table — add a row with the --inference value, supported agents, and what the provider connects to.
"--endpoint" table — add a row for each agent + new provider combination, stating whether --endpoint is supported and what effect it has.
"--model" table — add a row for each agent + new provider combination, stating what file the model is written to.
"Agent × Inference Supported Features" table — add a row for each agent that supports the new provider, filling in the "Inference settings", "Endpoint override", and "Model selection" columns.
"Sandbox policy" section — add a sentence describing what endpoints the new inference rule allows.
"Full option reference" table — update the --inference row description to include the new value.
Checklist
src/inference/<provider>.rs created with Inference trait implementation
src/inference/<provider>.rs unit tests cover all endpoint and binary-embedding cases
src/inference/mod.rs: mod, pub use (cfg test), InferenceKind variant, from_kind arm added
DEFAULT_BASE_URL exported from mod.rs if the provider is local
resolve_base_url() updated in main.rs if the provider has a default local URL
Rejection added in run() if --endpoint is unsupported
supported_inference() updated in each agent that supports the new provider
supported_inference() exclusion tests added for agents that don't support it
set_inference() updated (and new opencode submodule written) if config files are needed
env_vars() updated if a baked-in env var is needed
build_policy_with_myprovider_* unit tests added in src/main.rs
Integration test policy check helper added; image_tests! macro and all existing calls updated
Image singletons, accessors, image_tests! calls, and cleanup entries added
Behavioural mod block written with positive, content, ownership, negative, and rejection tests
.agents/skills/add-inference/SKILL.md Description updated with the new provider entry