- name
- common-custom-code-router
- description
- Use when adding or updating Azure CLI command module custom code and deciding whether the requested work should use AAZ subclass custom, legacy SDK-backed custom, or legacy non-SDK custom before generating code.
- argument-hint
- Describe the module, command group, command/action, and intended behavior if known.
# Common Custom Code Router
Use this workflow before generating Azure CLI command module custom code when the requested change may fit more than one authoring pattern.
The router classifies the work into exactly one primary route:
1. `aaz-subclass-custom`
2. `legacy-sdk-backed-custom`
3. `legacy-non-sdk-custom`
This skill is a classifier. Do not implement the command while routing unless the route is already clear and the user asked for implementation.
## Module-General Scope
Apply this classification across all Azure CLI command modules under `src/azure-cli/azure/cli/command_modules`. Module names such as `acr`, `acs`, or command groups such as `aks safeguards` are examples only. Do not treat any example module as the scope of this skill.
Always classify by the requested behavior and local evidence in the target module: generated AAZ assets, command registration style, available client factories, handler shape, and neighboring command patterns.
## Inputs
Start with the information available in the prompt and editor context:
- target module, such as `acr` or `acs`
- target command group, such as `acr`, `acr helm`, `aks safeguards`, or any other module command group
- target command or action, such as `show`, `create`, `login`, `check-health`, or a new action name
- intended behavior or service operation
- current file path, if the user is editing one
If a required input is missing, infer it from the current file path or nearest existing module pattern. Ask the user only when the missing input is a product or API decision, not when it can be discovered from the repository.
## Evidence To Gather
Use narrow searches and nearby reads. Prefer the target module only.
1. Locate the module root under `src/azure-cli/azure/cli/command_modules/<module>/`.
2. Read or search the module's `__init__.py` for `load_aaz_command_table`.
3. Search `aaz/latest` for generated files matching the target resource/action, such as `_create.py`, `_show.py`, `_list.py`, `_delete.py`, `_update.py`, or `_wait.py`.
4. Search `commands.py` for the target command group and nearby `CliCommandType` definitions.
5. Search `custom.py` and neighboring files for existing custom classes inheriting generated AAZ command classes.
6. Search `_client_factory.py` and nearby command registrations for reusable `cf_*` client factories.
7. Inspect neighboring commands with the same resource family or command group.
For new commands, do not require an existing exact command. Use the nearest command group, nearest resource family, generated AAZ assets, and intended service operation as evidence.
## Route Decision
### Route 1: AAZ Subclass Custom
Choose `aaz-subclass-custom` when the requested work customizes or wraps an AAZ generated command.
Strong signals:
- Matching generated command exists under `aaz/latest/.../_<verb>.py`.
- Generated file contains `# Code generated by aaz-dev-tools` and `class <Verb>(AAZCommand)`.
- Existing nearby custom code imports from `.aaz.latest...` and defines `class XxxCustom(Create|Show|List|Update|Delete|Wait)`.
- The requested change is mainly argument UX, argument schema, pre-validation, post-processing, lifecycle hooks, or a small behavior override around an existing generated operation.
- Code would naturally use `self.ctx.args`, `has_value`, `AAZStrArg`, `AAZResourceGroupNameArg`, `pre_operations`, `post_operations`, or `_build_arguments_schema`.
Do not choose this route just because the module has an `aaz/` directory. The generated command must match the requested resource/action or the command group must already be AAZ-first.
### Route 2: Legacy SDK-Backed Custom
Choose `legacy-sdk-backed-custom` when the command should be a hand-written function that calls an Azure Python SDK client.
Strong signals:
- Existing command group uses `CliCommandType(..., client_factory=cf_xxx)`.
- Command registration uses `g.command(...)`, `g.show_command(...)`, or `g.generic_update_command(...)` with an `operations_tmpl` pointing to a module function.
- Handler is or should be a `def` function in `custom.py` or another module file.
- The handler takes `client` or can reuse a `cf_*` client factory.
- Main behavior is `client.get(...)`, `client.list(...)`, `client.list_by_resource_group(...)`, `client.begin_create...`, `client.begin_update...`, `client.begin_delete...`, or similar SDK methods.
- Code constructs SDK models through `cmd.get_models(...)`.
- The change is CRUD, update, action-on-resource, identity/encryption/network policy, LRO, or `generic_update_command` style behavior.
If both AAZ and SDK are viable, prefer the existing command group's dominant style. If the group is mixed and both implementations are equally plausible, ask one question about the intended API source.
### Route 3: Legacy Non-SDK Custom
Choose `legacy-non-sdk-custom` when the command is hand-written but the main behavior is not a simple SDK resource operation.
Strong signals:
- Main behavior uses local tools or subprocesses, such as `docker`, `podman`, `kubectl`, `helm`, `notary`, `Popen`, `subprocess.run`, or `subprocess.check_output`.
- Main behavior uses raw HTTP, data-plane APIs, custom REST calls, external downloads, or `send_raw_request`, `requests`, `urlopen`, or generated AAZ commands only as internal helpers.
- Main behavior orchestrates multiple services, local files, environment variables, credentials, diagnostics, install flows, archive packaging, kubeconfig, or browser/proxy behavior.
- The command may still be registered through `CliCommandType`, but a SDK CRUD/action template would not describe the implementation.
Examples include login, check-health, install-cli, browse, repository/data-plane operations, import/export helpers, and local packaging flows.
## Tie Breakers
Use these tie breakers in order:
1. Prefer the dominant style of the target command group.
2. Prefer the nearest sibling command that uses the same resource family and verb.
3. Prefer AAZ subclass custom only when matching generated AAZ command assets already exist and the customization is around that operation.
4. Prefer legacy SDK-backed custom when the SDK operation/client factory is the primary service interface.
5. Prefer legacy non-SDK custom when the behavior is a workflow, local-tool operation, data-plane operation, or diagnostic flow.
6. If still ambiguous, ask one concise question that names the two plausible routes and the missing decision.
## Output Format
Return a compact routing result before implementation:
```yaml
route: aaz-subclass-custom | legacy-sdk-backed-custom | legacy-non-sdk-custom
confidence: high | medium | low
evidence:
- "Concrete repo signal, file, symbol, or pattern."
- "Concrete repo signal, file, symbol, or pattern."
resolved_slots:
module_name: "<module or unknown>"
command_group: "<group or unknown>"
operation_module: "<module path or unknown>"
generated_aaz_base: "<class import or not-applicable>"
client_factory: "<cf_xxx or not-applicable>"
primary_service_interface: "aaz | sdk | non-sdk | unknown"
open_questions:
- "Only include if required to proceed."
next_skill: "common-aaz-custom-code-generation | common-legacy-sdk-backed-custom-code-generation | common-legacy-non-sdk-custom-code-generation"
```
Keep `evidence` grounded in existing files or in the user's stated intended behavior. Do not claim an exact route based only on module name.
## Common Mistakes To Avoid
- Do not classify a whole module as AAZ just because `aaz/latest` exists.
- Do not classify every non-AAZ custom function as SDK-backed.
- Do not classify commands that call `docker`, `kubectl`, `helm`, raw HTTP, or data-plane APIs as SDK-backed just because they live in `custom.py`.
- Do not require an exact existing command when the user is adding a new command. Use command group style, generated assets, SDK availability, and requested behavior.
- Do not edit generated AAZ files under `aaz/latest` unless the user explicitly asks to modify generated output and understands regeneration risk.
Ver en GitHub