{"id":"fa28d66c-4e02-4670-b17d-3af066d81749","shortId":"BMq8Wm","kind":"skill","title":"pydantic","tagline":"Use when defining Pydantic models, BaseModel, BaseSettings, pydantic_settings, field validators, model validators, serializers, TypeAdapter, settings env config, external data validation, or v1-to-v2 migration.","description":"# Pydantic Skill\n\nPydantic v2 is a high-performance Python data validation library with first-class support for type hints, environment configuration via `BaseSettings`, and a complete rewrite from v1 with significant API changes.\n\n## Code Style Rules\n\n- Use PEP 604 for unions: `T | None` (not `Optional[T]`)\n- Use `model_config = ConfigDict(...)` not inner `class Config`\n- Use `model_validate()` for untrusted external input (not `__init__`)\n- Use `Annotated[T, Field(...)]` over `Field(...)` as a default value\n\n## Quick Reference\n\n### ConfigDict\n\n```python\nfrom pydantic import BaseModel, ConfigDict\n\nclass MyModel(BaseModel):\n    model_config = ConfigDict(\n        from_attributes=True,       # replaces orm_mode=True (v1)\n        extra=\"forbid\",             # \"allow\", \"ignore\", or \"forbid\"\n        validate_assignment=True,   # re-validate on attribute set\n        arbitrary_types_allowed=True,\n        populate_by_name=True,      # allow field name or alias\n        str_strip_whitespace=True,\n        frozen=True,                # make model immutable\n    )\n```\n\n### Validators\n\n```python\nfrom pydantic import BaseModel, field_validator, model_validator, computed_field\n\nclass Order(BaseModel):\n    quantity: int\n    unit_price: float\n    discount: float = 0.0\n\n    @field_validator(\"quantity\")\n    @classmethod\n    def quantity_must_be_positive(cls, v: int) -> int:\n        if v <= 0:\n            raise ValueError(\"quantity must be > 0\")\n        return v\n\n    @field_validator(\"discount\")\n    @classmethod\n    def discount_in_range(cls, v: float) -> float:\n        if not (0.0 <= v <= 1.0):\n            raise ValueError(\"discount must be between 0 and 1\")\n        return v\n\n    @model_validator(mode=\"before\")\n    @classmethod\n    def check_raw_data(cls, data: dict) -> dict:\n        # runs before individual field validation\n        if \"unit_price\" in data and data[\"unit_price\"] < 0:\n            raise ValueError(\"unit_price cannot be negative\")\n        return data\n\n    @model_validator(mode=\"after\")\n    def check_total(self) -> \"Order\":\n        # runs after all fields are validated; self is fully populated\n        if self.quantity * self.unit_price > 1_000_000:\n            raise ValueError(\"order total exceeds limit\")\n        return self\n\n    @computed_field\n    @property\n    def total(self) -> float:\n        return self.quantity * self.unit_price * (1 - self.discount)\n```\n\n### Serialization\n\n```python\nmodel = Order(quantity=2, unit_price=9.99)\n\n# model_dump options\nmodel.model_dump()\nmodel.model_dump(by_alias=True)          # use field aliases in output\nmodel.model_dump(exclude_unset=True)     # omit fields not explicitly set\nmodel.model_dump(exclude_none=True)      # omit None-valued fields\nmodel.model_dump(include={\"quantity\"})   # only these fields\nmodel.model_dump(exclude={\"discount\"})   # all except these fields\nmodel.model_dump(mode=\"json\")            # JSON-serializable types\n\n# JSON string\nmodel.model_dump_json()\nmodel.model_dump_json(by_alias=True, exclude_none=True)\n\n# Custom field serializer\nfrom pydantic import field_serializer\n\nclass Item(BaseModel):\n    price: float\n\n    @field_serializer(\"price\")\n    def serialize_price(self, v: float) -> str:\n        return f\"${v:.2f}\"\n\n# Custom model serializer\nfrom pydantic import model_serializer\n\nclass Item(BaseModel):\n    name: str\n    price: float\n\n    @model_serializer\n    def custom_serialize(self) -> dict:\n        return {\"label\": self.name, \"cost\": self.price}\n```\n\n### TypeAdapter — Bulk Validation\n\n```python\nfrom pydantic import TypeAdapter\n\n# Significantly faster than calling MyModel(...) in a loop\nadapter = TypeAdapter(list[MyModel])\nitems = adapter.validate_python(raw_list)          # from Python objects\nitems = adapter.validate_json(json_string)         # from JSON bytes/str\n\n# Also works for non-model types\nint_adapter = TypeAdapter(int)\nint_adapter.validate_python(\"42\")  # returns 42\n```\n\n### Custom Types — Annotated Pattern\n\n```python\nfrom typing import Annotated\nfrom pydantic import BeforeValidator, PlainSerializer, WithJsonSchema\nfrom pydantic.functional_validators import AfterValidator\n\ndef parse_comma_list(v: str | list) -> list[str]:\n    if isinstance(v, str):\n        return [item.strip() for item in v.split(\",\")]\n    return v\n\ndef validate_positive(v: int) -> int:\n    assert v > 0, \"must be positive\"\n    return v\n\nCommaList = Annotated[\n    list[str],\n    BeforeValidator(parse_comma_list),\n    WithJsonSchema({\"type\": \"string\", \"description\": \"Comma-separated values\"}),\n]\n\nPositiveInt = Annotated[int, AfterValidator(validate_positive)]\n\nTagList = Annotated[\n    list[str],\n    BeforeValidator(parse_comma_list),\n    PlainSerializer(lambda v: \",\".join(v), return_type=str),\n]\n```\n\n### BaseSettings — Environment Configuration\n\n```python\nfrom pydantic_settings import BaseSettings, SettingsConfigDict\n\nclass AppSettings(BaseSettings):\n    model_config = SettingsConfigDict(\n        env_file=\".env\",\n        env_file_encoding=\"utf-8\",\n        env_nested_delimiter=\"__\",   # DATABASE__HOST → database.host\n        case_sensitive=False,\n        extra=\"ignore\",\n    )\n\n    debug: bool = False\n    secret_key: str\n    allowed_hosts: list[str] = [\"localhost\"]\n\nsettings = AppSettings()   # reads from env + .env file\n```\n\nPriority chain: **explicit args > env vars > .env file > defaults**\n\nSee [BaseSettings Deep Reference](references/basesettings.md) for nested models, secrets directory, multiple env files, and custom sources.\n\n### PrivateAttr — Non-Validated Internal State\n\n```python\nfrom pydantic import BaseModel, PrivateAttr\n\nclass Connection(BaseModel):\n    host: str\n    port: int = 5432\n    _client: object = PrivateAttr(default=None)\n\n    def connect(self) -> None:\n        self._client = create_client(self.host, self.port)\n```\n\n### Constrained Types via Field\n\n```python\nfrom pydantic import BaseModel, Field\n\nclass Product(BaseModel):\n    name: str = Field(min_length=1, max_length=100)\n    price: float = Field(gt=0, le=999_999.99)\n    stock: int = Field(ge=0)\n    sku: str = Field(pattern=r\"^[A-Z]{3}-\\d{4}$\")\n    tags: list[str] = Field(min_length=0, max_length=10)\n```\n\n### Special Types\n\n```python\nfrom pydantic import EmailStr, SecretStr, AnyUrl, AnyHttpUrl\nfrom pydantic import PastDate, FutureDate, AwareDatetime, ByteSize\n\nclass UserProfile(BaseModel):\n    email: EmailStr              # validates email format\n    password: SecretStr          # hidden in repr/serialization\n    website: AnyHttpUrl | None = None\n    birth_date: PastDate | None = None\n    appointment: AwareDatetime | None = None  # timezone-aware datetime\n    avatar_size: ByteSize = \"5MB\"             # \"5MB\", \"1GiB\", etc.\n```\n\n### V1 → V2 Migration Quick Reference\n\n| V1 | V2 |\n|----|-----|\n| `class Config: orm_mode = True` | `model_config = ConfigDict(from_attributes=True)` |\n| `@root_validator` | `@model_validator(mode='before'/'after')` |\n| `@validator` | `@field_validator` |\n| `.dict()` | `.model_dump()` |\n| `.json()` | `.model_dump_json()` |\n| `.parse_obj(data)` | `.model_validate(data)` |\n| `.parse_raw(json_str)` | `.model_validate_json(json_str)` |\n| `__fields__` | `model_fields` |\n| `Field(alias=..., allow_population_by_field_name=True)` | `Field(alias=...) + ConfigDict(populate_by_name=True)` |\n\nSee [V1→V2 Migration Guide](references/migration-v1-v2.md) for full mapping, breaking changes, and coexistence patterns.\n\n### Performance\n\n```python\n# Prefer model_validate() for untrusted/external data — skips Python __init__ overhead\nobj = MyModel.model_validate(raw_dict)\n\n# TypeAdapter for batch operations — do NOT use list comprehension with __init__\nadapter = TypeAdapter(list[MyModel])\nitems = adapter.validate_python(raw_list)   # single validation pass\n\n# Selective model_dump — avoid serializing the whole model if you only need a few fields\nsubset = obj.model_dump(include={\"id\", \"name\"})\n```\n\n<workflow>\n\n## Workflow\n\n### Step 1: Define Models\n\nCreate `BaseModel` subclasses with type-annotated fields. Use `ConfigDict` at the top of each model to set behavior. Prefer `Annotated[T, Field(...)]` over `Field(...)` as default values for reusability.\n\n### Step 2: Add Validators\n\nAdd `@field_validator` for single-field rules. Use `@model_validator(mode='before')` to preprocess raw input dicts and `@model_validator(mode='after')` for cross-field invariants on the fully constructed model. Add `@computed_field` for derived read-only properties.\n\n### Step 3: Handle Serialization\n\nUse `model_dump(exclude_unset=True)` when patching. Use `by_alias=True` when the API consumer expects camelCase or snake_case aliases. Use `@field_serializer` or `@model_serializer` for custom output formats.\n\n### Step 4: Configure Settings\n\nCreate a `BaseSettings` subclass in `pydantic_settings` for environment-driven config. Set `env_nested_delimiter=\"__\"` to support nested models from flat env vars. Load once at startup and inject as a dependency.\n\n### Step 5: Validate\n\nRun `mypy` or `pyright` with the pydantic plugin. Use `TypeAdapter` when validating collections for performance. Run tests to confirm validator error messages are user-friendly.\n\n</workflow>\n\n<guardrails>\n\n## Guardrails\n\n- **Use `ConfigDict` not inner `class Config`** -- `class Config` is the V1 pattern and silently ignored in some V2 contexts.\n- **Use `model_validate()` for untrusted input** -- it is faster and safer than calling `__init__` directly; triggers full validation pipeline.\n- **Use `BaseSettings` for environment configuration** -- never read `os.environ` manually in application code; BaseSettings handles type coercion, defaults, and `.env` loading.\n- **Use `TypeAdapter` for bulk operations** -- never use a list comprehension calling `MyModel(...)` or `MyModel.model_validate(...)` in a loop; a single `TypeAdapter(list[MyModel]).validate_python(data)` is significantly faster.\n- **Never mix V1 and V2 patterns in the same model** -- mixing `@validator` (V1) with `@field_validator` (V2) in the same class causes silent misbehavior or errors.\n- **Use `Annotated[T, Field(...)]` over `Field(...)` as a default value** -- the `Annotated` pattern allows reuse as a type alias and avoids mutable default pitfalls.\n- **Use `SecretStr` for passwords and tokens** -- prevents accidental leakage in logs, repr, and serialization.\n- **Avoid `model_dump(mode='json')` in hot paths** -- use `model_dump_json()` directly when you need a JSON string; it skips the intermediate dict.\n\n</guardrails>\n\n<validation>\n\n### Validation Checkpoint\n\nBefore delivering Pydantic code, verify:\n\n- [ ] `model_config = ConfigDict(...)` used (not inner `class Config`)\n- [ ] `model_validate()` used for external/untrusted data (not bare `__init__`)\n- [ ] `TypeAdapter` used for bulk list/collection validation\n- [ ] No V1 patterns (`@validator`, `@root_validator`, `.dict()`, `.json()`) in new code\n- [ ] `BaseSettings` used for environment configuration, not `os.environ`\n- [ ] Passwords/tokens use `SecretStr`\n- [ ] `Annotated[T, Field(...)]` pattern used for constrained fields\n- [ ] `@computed_field` used for derived properties (not plain `@property`)\n\n</validation>\n\n<example>\n\n## Example\n\n**Task:** User registration model with validation + app settings loaded from environment.\n\n```python\nfrom __future__ import annotations  # NOT used — pydantic needs runtime type eval\n\nfrom typing import Annotated\nfrom pydantic import (\n    BaseModel,\n    ConfigDict,\n    EmailStr,\n    Field,\n    SecretStr,\n    computed_field,\n    field_validator,\n    model_validator,\n)\nfrom pydantic_settings import BaseSettings, SettingsConfigDict\n\n\n# --- Reusable constrained type aliases ---\nUsername = Annotated[str, Field(min_length=3, max_length=32, pattern=r\"^\\w+$\")]\nPassword = Annotated[SecretStr, Field(min_length=8)]\n\n\n# --- Domain model ---\nclass UserRegistration(BaseModel):\n    model_config = ConfigDict(str_strip_whitespace=True)\n\n    username: Username\n    email: EmailStr\n    password: Password\n    confirm_password: Password\n\n    @field_validator(\"username\")\n    @classmethod\n    def username_not_reserved(cls, v: str) -> str:\n        reserved = {\"admin\", \"root\", \"system\"}\n        if v.lower() in reserved:\n            raise ValueError(f\"'{v}' is a reserved username\")\n        return v\n\n    @model_validator(mode=\"after\")\n    def passwords_match(self) -> \"UserRegistration\":\n        if self.password != self.confirm_password:\n            raise ValueError(\"passwords do not match\")\n        return self\n\n    @computed_field\n    @property\n    def display_name(self) -> str:\n        return self.username.capitalize()\n\n\n# --- Settings from environment ---\nclass DatabaseSettings(BaseModel):\n    host: str = \"localhost\"\n    port: int = 5432\n    name: str = \"app\"\n    user: str = \"postgres\"\n    password: SecretStr = SecretStr(\"postgres\")\n\n    @computed_field\n    @property\n    def url(self) -> str:\n        pwd = self.password.get_secret_value()\n        return f\"postgresql+asyncpg://{self.user}:{pwd}@{self.host}:{self.port}/{self.name}\"\n\n\nclass AppSettings(BaseSettings):\n    model_config = SettingsConfigDict(\n        env_file=\".env\",\n        env_nested_delimiter=\"__\",\n        extra=\"ignore\",\n    )\n\n    debug: bool = False\n    secret_key: SecretStr\n    database: DatabaseSettings = DatabaseSettings()\n    allowed_hosts: list[str] = [\"localhost\"]\n\n\n# --- Usage ---\n# Validate untrusted input\nregistration = UserRegistration.model_validate({\n    \"username\": \"alice\",\n    \"email\": \"alice@example.com\",\n    \"password\": \"s3cure!pw\",\n    \"confirm_password\": \"s3cure!pw\",\n})\n\n# Load settings once at startup\n# DATABASE__HOST=db.prod DATABASE__PORT=5433 SECRET_KEY=xyz python app.py\nsettings = AppSettings()\ndb_url = settings.database.url\n```\n\n</example>\n\n---\n\n## References Index\n\nFor detailed guides and configuration examples, refer to the following documents in `references/`:\n\n- **[BaseSettings Deep Reference](references/basesettings.md)** -- SettingsConfigDict options, nested models, secrets directory, multiple env files, custom sources, and full working example.\n- **[V1→V2 Migration Guide](references/migration-v1-v2.md)** -- Full API mapping table, breaking changes, gotchas, and coexistence patterns during incremental migration.\n\n---\n\n## Official References\n\n- <https://docs.pydantic.dev/latest/>\n- <https://docs.pydantic.dev/latest/concepts/models/>\n- <https://docs.pydantic.dev/latest/concepts/validators/>\n- <https://docs.pydantic.dev/latest/concepts/serialization/>\n- <https://docs.pydantic.dev/latest/concepts/pydantic_settings/>\n- <https://docs.pydantic.dev/latest/migration/>\n- <https://github.com/pydantic/pydantic>\n- <https://github.com/pydantic/pydantic-settings>\n\n## Shared Styleguide Baseline\n\n- Use shared styleguides for generic language/framework rules to reduce duplication in this skill.\n- [General Principles](https://github.com/cofin/flow/blob/main/templates/styleguides/general.md)\n- [Python](https://github.com/cofin/flow/blob/main/templates/styleguides/languages/python.md)\n- Keep this skill focused on tool-specific workflows, edge cases, and integration details.","tags":["pydantic","flow","cofin","agent-skills","ai-agents","beads","claude-code","codex","cursor","developer-tools","gemini-cli","opencode"],"capabilities":["skill","source-cofin","skill-pydantic","topic-agent-skills","topic-ai-agents","topic-beads","topic-claude-code","topic-codex","topic-cursor","topic-developer-tools","topic-gemini-cli","topic-opencode","topic-plugin","topic-slash-commands","topic-spec-driven-development"],"categories":["flow"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/cofin/flow/pydantic","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add cofin/flow","source_repo":"https://github.com/cofin/flow","install_from":"skills.sh"}},"qualityScore":"0.455","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 11 github stars · SKILL.md body (14,993 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:07:38.791Z","embedding":null,"createdAt":"2026-04-23T13:04:00.907Z","updatedAt":"2026-05-18T19:07:38.791Z","lastSeenAt":"2026-05-18T19:07:38.791Z","tsv":"'-8':626 '/cofin/flow/blob/main/templates/styleguides/general.md)':1755 '/cofin/flow/blob/main/templates/styleguides/languages/python.md)':1759 '/latest/':1713 '/latest/concepts/models/':1716 '/latest/concepts/pydantic_settings/':1725 '/latest/concepts/serialization/':1722 '/latest/concepts/validators/':1719 '/latest/migration/':1728 '/pydantic/pydantic':1731 '/pydantic/pydantic-settings':1734 '0':202,208,234,266,559,741,749,767 '0.0':186,225 '000':300,301 '1':236,299,321,733,970 '1.0':227 '10':770 '100':736 '1gib':823 '2':328,1004 '2f':430 '3':758,1050,1453 '32':1456 '4':760,1086 '42':507,509 '5':1123 '5432':700,1560 '5433':1646 '5mb':821,822 '604':69 '8':1466 '9.99':331 '999':743 '999.99':744 'a-z':755 'accident':1296 'adapt':474,502,935 'adapter.validate':479,487,940 'add':1005,1007,1040 'admin':1501 'aftervalid':529,584 'alia':154,340,399,879,887,1063,1283 'alias':344,1074,1446 'alic':1626 'alice@example.com':1628 'allow':129,144,150,644,880,1278,1613 'also':494 'annot':95,512,518,566,582,588,979,993,1266,1276,1378,1411,1422,1448,1461 'anyhttpurl':780,802 'anyurl':779 'api':62,1067,1697 'app':1402,1563 'app.py':1651 'applic':1200 'appoint':810 'appset':614,650,1591,1653 'arbitrari':142 'arg':659 'assert':557 'assign':134 'attribut':120,140,841 'avatar':818 'avoid':950,1285,1303 'awar':816 'awaredatetim':786,811 'bare':1349 'baselin':1737 'basemodel':7,111,115,169,178,414,441,691,695,723,727,790,974,1426,1471,1554 'baseset':8,53,603,611,615,666,1091,1191,1202,1368,1441,1592,1672 'batch':926 'beforevalid':522,569,591 'behavior':991 'birth':805 'bool':639,1605 'break':902,1700 'bulk':459,1213,1354 'bytes':787,820 'bytes/str':493 'call':469,1183,1220 'camelcas':1070 'cannot':271 'case':633,1073,1770 'caus':1260 'chain':657 'chang':63,903,1701 'check':245,281 'checkpoint':1328 'class':45,83,113,176,412,439,613,693,725,788,832,1156,1158,1259,1340,1469,1552,1590 'classmethod':190,214,243,1491 'client':701,712 'cls':196,219,248,1496 'code':64,1201,1332,1367 'coercion':1205 'coexist':905,1704 'collect':1137 'comma':532,571,578,593 'comma-separ':577 'commalist':565 'complet':56 'comprehens':932,1219 'comput':174,310,1041,1386,1431,1539,1571 'config':19,79,84,117,617,833,838,1100,1157,1159,1335,1341,1473,1594 'configdict':80,106,112,118,839,888,982,1153,1336,1427,1474 'configur':51,605,1087,1194,1372,1663 'confirm':1143,1485,1632 'connect':694,707 'constrain':715,1384,1444 'construct':1038 'consum':1068 'context':1170 'cost':456 'creat':711,973,1089 'cross':1032 'cross-field':1031 'custom':404,431,449,510,679,1082,1685 'd':759 'data':21,39,247,249,261,263,275,862,865,914,1235,1347 'databas':630,1610,1641,1644 'database.host':632 'databaseset':1553,1611,1612 'date':806 'datetim':817 'db':1654 'db.prod':1643 'debug':638,1604 'deep':667,1673 'def':191,215,244,280,313,420,448,530,551,706,1492,1522,1542,1574 'default':102,664,704,999,1206,1273,1287 'defin':4,971 'delimit':629,1104,1601 'deliv':1330 'depend':1121 'deriv':1044,1390 'descript':576 'detail':1660,1773 'dict':250,251,452,853,923,1024,1326,1363 'direct':1185,1315 'directori':674,1681 'discount':184,213,216,230,377 'display':1543 'docs.pydantic.dev':1712,1715,1718,1721,1724,1727 'docs.pydantic.dev/latest/':1711 'docs.pydantic.dev/latest/concepts/models/':1714 'docs.pydantic.dev/latest/concepts/pydantic_settings/':1723 'docs.pydantic.dev/latest/concepts/serialization/':1720 'docs.pydantic.dev/latest/concepts/validators/':1717 'docs.pydantic.dev/latest/migration/':1726 'document':1669 'domain':1467 'driven':1099 'dump':333,336,338,348,358,368,375,383,393,396,855,858,949,964,1055,1305,1313 'duplic':1747 'edg':1769 'email':791,794,1481,1627 'emailstr':777,792,1428,1482 'encod':624 'env':18,619,621,622,627,653,654,660,662,676,1102,1111,1208,1596,1598,1599,1683 'environ':50,604,1098,1193,1371,1406,1551 'environment-driven':1097 'error':1145,1264 'etc':824 'eval':1418 'exampl':1395,1664,1690 'exceed':306 'except':379 'exclud':349,359,376,401,1056 'expect':1069 'explicit':355,658 'extern':20,90 'external/untrusted':1346 'extra':127,636,1602 'f':428,1510,1583 'fals':635,640,1606 'faster':467,1179,1238 'field':11,97,99,151,170,175,187,211,255,288,311,343,353,366,373,381,405,410,417,718,724,730,739,747,752,764,851,875,877,878,883,886,961,980,995,997,1008,1013,1033,1042,1076,1253,1268,1270,1380,1385,1387,1429,1432,1433,1450,1463,1488,1540,1572 'file':620,623,655,663,677,1597,1684 'first':44 'first-class':43 'flat':1110 'float':183,185,221,222,316,416,425,445,738 'focus':1763 'follow':1668 'forbid':128,132 'format':795,1084 'friend':1150 'frozen':159 'full':900,1187,1688,1696 'fulli':293,1037 'futur':1409 'futured':785 'ge':748 'general':1751 'generic':1742 'github.com':1730,1733,1754,1758 'github.com/cofin/flow/blob/main/templates/styleguides/general.md)':1753 'github.com/cofin/flow/blob/main/templates/styleguides/languages/python.md)':1757 'github.com/pydantic/pydantic':1729 'github.com/pydantic/pydantic-settings':1732 'gotcha':1702 'gt':740 'guardrail':1151 'guid':897,1661,1694 'handl':1051,1203 'hidden':798 'high':36 'high-perform':35 'hint':49 'host':631,645,696,1555,1614,1642 'hot':1309 'id':966 'ignor':130,637,1166,1603 'immut':163 'import':110,168,409,436,464,517,521,528,610,690,722,776,783,1410,1421,1425,1440 'includ':369,965 'increment':1707 'index':1658 'individu':254 'init':93,917,934,1184,1350 'inject':1118 'inner':82,1155,1339 'input':91,1023,1176,1621 'int':180,198,199,501,504,555,556,583,699,746,1559 'int_adapter.validate':505 'integr':1772 'intermedi':1325 'intern':685 'invari':1034 'isinst':540 'item':413,440,478,486,546,939 'item.strip':544 'join':598 'json':385,387,390,394,397,488,489,492,856,859,868,872,873,1307,1314,1320,1364 'json-serializ':386 'keep':1760 'key':642,1608,1648 'label':454 'lambda':596 'language/framework':1743 'le':742 'leakag':1297 'length':732,735,766,769,1452,1455,1465 'librari':41 'limit':307 'list':476,482,533,536,537,567,572,589,594,646,762,931,937,943,1218,1231,1615 'list/collection':1355 'load':1113,1209,1404,1636 'localhost':648,1557,1617 'log':1299 'loop':473,1227 'make':161 'manual':1198 'map':901,1698 'match':1524,1536 'max':734,768,1454 'messag':1146 'migrat':28,827,896,1693,1708 'min':731,765,1451,1464 'misbehavior':1262 'mix':1240,1249 'mode':124,241,278,384,835,847,1018,1028,1306,1520 'model':6,13,78,86,116,162,172,239,276,325,332,432,437,446,499,616,672,837,845,854,857,863,870,876,910,948,954,972,988,1016,1026,1039,1054,1079,1108,1172,1248,1304,1312,1334,1342,1399,1435,1468,1472,1518,1593,1679 'model.model':335,337,347,357,367,374,382,392,395 'multipl':675,1682 'must':193,206,231,560 'mutabl':1286 'mymodel':114,470,477,938,1221,1232 'mymodel.model':920,1223 'mypi':1126 'name':148,152,442,728,884,891,967,1544,1561 'need':958,1318,1415 'negat':273 'nest':628,671,1103,1107,1600,1678 'never':1195,1215,1239 'new':1366 'non':498,683 'non-model':497 'non-valid':682 'none':73,360,364,402,705,709,803,804,808,809,812,813 'none-valu':363 'obj':861,919 'obj.model':963 'object':485,702 'offici':1709 'omit':352,362 'oper':927,1214 'option':75,334,1677 'order':177,284,304,326 'orm':123,834 'os.environ':1197,1374 'output':346,1083 'overhead':918 'pars':531,570,592,860,866 'pass':946 'password':796,1292,1460,1483,1484,1486,1487,1523,1530,1533,1567,1629,1633 'passwords/tokens':1375 'pastdat':784,807 'patch':1060 'path':1310 'pattern':513,753,906,1163,1244,1277,1359,1381,1457,1705 'pep':68 'perform':37,907,1139 'pipelin':1189 'pitfal':1288 'plain':1393 'plainseri':523,595 'plugin':1132 'popul':146,294,881,889 'port':698,1558,1645 'posit':195,553,562,586 'positiveint':581 'postgr':1566,1570 'postgresql':1584 'prefer':909,992 'preprocess':1021 'prevent':1295 'price':182,259,265,270,298,320,330,415,419,422,444,737 'principl':1752 'prioriti':656 'privateattr':681,692,703 'product':726 'properti':312,1048,1391,1394,1541,1573 'pw':1631,1635 'pwd':1578,1586 'pydant':1,5,9,29,31,109,167,408,435,463,520,608,689,721,775,782,1094,1131,1331,1414,1424,1438 'pydantic.functional':526 'pyright':1128 'python':38,107,165,324,461,480,484,506,514,606,687,719,773,908,916,941,1234,1407,1650,1756 'quantiti':179,189,192,205,327,370 'quick':104,828 'r':754,1458 'rais':203,228,267,302,1508,1531 'rang':218 'raw':246,481,867,922,942,1022 're':137 're-valid':136 'read':651,1046,1196 'read-on':1045 'reduc':1746 'refer':105,668,829,1657,1665,1671,1674,1710 'references/basesettings.md':669,1675 'references/migration-v1-v2.md':898,1695 'registr':1398,1622 'replac':122 'repr':1300 'repr/serialization':800 'reserv':1495,1500,1507,1514 'return':209,237,274,308,317,427,453,508,543,549,563,600,1516,1537,1547,1582 'reus':1279 'reusabl':1002,1443 'rewrit':57 'root':843,1361,1502 'rule':66,1014,1744 'run':252,285,1125,1140 'runtim':1416 's3cure':1630,1634 'safer':1181 'secret':641,673,1580,1607,1647,1680 'secretstr':778,797,1290,1377,1430,1462,1568,1569,1609 'see':665,893 'select':947 'self':283,291,309,315,423,451,708,1525,1538,1545,1576 'self._client':710 'self.confirm':1529 'self.discount':322 'self.host':713,1587 'self.name':455,1589 'self.password':1528 'self.password.get':1579 'self.port':714,1588 'self.price':457 'self.quantity':296,318 'self.unit':297,319 'self.user':1585 'self.username.capitalize':1548 'sensit':634 'separ':579 'serial':15,323,406,411,418,421,433,438,447,450,951,1052,1077,1080,1302 'serializ':388 'set':10,17,141,356,609,649,990,1088,1095,1101,1403,1439,1549,1637,1652 'settings.database.url':1656 'settingsconfigdict':612,618,1442,1595,1676 'share':1735,1739 'signific':61,466,1237 'silent':1165,1261 'singl':944,1012,1229 'single-field':1011 'size':819 'skill':30,1750,1762 'skill-pydantic' 'skip':915,1323 'sku':750 'snake':1072 'sourc':680,1686 'source-cofin' 'special':771 'specif':1767 'startup':1116,1640 'state':686 'step':969,1003,1049,1085,1122 'stock':745 'str':155,426,443,535,538,542,568,590,602,643,647,697,729,751,763,869,874,1449,1475,1498,1499,1546,1556,1562,1565,1577,1616 'string':391,490,575,1321 'strip':156,1476 'style':65 'styleguid':1736,1740 'subclass':975,1092 'subset':962 'support':46,1106 'system':1503 'tabl':1699 'tag':761 'taglist':587 'task':1396 'test':1141 'timezon':815 'timezone-awar':814 'token':1294 'tool':1766 'tool-specif':1765 'top':985 'topic-agent-skills' 'topic-ai-agents' 'topic-beads' 'topic-claude-code' 'topic-codex' 'topic-cursor' 'topic-developer-tools' 'topic-gemini-cli' 'topic-opencode' 'topic-plugin' 'topic-slash-commands' 'topic-spec-driven-development' 'total':282,305,314 'trigger':1186 'true':121,125,135,145,149,158,160,341,351,361,400,403,836,842,885,892,1058,1064,1478 'type':48,143,389,500,511,516,574,601,716,772,978,1204,1282,1417,1420,1445 'type-annot':977 'typeadapt':16,458,465,475,503,924,936,1134,1211,1230,1351 'union':71 'unit':181,258,264,269,329 'unset':350,1057 'untrust':89,1175,1620 'untrusted/external':913 'url':1575,1655 'usag':1618 'use':2,67,77,85,94,342,930,981,1015,1053,1061,1075,1133,1152,1171,1190,1210,1216,1265,1289,1311,1337,1344,1352,1369,1376,1382,1388,1413,1738 'user':1149,1397,1564 'user-friend':1148 'usernam':1447,1479,1480,1490,1493,1515,1625 'userprofil':789 'userregistr':1470,1526 'userregistration.model':1623 'utf':625 'v':197,201,210,220,226,238,424,429,534,541,550,554,558,564,597,599,1497,1511,1517 'v.lower':1505 'v.split':548 'v1':25,59,126,825,830,894,1162,1241,1251,1358,1691 'v1-to-v2':24 'v2':27,32,826,831,895,1169,1243,1255,1692 'valid':12,14,22,40,87,133,138,164,171,173,188,212,240,256,277,290,460,527,552,585,684,793,844,846,850,852,864,871,911,921,945,1006,1009,1017,1027,1124,1136,1144,1173,1188,1224,1233,1250,1254,1327,1343,1356,1360,1362,1401,1434,1436,1489,1519,1619,1624 'valu':103,365,580,1000,1274,1581 'valueerror':204,229,268,303,1509,1532 'var':661,1112 'verifi':1333 'via':52,717 'w':1459 'websit':801 'whitespac':157,1477 'whole':953 'withjsonschema':524,573 'work':495,1689 'workflow':968,1768 'xyz':1649 'z':757","prices":[{"id":"93714398-ca1e-4dd7-9a70-54a14c8f63e7","listingId":"fa28d66c-4e02-4670-b17d-3af066d81749","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"cofin","category":"flow","install_from":"skills.sh"},"createdAt":"2026-04-23T13:04:00.907Z"}],"sources":[{"listingId":"fa28d66c-4e02-4670-b17d-3af066d81749","source":"github","sourceId":"cofin/flow/pydantic","sourceUrl":"https://github.com/cofin/flow/tree/main/skills/pydantic","isPrimary":false,"firstSeenAt":"2026-04-23T13:04:00.907Z","lastSeenAt":"2026-05-18T19:07:38.791Z"}],"details":{"listingId":"fa28d66c-4e02-4670-b17d-3af066d81749","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"cofin","slug":"pydantic","github":{"repo":"cofin/flow","stars":11,"topics":["agent-skills","ai-agents","beads","claude-code","codex","context-driven-development","cursor","developer-tools","gemini-cli","opencode","plugin","slash-commands","spec-driven-development","subagents","tdd","workflow"],"license":"apache-2.0","html_url":"https://github.com/cofin/flow","pushed_at":"2026-04-27T19:07:26Z","description":"Context-Driven Development toolkit for AI agents — spec-first planning, TDD workflow, and Beads integration.","skill_md_sha":"853311de04cf605e9b7a18d8328704695377cc0c","skill_md_path":"skills/pydantic/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/cofin/flow/tree/main/skills/pydantic"},"layout":"multi","source":"github","category":"flow","frontmatter":{"name":"pydantic","description":"Use when defining Pydantic models, BaseModel, BaseSettings, pydantic_settings, field validators, model validators, serializers, TypeAdapter, settings env config, external data validation, or v1-to-v2 migration."},"skills_sh_url":"https://skills.sh/cofin/flow/pydantic"},"updatedAt":"2026-05-18T19:07:38.791Z"}}