wicked-garden 12.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (640) hide show
  1. package/.claude-plugin/archetypes.json +166 -0
  2. package/.claude-plugin/components.json +75 -0
  3. package/.claude-plugin/marketplace.json +15 -0
  4. package/.claude-plugin/plugin.json +174 -0
  5. package/.claude-plugin/specialist.json +48 -0
  6. package/.claude-plugin/stack-registry.json +96 -0
  7. package/AGENTS.md +13 -0
  8. package/CHANGELOG.md +712 -0
  9. package/CONTRIBUTING.md +99 -0
  10. package/ETHOS.md +83 -0
  11. package/LICENSE +21 -0
  12. package/README.md +115 -0
  13. package/WICKED_GARDEN_BUS_EVENTS.md +149 -0
  14. package/agents/agentic/architect.md +449 -0
  15. package/agents/agentic/performance-analyst.md +702 -0
  16. package/agents/agentic/safety-reviewer.md +662 -0
  17. package/agents/crew/implementer.md +163 -0
  18. package/agents/crew/researcher.md +94 -0
  19. package/agents/crew/reviewer.md +184 -0
  20. package/agents/data/data-engineer.md +227 -0
  21. package/agents/engineering/api-documentarian.md +440 -0
  22. package/agents/engineering/migration-engineer.md +301 -0
  23. package/agents/engineering/solution-architect.md +208 -0
  24. package/agents/jam/brainstorm-facilitator.md +297 -0
  25. package/agents/jam/council.md +322 -0
  26. package/agents/jam/quick-facilitator.md +85 -0
  27. package/agents/persona/persona-agent.md +121 -0
  28. package/agents/platform/compliance-officer.md +266 -0
  29. package/agents/platform/privacy-expert.md +496 -0
  30. package/agents/platform/security-engineer.md +287 -0
  31. package/agents/product/a11y-expert.md +323 -0
  32. package/agents/product/requirements-analyst.md +238 -0
  33. package/agents/product/ui-reviewer.md +180 -0
  34. package/agents/product/ux-designer.md +199 -0
  35. package/agents/product/value-strategist.md +269 -0
  36. package/agents/qe/semantic-reviewer.md +78 -0
  37. package/commands/agentic/audit.md +24 -0
  38. package/commands/agentic/design.md +24 -0
  39. package/commands/agentic/frameworks.md +25 -0
  40. package/commands/agentic/review.md +27 -0
  41. package/commands/archetype/build.md +12 -0
  42. package/commands/archetype/decide.md +12 -0
  43. package/commands/archetype/explore.md +12 -0
  44. package/commands/archetype/incident.md +12 -0
  45. package/commands/archetype/migrate.md +12 -0
  46. package/commands/archetype/modernize.md +12 -0
  47. package/commands/archetype/review.md +14 -0
  48. package/commands/archetype/ship.md +12 -0
  49. package/commands/archetype/specify.md +12 -0
  50. package/commands/archetype/triage.md +12 -0
  51. package/commands/compile.md +37 -0
  52. package/commands/data/analyze.md +18 -0
  53. package/commands/data/data.md +21 -0
  54. package/commands/data/ml.md +18 -0
  55. package/commands/data/ontology.md +22 -0
  56. package/commands/data/pipeline.md +17 -0
  57. package/commands/deliberate.md +181 -0
  58. package/commands/engineering/add-field.md +77 -0
  59. package/commands/engineering/apply.md +58 -0
  60. package/commands/engineering/arch.md +26 -0
  61. package/commands/engineering/debug.md +27 -0
  62. package/commands/engineering/docs.md +27 -0
  63. package/commands/engineering/new-generator.md +257 -0
  64. package/commands/engineering/patch-plan.md +59 -0
  65. package/commands/engineering/plan.md +29 -0
  66. package/commands/engineering/remove.md +48 -0
  67. package/commands/engineering/rename.md +44 -0
  68. package/commands/engineering/review.md +32 -0
  69. package/commands/help.md +128 -0
  70. package/commands/install.md +118 -0
  71. package/commands/intent.md +54 -0
  72. package/commands/jam/brainstorm.md +37 -0
  73. package/commands/jam/council.md +49 -0
  74. package/commands/jam/quick.md +21 -0
  75. package/commands/jam/revisit.md +79 -0
  76. package/commands/persona/as.md +136 -0
  77. package/commands/persona/define.md +24 -0
  78. package/commands/persona/list.md +118 -0
  79. package/commands/platform/actions.md +20 -0
  80. package/commands/platform/assert.md +18 -0
  81. package/commands/platform/audit.md +23 -0
  82. package/commands/platform/compliance.md +20 -0
  83. package/commands/platform/gh.md +22 -0
  84. package/commands/platform/health.md +22 -0
  85. package/commands/platform/incident.md +23 -0
  86. package/commands/platform/infra.md +24 -0
  87. package/commands/platform/peer-health.md +103 -0
  88. package/commands/platform/plugin-health.md +58 -0
  89. package/commands/platform/security.md +38 -0
  90. package/commands/platform/toolchain.md +96 -0
  91. package/commands/platform/traces.md +20 -0
  92. package/commands/product/a11y.md +19 -0
  93. package/commands/product/acceptance.md +19 -0
  94. package/commands/product/align.md +20 -0
  95. package/commands/product/analyze.md +23 -0
  96. package/commands/product/elicit.md +19 -0
  97. package/commands/product/listen.md +24 -0
  98. package/commands/product/mockup.md +20 -0
  99. package/commands/product/screenshot.md +19 -0
  100. package/commands/product/strategy.md +40 -0
  101. package/commands/product/synthesize.md +23 -0
  102. package/commands/product/ux-review.md +42 -0
  103. package/commands/product/ux.md +20 -0
  104. package/commands/product/visual-direction.md +34 -0
  105. package/commands/prove.md +47 -0
  106. package/commands/report-issue.md +243 -0
  107. package/commands/reset.md +144 -0
  108. package/commands/search/blast-radius.md +58 -0
  109. package/commands/search/hotspots.md +55 -0
  110. package/commands/search/index.md +38 -0
  111. package/commands/search/lineage.md +47 -0
  112. package/commands/search/service-map.md +79 -0
  113. package/commands/setup.md +363 -0
  114. package/commands/smaht/briefing.md +200 -0
  115. package/commands/smaht/events-import.md +95 -0
  116. package/commands/smaht/state.md +19 -0
  117. package/commands/where-am-i.md +58 -0
  118. package/docs/README.md +32 -0
  119. package/docs/adr/0001-code-relationship-graph-engine.md +116 -0
  120. package/docs/adr/0002-major-cleanup-keep-cut.md +91 -0
  121. package/docs/adr/0003-peers-gate-required-layers-optin.md +41 -0
  122. package/docs/adr/0004-code-graph-moves-to-wicked-brain.md +47 -0
  123. package/docs/brain-chunk-format.md +135 -0
  124. package/docs/compiler.md +95 -0
  125. package/docs/daemon-api.md +70 -0
  126. package/docs/domains.md +197 -0
  127. package/docs/getting-started.md +208 -0
  128. package/docs/plans/2026-06-08-wicked-loom-conduct.md +1337 -0
  129. package/docs/plans/2026-06-08-wicked-loom-contract.md +638 -0
  130. package/docs/plans/2026-06-08-wicked-loom-cutover.md +1300 -0
  131. package/docs/plans/2026-06-08-wicked-loom-expand-compose.md +843 -0
  132. package/docs/plans/2026-06-08-wicked-loom-flow-cutover.md +403 -0
  133. package/docs/plans/2026-06-10-codegraph-to-brain-phase1a-graph-core.md +838 -0
  134. package/docs/plans/2026-06-10-codegraph-to-brain-phase1b-injected-edges.md +44 -0
  135. package/docs/required-peers.md +60 -0
  136. package/docs/specs/2026-06-08-wicked-loom-extraction.md +225 -0
  137. package/docs/specs/2026-06-10-codegraph-to-brain-migration.md +168 -0
  138. package/docs/v11/archetypes.md +231 -0
  139. package/hooks/hooks.json +275 -0
  140. package/hooks/scripts/bootstrap.py +1797 -0
  141. package/hooks/scripts/invoke.py +62 -0
  142. package/hooks/scripts/notification.py +166 -0
  143. package/hooks/scripts/permission_request.py +223 -0
  144. package/hooks/scripts/post_tool.py +1374 -0
  145. package/hooks/scripts/pre_compact.py +272 -0
  146. package/hooks/scripts/pre_tool.py +1278 -0
  147. package/hooks/scripts/prompt_submit.py +1109 -0
  148. package/hooks/scripts/session_end.py +95 -0
  149. package/hooks/scripts/stop.py +624 -0
  150. package/hooks/scripts/subagent_lifecycle.py +464 -0
  151. package/hooks/scripts/subscribers/on_gate_decided.py +84 -0
  152. package/hooks/scripts/task_completed.py +322 -0
  153. package/hooks/scripts/worktree_guard.py +148 -0
  154. package/hooks/subscriptions/on_gate_decided.json +9 -0
  155. package/install.mjs +128 -0
  156. package/package.json +41 -0
  157. package/pyproject.toml +59 -0
  158. package/schemas/README.md +32 -0
  159. package/schemas/assert_contracts.json +37 -0
  160. package/schemas/health_probe.json +46 -0
  161. package/schemas/plugin_status.json +37 -0
  162. package/scripts/_adapters/__init__.py +166 -0
  163. package/scripts/_adapters/jira_adapter.py +18 -0
  164. package/scripts/_adapters/linear_adapter.py +18 -0
  165. package/scripts/_adapters/miro_adapter.py +18 -0
  166. package/scripts/_adapters/notion_adapter.py +18 -0
  167. package/scripts/_agents.py +357 -0
  168. package/scripts/_brain_ingest/__init__.py +2 -0
  169. package/scripts/_brain_ingest/session_fact_extractor.py +341 -0
  170. package/scripts/_brain_port.py +163 -0
  171. package/scripts/_bus.py +1081 -0
  172. package/scripts/_bus_catalog_gen.py +93 -0
  173. package/scripts/_bus_consumers.json +46 -0
  174. package/scripts/_bus_emit.py +43 -0
  175. package/scripts/_capability_registry.py +334 -0
  176. package/scripts/_capability_resolver.py +322 -0
  177. package/scripts/_domain_store.py +559 -0
  178. package/scripts/_event_log_reader.py +154 -0
  179. package/scripts/_event_schema.py +305 -0
  180. package/scripts/_event_store.py +397 -0
  181. package/scripts/_heavy_cadence.py +324 -0
  182. package/scripts/_integration_resolver.py +321 -0
  183. package/scripts/_logger.py +151 -0
  184. package/scripts/_loom.py +482 -0
  185. package/scripts/_paths.py +133 -0
  186. package/scripts/_python.sh +22 -0
  187. package/scripts/_run.py +137 -0
  188. package/scripts/_session.py +502 -0
  189. package/scripts/_validate_registry.py +1042 -0
  190. package/scripts/_wicked_testing_probe.py +277 -0
  191. package/scripts/agentic/analyze_agents.py +391 -0
  192. package/scripts/agentic/detect_framework.py +420 -0
  193. package/scripts/agentic/issue_taxonomy.py +357 -0
  194. package/scripts/agentic/pattern_scorer.py +434 -0
  195. package/scripts/classify/persist.py +169 -0
  196. package/scripts/compiler/compile.py +552 -0
  197. package/scripts/compiler/phase0/VERDICT.md +60 -0
  198. package/scripts/compiler/phase0/detect.py +292 -0
  199. package/scripts/compiler/phase0/emit.py +228 -0
  200. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.bindings.json +30 -0
  201. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.lint-output.txt +17 -0
  202. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/.wg/evidence/failing-tests.txt +4 -0
  203. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/.wg/evidence/honest-tests.txt +2 -0
  204. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/fab-fail.build.md +8 -0
  205. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/fab-missing.build.md +8 -0
  206. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/honest.build.md +8 -0
  207. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/wg_check_claims.py +174 -0
  208. package/scripts/compiler/phase0/evidence/command_iq.bindings.json +45 -0
  209. package/scripts/compiler/phase0/evidence/command_iq.lint-output.txt +17 -0
  210. package/scripts/compiler/phase0/evidence/command_iq.stage/.projects/evidence-domain/phase-1-clarify/evidence/failing-tests.txt +4 -0
  211. package/scripts/compiler/phase0/evidence/command_iq.stage/.projects/evidence-domain/phase-1-clarify/evidence/honest-tests.txt +3 -0
  212. package/scripts/compiler/phase0/evidence/command_iq.stage/fab-fail.build.md +8 -0
  213. package/scripts/compiler/phase0/evidence/command_iq.stage/fab-missing.build.md +8 -0
  214. package/scripts/compiler/phase0/evidence/command_iq.stage/honest.build.md +8 -0
  215. package/scripts/compiler/phase0/evidence/command_iq.stage/wg_check_claims.py +174 -0
  216. package/scripts/compiler/phase0/evidence/memos.bindings.json +28 -0
  217. package/scripts/compiler/phase0/evidence/memos.lint-output.txt +17 -0
  218. package/scripts/compiler/phase0/evidence/memos.stage/.wg/evidence/failing-tests.txt +4 -0
  219. package/scripts/compiler/phase0/evidence/memos.stage/.wg/evidence/honest-tests.txt +2 -0
  220. package/scripts/compiler/phase0/evidence/memos.stage/fab-fail.build.md +8 -0
  221. package/scripts/compiler/phase0/evidence/memos.stage/fab-missing.build.md +8 -0
  222. package/scripts/compiler/phase0/evidence/memos.stage/honest.build.md +8 -0
  223. package/scripts/compiler/phase0/evidence/memos.stage/wg_check_claims.py +174 -0
  224. package/scripts/compiler/phase0/evidence/verdict.json +104 -0
  225. package/scripts/compiler/phase0/evidence/wicked-bus.bindings.json +29 -0
  226. package/scripts/compiler/phase0/evidence/wicked-bus.lint-output.txt +17 -0
  227. package/scripts/compiler/phase0/evidence/wicked-bus.stage/coverage/failing-tests.txt +4 -0
  228. package/scripts/compiler/phase0/evidence/wicked-bus.stage/coverage/honest-tests.txt +3 -0
  229. package/scripts/compiler/phase0/evidence/wicked-bus.stage/fab-fail.build.md +8 -0
  230. package/scripts/compiler/phase0/evidence/wicked-bus.stage/fab-missing.build.md +8 -0
  231. package/scripts/compiler/phase0/evidence/wicked-bus.stage/honest.build.md +8 -0
  232. package/scripts/compiler/phase0/evidence/wicked-bus.stage/wg_check_claims.py +174 -0
  233. package/scripts/compiler/phase0/evidence/wire-vault-transcript.txt +60 -0
  234. package/scripts/compiler/phase0/run_probe.py +234 -0
  235. package/scripts/compiler/phase0/wire_vault.py +310 -0
  236. package/scripts/crew/__init__.py +0 -0
  237. package/scripts/crew/_task_audit_writer.py +243 -0
  238. package/scripts/crew/_task_reader.py +389 -0
  239. package/scripts/crew/archetypes_v11.py +348 -0
  240. package/scripts/crew/detectors/__init__.py +12 -0
  241. package/scripts/crew/flow_compiler.py +121 -0
  242. package/scripts/crew/phase_manager.py +703 -0
  243. package/scripts/crew/scope_delta.py +264 -0
  244. package/scripts/crew/specialist_resolver.py +218 -0
  245. package/scripts/crew/stack_registry.py +189 -0
  246. package/scripts/data/data_profiler.py +271 -0
  247. package/scripts/data/ontology_recommender.py +231 -0
  248. package/scripts/data/schema_validator.py +267 -0
  249. package/scripts/delivery/drift.py +739 -0
  250. package/scripts/delivery/telemetry.py +614 -0
  251. package/scripts/engineering/patch/codegraph_db.py +125 -0
  252. package/scripts/engineering/patch/generators/__init__.py +56 -0
  253. package/scripts/engineering/patch/generators/base.py +373 -0
  254. package/scripts/engineering/patch/generators/csharp_generator.py +494 -0
  255. package/scripts/engineering/patch/generators/go_generator.py +430 -0
  256. package/scripts/engineering/patch/generators/java_generator.py +928 -0
  257. package/scripts/engineering/patch/generators/jsp_generator.py +454 -0
  258. package/scripts/engineering/patch/generators/kotlin_generator.py +561 -0
  259. package/scripts/engineering/patch/generators/perl_generator.py +510 -0
  260. package/scripts/engineering/patch/generators/php_generator.py +644 -0
  261. package/scripts/engineering/patch/generators/propagation_engine.py +929 -0
  262. package/scripts/engineering/patch/generators/python_generator.py +487 -0
  263. package/scripts/engineering/patch/generators/ruby_generator.py +463 -0
  264. package/scripts/engineering/patch/generators/rust_generator.py +400 -0
  265. package/scripts/engineering/patch/generators/sql_generator.py +594 -0
  266. package/scripts/engineering/patch/generators/typescript_generator.py +439 -0
  267. package/scripts/engineering/patch/patch.py +800 -0
  268. package/scripts/engineering/patch/safety.py +429 -0
  269. package/scripts/jam/__init__.py +0 -0
  270. package/scripts/jam/_bus_consumers.py +271 -0
  271. package/scripts/jam/agentic_cli_registry.py +703 -0
  272. package/scripts/jam/consensus.py +737 -0
  273. package/scripts/jam/detect_clis.py +409 -0
  274. package/scripts/jam/jam.py +283 -0
  275. package/scripts/jam/save_transcript.py +171 -0
  276. package/scripts/loom/__init__.py +22 -0
  277. package/scripts/loom/cli.py +170 -0
  278. package/scripts/loom/compose.py +180 -0
  279. package/scripts/loom/gate.py +120 -0
  280. package/scripts/loom/manifest.py +140 -0
  281. package/scripts/loom/resolve.py +59 -0
  282. package/scripts/persona/__init__.py +0 -0
  283. package/scripts/persona/registry.py +688 -0
  284. package/scripts/platform/guard_pipeline.py +1214 -0
  285. package/scripts/platform/guard_profiles.py +216 -0
  286. package/scripts/platform/observability/assert_contracts.py +434 -0
  287. package/scripts/platform/observability/health_probe.py +915 -0
  288. package/scripts/platform/observability/ops_log_viewer.py +209 -0
  289. package/scripts/platform/prereq_doctor.py +567 -0
  290. package/scripts/qe/conditions_manifest.py +260 -0
  291. package/scripts/qe/content_sanitizer.py +160 -0
  292. package/scripts/qe/coverage_tracker.py +535 -0
  293. package/scripts/qe/discover_scenarios.py +243 -0
  294. package/scripts/qe/evidence_tracker.py +232 -0
  295. package/scripts/qe/prove.py +196 -0
  296. package/scripts/qe/registry_lookup.py +80 -0
  297. package/scripts/qe/registry_store.py +176 -0
  298. package/scripts/qe/semantic_review.py +1005 -0
  299. package/scripts/qe/vault_gate.py +382 -0
  300. package/scripts/qe/verdict_audit.py +175 -0
  301. package/scripts/qe/verdict_schema.py +335 -0
  302. package/scripts/reset.py +220 -0
  303. package/scripts/resolve_path.py +22 -0
  304. package/scripts/sentinel/invariants.py +402 -0
  305. package/scripts/sentinel/pre_push.py +73 -0
  306. package/scripts/setup/__init__.py +1 -0
  307. package/scripts/setup/detect_state.py +114 -0
  308. package/scripts/setup/migrate_legacy.py +67 -0
  309. package/scripts/setup/migrate_v6_projects.py +232 -0
  310. package/scripts/setup/onboarding.py +114 -0
  311. package/scripts/smaht/_bus_consumers.py +98 -0
  312. package/scripts/smaht/adapters/__init__.py +83 -0
  313. package/scripts/smaht/adapters/brain_adapter.py +254 -0
  314. package/scripts/smaht/adapters/context7_adapter.py +438 -0
  315. package/scripts/smaht/adapters/delegation_adapter.py +104 -0
  316. package/scripts/smaht/adapters/domain_adapter.py +206 -0
  317. package/scripts/smaht/adapters/events_adapter.py +231 -0
  318. package/scripts/smaht/adapters/tools_adapter.py +49 -0
  319. package/scripts/smaht/cheatsheet_store.py +236 -0
  320. package/scripts/smaht/context_package.py +386 -0
  321. package/scripts/smaht/knowledge_graph.py +395 -0
  322. package/scripts/smaht/propose_skills.py +856 -0
  323. package/scripts/smaht/test_cheatsheet_store.py +428 -0
  324. package/scripts/statusline.py +151 -0
  325. package/scripts/where_am_i.py +236 -0
  326. package/skills/agentic/agentic-patterns/SKILL.md +91 -0
  327. package/skills/agentic/agentic-patterns/refs/anti-patterns-design.md +283 -0
  328. package/skills/agentic/agentic-patterns/refs/anti-patterns-operational.md +216 -0
  329. package/skills/agentic/agentic-patterns/refs/pattern-catalog.md +329 -0
  330. package/skills/agentic/context-engineering/SKILL.md +142 -0
  331. package/skills/agentic/context-engineering/refs/caching-and-optimization.md +251 -0
  332. package/skills/agentic/context-engineering/refs/compression-techniques.md +171 -0
  333. package/skills/agentic/context-engineering/refs/cost-calculation-budget.md +250 -0
  334. package/skills/agentic/context-engineering/refs/cost-optimization-reporting.md +300 -0
  335. package/skills/agentic/context-engineering/refs/selective-loading.md +179 -0
  336. package/skills/agentic/frameworks/SKILL.md +191 -0
  337. package/skills/agentic/frameworks/refs/framework-profiles-1.md +209 -0
  338. package/skills/agentic/frameworks/refs/framework-profiles-2.md +214 -0
  339. package/skills/agentic/frameworks/refs/migration-patterns-paths.md +267 -0
  340. package/skills/agentic/frameworks/refs/migration-patterns-testing.md +208 -0
  341. package/skills/agentic/refs/audit.md +134 -0
  342. package/skills/agentic/refs/design.md +137 -0
  343. package/skills/agentic/refs/frameworks.md +102 -0
  344. package/skills/agentic/refs/review.md +160 -0
  345. package/skills/agentic/review-methodology/SKILL.md +186 -0
  346. package/skills/agentic/review-methodology/refs/deliverable-templates.md +246 -0
  347. package/skills/agentic/review-methodology/refs/issue-taxonomy-quality-testing.md +277 -0
  348. package/skills/agentic/review-methodology/refs/issue-taxonomy-reliability-safety.md +253 -0
  349. package/skills/agentic/trust-and-safety/SKILL.md +177 -0
  350. package/skills/agentic/trust-and-safety/refs/guardrails-actions.md +246 -0
  351. package/skills/agentic/trust-and-safety/refs/guardrails-input-output.md +238 -0
  352. package/skills/agentic/trust-and-safety/refs/guardrails-resources.md +209 -0
  353. package/skills/agentic/trust-and-safety/refs/safety-checklist-advanced.md +209 -0
  354. package/skills/agentic/trust-and-safety/refs/safety-checklist-core.md +215 -0
  355. package/skills/archetype/SKILL.md +104 -0
  356. package/skills/archetype/refs/build.md +142 -0
  357. package/skills/archetype/refs/decide.md +117 -0
  358. package/skills/archetype/refs/explore.md +66 -0
  359. package/skills/archetype/refs/incident.md +149 -0
  360. package/skills/archetype/refs/migrate.md +170 -0
  361. package/skills/archetype/refs/modernize.md +187 -0
  362. package/skills/archetype/refs/review.md +145 -0
  363. package/skills/archetype/refs/ship.md +117 -0
  364. package/skills/archetype/refs/specify.md +108 -0
  365. package/skills/archetype/refs/triage.md +62 -0
  366. package/skills/classify/SKILL.md +157 -0
  367. package/skills/data/analysis/SKILL.md +125 -0
  368. package/skills/data/analysis/refs/templates.md +170 -0
  369. package/skills/data/data/SKILL.md +118 -0
  370. package/skills/data/data/refs/examples.md +235 -0
  371. package/skills/data/ml/SKILL.md +125 -0
  372. package/skills/data/ml/refs/templates.md +172 -0
  373. package/skills/data/pipeline/SKILL.md +136 -0
  374. package/skills/data/pipeline/refs/templates.md +175 -0
  375. package/skills/data/refs/analyze.md +123 -0
  376. package/skills/data/refs/data.md +95 -0
  377. package/skills/data/refs/ml.md +118 -0
  378. package/skills/data/refs/pipeline.md +92 -0
  379. package/skills/deliberate/SKILL.md +125 -0
  380. package/skills/deliberate/refs/architecture-lens.md +37 -0
  381. package/skills/deliberate/refs/assumptions-lens.md +43 -0
  382. package/skills/deliberate/refs/code-lens.md +38 -0
  383. package/skills/deliberate/refs/content-lens.md +37 -0
  384. package/skills/deliberate/refs/data-lens.md +43 -0
  385. package/skills/deliberate/refs/design-lens.md +37 -0
  386. package/skills/deliberate/refs/opportunity-patterns.md +107 -0
  387. package/skills/deliberate/refs/ops-lens.md +43 -0
  388. package/skills/deliberate/refs/product-lens.md +46 -0
  389. package/skills/deliberate/refs/rethink-framework.md +77 -0
  390. package/skills/deliberate/refs/security-lens.md +47 -0
  391. package/skills/deliberate/refs/testing-lens.md +45 -0
  392. package/skills/deliberate/refs/timing-lens.md +42 -0
  393. package/skills/engineering/architecture/SKILL.md +177 -0
  394. package/skills/engineering/architecture/refs/adr-template.md +268 -0
  395. package/skills/engineering/architecture/refs/architecture-template-deployment.md +176 -0
  396. package/skills/engineering/architecture/refs/architecture-template-design.md +300 -0
  397. package/skills/engineering/architecture/refs/examples-ecommerce-analytics.md +299 -0
  398. package/skills/engineering/architecture/refs/examples-saas-trading.md +291 -0
  399. package/skills/engineering/architecture/refs/patterns-advanced.md +238 -0
  400. package/skills/engineering/architecture/refs/patterns-structural.md +303 -0
  401. package/skills/engineering/backend/SKILL.md +102 -0
  402. package/skills/engineering/backend/refs/checklists.md +146 -0
  403. package/skills/engineering/backend/refs/patterns.md +181 -0
  404. package/skills/engineering/debugging/SKILL.md +99 -0
  405. package/skills/engineering/debugging/refs/patterns.md +248 -0
  406. package/skills/engineering/debugging/refs/process.md +203 -0
  407. package/skills/engineering/docs/SKILL.md +97 -0
  408. package/skills/engineering/engineering/SKILL.md +88 -0
  409. package/skills/engineering/engineering/refs/checklists.md +91 -0
  410. package/skills/engineering/engineering/refs/templates.md +71 -0
  411. package/skills/engineering/frontend/SKILL.md +92 -0
  412. package/skills/engineering/frontend/refs/checklists.md +96 -0
  413. package/skills/engineering/frontend/refs/patterns.md +167 -0
  414. package/skills/engineering/integration/SKILL.md +183 -0
  415. package/skills/engineering/integration/refs/error-handling-best-practices.md +139 -0
  416. package/skills/engineering/integration/refs/error-handling-error-classes-typescript.md +212 -0
  417. package/skills/engineering/integration/refs/error-handling-error-response-format.md +301 -0
  418. package/skills/engineering/integration/refs/error-handling-retry-strategies.md +190 -0
  419. package/skills/engineering/integration/refs/event-schemas-best-practices.md +225 -0
  420. package/skills/engineering/integration/refs/event-schemas-event-naming-conventions.md +303 -0
  421. package/skills/engineering/integration/refs/event-schemas-event-structure.md +288 -0
  422. package/skills/engineering/integration/refs/graphql-best-practices.md +138 -0
  423. package/skills/engineering/integration/refs/graphql-error-handling.md +198 -0
  424. package/skills/engineering/integration/refs/graphql-graphql-basics.md +197 -0
  425. package/skills/engineering/integration/refs/graphql-query-examples.md +226 -0
  426. package/skills/engineering/integration/refs/graphql-schema-design-patterns.md +280 -0
  427. package/skills/engineering/integration/refs/grpc-grpc-overview.md +246 -0
  428. package/skills/engineering/integration/refs/grpc-implementation-examples.md +269 -0
  429. package/skills/engineering/integration/refs/grpc-metadata-headers.md +304 -0
  430. package/skills/engineering/integration/refs/grpc-testing.md +49 -0
  431. package/skills/engineering/integration/refs/openapi-template.yaml +682 -0
  432. package/skills/engineering/integration/refs/resilience-best-practices.md +109 -0
  433. package/skills/engineering/integration/refs/resilience-circuit-breaker-pattern.md +302 -0
  434. package/skills/engineering/integration/refs/resilience-rate-limiting.md +245 -0
  435. package/skills/engineering/integration/refs/resilience-timeout-pattern.md +212 -0
  436. package/skills/engineering/integration/refs/rest-api-fundamentals.md +299 -0
  437. package/skills/engineering/integration/refs/rest-api-responses-security.md +302 -0
  438. package/skills/engineering/integration/refs/versioning-breaking-changes.md +237 -0
  439. package/skills/engineering/integration/refs/versioning-migration-strategies.md +257 -0
  440. package/skills/engineering/integration/refs/versioning-versioning-strategies.md +296 -0
  441. package/skills/engineering/large-scale-migration/SKILL.md +65 -0
  442. package/skills/engineering/patch/SKILL.md +184 -0
  443. package/skills/engineering/refs/arch.md +126 -0
  444. package/skills/engineering/refs/debug.md +142 -0
  445. package/skills/engineering/refs/docs.md +190 -0
  446. package/skills/engineering/refs/plan.md +109 -0
  447. package/skills/engineering/refs/review.md +138 -0
  448. package/skills/engineering/system-design/SKILL.md +154 -0
  449. package/skills/engineering/system-design/refs/anti-patterns-big-ball-of-mud.md +254 -0
  450. package/skills/engineering/system-design/refs/anti-patterns-circular-dependencies.md +241 -0
  451. package/skills/engineering/system-design/refs/anti-patterns-feature-envy.md +168 -0
  452. package/skills/engineering/system-design/refs/anti-patterns-god-object.md +247 -0
  453. package/skills/engineering/system-design/refs/component-template-lifecycle.md +210 -0
  454. package/skills/engineering/system-design/refs/component-template-maintenance.md +219 -0
  455. package/skills/engineering/system-design/refs/component-template-structure.md +276 -0
  456. package/skills/engineering/system-design/refs/dependencies-best-practices.md +260 -0
  457. package/skills/engineering/system-design/refs/dependencies-dependency-principles.md +295 -0
  458. package/skills/engineering/system-design/refs/dependencies-dependency-tracking.md +261 -0
  459. package/skills/engineering/system-design/refs/interface-template-lifecycle.md +211 -0
  460. package/skills/engineering/system-design/refs/interface-template-maintenance.md +212 -0
  461. package/skills/engineering/system-design/refs/interface-template-structure.md +269 -0
  462. package/skills/engineering/system-design/refs/patterns-dependency-injection.md +151 -0
  463. package/skills/engineering/system-design/refs/patterns-facade-pattern.md +257 -0
  464. package/skills/engineering/system-design/refs/patterns-layered-pattern.md +204 -0
  465. package/skills/engineering/system-design/refs/patterns-plugin-architecture.md +229 -0
  466. package/skills/engineering/unit-test-quality/SKILL.md +194 -0
  467. package/skills/ground/SKILL.md +130 -0
  468. package/skills/integration-discovery/SKILL.md +168 -0
  469. package/skills/integration-discovery/refs/capabilities.md +282 -0
  470. package/skills/integration-discovery/refs/cli-detection.md +295 -0
  471. package/skills/integration-discovery/refs/discovery-sources.md +233 -0
  472. package/skills/integration-discovery/refs/task-patterns.md +206 -0
  473. package/skills/jam/SKILL.md +45 -0
  474. package/skills/jam/refs/facilitation-patterns.md +125 -0
  475. package/skills/jam/refs/quick.md +64 -0
  476. package/skills/jam/refs/synthesis-patterns.md +114 -0
  477. package/skills/multi-model/SKILL.md +168 -0
  478. package/skills/multi-model/refs/aichat.md +119 -0
  479. package/skills/multi-model/refs/aider.md +100 -0
  480. package/skills/multi-model/refs/auditability.md +238 -0
  481. package/skills/multi-model/refs/codex.md +169 -0
  482. package/skills/multi-model/refs/context.md +306 -0
  483. package/skills/multi-model/refs/copilot.md +161 -0
  484. package/skills/multi-model/refs/examples.md +224 -0
  485. package/skills/multi-model/refs/gemini.md +185 -0
  486. package/skills/multi-model/refs/goose.md +112 -0
  487. package/skills/multi-model/refs/llm.md +124 -0
  488. package/skills/multi-model/refs/opencode.md +196 -0
  489. package/skills/multi-model/refs/orchestration.md +188 -0
  490. package/skills/multi-model/refs/pi.md +208 -0
  491. package/skills/persona/SKILL.md +144 -0
  492. package/skills/persona/refs/define.md +133 -0
  493. package/skills/platform/actions/refs/actions.md +114 -0
  494. package/skills/platform/audit/SKILL.md +174 -0
  495. package/skills/platform/audit/refs/audit.md +145 -0
  496. package/skills/platform/audit/refs/checklists-evidence-operations.md +144 -0
  497. package/skills/platform/audit/refs/checklists-gdpr-pci-evidence.md +213 -0
  498. package/skills/platform/audit/refs/checklists-soc2-hipaa.md +120 -0
  499. package/skills/platform/audit/refs/frameworks-gdpr-pci.md +225 -0
  500. package/skills/platform/audit/refs/frameworks-soc2-hipaa.md +228 -0
  501. package/skills/platform/compliance/SKILL.md +169 -0
  502. package/skills/platform/compliance/refs/checklists.md +303 -0
  503. package/skills/platform/compliance/refs/compliance.md +117 -0
  504. package/skills/platform/compliance/refs/frameworks.md +282 -0
  505. package/skills/platform/errors/SKILL.md +183 -0
  506. package/skills/platform/errors/refs/patterns.md +271 -0
  507. package/skills/platform/errors/refs/severity.md +264 -0
  508. package/skills/platform/gate-benchmark-rebaseline/SKILL.md +108 -0
  509. package/skills/platform/gh/refs/gh.md +105 -0
  510. package/skills/platform/gh-cli/SKILL.md +120 -0
  511. package/skills/platform/gh-cli/refs/automation.md +63 -0
  512. package/skills/platform/gh-cli/refs/gh-ops.md +103 -0
  513. package/skills/platform/gh-cli/refs/patterns.md +132 -0
  514. package/skills/platform/gh-cli/scripts/gh_ops.py +454 -0
  515. package/skills/platform/github-actions/SKILL.md +159 -0
  516. package/skills/platform/github-actions/refs/security.md +150 -0
  517. package/skills/platform/github-actions/refs/templates.md +230 -0
  518. package/skills/platform/github-actions/refs/troubleshooting.md +174 -0
  519. package/skills/platform/github-actions/scripts/workflow_gen.py +215 -0
  520. package/skills/platform/gitlab-ci/SKILL.md +140 -0
  521. package/skills/platform/gitlab-ci/refs/templates.md +223 -0
  522. package/skills/platform/gitlab-ci/refs/troubleshooting.md +213 -0
  523. package/skills/platform/glab-cli/SKILL.md +133 -0
  524. package/skills/platform/glab-cli/refs/ci-debugging.md +95 -0
  525. package/skills/platform/glab-cli/refs/glab-ops.md +78 -0
  526. package/skills/platform/glab-cli/refs/patterns.md +131 -0
  527. package/skills/platform/glab-cli/scripts/glab_ops.py +313 -0
  528. package/skills/platform/health/SKILL.md +177 -0
  529. package/skills/platform/health/refs/health.md +72 -0
  530. package/skills/platform/health/refs/sources.md +302 -0
  531. package/skills/platform/incident/refs/incident.md +136 -0
  532. package/skills/platform/infra/refs/infra.md +104 -0
  533. package/skills/platform/observability/SKILL.md +128 -0
  534. package/skills/platform/observability/refs/toolchain-discovery.md +243 -0
  535. package/skills/platform/prereq-doctor/SKILL.md +57 -0
  536. package/skills/platform/prereq-doctor/refs/tool-registry.md +58 -0
  537. package/skills/platform/traces/refs/traces.md +101 -0
  538. package/skills/product/acceptance-criteria/SKILL.md +193 -0
  539. package/skills/product/acceptance-criteria/refs/ac-anti-patterns.md +291 -0
  540. package/skills/product/acceptance-criteria/refs/ac-examples.md +277 -0
  541. package/skills/product/accessibility/SKILL.md +197 -0
  542. package/skills/product/accessibility/refs/aria-patterns-basics.md +250 -0
  543. package/skills/product/accessibility/refs/aria-patterns-dynamic.md +187 -0
  544. package/skills/product/accessibility/refs/aria-patterns-interactive.md +246 -0
  545. package/skills/product/accessibility/refs/audit-report-findings.md +248 -0
  546. package/skills/product/accessibility/refs/audit-report-results.md +276 -0
  547. package/skills/product/accessibility/refs/common-violations-html-css.md +270 -0
  548. package/skills/product/accessibility/refs/common-violations-interactive.md +303 -0
  549. package/skills/product/accessibility/refs/keyboard-testing-basics.md +222 -0
  550. package/skills/product/accessibility/refs/keyboard-testing-patterns.md +173 -0
  551. package/skills/product/accessibility/refs/screen-reader-testing-advanced.md +294 -0
  552. package/skills/product/accessibility/refs/screen-reader-testing-commands.md +255 -0
  553. package/skills/product/accessibility/refs/wcag-checklist.md +262 -0
  554. package/skills/product/analyze/SKILL.md +164 -0
  555. package/skills/product/analyze/refs/algorithms.md +238 -0
  556. package/skills/product/analyze/refs/sentiment-patterns.md +180 -0
  557. package/skills/product/imagery/SKILL.md +97 -0
  558. package/skills/product/imagery/alter/SKILL.md +105 -0
  559. package/skills/product/imagery/alter/refs/editing-reference.md +146 -0
  560. package/skills/product/imagery/create/SKILL.md +109 -0
  561. package/skills/product/imagery/create/refs/prompt-engineering.md +112 -0
  562. package/skills/product/imagery/create/refs/provider-reference.md +219 -0
  563. package/skills/product/imagery/review/SKILL.md +101 -0
  564. package/skills/product/imagery/review/refs/analysis-lenses.md +136 -0
  565. package/skills/product/imagery/review/refs/quality-gates.md +153 -0
  566. package/skills/product/imagery/scripts/analyze.sh +23 -0
  567. package/skills/product/imagery/scripts/edit.sh +14 -0
  568. package/skills/product/imagery/scripts/generate.sh +13 -0
  569. package/skills/product/imagery/scripts/provider.py +787 -0
  570. package/skills/product/listen/SKILL.md +175 -0
  571. package/skills/product/listen/refs/channels.md +220 -0
  572. package/skills/product/mockup/SKILL.md +106 -0
  573. package/skills/product/mockup/refs/templates.md +95 -0
  574. package/skills/product/refs/a11y.md +109 -0
  575. package/skills/product/refs/acceptance.md +79 -0
  576. package/skills/product/refs/align.md +67 -0
  577. package/skills/product/refs/analyze.md +77 -0
  578. package/skills/product/refs/elicit.md +67 -0
  579. package/skills/product/refs/listen.md +58 -0
  580. package/skills/product/refs/mockup.md +77 -0
  581. package/skills/product/refs/screenshot.md +59 -0
  582. package/skills/product/refs/strategy.md +77 -0
  583. package/skills/product/refs/synthesize.md +54 -0
  584. package/skills/product/refs/ux-review.md +68 -0
  585. package/skills/product/refs/ux.md +101 -0
  586. package/skills/product/requirements-analysis/SKILL.md +136 -0
  587. package/skills/product/requirements-analysis/refs/requirements-example-auth.md +264 -0
  588. package/skills/product/requirements-analysis/refs/requirements-example-export-integration.md +88 -0
  589. package/skills/product/requirements-analysis/refs/requirements-output-format-template.md +247 -0
  590. package/skills/product/requirements-analysis/refs/user-story-guide.md +296 -0
  591. package/skills/product/requirements-graph/SKILL.md +155 -0
  592. package/skills/product/requirements-graph/refs/examples.md +223 -0
  593. package/skills/product/requirements-graph/refs/schema.md +162 -0
  594. package/skills/product/requirements-migrate/SKILL.md +90 -0
  595. package/skills/product/requirements-navigate/SKILL.md +141 -0
  596. package/skills/product/requirements-navigate/refs/meta-templates.md +141 -0
  597. package/skills/product/screenshot/SKILL.md +147 -0
  598. package/skills/product/strategy/SKILL.md +198 -0
  599. package/skills/product/strategy/refs/frameworks.md +295 -0
  600. package/skills/product/strategy/refs/templates-competitive-market.md +299 -0
  601. package/skills/product/strategy/refs/templates-roi-value.md +207 -0
  602. package/skills/product/synthesize/SKILL.md +116 -0
  603. package/skills/product/synthesize/refs/journey-mapping.md +212 -0
  604. package/skills/product/synthesize/refs/prioritization.md +193 -0
  605. package/skills/product/ux-review/SKILL.md +164 -0
  606. package/skills/product/visual-direction/SKILL.md +137 -0
  607. package/skills/product/visual-review/SKILL.md +131 -0
  608. package/skills/runtime-exec/SKILL.md +138 -0
  609. package/skills/search/codebase-narrator/SKILL.md +131 -0
  610. package/skills/search/codebase-narrator/refs/output-template.md +100 -0
  611. package/skills/smaht/SKILL.md +72 -0
  612. package/skills/smaht/discovery/SKILL.md +65 -0
  613. package/skills/smaht/intent/SKILL.md +89 -0
  614. package/skills/smaht/propose-skills/SKILL.md +142 -0
  615. package/skills/smaht/refs/state.md +76 -0
  616. package/skills/swarm/SKILL.md +132 -0
  617. package/skills/swarm/refs/fan-out.md +104 -0
  618. package/skills/swarm/refs/independent-verification.md +86 -0
  619. package/skills/swarm/refs/receipts-and-evidence.md +69 -0
  620. package/skills/swarm/refs/recon-synthesis.md +87 -0
  621. package/skills/swarm/refs/ship-discipline.md +90 -0
  622. package/skills/wickedizer/SKILL.md +147 -0
  623. package/skills/wickedizer/refs/artifact-types.md +238 -0
  624. package/skills/wickedizer/refs/complexity.md +278 -0
  625. package/skills/wickedizer/refs/de-ai-pass.md +140 -0
  626. package/skills/wickedizer/refs/failure-modes.md +249 -0
  627. package/skills/wickedizer/refs/patterns.md +282 -0
  628. package/skills/wickedizer/refs/review.md +221 -0
  629. package/skills/wickedizer/refs/structure.md +282 -0
  630. package/skills/wickedizer/refs/voice-profile.md +125 -0
  631. package/skills/workflow/SKILL.md +132 -0
  632. package/skills/workflow/refs/archetype-adjustments.md +205 -0
  633. package/skills/workflow/refs/evidence.md +58 -0
  634. package/skills/workflow/refs/integration.md +130 -0
  635. package/skills/workflow/refs/risk-dimension-signals.md +260 -0
  636. package/skills/workflow/refs/scoring-rubric.md +49 -0
  637. package/skills/workflow/refs/signal-keywords.md +176 -0
  638. package/skills/workflow/refs/specialist-routing-rules.md +159 -0
  639. package/skills/worktrees/SKILL.md +87 -0
  640. package/skills/worktrees/refs/recipes.md +96 -0
