All skills
google avatar

/adk-style

@29933ce
by googlegoogle/adk-python22k stars
4,084

Python style and codebase conventions for ADK (Agent Development Kit): private-by-default file visibility, imports, type hints, Pydantic v2 models, formatting, docstrings, logging, async I/O, file and test layout, and unit test structure. Use when writing or editing ADK source or tests, deciding whether a new file or symbol should be public or private, naming or placing a test file, fixing a formatter, linter, or type-check failure (pyink, isort, ruff, mypy, addlicense, compliance-checks), or asking whether code matches house style. Don't use for reviewing a whole changeset (use adk-review), writing a developer guide or design doc for a code unit (use adk-unit-guide or adk-unit-design), building or configuring agents (use adk-agent-builder), or installing the toolchain (use adk-setup).

Use this Skill: https://skilld.dev/gh/google/adk-python/adk-style

This session only. Nothing lands on disk.

referencespydantic.md

≈1.1k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Pydantic Patterns

ADK models use Pydantic v2.

Basic Model Structure

  • Use Field() for validation, defaults, and descriptions.
  • Use PrivateAttr() for internal state that must not be serialized.
  • Use model_post_init() for setup logic, not __init__ — overriding __init__ on a Pydantic model bypasses validation ordering.
  • Use model_dump() / model_dump_json(), not the v1 dict() / json().

Which mechanism to use

Need Pattern
Simple numeric/string bounds Field(ge=0, le=100)
Single-field business logic @field_validator('field')
Cross-field consistency @model_validator(mode='after')
Field deprecation/migration @model_validator(mode='before')
Internal mutable state PrivateAttr(default_factory=...)
Post-construction setup model_post_init()

Field() with Constraints

Declare bounds on the field rather than writing a validator for them — it keeps the rule next to the data and shows up in the generated JSON schema.

compaction_interval: Optional[int] = Field(default=None, gt=0)
injected_latency_seconds: float = Field(default=0.0, le=120.0)

Documenting fields

The house style is an attribute docstring directly under the field, which Sphinx picks up:

model: Union[str, BaseLlm] = ''
"""The model to use for the agent.

When not set, the agent inherits the model from its ancestor.
"""

Those docstrings are documentation only. To also make them the field descriptions in the generated JSON schema, set use_attribute_docstrings=True in the model's ConfigDict; SerializedBaseModel already enables it.

class MyModel(BaseModel):
  model_config = ConfigDict(use_attribute_docstrings=True)

  field_name: str
  """Description of the field."""

On-Wire Models

A model that crosses a network or storage boundary — an API payload, a WebSocket message, a persisted event — should inherit from SerializedBaseModel in google.adk.utils._serialized_base_model rather than BaseModel. It sets alias_generator=to_camel with populate_by_name=True and defaults model_dump_json() to by_alias=True, so Python stays snake_case while the wire format stays camelCase without every call site remembering to pass by_alias.

field_validator — Single-Field Validation

Use @field_validator when a constraint needs logic that Field() cannot express.

@field_validator('max_llm_calls')
@classmethod
def validate_max_llm_calls(cls, value: int) -> int:
  if value <= 0:
    raise ValueError('max_llm_calls must be positive.')
  return value

Rules:

  • Add @classmethod under the decorator. Pydantic v2 applies it implicitly, but ADK writes it out — every validator in the codebase does.
  • Return the (possibly transformed) value.
  • Raise ValueError with a message that names the field and the bound.
  • The default mode is 'after', which runs post-coercion and is what you almost always want; omit the argument. Pass mode='before' only to intercept raw input.

model_validator — Cross-Field and Migration Validation

mode='before' — deprecation and field migration

Receives the raw input, usually a dict, before any field is parsed. Use it to rename or back-fill fields.

@model_validator(mode='before')
@classmethod
def check_for_deprecated_save_live_audio(cls, data: Any) -> Any:
  """If save_live_audio is passed, use it to set save_live_blob."""
  if isinstance(data, dict) and 'save_live_audio' in data:
    warnings.warn(
        'The `save_live_audio` config is deprecated, use `save_live_blob`.',
        DeprecationWarning,
        stacklevel=2,
    )
    if data['save_live_audio']:
      data['save_live_blob'] = True
  return data

Guard with isinstance(data, dict): the input can also arrive as an already constructed model instance, and indexing that raises.

mode='after' — cross-field consistency

Receives the constructed instance and must return it.

@model_validator(mode='after')
def _validate_parallel_worker_config(self) -> Node:
  if self.max_parallel_workers is not None and not self.parallel_worker:
    raise ValueError(
        'max_parallel_workers can only be set when parallel_worker is True.'
    )
  return self

Source: SKILL.md on GitHub

No alerts16d3 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    This skill provides comprehensive Python style and codebase conventions for the Agent Development Kit (ADK). It covers visibility, imports, typing, Pydantic models, formatting, and testing, all of which align with standard software development best practices.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

Signed by skilld at 29933ce. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated 2 months ago

README badge

README badge for google/adk-python/adk-style