Template Interpolation
Pylee’s template interpolation system provides powerful, flexible string templating capabilities for dynamic configuration generation. This system supports variable substitution, secret handling, and context-aware processing across different environments and use cases.
Overview
Template interpolation in Pylee allows you to:
- Dynamic value substitution: Replace placeholders with actual values at runtime
- Variable and secret integration: Seamlessly incorporate variables and secrets
- Context-aware processing: Different interpolation behavior based on usage context
- Multi-level precedence: Resolve values from organization, registry, and server levels
- Secure secret handling: Maintain security while enabling flexible configuration
Basic Syntax
Template strings use curly braces {}
to denote placeholders:
{
"remoteUrl": "https://{HOST}:{PORT}/api/v1",
"environment": {
"API_ENDPOINT": "{PROTOCOL}://{HOST}/api",
"DATABASE_URL": "postgresql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:5432/{DB_NAME}"
}
}
Simple Variable Substitution
{
"template": "Bearer {API_KEY}",
"context": { "API_KEY": "sk-1234567890" },
"result": "Bearer sk-1234567890"
}
Multiple Variables
{
"template": "http://{HOST}:{PORT}/api",
"context": { "HOST": "localhost", "PORT": "3000" },
"result": "http://localhost:3000/api"
}
Variable and Secret Prefixes
Variables
- Prefixed:
{var.VARIABLE_NAME}
- Explicitly references a variable
- Unprefixed:
{VARIABLE_NAME}
- References a variable or secret (with secrets taking precedence)
Secrets
- Prefixed:
{secret.SECRET_NAME}
- Explicitly references a secret
- Unprefixed:
{SECRET_NAME}
- References a variable or secret (with secrets taking precedence)
Prefix Examples
{
"templates": {
"explicit_variable": "Database host: {var.DB_HOST}",
"explicit_secret": "API key: {secret.API_KEY}",
"unprefixed": "Token: {AUTH_TOKEN}",
"mixed": "Connect to {var.HOST} with key {secret.API_KEY}"
}
}
Precedence Resolution
Precedence Order
Variables and secrets are resolved in the following order of precedence:
- Server level: Most specific configuration
- Registry level: Shared configuration across servers
- Organization level: Global organizational defaults
Precedence Example
{
"organization": {
"variables": { "API_URL": "https://org.api.com" },
"secrets": { "MASTER_KEY": "org-secret" }
},
"registry": {
"variables": { "API_URL": "https://registry.api.com" },
"secrets": { "SERVICE_KEY": "registry-secret" }
},
"server": {
"variables": { "DEBUG": "true" },
"secrets": { "API_KEY": "server-secret" }
}
}
Template {API_URL}
resolves to "https://registry.api.com"
(registry overrides organization).
Variable vs Secret Precedence
When both a variable and secret have the same name at the same level, secrets take precedence for unprefixed references:
{
"configuration": {
"variables": { "TOKEN": "var-token" },
"secrets": { "TOKEN": "secret-token" }
},
"templates": {
"unprefixed": "{TOKEN}",
"explicit_var": "{var.TOKEN}",
"explicit_secret": "{secret.TOKEN}"
},
"results": {
"unprefixed": "secret-token",
"explicit_var": "var-token",
"explicit_secret": "secret-token"
}
}
Advanced Features
Default Values
Provide fallback values when variables might be undefined:
{
"templates": {
"with_default": "Port: {PORT:-3000}",
"complex_default": "Database: {DB_URL:-postgresql://localhost:5432/default}"
}
}
Nested Interpolation
Variables can reference other variables:
{
"variables": {
"PROJECT_ROOT": "/opt/myapp",
"DATA_DIR": "{PROJECT_ROOT}/data",
"LOGS_DIR": "{PROJECT_ROOT}/logs"
},
"templates": {
"data_path": "Data stored in {DATA_DIR}",
"log_path": "Logs written to {LOGS_DIR}"
}
}
Complex Template Patterns
{
"templates": {
"api_endpoint": "{PROTOCOL}://{HOST}:{PORT}/api/{VERSION}",
"database_url": "postgresql://{DB_USER}:{secret.DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}",
"auth_header": "Bearer {secret.API_KEY}",
"service_config": "{var.SERVICE_NAME} running on {HOST}:{PORT} (debug: {var.DEBUG})"
}
}
Context-Aware Processing
Display Context
Templates processed for UI display with secrets masked:
{
"template": "API Key: {secret.API_KEY}",
"display_result": "API Key: [redacted]"
}
Copy Context
Templates processed for copying with full values:
{
"template": "export API_KEY={secret.API_KEY}",
"copy_result": "export API_KEY=sk-1234567890abcdef"
}
Execution Context
Templates processed for runtime execution:
{
"template": "docker run -e API_KEY={secret.API_KEY} myapp",
"execution_result": "docker run -e API_KEY=sk-1234567890abcdef myapp"
}
Usage Examples
Basic Configuration
{
"server": {
"variables": {
"HOST": "localhost",
"PORT": "3000",
"PROTOCOL": "http"
},
"secrets": {
"API_KEY": "sk-1234567890abcdef"
}
},
"templates": {
"endpoint": "{PROTOCOL}://{HOST}:{PORT}/api",
"auth": "Bearer {secret.API_KEY}"
},
"results": {
"endpoint": "http://localhost:3000/api",
"auth": "Bearer sk-1234567890abcdef"
}
}
Multi-Environment Configuration
{
"environments": {
"development": {
"variables": {
"HOST": "localhost",
"PORT": "3000",
"DEBUG": "true"
}
},
"production": {
"variables": {
"HOST": "api.production.com",
"PORT": "443",
"DEBUG": "false"
}
}
},
"templates": {
"api_url": "https://{HOST}:{PORT}/api",
"debug_mode": "Debug enabled: {DEBUG}"
}
}
Database Configuration
{
"database": {
"variables": {
"DB_HOST": "localhost",
"DB_PORT": "5432",
"DB_NAME": "myapp"
},
"secrets": {
"DB_USER": "admin",
"DB_PASSWORD": "secret123"
}
},
"templates": {
"connection_string": "postgresql://{secret.DB_USER}:{secret.DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}",
"host_info": "Database host: {DB_HOST}:{DB_PORT}"
}
}
Service Configuration
{
"service": {
"variables": {
"SERVICE_NAME": "user-service",
"VERSION": "v1.2.3",
"ENVIRONMENT": "production"
},
"secrets": {
"JWT_SECRET": "jwt-secret-key",
"DATABASE_URL": "postgresql://user:pass@host:5432/db"
}
},
"templates": {
"service_info": "{SERVICE_NAME} {VERSION} running in {ENVIRONMENT}",
"jwt_config": "JWT secret: {secret.JWT_SECRET}",
"database_config": "Database: {secret.DATABASE_URL}"
}
}
Integration with Pylee Components
The ConnectButton component uses template interpolation for dynamic configuration:
{
"connectButton": {
"remote": {
"url": "https://{HOST}:{PORT}/mcp",
"headers": {
"Authorization": "Bearer {secret.API_KEY}",
"X-Service-Version": "{var.VERSION}"
}
},
"package": {
"name": "{var.PACKAGE_NAME}",
"version": "{var.PACKAGE_VERSION}",
"args": ["--host", "{HOST}", "--port", "{PORT}"]
}
}
}
Environment Variable Generation
{
"environmentVariables": {
"API_ENDPOINT": "{PROTOCOL}://{HOST}:{PORT}/api",
"DATABASE_URL": "postgresql://{DB_USER}:{secret.DB_PASSWORD}@{DB_HOST}:5432/{DB_NAME}",
"SERVICE_NAME": "{var.SERVICE_NAME}",
"DEBUG_MODE": "{var.DEBUG}",
"SECRET_KEY": "{secret.APP_SECRET}"
}
}
Command Generation
{
"commands": {
"docker_run": "docker run -e API_KEY={secret.API_KEY} -e DEBUG={var.DEBUG} {var.IMAGE_NAME}",
"npm_start": "npm start -- --host {HOST} --port {PORT}",
"python_app": "python app.py --config {var.CONFIG_FILE} --env {var.ENVIRONMENT}"
}
}
Error Handling
Missing Variables
If a template variable is not found, the placeholder is left unchanged:
{
"template": "Bearer {UNKNOWN_KEY}",
"result": "Bearer {UNKNOWN_KEY}"
}
Malformed templates are left unchanged:
{
"templates": {
"malformed1": "{{VARIABLE}",
"malformed2": "{VARIABLE}}",
"malformed3": "{{VARIABLE}}"
},
"results": {
"malformed1": "{{VARIABLE}",
"malformed2": "{VARIABLE}}",
"malformed3": "{{VARIABLE}}"
}
}
Non-String Values
Non-string values are converted to strings:
{
"variables": {
"PORT": 3000,
"DEBUG": true,
"VERSION": 1.2
},
"templates": {
"port": "Port: {PORT}",
"debug": "Debug: {DEBUG}",
"version": "Version: {VERSION}"
},
"results": {
"port": "Port: 3000",
"debug": "Debug: true",
"version": "Version: 1.2"
}
}
Template Compilation
- Templates are compiled once and cached
- Use template caching for frequently used patterns
- Avoid complex nested interpolation chains
Memory Management
- Clean up unused template contexts
- Use weak references for large template sets
- Monitor memory usage with many templates
Optimization Strategies
{
"optimization": {
"caching": {
"enabled": true,
"maxCacheSize": 1000,
"ttl": 3600
},
"compilation": {
"precompile": true,
"validateOnCompile": true
}
}
}
Security Considerations
Secret Exposure Prevention
- Never log interpolated templates containing secrets
- Use context-appropriate secret handling
- Implement proper access controls
Template Injection Prevention
- Validate template syntax before processing
- Sanitize user-provided template strings
- Limit template complexity to prevent DoS
Secure Practices
{
"security": {
"templateValidation": {
"enabled": true,
"allowedPrefixes": ["var", "secret"],
"maxTemplateLength": 1000,
"maxNestingDepth": 5
},
"secretHandling": {
"maskInLogs": true,
"contextAware": true,
"auditAccess": true
}
}
}
Testing Templates
Unit Testing
{
"tests": [
{
"name": "basic_interpolation",
"template": "Hello {NAME}",
"context": { "NAME": "World" },
"expected": "Hello World"
},
{
"name": "secret_handling",
"template": "API Key: {secret.API_KEY}",
"context": { "secret.API_KEY": "sk-123" },
"expected": "API Key: sk-123"
},
{
"name": "precedence_test",
"template": "{VALUE}",
"context": {
"VALUE": "org-value",
"secret.VALUE": "secret-value"
},
"expected": "secret-value"
}
]
}
Integration Testing
{
"integrationTests": {
"connectButton": {
"template": "https://{HOST}/api?key={secret.API_KEY}",
"contexts": ["display", "copy", "execution"],
"expectations": {
"display": "https://localhost/api?key=[redacted]",
"copy": "https://localhost/api?key=sk-123",
"execution": "https://localhost/api?key=sk-123"
}
}
}
}
Migration Guide
From Legacy Template System
When migrating from older template systems:
{
"migration": {
"oldFormat": "${{ secrets.API_KEY }}",
"newFormat": "{secret.API_KEY}",
"steps": [
"Identify all template strings",
"Convert syntax to new format",
"Update variable/secret references",
"Test in all contexts",
"Validate security handling"
]
}
}
{
"migrationTool": {
"patterns": [
{
"from": "\\$\\{\\{\\s*secrets\\.([^}]+)\\s*\\}\\}",
"to": "{secret.$1}"
},
{
"from": "\\$\\{\\{\\s*vars\\.([^}]+)\\s*\\}\\}",
"to": "{var.$1}"
},
{
"from": "\\$\\{\\{\\s*([^}]+)\\s*\\}\\}",
"to": "{$1}"
}
]
}
}
Troubleshooting
Common Issues
Template Not Resolving
Template: "Bearer {API_KEY}"
Result: "Bearer {API_KEY}"
Solutions:
- Check variable exists in context
- Verify correct prefix usage
- Ensure proper precedence setup
Incorrect Precedence
Expected: "production-value"
Actual: "development-value"
Solutions:
- Review precedence configuration
- Check variable/secret levels
- Verify context processing
Secret Exposure
Display shows: "Bearer sk-1234567890abcdef"
Expected: "Bearer [redacted]"
Solutions:
- Check context configuration
- Verify secret handling rules
- Review component implementation
{
"debug": {
"templateInterpolation": {
"enabled": true,
"logResolution": true,
"logContext": true,
"logPrecedence": true
}
}
}
Best Practices
Template Design
- Use descriptive variable names
- Keep templates readable and maintainable
- Avoid overly complex nested interpolation
- Document template usage and dependencies
Variable Management
- Use consistent naming conventions
- Group related variables logically
- Implement proper validation
- Document variable purposes
Security
- Never expose secrets in display contexts
- Use appropriate prefixes for clarity
- Implement proper access controls
- Regular security audits
- Cache compiled templates
- Minimize template complexity
- Use efficient variable lookups
- Monitor performance metrics
Next Steps