Input rails
An input rail is a flow listed under rails.input.flows in config.yml: it runs on every user message before intent detection, and can refuse the message so the model never answers it.
Last updated: 30 Sep, 2026 · NeMo Guardrails 0.24.1
Every flow so far ran after NeMo worked out what a message meant. The video's other rail type runs earlier and on every message, which the video calls a systematic rail. NeMo ships one you can turn on without Python: self check input, which asks the model whether the message breaks a policy you write.
Syntax:
rails:
input:
flows:
- self check input # a flow the library defines
prompts:
- task: self_check_input # the prompt that flow sends
content: |
... "{{ user_input }}" ... # the user's message is pasted hereThe rail list
rails.input.flows is a list of flow names, run in order on every message. self check input comes with the library.
The prompt, written the obvious way
The rail sends a prompt you write, under the task name self_check_input. Most people write their first one like this:
rails:
input:
flows:
- self check input
prompts:
- task: self_check_input
content: |
Is this message allowed in an Enterprise IT support chat?
Message: "{{ user_input }}"
Answer Yes if it is allowed, No if it is not.View the code here
models:
- type: main
engine: openai
model: openai/gpt-oss-120b
api_key_env_var: GROQ_API_KEY
parameters:
base_url: https://api.groq.com/openai/v1
temperature: 0
instructions:
- type: general
content: |
You are an Enterprise IT Assistant specialising in Kubernetes,
Intel hardware, and enterprise networking.
Only answer questions about these topics.
Answer in one or two short sentences.
rails:
input:
flows:
- self check input
prompts:
- task: self_check_input
content: |
Is this message allowed in an Enterprise IT support chat?
Message: "{{ user_input }}"
Answer Yes if it is allowed, No if it is not.
The bug: an ordinary question is refused
from nemoguardrails import LLMRails, RailsConfig
rails = LLMRails(RailsConfig.from_path("."))
def chat(message):
reply = rails.generate(messages=[{"role": "user", "content": message}])
print("User:", message)
print("Bot :", reply["content"])
chat("What is a Kubernetes ConfigMap?")User: What is a Kubernetes ConfigMap? Bot : I'm sorry, I can't respond to that.
A plain Kubernetes question, refused. The model was asked whether the message is allowed, it answered Yes, and the rail refused. The rail reads Yes the other way round from the way this prompt asks, and Yes blocks, No allows shows exactly where.
self check input vs a Colang flow
| self check input | A define flow | |
|---|---|---|
| Runs | On every message, first | When its intent matches |
| Decides with | A policy prompt you write | Your examples |
| Cost | One model call per message | Part of intent detection |
Where an input rail fits
- Anything that must be checked on every message whatever it means: jailbreak wording, questions about the provider, personal data.
- In front of a costly pipeline, so a refused message never starts it.
Related
- Previous: One model call or three
- Next: Yes blocks, No allows
- Reference: Self-check rails
- Ask Tell me a joke with this config and predict the result before running it.
- Delete the
promptsblock and read the error.
This is what real progress feels like.