When you search for "LLM guardrails," most of what you find is about output filtering: moderation APIs, toxicity classifiers, post-generation checks that inspect what the model produced and decide whether to show it. The model runs first. The filter runs second. If the filter catches something bad, the response is suppressed or replaced.
I built KaryoSpace's guardrail system the other way around. The constraint check runs first. If a query violates a defined boundary, the model is never invoked at all. Here's why I made that decision, how the system is designed, and what I learned running it against real adversarial queries.
Output filtering has an inherent problem: you're paying to generate content you intend to suppress. In an enterprise AI product, this matters for three reasons beyond cost.
First, the model might produce something genuinely dangerous before the filter sees it, and the filter might miss it. Any filter has a false-negative rate. If the dangerous content is the response, you're relying entirely on the filter's accuracy.
Second, output filtering doesn't give you a clean audit trail. You know the model generated something and it was blocked. You don't know, from the filter alone, what the user was trying to extract and why.
Third, and most practically: model behaviour can change. If your guardrail logic is "run the model and filter the output," then a model update that changes how the model responds to a particular phrasing can silently change your enforcement. The filter becomes model-dependent in ways that are hard to reason about.
Input-side enforcement, classifying the intent before the model sees it, sidesteps all three problems. The model is not invoked. There is nothing to filter. The audit record captures the exact query that triggered the constraint.
KaryoSpace is an enterprise workplace AI: it has access to a user's email, chat history, project notes, incident records, and integrated services like Jira and ServiceNow. That's a large attack surface for a user who wants to extract things they shouldn't.
I identified three categories of constraint that needed hard enforcement from day one:
| Category | What it blocks | Why it matters |
|---|---|---|
| Credential & Key Access | Any request to view, retrieve, rotate, or modify API keys, DKIM/JWT tokens, secrets, or credentials | The AI has no legitimate access to credentials. Any query asking for them is either a mistake or an extraction attempt. |
| Code Generation | Requests to write scripts, generate SQL, build web pages, or produce code of any kind | KaryoSpace is scoped to org data and integrations, it's not a coding assistant. Code-gen requests are always out-of-product-scope. |
| Out-of-Scope Knowledge | General knowledge questions unrelated to the user's workspace data | The AI is not a general-purpose assistant. Answering general questions correctly would require invoking the model's training knowledge, not the user's data. |
The classifier runs as the first step in the request pipeline, before any retrieval, before any model call. It's implemented as two functions in Go: IsRAGQuery() and IsStatement().
IsRAGQuery() checks whether the query is asking something that should be answered from the user's workspace data, lookups like "what did Sarah say about the Q3 deadline?" or "find emails from John about the AWS migration." It matches against 30+ trigger phrases covering all the data sources KaryoSpace connects to.
IsStatement() catches phrasing that isn't a question at all: commands, affirmations, conversational messages, and routes them to a lightweight acknowledgement path instead of a full LLM call.
Everything that doesn't match a known-good workspace query pattern goes to the guardrail evaluation. The credential and codegen classifiers each check against specific keyword patterns and phrasing structures. Out-of-scope is the catch-all: if the query doesn't match workspace intent and doesn't trigger the other two categories, it's declined as out-of-scope.
The guardrail check returns before the model is invoked. There is no LLM call, no prompt, no token spend. The declined response is a pre-written constant, the same string every time, regardless of how the user phrased the query. This consistency is intentional: it prevents users from learning anything about the system's internal logic from the variation in declined responses.
Each constraint category returns a consistent, clearly worded canned response. The UI renders these with an amber "Guardrail Active" indicator so users understand immediately that this is a policy boundary, not an AI failure.
Before going live, I ran a systematic 9-category adversarial test matrix against the production system: real queries fired from a real user session, designed to probe each constraint category and its edges.
The categories tested:
All 9 routed correctly. The three guardrail categories caught their targets cleanly; the RAG query retrieved workspace content and answered correctly; the small talk received a lightweight acknowledgement without a model call.
The indirect credential query, "What is the Client ID for Microsoft integration?", was the one I was most uncertain about. It doesn't contain the word "key" or "secret." It caught cleanly because the credential classifier checks for integration-context phrasing and named platform references, not just credential nouns. Designing the classifier around intent rather than vocabulary was the right call.
Once the system was live and the AI Intelligence Observatory was collecting real queries, a pattern emerged that the test matrix alone couldn't have shown: users probe in sequences, not in isolation.
A user who gets a credential-declined response will often follow up with a slightly rephrased version of the same request, not immediately, but in the next session. AIO traces this as a cluster of guardrail activations in the same category for the same user, spread across time. It's not a smoking gun of malicious intent (some users are genuinely confused about the product's scope), but it's a signal worth surfacing to admins. That is exactly what the "attention" filter in AIO is designed to do.
This is the research question I find most interesting now: does displaying the guardrail label and reason change user behaviour? Does transparency about the constraint reduce future probing attempts, or does it teach users what to rephrase? I have the data to start answering that question. I don't have rigorous enough methodology yet.
One thing I underestimated: the importance of the response text. The canned messages needed to be precise enough to be honest but vague enough not to reveal classifier boundaries. Early versions were too specific, "I detected a credential request", which immediately told users exactly what phrase triggered the block. The current versions state what the AI can't do and why, without describing what the classifier saw. That's the right balance.
The other thing: guardrails need updating as the product evolves. A constraint that was correct at launch might be wrong six months later if the product's scope changes. I treat the constraint categories as first-class product decisions, not implementation details, and review them when the product roadmap changes.
KaryoSpace is live at karyospace.com. Questions about guardrail design or AI safety in enterprise products: sumanakkisetty@gmail.com