Universal CLI-based LLM provider.
One module, any CLI. Configuration is pure data — loaded from TOML or constructed in code. New CLI clients are added without writing Elixir code.
Default Providers
The following CLI providers ship as type = "cli" entries in
priv/config/llm_core.toml. Override or remove them via project
or global TOML overrides — no Elixir changes needed.
| Name | Binary | Notes |
|---|---|---|
:claude_code | claude | Wraps with /bin/sh for stdin redirect |
:droid | droid | Subcommand exec, rich flag set |
:pi_cli | pi | Pi CLI non-interactive dispatch (--print) |
:kimi_cli | kimi-cli | Kimi CLI with agent-file support |
:codex_cli | codex | OpenAI Codex CLI |
:gemini_cli | gemini | Google Gemini CLI |
Usage
{:ok, provider} = CLIProvider.from_config(:claude_code)
# Check availability
CLIProvider.available?(provider)
#=> true
# Send a prompt
{:ok, response} = CLIProvider.send(provider, "Explain this code")
# Stream
{:ok, stream} = CLIProvider.stream(provider, "Write a story")Custom Provider (no code needed)
config = %CLIProvider.Config{
name: :my_tool,
binary: "my-tool",
default_timeout: 60_000,
default_model: "v2",
flags: %{model: "--model", temperature: "--temp"}
}
provider = CLIProvider.from_config(config)
{:ok, response} = CLIProvider.send(provider, "hello", model: "v2")
Summary
Functions
Builds the CLI argument list from prompt and opts.
Builds an Error struct for common failure modes.
Returns {executable, args} for the CLI invocation.
Builds a ready-to-use %CLIProvider{} struct from an id or alias.
Builds a Response struct from CLI output, applying any configured normalization.
Returns the legacy built-in map (empty since all defaults moved to TOML).
Use list_all_configs/0 to get all known CLI provider configs.
Returns the config for a provider name.
Fetches a CLI config by id or alias. Returns a ready-to-use %CLIProvider.Config{}.
Creates a CLIProvider from a built-in name, a string id/alias, or a Config struct.
Returns a normalized invocation plan describing how the provider will run.
Returns all known CLI provider configs — runtime (TOML) merged with builtins. Runtime configs override builtins with the same name.
Runs declarative checks proving the CLI surface matches the configured contract.
Renders a prompt after applying any declared inline system-prompt fallback.
Resolves an alias or id string to the canonical provider name atom. Checks runtime definitions first (via Provider.Registry aliases), then builtins.
Returns whether the provider supports a semantic capability.
Types
@type t() :: %LlmCore.LLM.CLIProvider{config: LlmCore.LLM.CLIProvider.Config.t()}
Functions
@spec build_args(t(), LlmCore.LLM.Provider.prompt(), keyword()) :: [String.t()]
Builds the CLI argument list from prompt and opts.
@spec build_error(t(), atom() | {:exit_code, non_neg_integer()}, keyword()) :: LlmCore.LLM.Error.t()
Builds an Error struct for common failure modes.
@spec build_invocation(t(), LlmCore.LLM.Provider.prompt(), keyword()) :: {String.t(), [String.t()]}
Returns {executable, args} for the CLI invocation.
Builds a ready-to-use %CLIProvider{} struct from an id or alias.
@spec build_response(t(), String.t(), keyword()) :: LlmCore.LLM.Response.t()
Builds a Response struct from CLI output, applying any configured normalization.
@spec builtins() :: %{required(atom()) => LlmCore.LLM.CLIProvider.Config.t()}
Returns the legacy built-in map (empty since all defaults moved to TOML).
Use list_all_configs/0 to get all known CLI provider configs.
@spec config(atom()) :: {:ok, LlmCore.LLM.CLIProvider.Config.t()} | {:error, String.t()}
Returns the config for a provider name.
Resolution order:
- Runtime store (TOML-loaded CLI configs)
- Built-in
@builtins - Error
@spec fetch_config(atom() | String.t()) :: {:ok, LlmCore.LLM.CLIProvider.Config.t()} | {:error, :not_found}
Fetches a CLI config by id or alias. Returns a ready-to-use %CLIProvider.Config{}.
@spec from_config(atom() | String.t() | LlmCore.LLM.CLIProvider.Config.t()) :: t()
Creates a CLIProvider from a built-in name, a string id/alias, or a Config struct.
@spec invocation_plan(t(), LlmCore.LLM.Provider.prompt(), keyword()) :: map()
Returns a normalized invocation plan describing how the provider will run.
@spec list_all_configs() :: %{required(atom()) => LlmCore.LLM.CLIProvider.Config.t()}
Returns all known CLI provider configs — runtime (TOML) merged with builtins. Runtime configs override builtins with the same name.
Runs declarative checks proving the CLI surface matches the configured contract.
@spec provider_type(t()) :: :cli
@spec render_prompt(t(), LlmCore.LLM.Provider.prompt(), keyword()) :: String.t()
Renders a prompt after applying any declared inline system-prompt fallback.
Resolves an alias or id string to the canonical provider name atom. Checks runtime definitions first (via Provider.Registry aliases), then builtins.
@spec send(t(), LlmCore.LLM.Provider.prompt(), keyword()) :: {:ok, LlmCore.LLM.Response.t()} | {:error, LlmCore.LLM.Error.t()}
@spec stream(t(), LlmCore.LLM.Provider.prompt(), keyword()) :: {:ok, Enumerable.t()} | {:error, LlmCore.LLM.Error.t()}
Returns whether the provider supports a semantic capability.