Customizing Guardrails with Vijil Dome

Customizing Guardrails with Vijil Dome

Customizing Guardrails with Vijil Dome

Product

Varun Cherukuri

July 29, 2025

Welcome back to our Vijil Dome series! In Part 1, we explored how to get started with Dome and integrate it seamlessly with OpenAI clients. Part 2 showed you how to leverage Dome's powerful Langchain integrations for more complex AI workflows.

Today, we're diving into one of Dome's most powerful features: creating custom guardrails. While Dome comes with robust built-in detectors for common security, privacy, and moderation concerns, every application has unique requirements. Custom guardrails allow you to implement business-specific logic, domain-specific validations, and tailored protection mechanisms that align perfectly with your use case.

Why Custom Guardrails Matter

AI applications often need specialized protection beyond standard safety filters. Consider these scenarios:

  • Financial services might need to detect and block queries attempting to manipulate trading decisions

  • Healthcare applications require validation that medical advice requests are appropriate for the AI's scope

  • Educational platforms may want to ensure student queries remain within curriculum boundaries

  • Enterprise systems often need to enforce company-specific policies and compliance requirements

Custom guardrails give you the flexibility to implement these domain-specific protections while leveraging Dome's powerful infrastructure for detection, logging, and response handling.

Building Your First Custom Guardrail: PII Phone Number Detector

Let's walk through creating a practical custom guardrail that detects and blocks potential phone number sharing in user queries. This is particularly useful for applications that need to prevent users from accidentally sharing personal contact information.

Step 1: Setting Up the Custom Detector

First, let's create our phone number detection logic:

import re
from vijil_dome.detectors import (
    DetectionCategory,
    DetectionResult,
    DetectionMethod,
    register_method,
)
# Define our custom detector name
PHONE_NUMBER_DETECTOR = "phone-number-detector"
# Register with the Privacy category since we're protecting PII
@register_method(DetectionCategory.Privacy, PHONE_NUMBER_DETECTOR)
class PhoneNumberDetector(DetectionMethod):
    def __init__(self, 
                 block_international=True, 
                 strict_mode=False):
        super().__init__()
        self.block_international = block_international
        self.strict_mode = strict_mode
        
        # Define phone number patterns
        self.us_pattern = re.compile(
            r'(\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}|\d{10})'
        )
        
        self.international_pattern = re.compile(
            r'(\+\d{1,3}[-.\s]?\(?\d{1,4}\)?[-.\s]?\d{1,4}[-.\s]?\d{1,4}[-.\s]?\d{1,9})'
        )
    
    async def detect(self, query_string: str) -> DetectionResult:
        # Check for US phone numbers
        us_matches = self.us_pattern.findall(query_string)
        
        # Check for international numbers if enabled
        intl_matches = []
        if self.block_international:
            intl_matches = self.international_pattern.findall(query_string)
        
        # Determine if we should flag this query
        flagged = bool(us_matches or intl_matches)
        
        # In strict mode, be more aggressive about potential numbers
        if self.strict_mode and not flagged:
            # Look for sequences that might be phone numbers
            digit_sequences = re.findall(r'\d{7,}', query_string)
            flagged = len(digit_sequences) > 0
        
        # Build metadata for logging and analysis
        metadata = {
            "type": type(self),
            "query_string": query_string,
            "us_phone_matches": us_matches,
            "international_matches": intl_matches,
            "strict_mode_triggered": self.strict_mode and bool(re.findall(r'\d{7,}', query_string)),
            "response_string": (
                "I can't process requests containing phone numbers to protect your privacy. "
                "Please remove any phone numbers and try again."
            ) if flagged else "Query processed successfully"
        }        
        return flagged, metadata

Step 2: Integrating with Your Dome Configuration

Now let's integrate our custom detector into a Dome configuration. Remember to define your custom detector before instantiating your configuration:

# Import and define custom detector (code from Step 1 goes here)
# ... PhoneNumberDetector class definition ...
from vijil_dome import Dome
# Configure Dome with our custom guardrail
dome_config = {
    "pii-detection": {
        "type": "privacy",
        "methods": ["phone-number-detector"],
        "early-exit": True,
    },
    "input-guards": ["pii-detection"],
    "output-guards": ["pii-detection"],
    "input-early-exit": True
}
# Initialize Dome
dome = Dome(dome_config)

