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.

referencestyping.md

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

Type Hints and Strong Typing

General Rules

  • Annotate everything: type hints on all function arguments and return types.
  • Minimize Any: use a specific type or a TypeVar. Any disables checking for every value that flows through it.
  • from __future__ import annotations goes at the top of every module under src/google/adk/, immediately after the license header and before any other import. scripts/compliance_checks.py fails the commit if it is missing. Exempt: __init__.py, version.py, tests/, and contributing/samples/.
  • No quoted type hints. Deferred annotations make forward references work unquoted, so write list[str], not "list[str]".
  • Builtin generics for new code: list[str], dict[str, int], tuple[str, ...]. typing.List / typing.Dict survive in older modules; don't add more, and don't churn existing ones.

Mypy

Mypy runs in strict mode against src/ with the Pydantic plugin, targeting Python 3.11 ([tool.mypy] in pyproject.toml). tests/ and contributing/samples/ are excluded.

mypy .

The CI job compares your branch's errors against the base branch and fails only on new ones, so a pre-existing error in a file you touched is not your problem — an error on a line you added is.

Optional[X] vs X | None

Both appear in the codebase. Follow this convention:

  • New code (especially in workflow/): prefer X | None.
  • Existing files: match the style already in the file.
  • Do not refactor one into the other without a reason.

Abstract Types for Function Parameters

Annotate parameters with abstract types from collections.abc so callers can pass any compatible container; annotate returns with the concrete type so callers know exactly what they get.

from collections.abc import Mapping
from collections.abc import Sequence

def merge_labels(
    labels: Mapping[str, str], extra: Sequence[str]
) -> dict[str, str]:
  ...

Keyword-Only Arguments

Put * before the parameters of any constructor or function where argument order is easy to get wrong — two parameters of the same type is enough for a silent bug.

class NodeRunner:

  def __init__(
      self,
      *,
      node: BaseNode,
      parent_ctx: Context,
      run_id: str | None = None,
  ):
    ...

Use it for: constructors with 2+ non-self parameters, any function where swapping two arguments would still typecheck, and methods taking several str or int parameters.

Mutable Default Arguments

A mutable default is evaluated once at definition time and shared by every call, so one caller's mutation leaks into the next. Use None as a sentinel:

# Bad — every caller shares one list.
def add(item: str, items: list[str] = []) -> list[str]:
  ...

# Good
def add(item: str, items: list[str] | None = None) -> list[str]:
  items = list(items) if items else []
  ...

This applies to list, dict, set, and any other mutable type.

Runtime Type Discrimination with isinstance()

isinstance() is the codebase's standard way to handle polymorphic input. Write exhaustive if/elif chains and always terminate them:

if isinstance(node, FunctionNode):
  ...
elif isinstance(node, (JoinNode, ToolNode)):
  ...
else:
  raise TypeError(f'Unsupported node type: {type(node)}')
  • Always include an else that raises TypeError or handles the unknown case, so a new subclass fails loudly instead of silently doing nothing.
  • Prefer isinstance(x, SomeType) over type(x) is SomeType — it handles subclasses.
  • Check several types at once with a tuple: isinstance(x, (TypeA, TypeB)).

No Asserts in Production Code

assert is stripped when Python runs with -O, so an assertion is not a runtime guarantee, and its failure message tells the caller nothing. Raise ValueError, TypeError, or RuntimeError instead. Asserts in tests are fine.

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