## Running


## run.run()


Execute a [RunSpec](running.md#spawnllm.RunSpec) asynchronously, retrying transient failures with backoff.


Usage

``` python
run.run(
    spec,
    *,
    backend=None,
)
```


Each attempt runs through `backend.aexecute`; the core's `retry_decision` op classifies a `Response.error` (a 529, overloaded, rate-limit, or `5xx`) and returns the backoff to sleep before another attempt, up to `spec.max_attempts`. The final [Response](running.md#spawnllm.Response) -- success or last failure -- is returned without raising; every operational failure (nonzero exit, error envelope, timeout, validation) lives in `resp.error`.


#### Parameters


`spec: `<a href="running.html#spawnllm.RunSpec" class="gdls-link gdls-code"><code>RunSpec</code></a>  
The configured run to execute.

`backend: `<a href="backends.html#spawnllm.LlmBackend" class="gdls-link gdls-code"><code>LlmBackend</code></a>` | None = None`  
The backend to run on; defaults to [select_backend()](backends.md#spawnllm.select_backend).


#### Returns


<a href="running.html#spawnllm.Response" class="gdls-link gdls-code"><code>Response</code></a>  
The resolved [Response](running.md#spawnllm.Response) of the last attempt, carrying every retried-away

attempt in `discarded_attempts`.


## run.run_sync()


Execute a [RunSpec](running.md#spawnllm.RunSpec) synchronously, retrying transient failures with backoff.


Usage

``` python
run.run_sync(spec, *, backend=None)
```


The synchronous companion to [run](running.md#spawnllm.run.run): each attempt runs through `backend.execute`, the core decides retry and backoff, and the last [Response](running.md#spawnllm.Response) is returned without raising.


#### Parameters


`spec: `<a href="running.html#spawnllm.RunSpec" class="gdls-link gdls-code"><code>RunSpec</code></a>  
The configured run to execute.

`backend: `<a href="backends.html#spawnllm.LlmBackend" class="gdls-link gdls-code"><code>LlmBackend</code></a>` | None = None`  
The backend to run on; defaults to [select_backend()](backends.md#spawnllm.select_backend).


#### Returns


<a href="running.html#spawnllm.Response" class="gdls-link gdls-code"><code>Response</code></a>  
The resolved [Response](running.md#spawnllm.Response) of the last attempt, carrying every retried-away

attempt in `discarded_attempts`.


## RunSpec


A single configured run, translated per backend at execution time.


Usage

``` python
RunSpec(
    prompt,
    model,
    response_model=None,
    schema=None,
    agent=False,
    isolated=True,
    cwd=None,
    env=None,
    api_auth=False,
    timeout=180,
    max_attempts=5,
    provider_configs=dict()
)
```


Common fields are interpreted by every backend; `provider_configs` carries optional per-provider flag passthrough that only the matching backend reads. `model` is a literal provider model id (`opus`, `sonnet`, …) passed straight through with no tier mapping. `isolated` (default `True`) runs the backend against a fresh, host-free config home so a spawned CLI ignores ambient settings, MCP servers, and hooks. `api_auth` (default `False`) strips the provider's API-key environment variables from the child process so the CLI bills the logged-in subscription; `True` inherits the environment untouched. Structured output comes from either a `response_model` (validated to a model) or a raw `schema` (a JSON-Schema dict or pre-serialized string, passed to the provider verbatim, with nothing to validate); setting both raises `ValueError`.


#### Parameter Attributes


`prompt: str`  

`model: str`  

`response_model: type[BaseModel] | None = None`  

`schema: dict[str, object] | str | None = None`  

`agent: bool = ``False`  

`isolated: bool = ``True`  

`cwd: str | None = None`  

`env: dict[str, str] | None = None`  

`api_auth: bool = ``False`  

`timeout: int = ``180`  

`max_attempts: int = ``5`  

`provider_configs: dict[ProviderName, ProviderConfig] = dict()`    


#### Example

``` python
>>> RunSpec(prompt="ping", model="opus")
```


#### Methods

| Name | Description |
|----|----|
| [config_for()](#spawnllm.RunSpec.config_for) | Return the first provider config that is an instance of `kind`, or None. |


##### config_for()


Return the first provider config that is an instance of `kind`, or None.


Usage

``` python
config_for(kind)
```


## Response


A backend's fully-resolved outcome: the spec, the raw output, and exactly one of result/error.


Usage

``` python
Response(spec, output, result=None, error=None, discarded_attempts=())
```


A backend runs the process, reads its output wherever the provider writes it, detects failure, and validates -- then hands back one [Response](running.md#spawnllm.Response). `spec` and `output` are always present (the raw bytes live in `output.raw` even on failure); exactly one of `result`/`error` is set. Every failure -- a nonzero exit, an error envelope, a timeout, or a validation error -- routes through `error`, never a raise from [run](running.md#spawnllm.run.run). `discarded_attempts` carries the transient failures [run](running.md#spawnllm.run.run) retried away before this one, empty when there were none.


#### Parameter Attributes


`spec: `<a href="running.html#spawnllm.RunSpec" class="gdls-link gdls-code"><code>RunSpec</code></a>  

`output: `<a href="running.html#spawnllm.Output" class="gdls-link gdls-code"><code>Output</code></a>  

`result: `<a href="running.html#spawnllm.Result" class="gdls-link gdls-code"><code>Result</code></a>` | None = None`  

`error: `<a href="running.html#spawnllm.Error" class="gdls-link gdls-code"><code>Error</code></a>` | None = None`  

`discarded_attempts: tuple[`<a href="running.html#spawnllm.DiscardedAttempt" class="gdls-link gdls-code"><code>DiscardedAttempt</code></a>`, …] = ()`    


#### Example

``` python
>>> Response(spec=spec, output=Output(raw="hi"), result=Result(raw="hi"))
```


## Result


A successful run: the extracted final text and the optional validated model.


Usage

``` python
Result(raw, parsed=None)
```


`raw` is the extracted final text; `parsed` is the validated model, set only when the [RunSpec](running.md#spawnllm.RunSpec) carried a `response_model`.


#### Parameter Attributes


`raw: str`  

`parsed: BaseModel | None = None`  


#### Example

``` python
>>> Result(raw="hello", parsed=None)
```


## Output


The full unparsed transport stream, present on success and failure alike.


Usage

``` python
Output(raw)
```


`raw` is the complete output the provider wrote -- the `claude --output-format json` event stream, the `codex -o` file, or plain stdout -- before any extraction.


#### Parameter Attributes


`raw: str`  


#### Example

``` python
>>> Output(raw='[{"type": "system"}, {"type": "result", "result": "hi"}]')
```


## Error


A failed run: a human-readable message plus the underlying exception.


Usage

``` python
Error(msg, ex)
```


`ex` preserves the real exception so a caller can re-raise it unchanged -- a `BackendCallError` for a nonzero exit or error envelope, a normalized timeout error, or a `pydantic.ValidationError` for a non-conforming model.


#### Parameter Attributes


`msg: str`  

`ex: Exception`  


#### Example

``` python
>>> Error(msg="codex exited 127: codex: not found", ex=RuntimeError("..."))
```


## DiscardedAttempt


A transient failure the retry loop threw away, summarized for spend accounting.


Usage

``` python
DiscardedAttempt(attempt, error, cost_usd, usage, raw_bytes)
```


[run](running.md#spawnllm.run.run)/[run_sync](running.md#spawnllm.run.run_sync) return only the final attempt's [Response](running.md#spawnllm.Response), so a caller tracking spend never sees the cost of the retries that preceded it. Each discarded attempt is summarized here: `cost_usd` and `usage` when the attempt's output carried parseable accounting, else `None`; `raw_bytes` is always the UTF-8 byte length of the discarded output. `attempt` is the zero-based index and `error` the discarded exception's class name.


#### Parameter Attributes


`attempt: int`  

`error: str`  

`cost_usd: float | None`  

`usage: dict[str, object] | None`  

`raw_bytes: int`  


#### Example

``` python
>>> DiscardedAttempt(attempt=0, error="BackendCallError", cost_usd=0.02, usage=None, raw_bytes=57)
```


## AppleConfig


Apple Foundation Models knobs applied only by the Apple backend.


Usage

``` python
AppleConfig(
    use_case="general",
    guardrails="default",
    instructions=None,
    temperature=None,
    maximum_response_tokens=None,
    sampling=None,
    sampling_top=None,
    sampling_probability_threshold=None,
    sampling_seed=None
)
```


`use_case` and `guardrails` select the `SystemLanguageModelUseCase` and `SystemLanguageModelGuardrails` the `spawnllm-apple` sidecar builds its session with. The sampling knobs are flat rather than a nested mode because Apple exposes `SamplingMode` as a factory (`greedy()` / `random()`) that no serializable value can carry: `sampling` picks the factory and `sampling_top`, `sampling_probability_threshold`, and `sampling_seed` are the arguments `random` takes. `None` everywhere leaves the framework default.


#### Parameter Attributes


`use_case: Literal[``"general", `<span class="st">`"content_tagging"``]`</span>` = ``"general"`  

`guardrails: Literal[``"default", `<span class="st">`"permissive_content_transformations"``]`</span>` = ``"default"`  

`instructions: str | None = None`  

`temperature: float | None = None`  

`maximum_response_tokens: int | None = None`  

`sampling: Literal[``"greedy", `<span class="st">`"random"``] | None`</span>` = None`  

`sampling_top: int | None = None`  

`sampling_probability_threshold: float | None = None`  

`sampling_seed: int | None = None`  


#### Example

``` python
>>> AppleConfig(use_case="content_tagging", sampling="random", sampling_top=20)
```


#### Raises


`ValueError`  
When a `random`-only argument is set without `sampling="random"`, a combination the framework would silently discard; when `sampling_top` and `sampling_probability_threshold` are set together, a pair the framework rejects; or when `sampling_seed` is negative, which the framework's `UInt64` cannot carry.


## ClaudeConfig


Claude CLI flag passthrough applied only by the Claude backend.


Usage

``` python
ClaudeConfig(
    permission_mode=None,
    mcp_config=None,
    strict_mcp=False,
    append_system_prompt=None,
    system_prompt=None,
    settings=None,
    disallowed_tools=(),
    max_turns=None,
    max_budget_usd=None,
    tools=None,
    disable_slash_commands=False,
    output_format=None,
    verbose=False
)
```


Fields map one-to-one onto `claude` flags: the agent/system-prompt knobs (`permission_mode`, `mcp_config`, `strict_mcp`, `append_system_prompt`, `system_prompt`, `settings`, `disallowed_tools`) and orthogonal extras (`max_turns`, `max_budget_usd`, `tools`, `disable_slash_commands`, `output_format`, `verbose`). `tools` selects the built-in toolset: `None` keeps the CLI default, `()` disables every built-in tool, and names restrict the session to those tools.


#### Parameter Attributes


`permission_mode: str | None = None`  

`mcp_config: str | None = None`  

`strict_mcp: bool = ``False`  

`append_system_prompt: str | None = None`  

`system_prompt: str | None = None`  

`settings: str | None = None`  

`disallowed_tools: tuple[str, …] = ()`    

`max_turns: int | None = None`  

`max_budget_usd: float | None = None`  

`tools: tuple[str, …] | None = None`  

`disable_slash_commands: bool = ``False`  

`output_format: str | None = None`  

`verbose: bool = ``False`  


#### Example

``` python
>>> ClaudeConfig(permission_mode="bypassPermissions", strict_mcp=True)
>>> ClaudeConfig(tools=())  # bare session: no built-in tools
```


## CodexConfig


Codex CLI knobs applied only by the Codex backend.


Usage

``` python
CodexConfig(
    sandbox=None,
    enable_hooks=False,
    enable_mcp=False,
    service_tier="fast",
    developer_instructions=None
)
```


`service_tier` (default `"fast"`) is emitted as `-c service_tier=<value>` on every invocation, isolated or not: isolated runs pass `--ignore-user-config`, which drops a `service_tier` pin in the user's `~/.codex/config.toml`, and the standard tier turns long prompts into multi-minute runs. Set it to `None` to drop the flag; an isolated run still passes `--ignore-user-config`, so a user-level tier pin applies only with `isolated=False`. `developer_instructions` injects the system-prompt layer via `-c developer_instructions=<value>`, serialized as a TOML string so any text -- multi-line, or TOML-ambiguous words like `true` -- arrives as a string.


#### Parameter Attributes


`sandbox: str | None = None`  

`enable_hooks: bool = ``False`  

`enable_mcp: bool = ``False`  

`service_tier: str | None = ``"fast"`  

`developer_instructions: str | None = None`  


#### Example

``` python
>>> CodexConfig(sandbox="read-only", enable_mcp=True)
```


## GeminiConfig


Gemini CLI knobs applied only by the Gemini and Antigravity backends.


Usage

``` python
GeminiConfig(approval_mode=None, extensions=None)
```


#### Parameter Attributes


`approval_mode: str | None = None`  

`extensions: tuple[str, …] | None = None`  


#### Example

``` python
>>> GeminiConfig(approval_mode="auto", extensions=("search",))
```
