| name | add-recipe-field |
| description | Add a new field to the NAPT recipe YAML schema. Categorizes the field (org-policy / strategy-specific / required / optional / computed) first, then walks the per-category checklist, documentation, changelog, and tests. |
| disable-model-invocation | true |
| user-invocable | true |
| allowed-tools | Read Edit Write Glob Grep Bash(*python* -m *) |
| argument-hint | field name (and optionally a brief description) |
You are adding a new field to the NAPT recipe schema. Categorize first — the category determines where validation, defaults, and access logic live. Follow every step in order.
Step 1: Categorize the new field
Every config value belongs to exactly one category. Use this flowchart:
Is this field set the same way across all/most recipes?
YES → Would an org admin configure it in org.yaml?
YES → Org-policy
NO → Is it required for the feature to work?
YES → Recipe-required
NO → Absent-means-skip
NO → Is it specific to a discovery/build strategy?
YES → Strategy-specific
NO → Does it depend on other config values?
YES → Computed/derived
NO → Absent-means-skip
Tell the user which category you've assigned and why before writing any code.
Step 2: Implement per the category checklist
Org-policy (e.g., run_as_account, log_format, build_types):
A test (test_org_yaml_template_covers_all_sections) validates that all sections in DEFAULT_CONFIG are mentioned in ORG_YAML_TEMPLATE.
Strategy-specific (e.g., timeout, prerelease, method):
Recipe-required (e.g., name, id, discovery.strategy):
Absent-means-skip (e.g., description, logo_path, notes):
Computed/derived (e.g., RequireAdmin, AppScriptDate):
Validation patterns. For installed-check fields, use the _INSTALLED_CHECK_FIELDS pattern in napt/validation.py:
_INSTALLED_CHECK_FIELDS: dict[str, tuple[type, list[str] | None, str]] = {
"new_field": (str, ["value1", "value2"], "field description"),
}
For other fields, add type/value validation in the appropriate validate_* function (or the strategy's validate_config() for strategy-specific fields).
Step 3: Document in docs/recipe-reference.md
Add field documentation following the standard format:
#### field_name
**Type:** `string`
**Required:** No
**Default:** `"default_value"`
**Allowed values:** `"value1"`, `"value2"`
Description of what the field does and when to use it.
Field documentation order: Type → Required → Default (if applicable) → Allowed values (if applicable) → Description → Examples (if helpful)
Step 4: Update examples
Add the field to example recipes in docs/common-tasks.md if it's commonly used, or note it as optional in relevant strategy examples.
Step 5: Update the changelog
Recipe schema changes are user-facing. Add an entry under [Unreleased] in docs/changelog.md following Keep a Changelog format (usually ### Added for a new field). Describe what recipe authors can now do, not the implementation.
Step 6: Verify implementation
Check these to ensure the field is actually used:
- Search codebase: grep for the field name in
napt/
- Verify it's read from config in relevant modules
- Check if field exists in defaults but isn't used (planned feature — flag this)
Step 7: Add tests and run the suite
Final invariants
All documented fields should either:
- Be validated in
validation.py AND used in the code, OR
- Be clearly marked as planned/future functionality, OR
- Be removed if no longer needed
Never leave a field that's documented but unimplemented without a "planned" note.