Simon Willison has released llm 0.33, an update to the open-source command-line tool and Python library for interacting with large language models. The release introduces template composition, stateless per-call embedding credentials, and server-side tool execution visibility in logs, alongside an upgrade to the OpenAI Python 3.x client and httpx2.
Template Composition and Parameter Decoupling
The primary workflow enhancement in version 0.33 is the ability to repeat the -t or --template flag to chain multiple templates in execution order. This allows developers to decouple model configurations and inference hyperparameters from prompt content.
Previously, combining model settings such as reasoning effort with distinct prompt templates required duplicate definitions or manual flag overrides. Under the new chaining pattern, developers can define a reusable configuration template:
llm -m gpt-5.6-luna -o reasoning_effort high --save reasoning-config
llm "Generate an SVG diagram of a neural network layer" --save svg-diagram
llm -t reasoning-config -t svg-diagramWhen evaluated, the CLI resolves options and system configurations sequentially, merging runtime parameters before injecting the final prompt template.

Per-Invocation Embedding Credentials
To address concurrency issues in multi-tenant or multi-key workflows, llm embed and llm embed-multi now accept an explicit --key CLI option.
In the Python API, the key= parameter has been added across core embedding methods:
EmbeddingModel.embed()EmbeddingModel.embed_multi()Collection.embed()Collection.embed_multi()
Passing credentials directly to invocation methods routes the resolved key to underlying embedding plugins without mutating shared model instance state. Plugins relying on the legacy self.key property continue to function via a backwards-compatibility fallback.
Server-Side Tool Execution and Reasoning Stream Preservation
For models supporting server-side tool execution, llm logs now displays tool outputs in a dedicated Tool results section within the recorded response. In structured output modes (--json and --short), these entries include a server_executed boolean flag to differentiate server-run operations from local tool calls.
The release also refines handling of reasoning model streams. Provider stream chunks that carry metadata without text tokens are now stored as ReasoningPart objects. This preserves opaque cryptographic signatures and redacted reasoning blocks from providers such as Anthropic during round-trip serialization.
Additionally, models accessed through OpenAI-compatible Responses API endpoints gain support for a reasoning_summary configuration parameter with auto, concise, and detailed settings.
Validation and Schema Error Handling
Version 0.33 adds stricter pre-flight validation across conversation and structured output pipelines:
- Attachment validation: Conversation prompts now verify that attached assets (such as images or documents) are supported by the selected model architecture before dispatching requests across both synchronous and asynchronous execution paths.
- Schema DSL errors: The
schema_dsl()parser now raises explicitValueErrorexceptions when encountering duplicate field identifiers or unrecognized data types, replacing prior behavior that silently coerced invalid types to strings. - Collection defaults:
llm embed-multiautomatically reuses an existing collection's configured embedding model when no default model is globally specified.



