home / skills / a5c-ai / babysitter / mutually-exclusive-group-handler

This skill generates robust mutually exclusive group handling for CLI arguments, with validation, dependencies, and custom error messages across languages.

npx playbooks add skill a5c-ai/babysitter --skill mutually-exclusive-group-handler

Review the files below or copy the command above to add this skill to your agents.

Files (2)
SKILL.md
4.8 KB
---
name: mutually-exclusive-group-handler
description: Generate logic for handling mutually exclusive argument groups with clear error messages and validation in CLI applications.
allowed-tools: Read, Write, Edit, Bash, Glob, Grep
---

# Mutually Exclusive Group Handler

Generate logic for handling mutually exclusive CLI argument groups.

## Capabilities

- Generate mutually exclusive group validation
- Create dependent argument relationships
- Set up required group validation
- Implement custom conflict messages
- Configure OR/XOR group logic
- Generate documentation for groups

## Usage

Invoke this skill when you need to:
- Implement mutually exclusive options
- Create dependent argument chains
- Validate argument relationships
- Generate clear conflict messages

## Inputs

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| language | string | Yes | Target language |
| groups | array | Yes | Mutually exclusive group definitions |

### Group Structure

```json
{
  "groups": [
    {
      "name": "output-format",
      "type": "mutually_exclusive",
      "required": true,
      "options": ["--json", "--yaml", "--table"],
      "errorMessage": "Choose one output format: --json, --yaml, or --table"
    },
    {
      "name": "auth-method",
      "type": "mutually_exclusive",
      "options": ["--token", "--username"],
      "dependencies": {
        "--username": ["--password"]
      }
    }
  ]
}
```

## Generated Patterns

### TypeScript Group Handler

```typescript
interface GroupValidation {
  name: string;
  options: string[];
  required?: boolean;
  errorMessage?: string;
  dependencies?: Record<string, string[]>;
}

export function validateMutuallyExclusiveGroups(
  args: Record<string, unknown>,
  groups: GroupValidation[]
): void {
  for (const group of groups) {
    const presentOptions = group.options.filter(opt => {
      const key = opt.replace(/^--/, '').replace(/-/g, '_');
      return args[key] !== undefined;
    });

    // Check mutual exclusivity
    if (presentOptions.length > 1) {
      throw new Error(
        group.errorMessage ||
        `Options ${presentOptions.join(', ')} are mutually exclusive`
      );
    }

    // Check required group
    if (group.required && presentOptions.length === 0) {
      throw new Error(
        `One of ${group.options.join(', ')} is required`
      );
    }

    // Check dependencies
    if (group.dependencies && presentOptions.length === 1) {
      const selected = presentOptions[0];
      const deps = group.dependencies[selected];
      if (deps) {
        for (const dep of deps) {
          const depKey = dep.replace(/^--/, '').replace(/-/g, '_');
          if (args[depKey] === undefined) {
            throw new Error(
              `${selected} requires ${dep} to be specified`
            );
          }
        }
      }
    }
  }
}
```

### Python Group Handler

```python
from typing import Dict, List, Optional, Any

class MutuallyExclusiveGroup:
    def __init__(
        self,
        name: str,
        options: List[str],
        required: bool = False,
        error_message: Optional[str] = None,
        dependencies: Optional[Dict[str, List[str]]] = None
    ):
        self.name = name
        self.options = options
        self.required = required
        self.error_message = error_message
        self.dependencies = dependencies or {}

def validate_groups(args: Dict[str, Any], groups: List[MutuallyExclusiveGroup]) -> None:
    for group in groups:
        present = [
            opt for opt in group.options
            if args.get(opt.lstrip('-').replace('-', '_')) is not None
        ]

        # Check mutual exclusivity
        if len(present) > 1:
            raise ValueError(
                group.error_message or
                f"Options {', '.join(present)} are mutually exclusive"
            )

        # Check required
        if group.required and not present:
            raise ValueError(
                f"One of {', '.join(group.options)} is required"
            )

        # Check dependencies
        if present and group.dependencies:
            selected = present[0]
            deps = group.dependencies.get(selected, [])
            for dep in deps:
                dep_key = dep.lstrip('-').replace('-', '_')
                if args.get(dep_key) is None:
                    raise ValueError(
                        f"{selected} requires {dep} to be specified"
                    )
```

## Workflow

1. **Define groups** - Specify mutually exclusive options
2. **Set requirements** - Required vs optional groups
3. **Add dependencies** - Dependent argument chains
4. **Create messages** - Custom error messages
5. **Generate validator** - Validation logic
6. **Generate docs** - Group documentation

## Target Processes

- argument-parser-setup
- error-handling-user-feedback
- cli-command-structure-design

Overview

This skill generates robust validation and error messaging for mutually exclusive argument groups in CLI applications. It produces language-targeted logic, dependency checks, required-group handling, and clear conflict messages to prevent ambiguous CLI usage. Use it to embed deterministic, developer-friendly argument rules into parsers and command handlers.

How this skill works

Provide a target language and a list of group definitions describing options, required flags, dependencies, and custom messages. The skill emits validation code that detects multiple selections in the same group, enforces required groups, validates dependent arguments when a particular option is chosen, and returns or throws concise error messages. It supports OR/XOR semantics and can generate small documentation snippets describing group behavior.

When to use it

  • When implementing CLI commands that must not accept multiple conflicting options
  • When some flags require companion flags (dependent argument chains)
  • When you need clear, user-friendly error messages for argument conflicts
  • When generating cross-language validation helpers for consistent CLI behavior
  • When you must enforce required groups (one of these options is mandatory)

Best practices

  • Model groups explicitly with names, option lists, required flags, and dependency maps
  • Normalize option keys (strip leading dashes and convert hyphens to underscores) for predictable arg access
  • Prefer custom errorMessage per group for domain-specific guidance instead of generic text
  • Validate dependencies only after confirming exactly one option in the group is present
  • Document groups in command help output so users see mutually exclusive relationships

Example use cases

  • Output format selection (--json | --yaml | --table) where exactly one format must be chosen
  • Authentication methods (--token or --username) where --username requires --password
  • Feature toggles where enabling one feature must disable others to avoid state conflicts
  • Subcommand flags that are mutually exclusive across shared top-level options
  • Automated generation of validator functions in JavaScript or Python for a CLI framework

FAQ

Can this enforce OR vs XOR semantics?

Yes. XOR (exactly one) is enforced by marking group.required true and rejecting multiple options. OR (one or more) can be modeled by setting required false and allowing multiple selections.

How are option names mapped to runtime args?

Options are normalized by stripping leading dashes and converting hyphens to underscores so they map to common argument object keys used by parsers and handlers.