@action and register_action
An action is a Python function decorated with @action that a Colang flow runs with execute; register_action attaches it to an LLMRails object so the flow can find it.
Last updated: 30 Sep, 2026 · NeMo Guardrails 0.24.1
Every rail so far asked a model. Some checks need no model: an email address or an API token has a shape a regular expression can find. The video writes those checks as Python actions.
Syntax:
@action(is_system_action=True) # mark the function as an action
async def detect_pii_in_input(context=None):
... # return anything the flow can test
rails.register_action(detect_pii_in_input) # the flow calls it by this nameThe PII action from the video
The video's detect_pii_in_input, unchanged: five patterns, and the list of the ones found. An empty list means clean, and is falsy in the flow. Save it as actions.py.
import re
from typing import Optional
from nemoguardrails.actions import action
@action(is_system_action=True)
async def detect_pii_in_input(context: Optional[dict] = None):
"""Returns list of PII types found, or empty list (falsy) if clean."""
user_message = context.get("user_message", "") if context else ""
patterns = {
"email": r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b",
"phone": r"\b(\+\d{1,2}\s?)?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}\b",
"ssn": r"\b\d{3}-\d{2}-\d{4}\b",
"api_key": r"(api[_\s-]?key|token|secret)[:\s]+[A-Za-z0-9_\-]{10,}",
"credit_card": r"\b\d{4}[\s-]\d{4}[\s-]\d{4}[\s-]\d{4}\b",
}
found = [ptype for ptype, pat in patterns.items()
if re.search(pat, user_message, re.IGNORECASE)]
return found # empty list = no PII = falsyThe flow that calls it
$pii_found = execute detect_pii_in_input runs the action and keeps its result. The if reads it like Python.
define bot ask to remove pii
"I noticed your message may contain sensitive information (email, phone, API key, etc.). Please remove any personal or secret data before sending — I don't store sensitive details!"
define flow check input for pii
$pii_found = execute detect_pii_in_input
if $pii_found
bot ask to remove pii
stopRunning it on every message
rails:
input:
flows:
- check input for piiView 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:
- check input for pii
The video's PII messages
from actions import detect_pii_in_input
from nemoguardrails import LLMRails, RailsConfig
rails = LLMRails(RailsConfig.from_path("."))
rails.register_action(detect_pii_in_input)
def chat(message):
reply = rails.generate(messages=[{"role": "user", "content": message}])
print("User:", message)
print("Bot :", reply["content"])
chat("My email is john.doe@company.com, help me set up Kubernetes RBAC")
chat("My API token is token:xK9mL3vQ2nR8pT5w, is this safe in a ConfigMap?")
chat("How do I set up Kubernetes RBAC?")User: My email is john.doe@company.com, help me set up Kubernetes RBAC Bot : I noticed your message may contain sensitive information (email, phone, API key, etc.). Please remove any personal or secret data before sending — I don't store sensitive details! User: My API token is token:xK9mL3vQ2nR8pT5w, is this safe in a ConfigMap? Bot : I noticed your message may contain sensitive information (email, phone, API key, etc.). Please remove any personal or secret data before sending — I don't store sensitive details! User: How do I set up Kubernetes RBAC? Bot : Create a Role (or ClusterRole) that lists the allowed API verbs and resources, then attach it to a user, group, or ServiceAccount with a RoleBinding (or ClusterRoleBinding). This grants the specified permissions within the defined namespace (or cluster‑wide).
What the action did
- The email and the API token were refused by your own words, and no model was called for them: the action ran, the flow stopped.
- The clean question passed the check and went on to the model.
- register_action(detect_pii_in_input) used the function's name, which is the name the flow calls.
The video writes its messages with a long dash after the email address; this page uses a comma. The pattern matches either way.
A regex action vs a self-check rail
| Regex action | self check input | |
|---|---|---|
| Cost | No model call | One model call |
| Catches | Exact shapes: email, SSN, tokens | Meaning: jailbreaks, provider questions |
| Misses | Anything not in a pattern | May miss an exact token |
Where you write actions
- Personal data, lengths and formats, before any model call.
- Lookups in your own systems, as the Execution rails lesson does with tickets.
async. The runtime awaits them, so a slow call inside, such as an HTTP request to a moderation service, belongs there; a blocking time.sleep or a sync client stalls every conversation.Related
- Previous: Finding the rail that fired
- Next: Action parameters
- Reference: Creating actions
- Send the video's My SSN number is 123-45-6789 and check which pattern found it.
- Remove the
register_actionline and read the reply.
Slow is fine. Stopping is the only problem.