[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6PVC6MAJNRT58CT4JXGP8W1":3,"skill-same:01M6PVC6MAJNRT58CT4JXGP8W1":81},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":31,"publishedAt":47,"linkOnly":48,"markdownContent":49,"markdownBody":50,"frontMatter":51,"refName":55,"commitSha":56,"skillDirectory":57,"forksCount":54,"repositoryHtmlUrl":58,"repositoryHomepageUrl":6,"ownerHtmlUrl":59,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":60,"install":61,"resources":74},"01M6PVC6MAJNRT58CT4JXGP8W1","interface-design",null,"Shape a public contract so a reader with none of your context can use it. Use on any CRUD to a public interface — a field, method, type or enum member added, retyped, renamed or removed — and when reviewing a diff that touches one.","muratovv\u002Fai-hats","muratovv","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F7502801?v=4","01M6JGCBN4KEJX012GPJVSH04T","Fedor Muratov","01M6JGCBSNMN7CW3RGTPPE0MN2",3,"MIT","https:\u002F\u002Fgithub.com\u002Fmuratovv\u002Fai-hats\u002Fblob\u002Fmaster\u002Fpackages\u002Fai-hats-library\u002Fsrc\u002Fai_hats_library\u002Fexperimental\u002Fcore\u002Fskills\u002Finterface-design\u002FSKILL.md",[18,23,28],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000032","设计师","PROFESSION","适用职业",{"categoryNo":29,"categoryName":30,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000037","律师与法务",[32,33,34,35,36,37,38,39,40,41,42,43,44,45,46],"design","interface design","interface","crud","reader","public","context","use","diff","shape","contract","type","it","with","can","2026-11-10 10:12:30",false,"---\nname: interface-design\ndescription: >-\n  Shape a public contract so a reader with none of your context can use\n  it. Use on any CRUD to a public interface — a field, method, type or\n  enum member added, retyped, renamed or removed — and when reviewing a\n  diff that touches one.\nlicense: MIT\nai_hats:\n  schema_version: 1\n  type: skill\n---\n\n# Interface Design\n\nYou write an interface from the inside — what you put there, how it works — and\nit is read from the outside, by someone who knows neither. Every shape below is\none place that gap produced a defect in review.\n\n## When to Use\n\nAny CRUD on a public contract. Two neighbours: **api-evolution-checklist** asks\nwhether a change breaks existing callers (compatibility over time; this is the\nshape itself), and **design-minimalism** asks whether the primitive should exist\nat all — settle that first, this skill assumes you decided it should.\n\n## The shapes\n\n### Start from the minimal need, and do not let callers grow it\n\nPublish the smallest surface the caller needs; if what is already there expresses\nit, that is the path — a new method duplicating an existing capability is a second\nway to do one thing (below). Machinery stays behind the surface, not beside it.\n\nThe same rule from the other end: **a mechanism does not name its callers.** The\nset of things it can run is its own; the set of *uses* is the application's.\n\n```\n❌  class StepId(Enum):          ✅  class StepId(Enum):\n        LOAD, TRANSFORM,             LOAD, TRANSFORM, WRITE\n        REPORT_NIGHTLY,          # the application keeps its own catalog:\n        REPORT_WEEKLY            NIGHTLY = (LOAD, TRANSFORM, WRITE)\n```\n\n    application ──knows──▶ mechanism        mechanism ──must not know──▶ application\n\n### Public data is expressed in types\n\nA primitive on a public surface throws away what the value *is* and leaves the\nreader to guess. The same move applies at three scales:\n\n```\n❌  def get_id() -> str          ✅  def get_id() -> UserId\n❌  isolation: str = \"\"          ✅  isolation: Isolation      # closed set → enum\n❌  Request(role, project_dir, composition, manager, tracer, interactive,\n            prompt_path, model, isolation, ticket, tags, extra_args, target)\n✅  Request(what_to_run: Materialized, where: Placement, how: HarnessParams)\n```\n\nThirteen fields are thirteen because that is what the one call site had in scope.\nTo find the grouping, work out **which reader consumes each field**: the domain\ntypes fall out of the answer, and a field whose reader you cannot name is a field\nnobody reads — the three such fields above belonged to one caller only.\n\nThat question is a design move and stays one. Do **not** write its answer into the\ncomment: consumers change, comments do not, and a contract naming its consumers\nhas re-imported them. Comments say why a field exists when that is not obvious,\nand nothing about who calls it.\n\nBefore borrowing a word from surrounding code, follow it to its use: a field named\nfor the ticket *system* while carrying a card id, typed `str` where it needs two\nvalues, is two defects wearing one plausible name.\n\n### A field's type comes from its writer\n\nRead the code that *produces* the value, not the consumer you imagine. A field\ntyped `tuple[str, ...]` whose writer produces `dict[step, Exception]` throws the\nexceptions away and keeps the names — and nothing goes red, because its only\nreader is not written yet.\n\n### An undefined type is declared once, in a shared home, with a card\n\n```\n❌  def run(tracer_factory: object): ...      # here\n    TracerFactory = object                    # and again, three files away\n    Tracer = object                           # and now: same thing or not?\n\n✅  # types.py — the one home\n    TracerFactory = object   # placeholder: real type lands with the tracer\n```\n\nWhoever does not read your file declares their own alias, and a third person\ncannot tell whether the two names mean the same thing.\n\n### An identifier of another subsystem is that subsystem's import\n\n```\n❌  run(ticket_id: str)           # the contract now depends on the backlog,\n                                  # invisibly — nothing in the signature says so\n✅  run(prompt_context: Context)  # a caller resolves the id; the contract takes\n                                  # the result and stays unaware of its origin\n```\n\n    ❌  contract ──id──▶ [must reach into the other subsystem to mean anything]\n    ✅  caller ──resolves──▶ contract ──takes the resolved value──▶ done\n\n### Exactly one way to perform one action\n\nTwo spellings of the same read are a defect even when both work: the second is\nwhat the next migration standardises on by accident — nobody chooses it, it is\nsimply the one in front of the agent doing the conversion. The fix is not\ndocumenting which to prefer, it is deleting the choice: **lift**\nthe keys the contract answers for out of the raw bag instead of copying them\nbeside it, so a typed field has no raw twin. That form is testable: pin the typed\nfield list, and a field added without lifting its key is red.\n\n### Say why the field exists\n\n\"Resolved once by the entry point and passed down\" describes the process. \"Every\npath that touches a step hangs off it, and it is resolved once so nothing below\nrediscovers it\" says why the reader should care. Where the type already says it,\nsay nothing.\n\nNever illustrate with something the contract does not know: \"None for `init` and\n`nightly-report`\" re-imports the vocabulary the type was just cleared of.\nDescribe the **condition** — \"the run launched no session\" — not the instances.\n\n## Verify before the contract lands\n\nEach step names an action and what it proves. Do the action — a yes\u002Fno answered\nfrom memory is the failure this list exists to prevent.\n\n1. **Read every member name aloud against the mechanism's own vocabulary.** A\n   name only the application uses is a caller that leaked in; move it to the\n   application's catalog.\n2. **For each field, work out its reader and say what it consumes.** A reader you\n   cannot name means the field belongs to one caller, not to this contract.\n3. **Open each field's writer and read what it produces.** The type comes from\n   what is written, not from the consumer you pictured.\n4. **List every primitive on the surface and say what domain value it stands\n   for.** If it stands for one, it needs that type; a closed set needs an enum.\n5. **Grep the surface for `object` and for aliases of it.** Each undefined type\n   resolves to one declaration in a shared home, carrying the card that closes it.\n6. **Name every way to perform each action and count them.** More than one means\n   deleting the extra, not documenting which to prefer.\n7. **Open all call sites and wire the contract into them.** \"It will be typed\n   when its consumer arrives\" is not an answer: the next author builds against\n   what ships now.\n\n## Completion\n\nThe contract is judged on the **diff at real call sites**, not on a draft: wire it\ninto its callers and read what it costs them. A draft shows the shape, the diff\nshows the price. A full contract with every shape applied, data and interfaces\nboth → `references\u002Fworked-example.md`.\n\n**Validation scenario (RED).** Twelve interface defects from four review rounds\non one contract — an enum naming its callers, thirteen fields in a row, `object`\nre-aliased locally, a `str` mode, a foreign id, a typed field with a raw twin. An\nagent without this skill wrote all twelve and defended several; GREEN is each one\ncoming out in its ✅ form unprompted.\n\n## Anti-Patterns\n\n- Naming the principle instead of showing the shape — reciting SOLID does not\n  stop the thirteen-field bag.\n- Publishing a new method for a case an existing one already expresses.\n- Writing the consumer's name into a field's comment instead of why it exists.\n","# Interface Design\n\nYou write an interface from the inside — what you put there, how it works — and\nit is read from the outside, by someone who knows neither. Every shape below is\none place that gap produced a defect in review.\n\n## When to Use\n\nAny CRUD on a public contract. Two neighbours: **api-evolution-checklist** asks\nwhether a change breaks existing callers (compatibility over time; this is the\nshape itself), and **design-minimalism** asks whether the primitive should exist\nat all — settle that first, this skill assumes you decided it should.\n\n## The shapes\n\n### Start from the minimal need, and do not let callers grow it\n\nPublish the smallest surface the caller needs; if what is already there expresses\nit, that is the path — a new method duplicating an existing capability is a second\nway to do one thing (below). Machinery stays behind the surface, not beside it.\n\nThe same rule from the other end: **a mechanism does not name its callers.** The\nset of things it can run is its own; the set of *uses* is the application's.\n\n```\n❌  class StepId(Enum):          ✅  class StepId(Enum):\n        LOAD, TRANSFORM,             LOAD, TRANSFORM, WRITE\n        REPORT_NIGHTLY,          # the application keeps its own catalog:\n        REPORT_WEEKLY            NIGHTLY = (LOAD, TRANSFORM, WRITE)\n```\n\n    application ──knows──▶ mechanism        mechanism ──must not know──▶ application\n\n### Public data is expressed in types\n\nA primitive on a public surface throws away what the value *is* and leaves the\nreader to guess. The same move applies at three scales:\n\n```\n❌  def get_id() -> str          ✅  def get_id() -> UserId\n❌  isolation: str = \"\"          ✅  isolation: Isolation      # closed set → enum\n❌  Request(role, project_dir, composition, manager, tracer, interactive,\n            prompt_path, model, isolation, ticket, tags, extra_args, target)\n✅  Request(what_to_run: Materialized, where: Placement, how: HarnessParams)\n```\n\nThirteen fields are thirteen because that is what the one call site had in scope.\nTo find the grouping, work out **which reader consumes each field**: the domain\ntypes fall out of the answer, and a field whose reader you cannot name is a field\nnobody reads — the three such fields above belonged to one caller only.\n\nThat question is a design move and stays one. Do **not** write its answer into the\ncomment: consumers change, comments do not, and a contract naming its consumers\nhas re-imported them. Comments say why a field exists when that is not obvious,\nand nothing about who calls it.\n\nBefore borrowing a word from surrounding code, follow it to its use: a field named\nfor the ticket *system* while carrying a card id, typed `str` where it needs two\nvalues, is two defects wearing one plausible name.\n\n### A field's type comes from its writer\n\nRead the code that *produces* the value, not the consumer you imagine. A field\ntyped `tuple[str, ...]` whose writer produces `dict[step, Exception]` throws the\nexceptions away and keeps the names — and nothing goes red, because its only\nreader is not written yet.\n\n### An undefined type is declared once, in a shared home, with a card\n\n```\n❌  def run(tracer_factory: object): ...      # here\n    TracerFactory = object                    # and again, three files away\n    Tracer = object                           # and now: same thing or not?\n\n✅  # types.py — the one home\n    TracerFactory = object   # placeholder: real type lands with the tracer\n```\n\nWhoever does not read your file declares their own alias, and a third person\ncannot tell whether the two names mean the same thing.\n\n### An identifier of another subsystem is that subsystem's import\n\n```\n❌  run(ticket_id: str)           # the contract now depends on the backlog,\n                                  # invisibly — nothing in the signature says so\n✅  run(prompt_context: Context)  # a caller resolves the id; the contract takes\n                                  # the result and stays unaware of its origin\n```\n\n    ❌  contract ──id──▶ [must reach into the other subsystem to mean anything]\n    ✅  caller ──resolves──▶ contract ──takes the resolved value──▶ done\n\n### Exactly one way to perform one action\n\nTwo spellings of the same read are a defect even when both work: the second is\nwhat the next migration standardises on by accident — nobody chooses it, it is\nsimply the one in front of the agent doing the conversion. The fix is not\ndocumenting which to prefer, it is deleting the choice: **lift**\nthe keys the contract answers for out of the raw bag instead of copying them\nbeside it, so a typed field has no raw twin. That form is testable: pin the typed\nfield list, and a field added without lifting its key is red.\n\n### Say why the field exists\n\n\"Resolved once by the entry point and passed down\" describes the process. \"Every\npath that touches a step hangs off it, and it is resolved once so nothing below\nrediscovers it\" says why the reader should care. Where the type already says it,\nsay nothing.\n\nNever illustrate with something the contract does not know: \"None for `init` and\n`nightly-report`\" re-imports the vocabulary the type was just cleared of.\nDescribe the **condition** — \"the run launched no session\" — not the instances.\n\n## Verify before the contract lands\n\nEach step names an action and what it proves. Do the action — a yes\u002Fno answered\nfrom memory is the failure this list exists to prevent.\n\n1. **Read every member name aloud against the mechanism's own vocabulary.** A\n   name only the application uses is a caller that leaked in; move it to the\n   application's catalog.\n2. **For each field, work out its reader and say what it consumes.** A reader you\n   cannot name means the field belongs to one caller, not to this contract.\n3. **Open each field's writer and read what it produces.** The type comes from\n   what is written, not from the consumer you pictured.\n4. **List every primitive on the surface and say what domain value it stands\n   for.** If it stands for one, it needs that type; a closed set needs an enum.\n5. **Grep the surface for `object` and for aliases of it.** Each undefined type\n   resolves to one declaration in a shared home, carrying the card that closes it.\n6. **Name every way to perform each action and count them.** More than one means\n   deleting the extra, not documenting which to prefer.\n7. **Open all call sites and wire the contract into them.** \"It will be typed\n   when its consumer arrives\" is not an answer: the next author builds against\n   what ships now.\n\n## Completion\n\nThe contract is judged on the **diff at real call sites**, not on a draft: wire it\ninto its callers and read what it costs them. A draft shows the shape, the diff\nshows the price. A full contract with every shape applied, data and interfaces\nboth → `references\u002Fworked-example.md`.\n\n**Validation scenario (RED).** Twelve interface defects from four review rounds\non one contract — an enum naming its callers, thirteen fields in a row, `object`\nre-aliased locally, a `str` mode, a foreign id, a typed field with a raw twin. An\nagent without this skill wrote all twelve and defended several; GREEN is each one\ncoming out in its ✅ form unprompted.\n\n## Anti-Patterns\n\n- Naming the principle instead of showing the shape — reciting SOLID does not\n  stop the thirteen-field bag.\n- Publishing a new method for a case an existing one already expresses.\n- Writing the consumer's name into a field's comment instead of why it exists.\n",{"name":5,"ai_hats":52,"license":15,"description":7},{"type":53,"schema_version":54},"skill",1,"master","f922a7f627276366873d546942d9ad899a86f71a","packages\u002Fai-hats-library\u002Fsrc\u002Fai_hats_library\u002Fexperimental\u002Fcore\u002Fskills\u002Finterface-design","https:\u002F\u002Fgithub.com\u002Fmuratovv\u002Fai-hats","https:\u002F\u002Fgithub.com\u002Fmuratovv","2026-11-05 20:59:10",{"source":8,"skillName":5,"commands":62,"prompt":72,"zipAvailable":73},[63,66,69],{"tool":64,"command":65},"npx","npx skills add muratovv\u002Fai-hats --skill interface-design",{"tool":67,"command":68},"bunx","bunx skills add muratovv\u002Fai-hats --skill interface-design",{"tool":70,"command":71},"pnpm","pnpm dlx skills add muratovv\u002Fai-hats --skill interface-design","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fmuratovv\u002Fai-hats\u002Fblob\u002Fmaster\u002Fpackages\u002Fai-hats-library\u002Fsrc\u002Fai_hats_library\u002Fexperimental\u002Fcore\u002Fskills\u002Finterface-design\u002FSKILL.md",true,[75],{"path":76,"resourceType":77,"resourceTypeDesc":78,"sizeBytes":79,"sourceHtmlUrl":80},"references\u002Fworked-example.md","REFERENCE","参考文档",2240,"https:\u002F\u002Fgithub.com\u002Fmuratovv\u002Fai-hats\u002Fblob\u002Fmaster\u002Fpackages\u002Fai-hats-library\u002Fsrc\u002Fai_hats_library\u002Fexperimental\u002Fcore\u002Fskills\u002Finterface-design\u002Freferences\u002Fworked-example.md",[82,108,132,153,177,191],{"skillNo":83,"name":84,"nameZh":6,"description":85,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":86,"categories":87,"keywords":88,"publishedAt":47},"01M6PVFB1SM738R2SRSRSF7CY6","tool-evaluation-protocol","Time-bounded protocol for evaluating new tools, libraries, or methodologies before adoption. Use when evaluating a candidate dependency for the project, researching a methodology (e.g. ML\u002FLLM frameworks, testing approaches), or following up on a hype-driven recommendation.","https:\u002F\u002Fgithub.com\u002Fmuratovv\u002Fai-hats\u002Fblob\u002Fmaster\u002Fpackages\u002Fai-hats-library\u002Fsrc\u002Fai_hats_library\u002Fexperimental\u002Fusage\u002Fskills\u002Ftool-evaluation-protocol\u002FSKILL.md",[],[89,90,91,92,93,94,95,96,97,98,39,99,100,101,102,103,104,105,106,107],"protocol","Evaluation","tool","tool evaluation protocol","testing","ml","libraries","adoption","methodology","Tools","dependency","up","frameworks","time","project","recommendation","for","bounded","candidate",{"skillNo":109,"name":110,"nameZh":6,"description":111,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":112,"categories":113,"keywords":114,"publishedAt":47},"01M6PVF7HATBEX1G7N50E2QT57","systematic-debugging","4-phase bug-fix protocol (evidence, pattern, hypothesis, verify). Use when investigating any error, failure, or unexpected behavior, handling bug reports from users or monitoring, or diagnosing test failures with non-obvious causes.","https:\u002F\u002Fgithub.com\u002Fmuratovv\u002Fai-hats\u002Fblob\u002Fmaster\u002Fpackages\u002Fai-hats-library\u002Fsrc\u002Fai_hats_library\u002Fexperimental\u002Fusage\u002Fskills\u002Fsystematic-debugging\u002FSKILL.md",[],[115,116,117,118,89,119,120,121,122,123,39,124,125,126,127,128,129,45,130,131],"systematic debugging","debugging","systematic","test","monitoring","hypothesis","verify","behavior","fix","evidence","bug","reports","pattern","users","error","bug-fix","phase",{"skillNo":133,"name":134,"nameZh":6,"description":135,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":136,"categories":137,"keywords":141,"publishedAt":47},"01M6PVF3MTQN3RPF73AN34856J","skill-template","Canonical template and validation guide for ai-hats skills. Use when creating a new skill, reviewing an existing one for structural compliance, or deciding which pattern fits a new behavior.","https:\u002F\u002Fgithub.com\u002Fmuratovv\u002Fai-hats\u002Fblob\u002Fmaster\u002Fpackages\u002Fai-hats-library\u002Fsrc\u002Fai_hats_library\u002Fexperimental\u002Fusage\u002Fskills\u002Fskill-template\u002FSKILL.md",[138],{"categoryNo":139,"categoryName":140,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[142,143,144,145,146,122,147,39,148,127,149,150,151,105,152],"template","skill template","validation","compliance","hats","guide","new skill","structural","canonical","which","Existing",{"skillNo":154,"name":155,"nameZh":6,"description":156,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":157,"categories":158,"keywords":160,"publishedAt":47},"01M6PVF06SCV28QARM5MQPANC9","skill-optimization","Audit and refactor library components to eliminate redundancy and staleness. Use during periodic library maintenance, after adding multiple new skills or rules, when a role's token budget is too high, or after retrospectives identify component issues.","https:\u002F\u002Fgithub.com\u002Fmuratovv\u002Fai-hats\u002Fblob\u002Fmaster\u002Fpackages\u002Fai-hats-library\u002Fsrc\u002Fai_hats_library\u002Fexperimental\u002Fusage\u002Fskills\u002Fskill-optimization\u002FSKILL.md",[159],{"categoryNo":139,"categoryName":140,"taxonomyType":21,"taxonomyTypeDesc":22},[161,162,163,164,165,166,167,168,169,170,39,171,172,173,174,175,176],"Optimization","skill optimization","components","component","issues","library","audit","refactor","Budget","Rules","periodic","maintenance","token","token budget","role","high",{"skillNo":178,"name":179,"nameZh":6,"description":180,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":181,"categories":182,"keywords":183,"publishedAt":47},"01M6PVEXM9717016T9MW82HDCT","silent-fallback-gate","PreToolUse hook — refuses an Edit or Write that adds an inert broad except. Use when a Python edit was blocked for a silent fallback.","https:\u002F\u002Fgithub.com\u002Fmuratovv\u002Fai-hats\u002Fblob\u002Fmaster\u002Fpackages\u002Fai-hats-library\u002Fsrc\u002Fai_hats_library\u002Fexperimental\u002Fusage\u002Fskills\u002Fsilent-fallback-gate\u002FSKILL.md",[],[184,185,186,187,188,189,39,190,105],"gate","fallback","silent fallback gate","python","write","edit","hook",{"skillNo":192,"name":193,"nameZh":6,"description":194,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":195,"categories":196,"keywords":198,"publishedAt":47},"01M6PVESM49C5NT7SB7N3F76VS","retro-to-framework","Convert an observation about agent behavior — from a retrospective or from a single incident — into a framework-level change (hook, rule, skill, skill update). Use after a retrospective identifies problems that are not project-specific, after an incident where an agent misapplied a component it had read, when CLAUDE.md band-aids accumulate (more than 3 per-project rules that could be generic), or when the same problem recurs across multiple projects.","https:\u002F\u002Fgithub.com\u002Fmuratovv\u002Fai-hats\u002Fblob\u002Fmaster\u002Fpackages\u002Fai-hats-library\u002Fsrc\u002Fai_hats_library\u002Fexperimental\u002Fusage\u002Fskills\u002Fretro-to-framework\u002FSKILL.md",[197],{"categoryNo":139,"categoryName":140,"taxonomyType":21,"taxonomyTypeDesc":22},[199,200,201,202,164,203,204,205,170,122,39,206,207,103,208,209,210,211,212,213],"framework","retro","retro to framework","change","retrospective","projects","convert","incident","across","problem","about","more","skill update","single","generic"]