Step 3: Testing Your Custom Guardrail

Let's test our phone number detector with various inputs:

import asyncio
async def test_phone_detector():
    # Test cases
    test_queries = [
        "Call me at (555) 123-4567 when you're ready",
        "My number is 555-123-4567",
        "Contact support at +1-800-555-0123",
        "I need help with my account balance",  # Safe query
        "The reference number is 1234567890",   # Might trigger strict mode
    ]
    
    for query in test_queries:
        try:
            # Process through Dome
            result = await dome.async_guard_input(query)
            print(f"Query: '{query}'")
            flagged = result.flagged
            response = result.response_string
            print(f"Result: {flagged=} {response=}")
            print("-" * 50)
        except Exception as e:
            print(f"Error processing '{query}': {e}")
# Run the test
asyncio.run(test_phone_detector())

Expected Output

When you run this test, you should see something like:

Query: 'Call me at (555) 123-4567 when you're ready'
Result: flagged=True response="Blocked by input guardrail at Guard:pii-detection I can't process requests containing phone numbers to protect your privacy. Please remove any phone numbers and try again."
--------------------------------------------------
Query: 'My number is 555-123-4567'
Result: flagged=True response="Blocked by input guardrail at Guard:pii-detection I can't process requests containing phone numbers to protect your privacy. Please remove any phone numbers and try again."
--------------------------------------------------
Query: 'Contact support at +1-800-555-0123'
Result: flagged=True response="Blocked by input guardrail at Guard:pii-detection I can't process requests containing phone numbers to protect your privacy. Please remove any phone numbers and try again."
--------------------------------------------------
Query: 'I need help with my account balance'
Result: flagged=False response='Query processed successfully'
--------------------------------------------------
Query: 'The reference number is 1234567890'
Result: flagged=True response="Blocked by input guardrail at Guard:pii-detection I can't process requests containing phone numbers to protect your privacy. Please remove any phone numbers and try again."

Best Practices for Custom Guardrails

1. Choose the Right Detection Category

  • Security: Threats, injections, malicious content

  • Privacy: PII, sensitive data, personal information

  • Moderation: Inappropriate content, harassment, spam

  • Integrity: Misinformation, bias, factual accuracy

  • Generic: General-purpose, business logic, custom rules

2. Implement Comprehensive Logging

Always include detailed metadata in your DetectionResult. This helps with:

  • Debugging and improving your detectors

  • Compliance and audit requirements

  • Understanding user behavior patterns

  • Fine-tuning detection sensitivity

3. Test Thoroughly

Create comprehensive test suites covering:

  • Expected positive cases (should be blocked)

  • Expected negative cases (should be allowed)

  • Edge cases and boundary conditions

  • Performance with large inputs

4. Consider Performance

Custom detectors run on every request, so optimize for:

  • Efficient regex patterns

  • Minimal external API calls

  • Appropriate caching strategies

  • Asynchronous operations where possible

Conclusion

Custom guardrails in Vijil Dome provide the flexibility to implement domain-specific protection while leveraging a robust, battle-tested infrastructure. Whether you're building financial applications, healthcare platforms, or enterprise systems, custom detectors allow you to encode your unique business logic and compliance requirements directly into your AI safety layer.

In our phone number detector example, we've seen how to create a practical custom guardrail that protects user privacy while providing clear feedback. The same patterns can be applied to create detectors for industry-specific terminology, company policies, regulatory compliance, or any other custom logic your application requires.

As you build your custom guardrails, remember that they're most effective when combined with Dome's built-in detectors and integrated into a comprehensive AI safety strategy. Start with simple detectors, test thoroughly, and iterate based on real-world usage patterns.

Ready to implement your own custom guardrails? Check out the complete documentation for more advanced patterns and examples. And if you missed the earlier parts of this series, be sure to read Part 1 on getting started with OpenAI integration and Part 2 on Langchain workflows.

Have questions about implementing custom guardrails for your specific use case? We'd love to hear from you and help you build robust, domain-specific AI protection systems with Vijil Dome.

© 2025 Vijil. All rights reserved.

© 2025 Vijil. All rights reserved.

© 2025 Vijil. All rights reserved.