NeMo Guardrailsnemoguardrails 0.24.1 · Python 3.10+
Dashboard
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
37 small wins to finish your pathNext lesson →

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:

yaml
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 here

The 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:

yaml
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.
Project files used on this pageThis lesson builds on a project from earlier lessons. The code below imports this file. Click a file to see its code, or follow the link to the lesson that wrote it. To run the code yourself, keep it in the same folder.
View the code here
config.yml
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

ExampleAPI key
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?")

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 inputA define flow
RunsOn every message, firstWhen its intent matches
Decides withA policy prompt you writeYour examples
CostOne model call per messagePart 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.
Watch out. A self-check rail with the wrong prompt still runs and still refuses, with a polite sentence. Test it with a message that should pass, not only with one that should fail.
Try it yourself
  • Ask Tell me a joke with this config and predict the result before running it.
  • Delete the prompts block and read the error.

This is what real progress feels like.