Colang
Colang is the modeling language of NeMo Guardrails, in which you write what users say, what the bot says and the flows that connect the two.
Last updated: 09 Oct, 2026 · NeMo Guardrails 0.24
NeMo Guardrails pasted a topic guard into the config and ran it. This page reads that rail one block at a time, so you can write your own.
This part of the video starts at 0:39:44. Colang sits between natural language and a programming language: it is neither of the two, and a mixture of both. The board shows the extension of a Colang file, .co. The NeMo runtime is what reads a .co file; the model only sees the prompts NeMo builds from it.
Writing a rail in three blocks
This part of the video starts at 0:42:08. A rail is added in one fixed format. You define a user who goes off topic and list the ways, in the video "how to make a coffee", "tell me a joke" and "tell me about this movie". You define a bot and what it says. Then you define a flow: if the user goes off topic, the bot gives its off-topic reply, which the video compares to an if-else condition. The words after define user and define bot are names you choose; Colang keeps the word variable for names that start with $.
define user: an intent and its examples
define user names a user intent and lists example messages for it, one per line, indented by two spaces. The words after define user are a name you choose. NeMo calls it the canonical form of the message.
define user ask off topic
"tell me a joke"
"what is the capital of france"
"write me a poem"The examples are samples of a meaning, not a list of exact strings to match. A message that says the same thing in other words can still get this intent.
define bot: the exact words
define bot names a bot message and gives its text. When a flow reaches this name, the text is sent word for word, with no model call to write it.
define bot refuse off topic
"I'm an Enterprise IT Assistant focused on Kubernetes, Intel hardware, and networking. I can't help with that — but ask me anything technical!"define flow: what follows what
define flow names a sequence. This one reads: when the user's intent is ask off topic, the bot says refuse off topic, then the flow stops. The flow's own name, handle off topic, is also a label you choose.
define flow handle off topic
user ask off topic
bot refuse off topic
stopThese three blocks are the core of Colang 1.0. The language also has define subflow, execute to run an action, if and else, when, stop and variables that start with $.
This part of the video starts at 0:45:39. The Colang of the demo app is on screen. It defines a user who can ask off topic, with examples such as "who won the game yesterday" and "what is 2 plus 2". It defines how the bot refuses. The flow, named handle off topic, says: if the user asks off topic, the bot refuses off topic, and stop.
Loading the Colang and listing what it defines
RailsConfig.from_content parses Colang from a string. Parsing calls no model and needs no key, so this is a quick way to check a rail before running it. The Colang below is the full rail from the video's repo.
from nemoguardrails import RailsConfig
TOPIC = '''
define user ask off topic
"tell me a joke"
"what is the capital of france"
"write me a poem"
"what is 2 plus 2"
"what should I eat for dinner"
"who won the game yesterday"
"recommend a movie"
"what is the weather like"
define bot refuse off topic
"I'm an Enterprise IT Assistant focused on Kubernetes, Intel hardware, and networking. I can't help with that — but ask me anything technical!"
define flow handle off topic
user ask off topic
bot refuse off topic
stop
'''
config = RailsConfig.from_content(colang_content=TOPIC)
print("Colang version:", config.colang_version)
for name, examples in config.user_messages.items():
print("user intent:", name, "|", len(examples), "examples")
for name, texts in config.bot_messages.items():
print("bot message:", name, "|", len(texts), "text")
for flow in config.flows:
steps = [step.get("intent_name") or step["action_params"]["value"] for step in flow["elements"]]
print("flow:", flow["id"], "|", steps)Colang version: 1.0 user intent: ask off topic | 8 examples bot message: refuse off topic | 1 text flow: handle off topic | ['ask off topic', 'refuse off topic', 'stop']
What the parser found
- Colang version 1.0. No YAML was given, so the default applies.
- One user intent with 8 examples,
ask off topic, and one bot message with one text,refuse off topic. - One flow with three steps, in order: the user intent, the bot message,
stop. The parser stored the names only; nothing has been matched against a message yet.
Running the flow on new wording
This example runs under the setup code of NeMo Guardrails (the two import lines, the YAML and SEARCH strings, the AllExamples class, build_rails and chat) and the TOPIC string above: paste it below them in one file. Both messages are test prompts from the video's demo app, and neither is one of the eight examples. colang_history holds the turn the way Colang would write it; the code prints its first three lines.
rails = build_rails(TOPIC, model="openai/gpt-oss-120b")
for message in ["haha tell me a funny joke real quick", "how does SR-IOV reduce CPU overhead?"]:
info = chat(rails, message)
print("--- first lines of the Colang history")
print("\n".join(info.colang_history.splitlines()[:3]))
print()User: haha tell me a funny joke real quick Bot : I'm an Enterprise IT Assistant focused on Kubernetes, Intel hardware, and networking. I can't help with that — but ask me anything technical! --- first lines of the Colang history user "haha tell me a funny joke real quick" ask off topic bot refuse off topic User: how does SR-IOV reduce CPU overhead? Bot : SR‑IOV (Single‑Root I/O Virtualization) reduces CPU overhead primarily by moving I/O processing out of the hypervisor and into the hardware‑accelerated virtual functions (VFs). **Key mechanisms** | Mechanism | How it cuts CPU work | |-----------|----------------------| | **Direct device assignment** | Each VF appears as a separate PCI device that a guest (or a Kubernetes pod) can program directly, eliminating the need for the hypervisor to mediate every packet. | | **Reduced context switches** | Packets go straight from the NIC to the VM’s memory via DMA, so the host kernel avoids the extra VM‑exit/VM‑entry cycles that a virtio or emulated NIC would incur. | | **Off‑loaded packet handling** | Modern Intel Ethernet controllers (e.g., X710, XL710, Ice) can perform checksum, segmentation‑offload, and even flow steering in hardware for each VF, so the guest’s CPU does not have to compute these. | | **Simplified networking stack** | With a VF, the guest runs a full‑featured driver (e.g., i40e, ice) instead of a lightweight virtio driver, allowing it to use the same fast path optimizations it would have on bare metal. | | **Better cache locality** | Because the NIC writes directly into the VM’s memory buffers, data stays in the CPU cache of the guest, reducing memory‑copy overhead on the host side. | **Resulting CPU savings** - **Lower per‑packet CPU cycles** – typical virtio NICs may consume 150–200 cycles/packet; SR‑IOV can drop this to < 50 cycles/packet on Intel NICs. - **Higher throughput per core** – a single core can handle many more Gbps when using SR‑IOV (often 2–3× the throughput of virtio on the same hardware). - **Scalable multi‑tenant workloads** – in Kubernetes, the Intel device‑plugin can expose VFs as resources, letting many pods share the same physical NIC without each pod incurring hypervisor‑level processing. In short, SR‑IOV lets the NIC do the heavy lifting and bypasses the software layers that normally consume CPU, delivering near‑bare‑metal performance for virtualized workloads. --- first lines of the Colang history user "how does SR-IOV reduce CPU overhead?" ask technical question bot general response
Reading the Colang history
- The joke message is not one of the eight examples, yet the history shows
ask off topicunder it, thenbot refuse off topic: the flow ran and the reply is the scripted text. - The SR-IOV question got the intent
ask technical question. That name is nowhere in the Colang: the model wrote a new intent because none of yours fitted. - No flow starts with that intent, so the next line is
bot general response, the model answering in its own words. - The long answer is the model's own. Its table and its cycle counts were not checked by any rail.
An example line without its indent
Colang 1.0 reads structure from indentation, like Python. Here the second example has lost its two spaces.
from nemoguardrails import RailsConfig
BROKEN = '''
define user ask off topic
"tell me a joke"
"what is the capital of france"
'''
try:
RailsConfig.from_content(colang_content=BROKEN)
except Exception as error:
print(error)Error parsing line 4 in main.co: Unknown main token '"what' on line 4
The parser stops at line 4 of the Colang, the example that lost its indent. At the start of a line it expects a keyword such as define, and it found a quoted string.
Colang 1.0 vs Colang 2.x
NeMo Guardrails ships two versions of the language. Version 1.0 is the default, as the parser output above shows, and it is what the video writes. Version 2.x is switched on with colang_version: "2.x" in the YAML and has a different syntax, closer to Python: flows are declared with flow, a standard library is brought in with import core, and matching a message is written user said.
import core
flow main
user said "hi"
bot say "Hello World!"| Colang 1.0 | Colang 2.x | |
|---|---|---|
| Selected by | Default | colang_version: "2.x" in the YAML |
| A flow starts with | define flow | flow |
| A user message | define user with examples | user said "..." or a flow you define |
| A bot message | define bot with text | bot say "..." |
| Used in | The video and this page | Newer NVIDIA examples |
Where you use Colang
- One block set per thing you want to control. The video writes one for off-topic questions, one for jailbreak attempts, one for sensitive topics and one for greetings.
- Answers that must be the same every time. A refusal, a greeting or a notice goes in
define bot. - Calling your own Python. A flow can run a function with
executeand branch on the result withif, which Input and output rails does.
define user are matched by meaning, with a model's help, so a rail can miss a message it should catch or catch one it should not. Test every rail with messages that are not among its examples, both ones it should refuse and ones it should let through.Related
- Previous: NeMo Guardrails
- Next: Intent detection in NeMo Guardrails
- Reference: Colang 1.0 language syntax
- Add
"how to make a coffee", the video's first example, toask off topicand run the parser again: the count goes up by one. - Delete the
stopline and run the joke message again. After a scripted bot message the reply is the same refusal. - Change
bot refuse off topicin the flow tobot refuse politely, a name with nodefine bot, and run the parser again: the flow lists the new name although no text exists for it.
Slow is fine. Stopping is the only problem.