# Understanding the @contract Decorator in SymbolicAI: Design-by-Contract for Neuro-Symbolic AI

> Explore the @contract decorator in SymbolicAI for robust Design-by-Contract. It adds type validation, checks conditions, and uses LLMs for automatic remediation, enhancing neuro-symbolic AI reliability.

- Repository: [ExtensityAI/symbolicai](https://github.com/extensityai/symbolicai)
- Tags: how-to-guide
- Published: 2026-03-01

---

**The `@contract` decorator in SymbolicAI enforces Design-by-Contract (DbC) principles on `Expression` classes by wrapping the `forward` method with automatic type validation, pre/post-condition checks, and LLM-driven remediation retries.**

The `@contract` decorator is a core component of the [SymbolicAI](https://github.com/extensityai/symbolicai) framework, implementing Design-by-Contract for neuro-symbolic applications. Applied to classes inheriting from `symai.Expression`, it automatically validates inputs and outputs against `LLMDataModel` schemas and attempts autonomous remediation when validation fails, significantly improving reliability when underlying language models produce unexpected outputs.

## What Is the @contract Decorator in SymbolicAI?

The `@contract` decorator is defined in [`symai/strategy.py`](https://github.com/extensityai/symbolicai/blob/main/symai/strategy.py) and serves as a class-level decorator that transforms `Expression` subclasses into self-validating components. When applied, it intercepts the `forward` method and injects a validation-and-remediation pipeline that ensures data integrity before and after the core logic executes.

According to the SymbolicAI source code, the decorator specifically targets the `forward` method because this is the standard entry point for all `Expression` subclasses. By wrapping this method, `@contract` can enforce type safety, run pre-conditions, validate post-conditions, and trigger automatic retries without modifying the underlying business logic.

## How the Contract Decorator Works Under the Hood

The implementation in [`symai/strategy.py`](https://github.com/extensityai/symbolicai/blob/main/symai/strategy.py) reveals a sophisticated pipeline that handles validation at multiple stages. The decorator creates a `TypeValidationFunction` instance that orchestrates the entire flow.

### Type Safety Enforcement

The decorator enforces that all inputs and outputs conform to `LLMDataModel` subclasses or valid Python types. The helper functions `_is_valid_input` and `_is_valid_output` perform these checks at runtime【`symai/strategy.py#L30-L55`](https://github.com/extensityai/symbolicai/blob/main/symai/strategy.py#L30-L55).

When a type mismatch occurs, the decorator attempts to coerce the data into the expected schema using the configured LLM engine. This dynamic wrapping ensures that even raw strings or dictionaries can be validated against strict Pydantic-based models.

### Pre-Condition Validation and Remediation

Before executing the `forward` method, the decorator checks for a `pre` method on the class. If `pre_remedy=True` is passed to the decorator, validation failures trigger an LLM-driven remediation attempt to correct the input【`symai/strategy.py#L12-L28`](https://github.com/extensityai/symbolicai/blob/main/symai/strategy.py#L12-L28).

The `pre` method receives the input instance and returns a boolean. If it raises an exception or returns `False`, the remediation pipeline attempts to fix the input using the LLM before retrying the validation.

### Post-Condition Validation and Remediation

After the `forward` method completes, the decorator checks for a `post` method to validate the output. With `post_remedy=True`, failures here also trigger LLM-based fixes【`symai/strategy.py#L14-L30`](https://github.com/extensityai/symbolicai/blob/main/symai/strategy.py#L14-L30).

This two-stage validation ensures that both inputs and outputs maintain semantic consistency with the declared data models, catching hallucinations or format violations immediately after generation.

### Automatic Retry Logic with remedy_retry_params

The decorator accepts a `remedy_retry_params` dictionary that configures exponential backoff and retry behavior for validation failures. These parameters control the number of attempts, delay timing, jitter, and whether failures are swallowed gracefully【`symai/strategy.py#L94-L102`](https://github.com/extensityai/symbolicai/blob/main/symai/strategy.py#L94-L102).

Available parameters include:
- `tries`: Maximum number of remediation attempts
- `delay`: Initial delay between retries
- `max_delay`: Cap on delay growth
- `jitter`: Random variation to prevent thundering herd
- `backoff`: Exponential multiplier
- `graceful`: Whether to suppress exceptions after exhaustion

### Performance Monitoring and State Tracking

The decorator automatically instruments each validation stage, storing timing metrics in `self._contract_timing`. This dictionary contains durations for `input_validation`, `act` (forward execution), and `output_validation`【`symai/strategy.py#L38-L40`](https://github.com/extensityai/symbolicai/blob/main/symai/strategy.py#L38-L40).

After execution, the instance receives state flags:
- `contract_successful`: Boolean indicating overall validation success
- `contract_result`: The final returned value
- `contract_exception`: Captured exception if validation failed and graceful mode is off【`symai/strategy.py#L31-L33`](https://github.com/extensityai/symbolicai/blob/main/symai/strategy.py#L31-L33)

## Practical Implementation: Using @contract in SymbolicAI

Implementing the `@contract` decorator requires inheriting from `Expression` and defining data models that extend `LLMDataModel`.

### Basic Contract-Decorated Expression

The following example demonstrates a complete implementation with input and output validation:

```python
from symai import Expression
from symai.strategy import contract
from symai.models import LLMDataModel
from pydantic import Field
from typing import Optional

class GreetingInput(LLMDataModel):
    name: str = Field(description="Name of the person to greet.")
    shout: Optional[bool] = Field(default=False, description="Whether to uppercase the greeting.")

class GreetingOutput(LLMDataModel):
    message: str = Field(description="The final greeting string.")

@contract(pre_remedy=True, post_remedy=True)
class Greeter(Expression):
    @property
    def prompt(self) -> str:
        return "Create a friendly greeting based on the given input."

    def pre(self, input: GreetingInput) -> bool:
        if not input.name.strip():
            raise ValueError("Name cannot be empty.")
        return True

    def forward(self, input: GreetingInput) -> GreetingOutput:
        text = f"Hello, {input.name}"
        if input.shout:
            text = text.upper()
        return GreetingOutput(message=text)

```

When instantiated and called, this class automatically validates that inputs conform to `GreetingInput`, runs the `pre` check, executes `forward`, validates the output against `GreetingOutput`, and attempts LLM-driven fixes if any stage fails.

### Configuring Custom Retry Parameters

For production workloads requiring resilient validation, configure the retry behavior explicitly:

```python
@contract(
    pre_remedy=True,
    post_remedy=True,
    remedy_retry_params={
        "tries": 4,
        "delay": 0.3,
        "max_delay": 5,
        "jitter": 0.1,
        "backoff": 2,
        "graceful": False,
    },
)
class RobustGreeter(Expression):
    ...

```

These parameters are passed directly to the `TypeValidationFunction` class, implementing exponential backoff with jitter to handle transient LLM failures during remediation.

### Inspecting Contract Execution Metrics

After execution, inspect the contract state and timing information:

```python
greeter = Greeter()
result = greeter(GreetingInput(name="Alice"))

print(greeter.contract_successful)      # Boolean: True if all validations passed

print(greeter._contract_timing)        # Dict with stage durations

print(greeter.contract_result)         # Final returned value

if hasattr(greeter, 'contract_exception'):
    print(greeter.contract_exception)  # Captured error if not graceful

```

The `_contract_timing` dictionary contains granular performance data for `input_validation`, `act` (the forward pass), and `output_validation`, enabling bottleneck analysis in production pipelines.

## Key Source Files for the Contract Decorator

Understanding the `@contract` implementation requires familiarity with three primary locations in the SymbolicAI repository:

- **[`symai/strategy.py`](https://github.com/extensityai/symbolicai/blob/main/symai/strategy.py)** — Contains the `contract` class decorator definition, `TypeValidationFunction` orchestration, validation helpers (`_is_valid_input`, `_is_valid_output`), and retry logic【`symai/strategy.py#L12-L102`](https://github.com/extensityai/symbolicai/blob/main/symai/strategy.py).

- **[`docs/source/FEATURES/contracts.md`](https://github.com/extensityai/symbolicai/blob/main/docs/source/FEATURES/contracts.md)** — Provides the human-readable specification, parameter tables, and architectural diagrams for the contract system.

- **[`tests/contract/test_contract.py`](https://github.com/extensityai/symbolicai/blob/main/tests/contract/test_contract.py)** — Contains the comprehensive test suite validating pre-remedy paths, post-remedy failures, retry exhaustion, and graceful error handling.

## Summary

The `@contract` decorator in SymbolicAI provides robust Design-by-Contract capabilities for neuro-symbolic applications:

- **Automatic type validation** ensures all inputs and outputs conform to `LLMDataModel` schemas, with dynamic coercion attempts for mismatched types.
- **Pre-condition and post-condition hooks** allow custom validation logic via `pre` and `post` methods, with optional LLM-driven remediation when checks fail.
- **Configurable retry mechanisms** via `remedy_retry_params` support exponential backoff, jitter, and graceful degradation for production resilience.
- **Built-in instrumentation** captures detailed timing metrics and success states, enabling performance monitoring and debugging of validation pipelines.

## Frequently Asked Questions

### What happens when a pre-condition fails and pre_remedy is enabled?

When the `pre` method raises an exception or returns `False` and `pre_remedy=True`, the decorator invokes the LLM to generate a corrected input that satisfies the contract. This remediation attempt follows the `remedy_retry_params` configuration, potentially executing multiple LLM calls with exponential backoff until validation succeeds or retries are exhausted.

### Can I use @contract without LLMDataModel types?

While the decorator is optimized for `LLMDataModel` subclasses, it can validate standard Python types through dynamic wrapping. However, the full remediation capabilities and strict schema validation require Pydantic-based `LLMDataModel` definitions to provide the necessary structure for the LLM to understand and correct violations.

### How do I disable retries for contract violations?

Set `remedy_retry_params={"tries": 1, "graceful": True}` to execute exactly one attempt without retries, or set `pre_remedy=False` and `post_remedy=False` to disable remediation entirely. In this configuration, validation failures immediately raise exceptions or set `contract_successful` to `False` depending on the `graceful` parameter.

### Where can I find examples of @contract usage in the test suite?

The [`tests/contract/test_contract.py`](https://github.com/extensityai/symbolicai/blob/main/tests/contract/test_contract.py) file contains comprehensive examples demonstrating pre-remedy validation failures, post-remedy output correction, retry exhaustion scenarios, and graceful error handling. These tests illustrate how the decorator interacts with the `TypeValidationFunction` and validate the timing metrics collected in `_contract_timing`.