---
title: "Guardrail extensions"
manual: "LLM Foundation"
version: "main"
permalink: "https://docs.typo3.org/permalink/netresearch/nr-llm:api-guardrails@main"
source: "Api/Guardrails.rst"
rendered: "2026-11-12T15:41:35+00:00"
---

# Guardrail extensions {#api-guardrails}

Input and output checks are separate public extension points in
`Netresearch\NrLlm\Service\Guardrail`. Both inherit `GuardrailIdentity`:
`getIdentifier(): string` is a stable logical policy name and
`isMandatory(): bool` declares whether configurations may omit it.
The registry resolves mandatory status per identifier and refuses mismatched
input/output declarations. Renaming an identifier changes stored policy.

-   **`InputGuardrailInterface::checkInput(string $text): GuardrailResult`**

    Runs on outgoing message text before provider dispatch. Its
    `nr_llm.input_guardrail` autoconfiguration tag registers the check.

-   **`GuardrailInterface::checkOutput(CompletionResponse $response): GuardrailResult`**

    Runs on buffered provider output through `nr_llm.guardrail`. Output-only
    checks cannot inspect the original prompt through pipeline context.

## Minimal application policy {#api-guardrails-example}

Use separate input and output services: the interfaces have different
`TAG_NAME` constants. Their shared identifier links the policy.
This example blocks an explicit application marker. It illustrates registration
and return types; it is not a detector for all secret or harmful content.

**Separate input and output services with one policy identity**

```php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Guardrail;

use Netresearch\NrLlm\Domain\Model\CompletionResponse;
use Netresearch\NrLlm\Domain\ValueObject\GuardrailResult;
use Netresearch\NrLlm\Service\Guardrail\GuardrailInterface;
use Netresearch\NrLlm\Service\Guardrail\InputGuardrailInterface;

final class PublicationInputMarker implements InputGuardrailInterface
{
    public function getIdentifier(): string
    {
        return 'myext-publication-marker';
    }

    public function isMandatory(): bool
    {
        return false;
    }

    public function checkInput(string $text): GuardrailResult
    {
        return str_contains($text, 'DO_NOT_SEND')
            ? GuardrailResult::deny('Application marker present.')
            : GuardrailResult::allow();
    }

}

final class PublicationOutputMarker implements GuardrailInterface
{
    public function getIdentifier(): string
    {
        return 'myext-publication-marker';
    }

    public function isMandatory(): bool
    {
        return false;
    }

    public function checkOutput(CompletionResponse $response): GuardrailResult
    {
        return str_contains($response->content, 'DO_NOT_PUBLISH')
            ? GuardrailResult::deny('Application marker present.')
            : GuardrailResult::allow();
    }
}
```

## Verdicts and limits {#api-guardrails-verdicts}

`GuardrailResult` provides `allow()`, \``redact($text, $reason,
$thinking = null)``, ``deny($reason)``, ``retry($reason)`\` and
`requireApproval($reason)`. Input redaction replaces message text;
input retry has no useful pre-provider action and is ignored. Output checks
can request a bounded retry through the runtime policy.

Deny and approval-required verdicts become typed guardrail policy exceptions.
They do not by themselves create a resumable human-approval workflow. In a
persisted agent run that path settles to `FAILED` with the policy reason;
tool approvals are the separate [Persisted agent runtime](https://docs.typo3.org/permalink/netresearch/nr-llm:api-agent-runtime@main) lifecycle.
A paid output can therefore be withheld after the provider call succeeded.

For configuration/site-sensitive output policy implement
`ContextualGuardrailInterface::checkOutputInContext($response, $context)`
and `holdsStream($context)`. A held stream is screened as a whole before
release; do not assume every visible live token has passed final output checks.
Streaming redaction has its separate `StreamRedactableInterface` contract.

Text screening does not inspect every image byte, remote-tool side effect or
value ultimately written by a tool. Tool authorization, approval, input
validation and contextual output escaping remain separate responsibilities.
See [Effective policy](https://docs.typo3.org/permalink/netresearch/nr-llm:administration-governance@main) and [Tools, languages and workspaces](https://docs.typo3.org/permalink/netresearch/nr-llm:tool-workspaces@main).
