Two patterns appear at almost every decision point in an agentic system: routing (pattern 2 in the Gulli taxonomy) and guardrails (pattern 18). They are not the same thing, but they work together. Routing without guardrails produces efficient but ungoverned execution. Guardrails without routing produce governance that applies indiscriminately to everything, regardless of risk. The combination produces a system that routes work to the right place and checks it against the right rules before allowing it to proceed.

This article covers both patterns through the lens of how ticketyboo.dev implements them: the Gatekeep governance engine, the fixer-bot classifier, and the declarative rules model that has survived multiple infrastructure replacements unchanged.

Routing: classify before you execute

The routing pattern has a single core principle: classify the input before deciding what to do with it. An unclassified request is handled by whatever is available. A classified request is handled by what is appropriate. The difference in outcome is significant, and the cost of the classification step is almost always justified.

Gatekeep implements routing through three specialised personas, each responsible for a distinct domain of decision-making:

The classifier sits upstream of all three. It reads the incoming work item (a change, a deployment request, a code review, a cost alert) and determines which persona or personas should handle it. A change that introduces a new AWS service goes to both Auditor (cost check) and Architect (design review). A change that modifies an IAM policy goes to Sentinel. A change that refactors an internal module goes to Architect only.

Incoming work change / deploy / review / alert Classifier domain detection security / cost / design Sentinel security concerns IAM / creds / exposure Auditor cost and compliance Free Tier / tagging / drift Architect design decisions service / deps / trade-offs flag / block / escalate approve / reject / remediate approve / defer / recommend Work can route to multiple personas simultaneously. All must clear before proceed.
Gatekeep routing: the classifier reads the incoming work item and dispatches to one or more personas. Work touching multiple domains routes to all relevant personas and must clear all of them.

The fixer-bot classifier: routing by capability requirement

The Gatekeep persona model routes by domain (what kind of concern is this?). The fixer-bot classifier routes by capability requirement (how much capability does this task actually need?). These are different questions and they produce different routing decisions.

The fixer-bot takes GitHub issues and generates implementation plans. Not all issues are equally complex. A typo fix in a configuration file is simple: one file, one change, deterministic output. Refactoring a Lambda handler to add a new endpoint is medium: multiple files, some judgment required, tests to update. Designing a new auth flow is complex: multiple components, architectural decisions, potential security implications.

Running every issue through the heaviest available model is wasteful. Running every issue through the lightest model produces poor results on complex tasks. The classifier reads the issue and assigns a tier based on a rubric: number of files likely affected, presence of architectural keywords, existence of external dependencies, and whether the issue references security or cost concerns.

# fixer-bot tier classification (simplified)
# Simple:  1 file, no external deps, no architectural keywords
# Medium:  2-5 files, some judgment required, tests affected
# Complex: 5+ files, architectural keywords, security/cost flags

def classify_issue(issue: dict) -> str:
    """Route to execution tier based on capability requirement."""
    title = issue.get("title", "").lower()
    body  = issue.get("body",  "").lower()
    text  = title + " " + body

    security_flags = any(k in text for k in (
        "auth", "iam", "credential", "secret", "permission", "security"
    ))
    arch_flags = any(k in text for k in (
        "refactor", "migrate", "redesign", "architecture", "pattern", "introduce"
    ))
    file_count_hint = text.count(".py") + text.count(".tf") + text.count(".html")

    if security_flags or arch_flags or file_count_hint >= 5:
        return "complex"
    elif file_count_hint >= 2 or any(k in text for k in ("test", "update", "extend")):
        return "medium"
    else:
        return "simple"

Tier assignment drives model selection, context budget, and review requirements. Simple tasks get a fast, cheap execution path with no human review step. Medium tasks get a mid-tier model with automated test validation. Complex tasks get the heaviest model, a planning phase before implementation, and a mandatory human review gate before merge.

The important design choice: tier is a proxy for capability requirement, not for importance. A simple bug fix on a critical path is still Simple tier. It gets a fast, cheap execution path because that is all it needs. The review gate is not determined by how critical the code is. It is determined by how much autonomous judgment the task requires.

Guardrails: what the rules look like in practice

The guardrails pattern covers mechanisms that constrain agent behaviour within defined boundaries. The word "guardrails" suggests passive barriers. In practice, the most effective governance systems are active: they check, they classify, they route, and they either approve automatically or escalate for human review.

Gatekeep's rules model is declarative JSON. Each rule has a condition, a domain (which persona owns it), a severity, and an action (allow, block, escalate, flag). A simplified example from the cost rules:

# gatekeep cost rules (simplified)
{
  "rules": [
    {
      "id": "cost-001",
      "name": "New AWS service requires cost assessment",
      "domain": "auditor",
      "condition": "change introduces AWS service not in approved_services list",
      "severity": "high",
      "action": "escalate",
      "message": "New service {service} not in approved list. Auditor review required."
    },
    {
      "id": "cost-002",
      "name": "Lambda memory above threshold",
      "domain": "auditor",
      "condition": "lambda.memory_size > 256",
      "severity": "medium",
      "action": "flag",
      "message": "Lambda {name} configured at {memory}MB. Free Tier optimum is 128MB."
    },
    {
      "id": "sec-003",
      "name": "Secrets Manager blocked",
      "domain": "sentinel",
      "condition": "resource.type == 'aws_secretsmanager_secret'",
      "severity": "high",
      "action": "block",
      "message": "Secrets Manager ($0.40/secret/month) is blocked. Use SSM Parameter Store SecureString."
    }
  ]
}

