> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.conductorquantum.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.conductorquantum.com/_mcp/server.

# stanza.routines.core



## Module Contents

### Classes

| Name | Description |
|------|-------------|
| [`RoutineContext`](#stanzaroutinescoreroutinecontext) | Context object passed to routine functions containing resources and results. |
| [`RoutineRunner`](#stanzaroutinescoreroutinerunner) | Simple runner that executes decorated routine functions with resources and configs. |

### Functions

| Name | Description |
|------|-------------|
| [`routine`](#stanzaroutinescoreroutine) | Decorator to register a function as a routine. |
| [`get_registered_routines`](#stanzaroutinescoreget_registered_routines) | Get all registered routines. |
| [`clear_routine_registry`](#stanzaroutinescoreclear_routine_registry) | Clear all registred routines |

### Data

`logger`
`_routine_registry`

### API

```python
stanza.routines.core.logger
```

**Value**: `getLogger(...)`


```python
stanza.routines.core._routine_registry: dict[str, collections.abc.Callable[..., typing.Any]]
```

**Value**: `None`


```python
class stanza.routines.core.RoutineContext(resources: stanza.registry.ResourceRegistry, results: stanza.registry.ResultsRegistry)
```

Context object passed to routine functions containing resources and results.

### Initialization

Initialize context with resource and results registries.


```python
stanza.routines.core.routine(
    func: collections.abc.Callable[..., typing.Any] | None = None,
    *,
    name: str | None = None
) -> collections.abc.Callable[..., typing.Any]
```

Decorator to register a function as a routine.

The decorated function receives:
- ctx: RoutineContext with ctx.resources and ctx.results
- **params: Merged config and user parameters

Usage:
    @routine
    def my_sweep(ctx, gate, voltages, measure_contact):
        device = ctx.resources.device
        return device.sweep_1d(gate, voltages, measure_contact)

    @routine(name="custom_name")
    def analyze_sweep(ctx, **params):
        # Access previous sweep data
        sweep_data = ctx.results.get("my_sweep")
        if sweep_data:
            voltages, currents = sweep_data
            # Do analysis...
        return analysis_result


```python
stanza.routines.core.get_registered_routines() -> dict[str, collections.abc.Callable[..., typing.Any]]
```

Get all registered routines.


```python
stanza.routines.core.clear_routine_registry() -> None
```

Clear all registred routines


```python
class stanza.routines.core.RoutineRunner(resources: list[typing.Any] | None = None, configs: list[typing.Any] | None = None, base_dir: str | pathlib.Path | None = None)
```

Simple runner that executes decorated routine functions with resources and configs.

Resources can be provided in two ways:
1. Pass initialized resources directly via `resources` parameter
2. Pass configuration objects via `configs` parameter (runner instantiates resources)

When using the `configs` parameter, a DataLogger is automatically created and registered
with name="logger" for convenient logging within routines.

Examples:
    # With initialized resources
    >>> device = Device(name="device", ...)
    >>> logger = DataLogger(name="logger", ...)
    >>> runner = RoutineRunner(resources=[device, logger])

    # With configs (runner creates device + logger automatically)
    >>> device_config = DeviceConfig(...)
    >>> runner = RoutineRunner(configs=[device_config])
    >>> # Now ctx.resources.device and ctx.resources.logger are available

### Initialization

Initialize runner with resources or configs.

**Parameters:**

**Parameters:**

- **resources**: List of resource objects with .name attribute (Device, DataLogger, etc.)
- **configs**: List of configuration objects (DeviceConfig, etc.) to instantiate resources from

**Raises:**

ValueError: If neither resources nor configs provided, or if both provided


```python
_build_resources_from_configs(configs: list[typing.Any]) -> list[stanza.logger.data_logger.DataLogger | typing.Any]
```

Instantiate resources from configuration objects.

**Parameters:**

<ParamField path="configs" type="list[typing.Any]">
  List of configuration objects (e.g., DeviceConfig)
</ParamField>

**Returns:**

List of instantiated resource objects


```python
_extract_routine_configs(configs: list[typing.Any]) -> dict[str, dict[str, typing.Any]]
```

Extract routine parameters from configuration objects (recursive).

**Parameters:**

<ParamField path="configs" type="list[typing.Any]">
  List of configuration objects (e.g., DeviceConfig)
</ParamField>

**Returns:**

Dictionary mapping routine names to their parameters


```python
_extract_from_routine_config(
    routine_config: typing.Any,
    routine_configs: dict[str, dict[str, typing.Any]],
    parent_path: str = ''
) -> None
```

Recursively extract parameters from routine config and its nested routines.

**Parameters:**

<ParamField path="routine_config" type="typing.Any">
  The routine configuration to extract from
</ParamField>

<ParamField path="routine_configs" type="dict[str, dict[str, typing.Any]]">
  Dictionary to store extracted parameters
</ParamField>


```python
_get_routine_path(routine_name: str) -> str
```

Get the full path for a routine including parent hierarhcy.

**Parameters:**

<ParamField path="routine_name" type="str">
  Name of the routine
</ParamField>

**Returns:**

Full path like "health_check/noise_floor_measurement" or just "routine_name" if no parent


```python
_get_parent_params(routine_name: str) -> dict[str, typing.Any]
```

Get merged parameters from all parent routines in the hierarchy.

**Parameters:**

<ParamField path="routine_name" type="str">
  Name of the routine
</ParamField>

**Returns:**

Dictionary of merged parent parameters


```python
run(
    routine_name: str, **params: typing.Any
) -> typing.Any
```

Execute a registered routine.

**Parameters:**

<ParamField path="routine_name" type="str">
  Name of the routine to run
</ParamField>

**Returns:**

Result of the routine


```python
_resolve_base_dir() -> pathlib.Path
```

Resolve logger base directory in priority order.

Priority:
    1. Runner-level override (`base_dir` ctor arg)
    2. Session override/active session
    3. Local ./data fallback when nothing else is configured


```python
_update_logger_base_dir_if_needed() -> None
```

Synchronize the logger base directory if we own it.

We only mutate the logger path when:
    * the runner created the logger (so `_manages_logger_base_dir` is True), or
    * the caller provided an explicit `base_dir` override.

This prevents clobbering user-provided loggers while still keeping runner-created
loggers aligned with session overrides.


```python
run_all(parent_routine: str | list[str] | None = None) -> dict[str, typing.Any]
```

Execute all routines from config in order.

**Parameters:**

<ParamField path="parent_routine" type="str | list[str] | None">
  Optional parent routine name(s). If provided, only run
</ParamField>

**Returns:**

Dictionary mapping routine names to their results


```python
_run_routine_tree(
    routine_config: typing.Any,
    results: dict[str, typing.Any],
    parent_params: dict[str, typing.Any] | None = None
) -> None
```

Recursively run a routine and its nested routines.

**Parameters:**

<ParamField path="routine_config" type="typing.Any">
  The routine configuration to execute
</ParamField>

<ParamField path="results" type="dict[str, typing.Any]">
  Dictionary to store results
</ParamField>

<ParamField path="parent_params" type="dict[str, typing.Any] | None">
  Parameters from parent routine to inherit
</ParamField>


```python
get_result(routine_name: str) -> typing.Any
```

Get stored result from a routine.


```python
list_routines() -> list[str]
```

List all registered routines.


```python
list_results() -> list[str]
```

List all stored results.