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 Format

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:

  1. Server level: Most specific configuration
  2. Registry level: Shared configuration across servers
  3. 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

ConnectButton Integration

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

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"
  }
}

Performance Considerations

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"
    ]
  }
}

Batch Migration Tool

{
  "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

Debugging Tools

{
  "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

Performance

  • Cache compiled templates
  • Minimize template complexity
  • Use efficient variable lookups
  • Monitor performance metrics

Next Steps