The rules describe intent, not implementation. The enforcement engine reads the rules and evaluates them against the incoming change. The same rule file has been active through multiple changes to the underlying infrastructure: from Paperclip on Lightsail to Lambda functions, from manual deployment to Terraform-managed resources. The rules did not change when the execution engine changed.

Guardrails layer: where checks sit in the pipeline

1. agent action 2. infrastructure change 3. content publish pre-tool-use checks Rules applied: sec-001: no plaintext creds sec-002: scope validation cost-003: API call budget gov-001: tool allowlist proceed block pre-deploy checks Rules applied: cost-001: new service approval cost-002: memory sizing sec-003: no Secrets Mgr gov-002: tagging required proceed escalate pre-publish checks Rules applied: pub-001: data-draft flag pub-002: em dash audit pub-003: human review pub-004: canonical URL publish hold draft Guardrails are enforced at the boundary, before action. Rules defined after the fact are documentation. Rules enforced at the boundary are governance.
Three guardrail checkpoints in the ticketyboo.dev pipeline. Each applies a different rule set appropriate to the risk profile of that stage. Pre-publish rules are the simplest: a human review gate is sufficient because the blast radius of a bad publish is low.

Gatekeeper, not gate-blocker

The most common failure mode in governance systems is excessive friction. A gate-blocker stops every change until a human approves it. This produces compliance theatre: approvers approve without reading because the volume is too high for careful review. Approval becomes a rubber stamp, and the governance is illusory.

A gatekeeper is different. It routes work through the appropriate checks, approves automatically when rules are satisfied, and escalates to humans only when the rules are not satisfied or when the risk level warrants it. The human review queue contains real decisions, not routine approvals. Because the queue is short, the reviews are meaningful.

In practice, this means most changes in a well-governed system proceed without human intervention. A Lambda function that stays within the existing memory tier, uses SSM Parameter Store for secrets, includes required tags, and modifies files within an existing service boundary clears all automated checks and deploys without waiting for a review. The developer gets fast feedback that their change is compliant. Governance does not slow them down.

A change that introduces a new AWS service fails the cost-001 rule (new service not in approved list) and routes to the Auditor for a cost assessment. A change that adds an IAM policy fails the security scan and routes to the Sentinel. These changes represent genuine decisions that benefit from review. The rule system filters for them.

Declarative rules survive infrastructure changes

The ticketyboo.dev governance rules were defined while Paperclip ran on a Lightsail instance. They ran through the migration to Lambda functions. They will run through whatever comes next. This is not accidental. It is a consequence of keeping rules declarative and keeping the enforcement engine separate from the rule definition.

Declarative rules describe what is allowed. The enforcement engine reads the rules and evaluates them against the incoming change. Changing the enforcement engine does not require changing the rules. Adding a new rule does not require changing the enforcement engine.

This is the architectural principle behind guardrails: the rules are the valuable part. They encode accumulated knowledge about what has gone wrong, what costs money unexpectedly, what creates security exposure. The enforcement mechanism is infrastructure. Infrastructure gets replaced. Rules accumulate.

Where routing and guardrails intersect

Routing and guardrails are often treated as separate concerns. In practice, the routing decision is itself a form of guardrails enforcement. When the classifier determines that a change touches IAM policies and routes it to Sentinel, it is also applying a rule: "IAM changes require security review." The route is the rule.

This means the routing logic should be considered part of the governance architecture, not separate from it. A routing decision that bypasses a persona that should be consulted is a governance failure. A routing decision that routes work to a persona with the wrong context is an efficiency failure that may also be a governance failure.

The combination that works: a classifier that routes by domain, a persona model where each domain has clear ownership and a defined rule set, and a rule model that is declarative and independent of the execution engine. Build those three components and the routing-and-guardrails pair becomes a durable foundation for governing agentic workflows at development speed.

The signal from the empty escalation queue: when the human review queue is empty for a week, it means one of two things. Either no changes were made (bad). Or all changes satisfied the automated rules (good). The goal of a guardrails system is to make the second case the common case, not to generate a steady stream of escalations that signal governance activity without ensuring governance quality.
Pattern taxonomy from Antonio Gulli, "Agentic Design Patterns: A Hands-On Guide to Building Intelligent Systems" (Springer, 2025). All examples are original implementations from the ticketyboo.dev platform. No book content reproduced verbatim.

If the articles or tools have been useful, a coffee helps keep things running.

☕ buy me a coffee

More from the agentic patterns series

→ 21 agentic patterns, mapped to a real platform → How agents remember and talk to each other → Building on a budget with humans in the loop → Pattern picker: which pattern do you need?

ticketyboo brings governed AI development to your pull request workflow. 5 governance runs free, one-time welcome grant. No card required.

View pricing Start free →