Domain Inheritance¶
Domain inheritance allows you to create reusable constraint templates that can be shared across multiple domains. This powerful feature enables sophisticated CLI architectures with common patterns while avoiding code duplication.
Fragment Domains¶
Fragment domains are constraint templates that cannot be selected from the command line but can be inherited by concrete domains.
Basic Fragment Creation¶
class CloudTool : Arguments() {
// Fragment domain - not selectable, used as template
val authenticationFragment by domain(fragment = true)
.exactlyOne(::apiKey, ::serviceAccount, ::userCredentials)
.requireIfAnyPresent(::apiKey, ::region)
.required(::projectId)
// Concrete domains inherit the fragment
val deployDomain by domain("deploy")
.inherits(::authenticationFragment)
.required(::deploymentConfig)
val monitorDomain by domain("monitor")
.inherits(::authenticationFragment)
.atLeast(::metric, 1)
// Options
val apiKey by option("--api-key").hidden()
val serviceAccount by option("--service-account")
val userCredentials by option("--user-credentials").bool()
val region by option("--region")
val projectId by option("--project-id")
val deploymentConfig by option("--deployment-config")
val metric by option("--metric").list()
}
Usage Examples¶
# Fragment constraints are inherited by concrete domains
cloud-tool deploy --user-credentials --project-id my-project --deployment-config config.yml
# Error: Fragment constraint inherited
cloud-tool deploy --api-key key123 --project-id my-project
# Error: Option --region is required when --api-key is present (inherited from authenticationFragment)
# Cannot select fragment directly
cloud-tool authenticationFragment
# Error: Unknown command 'authenticationFragment'
Multiple Inheritance¶
Domains can inherit from multiple fragments, combining different constraint patterns:
Combining Fragment Patterns¶
class KubernetesTool : Arguments() {
// Authentication fragment
val authFragment by domain(fragment = true)
.exactlyOne(::kubeconfig, ::token, ::certificate)
.requireIfValue(::certificate, ::certificateKey) { it != null }
// Resource scoping fragment
val scopeFragment by domain(fragment = true)
.atMostOne(::namespace, ::allNamespaces)
.requireIfAnyPresent(::allNamespaces, ::clusterAdmin)
// Resource selection fragment
val selectorFragment by domain(fragment = true)
.atLeastOne(::labelSelector, ::fieldSelector, ::resourceName)
.requireIfValue(::labelSelector, ::selectorFile) { it?.contains("complex") == true }
// Concrete domains inheriting multiple fragments
val getDomain by domain("get")
.inherits(::authFragment, ::scopeFragment, ::selectorFragment)
.atMostOne(::output, ::watch)
val deleteDomain by domain("delete")
.inherits(::authFragment, ::scopeFragment, ::selectorFragment)
.required(::confirmDelete)
.conflicts(::dryRun, ::force)
val applyDomain by domain("apply")
.inherits(::authFragment, ::scopeFragment) // No selector fragment
.exactlyOne(::filename, ::directory, ::stdin)
// Authentication options
val kubeconfig by option("--kubeconfig")
val token by option("--token").hidden()
val certificate by option("--certificate")
val certificateKey by option("--certificate-key").hidden()
// Scoping options
val namespace by option("--namespace", "-n")
val allNamespaces by option("--all-namespaces").bool()
val clusterAdmin by option("--cluster-admin").bool()
// Selection options
val labelSelector by option("--selector", "-l")
val fieldSelector by option("--field-selector")
val resourceName by option("--name")
val selectorFile by option("--selector-file")
// Command-specific options
val output by option("--output", "-o").oneOf("json", "yaml", "wide")
val watch by option("--watch").bool()
val confirmDelete by option("--confirm-delete").bool()
val dryRun by option("--dry-run").bool()
val force by option("--force").bool()
val filename by option("--filename", "-f")
val directory by option("--directory")
val stdin by option("--stdin").bool()
}
Inheritance Order and Conflicts¶
When inheriting from multiple fragments, constraints are applied in order:
class DatabaseTool : Arguments() {
// First fragment
val connectionFragment by domain(fragment = true)
.required(::host)
.atMostOne(::sslMode, ::insecureMode)
// Second fragment that might conflict
val securityFragment by domain(fragment = true)
.required(::sslMode) // Conflicts with connectionFragment's atMostOne
.conflicts(::insecureMode)
val migrateDomain by domain("migrate")
.inherits(::connectionFragment, ::securityFragment)
// Resolution: securityFragment's required(::sslMode) takes precedence
// Result: sslMode is required, insecureMode conflicts
}
Hierarchical Inheritance¶
Multi-Level Inheritance¶
class ComplexTool : Arguments() {
// Base fragment - fundamental requirements
val baseFragment by domain(fragment = true)
.required(::configuration)
.atMostOne(::verbose, ::quiet)
// Network fragment - inherits base and adds network requirements
val networkFragment by domain(fragment = true)
.inherits(::baseFragment)
.required(::endpoint)
.exactlyOne(::httpProtocol, ::httpsProtocol, ::grpcProtocol)
// Security fragment - inherits network and adds security requirements
val securityFragment by domain(fragment = true)
.inherits(::networkFragment)
.requireIfValue(::httpsProtocol, ::tlsCertificate) { it == true }
.requireIfValue(::grpcProtocol, ::grpcCredentials) { it == true }
.conflicts(::insecureMode)
// Concrete domain inheriting the full hierarchy
val deployDomain by domain("deploy")
.inherits(::securityFragment) // Gets all constraints from the hierarchy
.required(::deploymentTarget)
// Options
val configuration by option("--configuration")
val verbose by option("--verbose").bool()
val quiet by option("--quiet").bool()
val endpoint by option("--endpoint")
val httpProtocol by option("--http").bool()
val httpsProtocol by option("--https").bool()
val grpcProtocol by option("--grpc").bool()
val tlsCertificate by option("--tls-cert")
val grpcCredentials by option("--grpc-creds")
val insecureMode by option("--insecure").bool()
val deploymentTarget by option("--deployment-target")
}
Effective Constraint Resolution¶
# The deploy domain effectively has all these constraints:
# From baseFragment:
# - required(::configuration)
# - atMostOne(::verbose, ::quiet)
# From networkFragment:
# - required(::endpoint)
# - exactlyOne(::httpProtocol, ::httpsProtocol, ::grpcProtocol)
# From securityFragment:
# - requireIfValue(::httpsProtocol, ::tlsCertificate) { it == true }
# - requireIfValue(::grpcProtocol, ::grpcCredentials) { it == true }
# - conflicts(::insecureMode)
# From deployDomain:
# - required(::deploymentTarget)
complex-tool deploy --configuration config.yml --endpoint api.example.com --https --tls-cert cert.pem --deployment-target prod
# Success: All inherited constraints satisfied
Selective Inheritance¶
Conditional Inheritance¶
class EnvironmentTool : Arguments() {
val environment by option("--environment").oneOf("dev", "staging", "prod")
// Development-specific constraints
val devFragment by domain(fragment = true)
.conflicts(::requireApproval)
.atMostOne(::fastMode, ::debugMode)
// Production-specific constraints
val prodFragment by domain(fragment = true)
.required(::approvalToken)
.required(::rollbackPlan)
.conflicts(::skipValidation)
// Common operational constraints
val opsFragment by domain(fragment = true)
.required(::operatorId)
.atLeastOne(::backupEnabled, ::monitoringEnabled)
val deployDomain by domain("deploy")
.inherits(::opsFragment) // Always inherit ops requirements
// Conditional inheritance based on environment would be done in business logic
val requireApproval by option("--require-approval").bool()
val fastMode by option("--fast").bool()
val debugMode by option("--debug").bool()
val approvalToken by option("--approval-token").hidden()
val rollbackPlan by option("--rollback-plan")
val skipValidation by option("--skip-validation").bool()
val operatorId by option("--operator-id")
val backupEnabled by option("--backup").bool()
val monitoringEnabled by option("--monitoring").bool()
}
Override Inheritance¶
Concrete domains can override inherited constraints:
class FlexibleTool : Arguments() {
val baseFragment by domain(fragment = true)
.atMostOne(::option1, ::option2) // Base constraint
val standardDomain by domain("standard")
.inherits(::baseFragment) // Inherits atMostOne constraint
val flexibleDomain by domain("flexible")
.inherits(::baseFragment)
.atLeastOne(::option1, ::option2) // Overrides to allow both (more permissive)
val strictDomain by domain("strict")
.inherits(::baseFragment)
.exactlyOne(::option1, ::option2) // Overrides to be more restrictive
val option1 by option("--option1").bool()
val option2 by option("--option2").bool()
}
Complex Inheritance Patterns¶
Mixin-Style Fragments¶
class MicroservicePlatform : Arguments() {
// Authentication mixin
val authMixin by domain(fragment = true)
.exactlyOne(::oauth, ::apiKey, ::mtls)
// Observability mixin
val observabilityMixin by domain(fragment = true)
.atLeastOne(::metrics, ::tracing, ::logging)
.requireIfAnyPresent(::tracing, ::tracingEndpoint)
// Resilience mixin
val resilienceMixin by domain(fragment = true)
.atMostOne(::retryPolicy, ::circuitBreaker)
.requireIfAnyPresent(::circuitBreaker, ::circuitBreakerConfig)
// High-level service operations combining mixins
val httpServiceDomain by domain("http-service")
.inherits(::authMixin, ::observabilityMixin, ::resilienceMixin)
.required(::port)
.conflicts(::mtls, ::insecureHttp) // HTTP-specific constraints
val grpcServiceDomain by domain("grpc-service")
.inherits(::authMixin, ::observabilityMixin, ::resilienceMixin)
.required(::grpcPort)
.requireIfValue(::mtls, ::tlsCertificate) { it == true }
val batchJobDomain by domain("batch-job")
.inherits(::authMixin, ::observabilityMixin) // No resilience for batch jobs
.required(::jobConfig)
.conflicts(::realTime)
// Authentication options
val oauth by option("--oauth").bool()
val apiKey by option("--api-key").hidden()
val mtls by option("--mtls").bool()
// Observability options
val metrics by option("--metrics").bool()
val tracing by option("--tracing").bool()
val logging by option("--logging").bool()
val tracingEndpoint by option("--tracing-endpoint")
// Resilience options
val retryPolicy by option("--retry-policy")
val circuitBreaker by option("--circuit-breaker").bool()
val circuitBreakerConfig by option("--circuit-breaker-config")
// Service-specific options
val port by option("--port").int()
val insecureHttp by option("--insecure-http").bool()
val grpcPort by option("--grpc-port").int()
val tlsCertificate by option("--tls-certificate")
val jobConfig by option("--job-config")
val realTime by option("--real-time").bool()
}
Cross-Cutting Concerns¶
class EnterpriseTool : Arguments() {
// Security cross-cutting concern
val securityConcern by domain(fragment = true)
.required(::auditLog)
.exactlyOne(::authMethod)
.requireIfValue(::environment, ::complianceMode) { it == "prod" }
// Performance cross-cutting concern
val performanceConcern by domain(fragment = true)
.atMostOne(::caching, ::noCaching)
.requireIfAnyPresent(::caching, ::cacheConfig)
.requireIfValue(::workload, ::performanceProfile) { it == "high" }
// Reliability cross-cutting concern
val reliabilityConcern by domain(fragment = true)
.required(::healthCheck)
.atLeastOne(::backup, ::replication)
.requireIfAnyPresent(::replication, ::replicationFactor)
// Business domains combining concerns as needed
val customerFacingDomain by domain("customer-facing")
.inherits(::securityConcern, ::performanceConcern, ::reliabilityConcern)
.required(::customerDatabase)
val internalToolDomain by domain("internal-tool")
.inherits(::securityConcern, ::performanceConcern) // No reliability concern
.required(::internalDatabase)
val batchProcessingDomain by domain("batch-processing")
.inherits(::reliabilityConcern) // Only reliability concern
.required(::batchConfig)
.conflicts(::realTimeMode)
// Security options
val auditLog by option("--audit-log")
val authMethod by option("--auth-method").oneOf("ldap", "oauth", "saml")
val environment by option("--environment").oneOf("dev", "staging", "prod")
val complianceMode by option("--compliance-mode").bool()
// Performance options
val caching by option("--caching").bool()
val noCaching by option("--no-caching").bool()
val cacheConfig by option("--cache-config")
val workload by option("--workload").oneOf("low", "medium", "high")
val performanceProfile by option("--performance-profile")
// Reliability options
val healthCheck by option("--health-check")
val backup by option("--backup").bool()
val replication by option("--replication").bool()
val replicationFactor by option("--replication-factor").int()
// Domain-specific options
val customerDatabase by option("--customer-database")
val internalDatabase by option("--internal-database")
val batchConfig by option("--batch-config")
val realTimeMode by option("--real-time").bool()
}
Error Messages with Inheritance¶
Inherited Constraint Errors¶
# Error from inherited fragment
my-tool deploy --api-key key123
# Error: Option --region is required when --api-key is present (inherited from authenticationFragment)
# Multiple inheritance constraint error
kubectl-tool get --all-namespaces
# Error: Option --cluster-admin is required when --all-namespaces is present (inherited from scopeFragment)
Inheritance Chain Errors¶
# Error showing inheritance chain
complex-tool deploy --https
# Error: Option --tls-cert is required when --https is true
# Constraint source: securityFragment -> networkFragment -> baseFragment
Best Practices¶
1. Design Cohesive Fragments¶
// Good: Cohesive authentication fragment
val authFragment by domain(fragment = true)
.exactlyOne(::password, ::keyFile, ::token)
.requireIfAnyPresent(::keyFile, ::keyPassword)
// Avoid: Mixing unrelated concerns
val mixedFragment by domain(fragment = true)
.required(::password) // Authentication
.required(::outputFile) // I/O
.conflicts(::verbose, ::quiet) // Logging
2. Use Descriptive Fragment Names¶
// Good: Clear purpose
val authenticationFragment by domain(fragment = true)
val networkConfigFragment by domain(fragment = true)
val securityPolicyFragment by domain(fragment = true)
// Avoid: Vague names
val fragment1 by domain(fragment = true)
val commonStuff by domain(fragment = true)
3. Layer Fragments Logically¶
// Good: Logical layering from general to specific
val baseFragment by domain(fragment = true) // Most general
val networkFragment by domain(fragment = true) // Network-specific
.inherits(::baseFragment)
val securityFragment by domain(fragment = true) // Security-specific
.inherits(::networkFragment)
// Avoid: Arbitrary inheritance chains
4. Document Fragment Purpose¶
// Good: Clear documentation
val authenticationFragment by domain(fragment = true)
// Provides common authentication patterns for all cloud operations
.exactlyOne(::apiKey, ::serviceAccount, ::userAuth)
val resourceManagementFragment by domain(fragment = true)
// Handles resource scoping and access control
.required(::resourceGroup)
.atMostOne(::namespace, ::allNamespaces)
Domain inheritance enables sophisticated CLI architectures where common patterns can be defined once and reused across multiple commands, reducing duplication while maintaining clear constraint relationships and error messages.