@@ -0,0 +1,688 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ registry.py — Persona registry for wicked-garden persona domain.
4
+
5
+ Single source of truth for persona resolution. Merges all sources:
6
+ 1. DomainStore('persona') — project-scoped custom personas (highest priority)
7
+ 2. Plugin cache — ~/.claude/plugins/wicked-garden/personas/*.json
8
+ 3. specialist.json — built-in specialists
9
+ 4. Hard-coded fallbacks — architect, skeptic, advocate (lowest priority)
10
+
11
+ CLI:
12
+ python3 registry.py --list [--role ROLE] [--source SOURCE] --json
13
+ python3 registry.py --get NAME --json
14
+ python3 registry.py --define NAME --focus FOCUS [--traits "t1,t2"] [--role ROLE] [--description DESC] --json
15
+ python3 registry.py --save-cache NAME --json
16
+
17
+ stdlib-only — no third-party dependencies.
18
+ """
19
+ from __future__ import annotations
20
+
21
+ import json
22
+ import os
23
+ import sys
24
+ from dataclasses import dataclass, field
25
+ from pathlib import Path
26
+ from typing import Optional
27
+
28
+ # ---------------------------------------------------------------------------
29
+ # Path helpers
30
+ # ---------------------------------------------------------------------------
31
+
32
+ _SCRIPTS_ROOT = Path(__file__).resolve().parent.parent
33
+ sys.path.insert(0, str(_SCRIPTS_ROOT))
34
+
35
+
36
+ def _plugin_root() -> Optional[Path]:
37
+ """Resolve CLAUDE_PLUGIN_ROOT env var or None if unset/invalid."""
38
+ root = os.environ.get("CLAUDE_PLUGIN_ROOT", "")
39
+ if root:
40
+ p = Path(root)
41
+ if p.exists():
42
+ return p
43
+ return None
44
+
45
+
46
+ def _cache_dir() -> Path:
47
+ """Resolve plugin cache directory for personas."""
48
+ return Path.home() / ".claude" / "plugins" / "wicked-garden" / "personas"
49
+
50
+
51
+ # ---------------------------------------------------------------------------
52
+ # Data model
53
+ # ---------------------------------------------------------------------------
54
+
55
+ @dataclass
56
+ class PersonaRecord:
57
+ """In-memory representation of a persona."""
58
+ name: str
59
+ description: str
60
+ focus: str = ""
61
+ traits: list = field(default_factory=list)
62
+ role: str = "custom"
63
+ source: str = "custom" # builtin | custom | fallback | cache
64
+ # Rich schema fields
65
+ personality: dict = field(default_factory=dict)
66
+ constraints: list = field(default_factory=list)
67
+ # Scope guard — concerns this persona deliberately does NOT own (the
68
+ # senior-engineer "NOT Your Focus" pattern). Keeps a methodology persona
69
+ # sharp instead of diffusing into a generic reviewer.
70
+ not_focus: list = field(default_factory=list)
71
+ memories: list = field(default_factory=list)
72
+ preferences: dict = field(default_factory=dict)
73
+
74
+ def to_dict(self) -> dict:
75
+ return {
76
+ "name": self.name,
77
+ "description": self.description,
78
+ "focus": self.focus,
79
+ "traits": self.traits,
80
+ "role": self.role,
81
+ "source": self.source,
82
+ "personality": self.personality,
83
+ "constraints": self.constraints,
84
+ "not_focus": self.not_focus,
85
+ "memories": self.memories,
86
+ "preferences": self.preferences,
87
+ }
88
+
89
+
90
+ # ---------------------------------------------------------------------------
91
+ # Synthesized rich defaults for built-in personas — METHODOLOGY EXEMPLARS ONLY
92
+ # ---------------------------------------------------------------------------
93
+ #
94
+ # This dict enriches the specialists declared in `.claude-plugin/specialist.json`
95
+ # (the source of truth for which built-in persona NAMES exist). A name present in
96
+ # specialist.json but absent here still resolves — as a thin role record (empty
97
+ # constraints / not_focus) — so `persona:as <name>` never hard-breaks.
98
+ #
99
+ # WHY THIS IS SMALL (the curated surface was cut): a blinded, independently-graded
100
+ # lift eval (tests/persona/EVAL_RESULTS.md, run 2026-06-12) found the built-in
101
+ # personas produce lift=0 vs the base model — a strong base model already flags
102
+ # every targeted failure mode unprompted. The generic role-restatement built-ins
103
+ # (engineering, product, data, jam, delivery, design) added curated surface with
104
+ # no measured value, so their rich profiles were REMOVED from this dict. They are
105
+ # still invokable by name (degrading to thin role records via specialist.json),
106
+ # and the FALLBACK personas + `persona:as`'s unknown-name handling cover ad-hoc
107
+ # roles gracefully.
108
+ #
109
+ # What REMAINS here is the illustrative "this is the GOOD pattern" set: only the
110
+ # three METHODOLOGY exemplars (platform, qe, agentic) whose constraints are NAMED
111
+ # FAILURE-MODE DEFENSES (`FAILURE MODE — …`) + a `not_focus` scope guard — the
112
+ # structural lift a base prompt lacks. The actual PRODUCT is `persona:define`:
113
+ # author a HOUSE persona that encodes a failure-mode defense the base model cannot
114
+ # know. Do NOT re-add generic role personas here without an eval showing lift > 0.
115
+ _BUILTIN_RICH: dict[str, dict] = {
116
+ "platform": {
117
+ "personality": {
118
+ "style": "security-first and systematic — never skips the threat model",
119
+ "temperament": "vigilant and skeptical of anything that touches auth or infra",
120
+ "humor": "gallows humor about the things that have gone wrong in prod",
121
+ },
122
+ # Methodology persona. Constraints below are NAMED FAILURE-MODE DEFENSES, not
123
+ # role restatements: each one is a guard the base model does NOT reliably
124
+ # self-apply (it volunteers "looks fine" when no secret is visible; it does
125
+ # not, unprompted, demand a rollback artifact or refuse a too-broad grant).
126
+ "constraints": [
127
+ "FAILURE MODE — silent secret exposure: scan every diff/log/error path for credentials, "
128
+ "tokens, and keys before approving. A change with no *visible* secret is NOT cleared; "
129
+ "name where the secret COULD leak (env dumps, stack traces, CI output) and require it ruled out.",
130
+ "FAILURE MODE — irreversible deploy: refuse to approve any deployment that lacks a written, "
131
+ "tested rollback procedure. 'We can roll forward' is not a rollback. Block until the rollback "
132
+ "artifact exists.",
133
+ "FAILURE MODE — privilege creep: treat every IAM/role/scope grant as guilty until proven minimal. "
134
+ "Flag any permission broader than the demonstrated need and state the least-privilege alternative.",
135
+ "FAILURE MODE — unbounded blast radius: for each failure path ask 'what else breaks, and how far?' "
136
+ "Require a blast-radius statement before sign-off on changes touching shared infra.",
137
+ ],
138
+ # SCOPE GUARD — what this persona deliberately does NOT own, so it stays sharp
139
+ # instead of diffusing into a generic reviewer (the senior-engineer "NOT Your
140
+ # Focus" pattern). Flag adjacent concerns, hand them off; do not deep-dive.
141
+ "not_focus": [
142
+ "Code readability / naming / refactor quality — hand to `engineering`.",
143
+ "Test coverage and scenario design — hand to `qe`.",
144
+ "Product value and UX trade-offs — hand to `product`.",
145
+ ],
146
+ "memories": [
147
+ "Responded to a breach caused by a misconfigured S3 bucket — now audits all storage ACLs",
148
+ "Traced a production outage to a missing health check — now requires health checks in every service",
149
+ "Discovered a credential leak in CI logs that lasted 6 months undetected — now scans all CI output",
150
+ ],
151
+ "preferences": {
152
+ "communication": "threat model first, then mitigation steps",
153
+ "code_style": "explicit over implicit — no magic, no assumptions",
154
+ "review_focus": "attack surface, secret handling, blast radius of failures",
155
+ "decision_making": "risk-adjusted — quantify the probability and impact before deciding",
156
+ },
157
+ },
158
+ "qe": {
159
+ "personality": {
160
+ "style": "quality-obsessed and systematic — finds the edge case everyone else missed",
161
+ "temperament": "constructively skeptical — assumes bugs exist until proven otherwise",
162
+ "humor": "finds humor in the absurdity of bugs that make it to production",
163
+ },
164
+ # Methodology persona. The base model writes happy-path tests and calls a green
165
+ # run 'done'. These constraints are the anti-patterns that catch what it skips:
166
+ # self-graded success, missing failure paths, and untested recovery.
167
+ "constraints": [
168
+ "FAILURE MODE — self-graded done: reject 'it works on my machine' and any claim of passing "
169
+ "without reproducible evidence. Demand the failing-then-passing artifact, not the assertion.",
170
+ "FAILURE MODE — happy-path-only: any test suite that exercises only the success path is "
171
+ "INCOMPLETE. For each path, name the error/edge case it does NOT cover and require it added "
172
+ "before approval.",
173
+ "FAILURE MODE — untested recovery: rollback, retry, and failure-recovery paths must be tested, "
174
+ "not assumed. A release with an unexercised rollback path is not shippable.",
175
+ "FAILURE MODE — coverage theater: a high coverage number is not test value. Ask of each test "
176
+ "'what real product bug does this catch?' — drop tests that catch nothing, add tests for what hurts.",
177
+ ],
178
+ "not_focus": [
179
+ "Implementation design and refactor quality — hand to `engineering`.",
180
+ "Threat modeling and secret handling — hand to `platform`.",
181
+ "Whether the feature is worth building — hand to `product`.",
182
+ ],
183
+ "memories": [
184
+ "Found a data corruption bug in prod that had been there 2 years — now requires data integrity tests on every write path",
185
+ "Watched a release fail because nobody tested the rollback path — now rollback is part of every test plan",
186
+ "Reduced production defects 60% by introducing contract tests between services",
187
+ ],
188
+ "preferences": {
189
+ "communication": "test scenarios and acceptance criteria over abstract quality goals",
190
+ "code_style": "prefer fewer, high-value tests over many low-value coverage metrics",
191
+ "review_focus": "test value — does each test catch a real product bug?",
192
+ "decision_making": "risk-based — test the things that hurt most when they break",
193
+ },
194
+ },
195
+ "agentic": {
196
+ "personality": {
197
+ "style": "safety-conscious and architecturally rigorous — agentic systems require extra care",
198
+ "temperament": "systematically cautious — evaluates failure modes before successes",
199
+ "humor": "dry commentary on the ways AI systems fail in surprising ways",
200
+ },
201
+ # Methodology persona. The base model reviews an agent design for whether it
202
+ # WORKS; it does not, unprompted, refuse a design for missing a termination
203
+ # condition or an approval gate. These are the four ways autonomous agents
204
+ # cause expensive, irreversible damage — each constraint blocks one.
205
+ "constraints": [
206
+ "FAILURE MODE — runaway loop: refuse any agent/tool-calling design without an explicit "
207
+ "termination condition (max turns, budget cap, or progress check). An unbounded loop is a "
208
+ "blocker, not a nit.",
209
+ "FAILURE MODE — irreversible action without a gate: any operation that can mutate or delete "
210
+ "production state MUST sit behind a human approval gate or be provably reversible. Name the "
211
+ "gate or block the design.",
212
+ "FAILURE MODE — over-broad tool access: an agent gets the LEAST tool scope that completes its "
213
+ "task. Flag every tool/permission the task does not demonstrably need and state the narrower grant.",
214
+ "FAILURE MODE — non-idempotent retry: any state-mutating operation that may be retried MUST be "
215
+ "idempotent. A retry that double-charges/double-writes is a defect — require an idempotency key "
216
+ "or dedupe before approval.",
217
+ ],
218
+ "not_focus": [
219
+ "General code quality of the agent's host app — hand to `engineering`.",
220
+ "Token cost / latency tuning when safety is already satisfied — hand to performance review.",
221
+ "Whether the agent should exist at all — hand to `product`.",
222
+ ],
223
+ "memories": [
224
+ "Reviewed an agent that deleted 3 weeks of production data because it had write access it didn't need — now enforces least-privilege",
225
+ "Caught an infinite tool-call loop that would have exhausted API limits — now requires termination conditions",
226
+ "Helped design a human-in-the-loop checkpoint that prevented a costly mistake in an automated pipeline",
227
+ ],
228
+ "preferences": {
229
+ "communication": "agent interaction diagrams and failure mode analysis over feature descriptions",
230
+ "code_style": "explicit state machines over implicit agent behavior",
231
+ "review_focus": "safety, idempotency, blast radius, and human oversight",
232
+ "decision_making": "safety-first — if in doubt, add a checkpoint",
233
+ },
234
+ },
235
+ }
236
+
237
+
238
+ # ---------------------------------------------------------------------------
239
+ # Source loaders
240
+ # ---------------------------------------------------------------------------
241
+
242
+ def _load_builtin_personas(plugin_root: Optional[Path]) -> list:
243
+ """Load specialists from .claude-plugin/specialist.json."""
244
+ if plugin_root is None:
245
+ print("registry: CLAUDE_PLUGIN_ROOT not set or invalid, skipping builtin load", file=sys.stderr)
246
+ return []
247
+
248
+ spec_path = plugin_root / ".claude-plugin" / "specialist.json"
249
+ if not spec_path.exists():
250
+ print(f"registry: specialist.json not found at {spec_path}", file=sys.stderr)
251
+ return []
252
+
253
+ try:
254
+ data = json.loads(spec_path.read_text(encoding="utf-8"))
255
+ except Exception as e:
256
+ print(f"registry: failed to parse specialist.json: {e}", file=sys.stderr)
257
+ return []
258
+
259
+ personas = []
260
+ for sp in data.get("specialists", []):
261
+ name = sp.get("name", "")
262
+ desc = sp.get("description", "")
263
+ role = sp.get("role", "custom")
264
+ rich = _BUILTIN_RICH.get(name, {})
265
+ personas.append(PersonaRecord(
266
+ name=name,
267
+ description=desc,
268
+ focus=desc,
269
+ traits=[],
270
+ role=role,
271
+ source="builtin",
272
+ personality=rich.get("personality", {}),
273
+ constraints=rich.get("constraints", []),
274
+ not_focus=rich.get("not_focus", []),
275
+ memories=rich.get("memories", []),
276
+ preferences=rich.get("preferences", {}),
277
+ ))
278
+ return personas
279
+
280
+
281
+ def _load_fallback_personas() -> list:
282
+ """Return hard-coded fallback personas when specialist.json is unavailable."""
283
+ return [
284
+ PersonaRecord(
285
+ name="architect",
286
+ description="Evaluates system design, trade-offs, and structural decisions",
287
+ focus="Evaluates system design, trade-offs, and structural decisions",
288
+ traits=["systematic", "big-picture", "trade-off-aware"],
289
+ role="fallback",
290
+ source="fallback",
291
+ personality={
292
+ "style": "systems-level and holistic — sees the whole before the parts",
293
+ "temperament": "deliberate and thorough, patient with complexity",
294
+ "humor": "wry observations about the gap between design and reality",
295
+ },
296
+ constraints=[
297
+ "Always evaluate long-term maintainability before short-term convenience",
298
+ "Never approve a design without considering failure modes",
299
+ "Require evidence of scalability assumptions being tested",
300
+ ],
301
+ memories=[
302
+ "Saw a microservices migration fail because network latency wasn't accounted for — now requires latency budgets",
303
+ ],
304
+ preferences={
305
+ "communication": "architecture diagrams and trade-off matrices",
306
+ "code_style": "explicit contracts and clear boundaries between components",
307
+ "review_focus": "structural integrity, trade-offs, and long-term evolution",
308
+ "decision_making": "principled trade-offs with explicit rationale",
309
+ },
310
+ ),
311
+ PersonaRecord(
312
+ name="skeptic",
313
+ description="Challenges assumptions, finds edge cases, questions premises",
314
+ focus="Challenges assumptions, finds edge cases, questions premises",
315
+ traits=["critical", "rigorous", "assumption-challenger"],
316
+ role="fallback",
317
+ source="fallback",
318
+ personality={
319
+ "style": "probing and Socratic — questions everything before accepting it",
320
+ "temperament": "constructively critical — the goal is truth, not conflict",
321
+ "humor": "deadpan questions that expose unstated assumptions",
322
+ },
323
+ constraints=[
324
+ "FAILURE MODE — unexamined claim: never accept an assertion without asking 'how do we "
325
+ "know this is true?' Demand the evidence or mark the claim unverified.",
326
+ "FAILURE MODE — happy-path approval: find at least one concrete edge case or failure mode "
327
+ "before approving anything. 'No problems found' is not an answer until you have looked for one.",
328
+ "FAILURE MODE — assumption-as-fact: flag every assumption presented as fact. Name it, and "
329
+ "state what would have to be true for it to hold.",
330
+ ],
331
+ not_focus=[
332
+ "Proposing the fix — the skeptic surfaces the doubt; another persona owns the solution.",
333
+ "Style and aesthetics — challenge substance, not formatting.",
334
+ ],
335
+ memories=[
336
+ "Asked 'what happens if the database is unavailable?' and discovered there was no fallback — saved a production incident",
337
+ ],
338
+ preferences={
339
+ "communication": "questions and counter-examples over assertions",
340
+ "code_style": "defensive over optimistic — assume inputs are wrong until proven otherwise",
341
+ "review_focus": "edge cases, failure modes, and unstated assumptions",
342
+ "decision_making": "evidence-required — no evidence, no decision",
343
+ },
344
+ ),
345
+ PersonaRecord(
346
+ name="advocate",
347
+ description="Champions the end-user perspective, accessibility, and simplicity",
348
+ focus="Champions the end-user perspective, accessibility, and simplicity",
349
+ traits=["empathetic", "user-centered", "simplicity-focused"],
350
+ role="fallback",
351
+ source="fallback",
352
+ personality={
353
+ "style": "warm and user-centered — translates technical decisions into user impact",
354
+ "temperament": "passionate about users, patient with technical constraints",
355
+ "humor": "friendly analogies that make technical concepts human",
356
+ },
357
+ constraints=[
358
+ "Always ask 'what does the user experience when this happens?'",
359
+ "Never accept jargon in user-facing text — plain language always",
360
+ "Accessibility is non-negotiable — flag any exclusion",
361
+ ],
362
+ memories=[
363
+ "Rewrote an error message from technical gibberish to plain English — support tickets dropped 40%",
364
+ ],
365
+ preferences={
366
+ "communication": "user stories and concrete scenarios over abstract features",
367
+ "code_style": "simple and obvious over clever and efficient",
368
+ "review_focus": "user experience, accessibility, and clarity",
369
+ "decision_making": "user impact and inclusion over technical elegance",
370
+ },
371
+ ),
372
+ ]
373
+
374
+
375
+ def _load_cache_personas() -> list:
376
+ """Load personas from plugin cache directory."""
377
+ cache = _cache_dir()
378
+ if not cache.exists():
379
+ return []
380
+
381
+ personas = []
382
+ for f in sorted(cache.glob("*.json")):
383
+ try:
384
+ data = json.loads(f.read_text(encoding="utf-8"))
385
+ data["source"] = "cache"
386
+ personas.append(_dict_to_record(data))
387
+ except Exception as e:
388
+ print(f"registry: skipping cache file {f}: {e}", file=sys.stderr)
389
+ return personas
390
+
391
+
392
+ def _load_custom_personas() -> list:
393
+ """Load custom personas from DomainStore('persona')."""
394
+ try:
395
+ from _domain_store import DomainStore
396
+ ds = DomainStore("persona")
397
+ records = ds.list("personas")
398
+ personas = []
399
+ for r in records:
400
+ r["source"] = "custom"
401
+ personas.append(_dict_to_record(r))
402
+ return personas
403
+ except Exception as e:
404
+ print(f"registry: failed to load custom personas: {e}", file=sys.stderr)
405
+ return []
406
+
407
+
408
+ def _dict_to_record(d: dict) -> PersonaRecord:
409
+ """Convert a dict (from JSON/DomainStore) to a PersonaRecord."""
410
+ return PersonaRecord(
411
+ name=d.get("name", ""),
412
+ description=d.get("description", ""),
413
+ focus=d.get("focus", d.get("description", "")),
414
+ traits=d.get("traits", []),
415
+ role=d.get("role", "custom"),
416
+ source=d.get("source", "custom"),
417
+ personality=d.get("personality", {}),
418
+ constraints=d.get("constraints", []),
419
+ not_focus=d.get("not_focus", []),
420
+ memories=d.get("memories", []),
421
+ preferences=d.get("preferences", {}),
422
+ )
423
+
424
+
425
+ # ---------------------------------------------------------------------------
426
+ # Merge
427
+ # ---------------------------------------------------------------------------
428
+
429
+ def _merge_personas(
430
+ custom: list,
431
+ cache: list,
432
+ builtin: list,
433
+ fallback: list,
434
+ ) -> dict:
435
+ """Merge persona sources with priority: custom > cache > builtin > fallback."""
436
+ merged: dict[str, PersonaRecord] = {}
437
+ # Lower priority first so higher priority overwrites
438
+ for p in fallback:
439
+ merged[p.name.lower()] = p
440
+ for p in builtin:
441
+ merged[p.name.lower()] = p
442
+ for p in cache:
443
+ merged[p.name.lower()] = p
444
+ for p in custom:
445
+ merged[p.name.lower()] = p
446
+ return merged
447
+
448
+
449
+ # ---------------------------------------------------------------------------
450
+ # Public API
451
+ # ---------------------------------------------------------------------------
452
+
453
+ def list_personas(*, role: Optional[str] = None, source: Optional[str] = None) -> list:
454
+ """List all available personas, optionally filtered."""
455
+ plugin_root = _plugin_root()
456
+ builtin = _load_builtin_personas(plugin_root)
457
+ fallback = _load_fallback_personas() if not builtin else []
458
+ cache = _load_cache_personas()
459
+ custom = _load_custom_personas()
460
+ merged = _merge_personas(custom, cache, builtin, fallback)
461
+
462
+ results = list(merged.values())
463
+
464
+ if role:
465
+ results = [p for p in results if p.role.lower() == role.lower()]
466
+ if source:
467
+ results = [p for p in results if p.source.lower() == source.lower()]
468
+
469
+ # Sort by source priority then name
470
+ _source_order = {"custom": 0, "cache": 1, "builtin": 2, "fallback": 3}
471
+ results.sort(key=lambda p: (_source_order.get(p.source, 9), p.name))
472
+ return [p.to_dict() for p in results]
473
+
474
+
475
+ def get_persona(name: str) -> Optional[dict]:
476
+ """Look up a single persona by name (case-insensitive)."""
477
+ plugin_root = _plugin_root()
478
+ builtin = _load_builtin_personas(plugin_root)
479
+ fallback = _load_fallback_personas() if not builtin else []
480
+ cache = _load_cache_personas()
481
+ custom = _load_custom_personas()
482
+ merged = _merge_personas(custom, cache, builtin, fallback)
483
+ record = merged.get(name.lower())
484
+ if record is None:
485
+ return None
486
+ return record.to_dict()
487
+
488
+
489
+ def save_persona(
490
+ name: str,
491
+ focus: str,
492
+ *,
493
+ description: str = "",
494
+ traits: Optional[list] = None,
495
+ role: str = "custom",
496
+ personality: Optional[dict] = None,
497
+ constraints: Optional[list] = None,
498
+ not_focus: Optional[list] = None,
499
+ memories: Optional[list] = None,
500
+ preferences: Optional[dict] = None,
501
+ ) -> dict:
502
+ """Save a custom persona to project-scoped DomainStore."""
503
+ if not focus:
504
+ raise ValueError("focus is required -- describe the perspective this persona applies.")
505
+
506
+ if not description:
507
+ description = f"{focus}-focused perspective"
508
+
509
+ payload = {
510
+ "name": name,
511
+ "description": description,
512
+ "focus": focus,
513
+ "traits": traits or [],
514
+ "role": role,
515
+ "source": "custom",
516
+ "personality": personality or {},
517
+ "constraints": constraints or [],
518
+ "not_focus": not_focus or [],
519
+ "memories": memories or [],
520
+ "preferences": preferences or {},
521
+ }
522
+
523
+ try:
524
+ from _domain_store import DomainStore
525
+ ds = DomainStore("persona")
526
+ existing = ds.get("personas", name)
527
+ if existing:
528
+ result = ds.update("personas", name, payload)
529
+ result["_updated"] = True
530
+ else:
531
+ payload["name"] = name
532
+ result = ds.create("personas", payload)
533
+ result["_updated"] = False
534
+ result["source"] = "custom"
535
+ return result
536
+ except Exception as e:
537
+ print(f"registry: DomainStore unavailable, returning payload: {e}", file=sys.stderr)
538
+ return payload
539
+
540
+
541
+ def save_to_cache(name: str, persona: dict) -> Path:
542
+ """Save a persona to the plugin-level cache for cross-project reuse."""
543
+ safe_name = Path(name).name # strip directory components to prevent traversal
544
+ if not safe_name or safe_name != name:
545
+ raise ValueError(f"Invalid persona name: {name!r}")
546
+ cache = _cache_dir()
547
+ cache.mkdir(parents=True, exist_ok=True, mode=0o700)
548
+ path = cache / f"{safe_name}.json"
549
+ persona_copy = dict(persona)
550
+ persona_copy["source"] = "cache"
551
+ path.write_text(json.dumps(persona_copy, indent=2), encoding="utf-8")
552
+ return path
553
+
554
+
555
+ def delete_persona(name: str) -> bool:
556
+ """Delete a custom persona from DomainStore.
557
+
558
+ Custom personas are stored under an auto-generated UUID ``id`` (the
559
+ DomainStore key); the human ``name`` lives in the record body. Deleting by
560
+ ``name`` therefore looked up ``{name}.json``, found nothing, and silently
561
+ returned False — the persona was never removed. Resolve ``name`` -> ``id``
562
+ first (case-insensitive, matching ``get_persona``) and delete by the real
563
+ key. Returns False when no custom persona matches the name.
564
+ """
565
+ try:
566
+ from _domain_store import DomainStore
567
+ ds = DomainStore("persona")
568
+ target = name.lower()
569
+ record_id = next(
570
+ (r.get("id") for r in ds.list("personas")
571
+ if str(r.get("name", "")).lower() == target and r.get("id")),
572
+ None,
573
+ )
574
+ if record_id is None:
575
+ return False
576
+ return ds.delete("personas", record_id)
577
+ except Exception as e:
578
+ print(f"registry: failed to delete persona: {e}", file=sys.stderr)
579
+ return False
580
+
581
+
582
+ # ---------------------------------------------------------------------------
583
+ # Output helpers
584
+ # ---------------------------------------------------------------------------
585
+
586
+ def _output(data, as_json: bool) -> None:
587
+ """Print data as JSON or human-readable."""
588
+ if as_json:
589
+ print(json.dumps(data, indent=2))
590
+ elif isinstance(data, list):
591
+ for p in data:
592
+ print(f" {p['name']:25s} {p.get('source',''):10s} {p.get('description','')[:60]}")
593
+ elif isinstance(data, dict):
594
+ for k, v in data.items():
595
+ if not k.startswith("_"):
596
+ print(f" {k}: {v}")
597
+
598
+
599
+ # ---------------------------------------------------------------------------
600
+ # CLI entry point
601
+ # ---------------------------------------------------------------------------
602
+
603
+ def main() -> None:
604
+ """CLI entry point — argparse with subcommands via flags."""
605
+ import argparse
606
+
607
+ parser = argparse.ArgumentParser(description="Persona registry")
608
+ group = parser.add_mutually_exclusive_group(required=True)
609
+ group.add_argument("--list", action="store_true", help="List all personas")
610
+ group.add_argument("--get", metavar="NAME", help="Get a persona by name")
611
+ group.add_argument("--define", metavar="NAME", help="Define/update a custom persona")
612
+ group.add_argument("--save-cache", metavar="NAME", help="Save persona to plugin cache")
613
+
614
+ parser.add_argument("--focus", help="Persona focus (required with --define)")
615
+ parser.add_argument("--traits", help="Comma-separated traits")
616
+ parser.add_argument("--role", help="Role category for filtering")
617
+ parser.add_argument("--source", help="Source filter for --list")
618
+ parser.add_argument("--description", help="One-line description")
619
+ parser.add_argument(
620
+ "--constraints",
621
+ help="Semicolon-separated non-negotiable rules. For a METHODOLOGY persona, "
622
+ "phrase each as a named failure-mode defense: "
623
+ "'FAILURE MODE — <name>: <the guard the base model skips>'.",
624
+ )
625
+ parser.add_argument(
626
+ "--not-focus",
627
+ dest="not_focus",
628
+ help="Semicolon-separated concerns this persona does NOT own (scope guard). "
629
+ "Keeps a methodology persona sharp instead of diffusing into a generic reviewer.",
630
+ )
631
+ parser.add_argument("--json", action="store_true", help="JSON output", dest="as_json")
632
+
633
+ args = parser.parse_args()
634
+
635
+ if args.list:
636
+ result = list_personas(role=args.role, source=args.source)
637
+ _output(result, args.as_json)
638
+
639
+ elif args.get:
640
+ result = get_persona(args.get)
641
+ if result is None:
642
+ print(json.dumps({
643
+ "error": f"Persona '{args.get}' not found",
644
+ "available": [p["name"] for p in list_personas()],
645
+ }), file=sys.stderr)
646
+ sys.exit(1)
647
+ _output(result, args.as_json)
648
+
649
+ elif args.define:
650
+ if not args.focus:
651
+ print(json.dumps({
652
+ "error": "focus is required -- describe the perspective this persona applies."
653
+ }), file=sys.stderr)
654
+ sys.exit(1)
655
+ traits = [t.strip() for t in args.traits.split(",")] if args.traits else []
656
+ # Constraints and not_focus are SEMICOLON-separated (commas are common inside
657
+ # a single failure-mode rule, so semicolon is the safer record separator).
658
+ constraints = (
659
+ [c.strip() for c in args.constraints.split(";") if c.strip()]
660
+ if args.constraints else []
661
+ )
662
+ not_focus = (
663
+ [n.strip() for n in args.not_focus.split(";") if n.strip()]
664
+ if args.not_focus else []
665
+ )
666
+ result = save_persona(
667
+ args.define,
668
+ args.focus,
669
+ description=args.description or "",
670
+ traits=traits,
671
+ role=args.role or "custom",
672
+ constraints=constraints,
673
+ not_focus=not_focus,
674
+ )
675
+ _output(result, args.as_json)
676
+
677
+ elif args.save_cache:
678
+ persona = get_persona(args.save_cache)
679
+ if persona is None:
680
+ print(json.dumps({"error": f"Persona '{args.save_cache}' not found"}),
681
+ file=sys.stderr)
682
+ sys.exit(1)
683
+ path = save_to_cache(args.save_cache, persona)
684
+ _output({"saved": str(path), "persona": persona}, args.as_json)
685
+
686
+
687
+ if __name__ == "__main__":
688
+ main()