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.
- package/.claude-plugin/archetypes.json +166 -0
- package/.claude-plugin/components.json +75 -0
- package/.claude-plugin/marketplace.json +15 -0
- package/.claude-plugin/plugin.json +174 -0
- package/.claude-plugin/specialist.json +48 -0
- package/.claude-plugin/stack-registry.json +96 -0
- package/AGENTS.md +13 -0
- package/CHANGELOG.md +712 -0
- package/CONTRIBUTING.md +99 -0
- package/ETHOS.md +83 -0
- package/LICENSE +21 -0
- package/README.md +115 -0
- package/WICKED_GARDEN_BUS_EVENTS.md +149 -0
- package/agents/agentic/architect.md +449 -0
- package/agents/agentic/performance-analyst.md +702 -0
- package/agents/agentic/safety-reviewer.md +662 -0
- package/agents/crew/implementer.md +163 -0
- package/agents/crew/researcher.md +94 -0
- package/agents/crew/reviewer.md +184 -0
- package/agents/data/data-engineer.md +227 -0
- package/agents/engineering/api-documentarian.md +440 -0
- package/agents/engineering/migration-engineer.md +301 -0
- package/agents/engineering/solution-architect.md +208 -0
- package/agents/jam/brainstorm-facilitator.md +297 -0
- package/agents/jam/council.md +322 -0
- package/agents/jam/quick-facilitator.md +85 -0
- package/agents/persona/persona-agent.md +121 -0
- package/agents/platform/compliance-officer.md +266 -0
- package/agents/platform/privacy-expert.md +496 -0
- package/agents/platform/security-engineer.md +287 -0
- package/agents/product/a11y-expert.md +323 -0
- package/agents/product/requirements-analyst.md +238 -0
- package/agents/product/ui-reviewer.md +180 -0
- package/agents/product/ux-designer.md +199 -0
- package/agents/product/value-strategist.md +269 -0
- package/agents/qe/semantic-reviewer.md +78 -0
- package/commands/agentic/audit.md +24 -0
- package/commands/agentic/design.md +24 -0
- package/commands/agentic/frameworks.md +25 -0
- package/commands/agentic/review.md +27 -0
- package/commands/archetype/build.md +12 -0
- package/commands/archetype/decide.md +12 -0
- package/commands/archetype/explore.md +12 -0
- package/commands/archetype/incident.md +12 -0
- package/commands/archetype/migrate.md +12 -0
- package/commands/archetype/modernize.md +12 -0
- package/commands/archetype/review.md +14 -0
- package/commands/archetype/ship.md +12 -0
- package/commands/archetype/specify.md +12 -0
- package/commands/archetype/triage.md +12 -0
- package/commands/compile.md +37 -0
- package/commands/data/analyze.md +18 -0
- package/commands/data/data.md +21 -0
- package/commands/data/ml.md +18 -0
- package/commands/data/ontology.md +22 -0
- package/commands/data/pipeline.md +17 -0
- package/commands/deliberate.md +181 -0
- package/commands/engineering/add-field.md +77 -0
- package/commands/engineering/apply.md +58 -0
- package/commands/engineering/arch.md +26 -0
- package/commands/engineering/debug.md +27 -0
- package/commands/engineering/docs.md +27 -0
- package/commands/engineering/new-generator.md +257 -0
- package/commands/engineering/patch-plan.md +59 -0
- package/commands/engineering/plan.md +29 -0
- package/commands/engineering/remove.md +48 -0
- package/commands/engineering/rename.md +44 -0
- package/commands/engineering/review.md +32 -0
- package/commands/help.md +128 -0
- package/commands/install.md +118 -0
- package/commands/intent.md +54 -0
- package/commands/jam/brainstorm.md +37 -0
- package/commands/jam/council.md +49 -0
- package/commands/jam/quick.md +21 -0
- package/commands/jam/revisit.md +79 -0
- package/commands/persona/as.md +136 -0
- package/commands/persona/define.md +24 -0
- package/commands/persona/list.md +118 -0
- package/commands/platform/actions.md +20 -0
- package/commands/platform/assert.md +18 -0
- package/commands/platform/audit.md +23 -0
- package/commands/platform/compliance.md +20 -0
- package/commands/platform/gh.md +22 -0
- package/commands/platform/health.md +22 -0
- package/commands/platform/incident.md +23 -0
- package/commands/platform/infra.md +24 -0
- package/commands/platform/peer-health.md +103 -0
- package/commands/platform/plugin-health.md +58 -0
- package/commands/platform/security.md +38 -0
- package/commands/platform/toolchain.md +96 -0
- package/commands/platform/traces.md +20 -0
- package/commands/product/a11y.md +19 -0
- package/commands/product/acceptance.md +19 -0
- package/commands/product/align.md +20 -0
- package/commands/product/analyze.md +23 -0
- package/commands/product/elicit.md +19 -0
- package/commands/product/listen.md +24 -0
- package/commands/product/mockup.md +20 -0
- package/commands/product/screenshot.md +19 -0
- package/commands/product/strategy.md +40 -0
- package/commands/product/synthesize.md +23 -0
- package/commands/product/ux-review.md +42 -0
- package/commands/product/ux.md +20 -0
- package/commands/product/visual-direction.md +34 -0
- package/commands/prove.md +47 -0
- package/commands/report-issue.md +243 -0
- package/commands/reset.md +144 -0
- package/commands/search/blast-radius.md +58 -0
- package/commands/search/hotspots.md +55 -0
- package/commands/search/index.md +38 -0
- package/commands/search/lineage.md +47 -0
- package/commands/search/service-map.md +79 -0
- package/commands/setup.md +363 -0
- package/commands/smaht/briefing.md +200 -0
- package/commands/smaht/events-import.md +95 -0
- package/commands/smaht/state.md +19 -0
- package/commands/where-am-i.md +58 -0
- package/docs/README.md +32 -0
- package/docs/adr/0001-code-relationship-graph-engine.md +116 -0
- package/docs/adr/0002-major-cleanup-keep-cut.md +91 -0
- package/docs/adr/0003-peers-gate-required-layers-optin.md +41 -0
- package/docs/adr/0004-code-graph-moves-to-wicked-brain.md +47 -0
- package/docs/brain-chunk-format.md +135 -0
- package/docs/compiler.md +95 -0
- package/docs/daemon-api.md +70 -0
- package/docs/domains.md +197 -0
- package/docs/getting-started.md +208 -0
- package/docs/plans/2026-06-08-wicked-loom-conduct.md +1337 -0
- package/docs/plans/2026-06-08-wicked-loom-contract.md +638 -0
- package/docs/plans/2026-06-08-wicked-loom-cutover.md +1300 -0
- package/docs/plans/2026-06-08-wicked-loom-expand-compose.md +843 -0
- package/docs/plans/2026-06-08-wicked-loom-flow-cutover.md +403 -0
- package/docs/plans/2026-06-10-codegraph-to-brain-phase1a-graph-core.md +838 -0
- package/docs/plans/2026-06-10-codegraph-to-brain-phase1b-injected-edges.md +44 -0
- package/docs/required-peers.md +60 -0
- package/docs/specs/2026-06-08-wicked-loom-extraction.md +225 -0
- package/docs/specs/2026-06-10-codegraph-to-brain-migration.md +168 -0
- package/docs/v11/archetypes.md +231 -0
- package/hooks/hooks.json +275 -0
- package/hooks/scripts/bootstrap.py +1797 -0
- package/hooks/scripts/invoke.py +62 -0
- package/hooks/scripts/notification.py +166 -0
- package/hooks/scripts/permission_request.py +223 -0
- package/hooks/scripts/post_tool.py +1374 -0
- package/hooks/scripts/pre_compact.py +272 -0
- package/hooks/scripts/pre_tool.py +1278 -0
- package/hooks/scripts/prompt_submit.py +1109 -0
- package/hooks/scripts/session_end.py +95 -0
- package/hooks/scripts/stop.py +624 -0
- package/hooks/scripts/subagent_lifecycle.py +464 -0
- package/hooks/scripts/subscribers/on_gate_decided.py +84 -0
- package/hooks/scripts/task_completed.py +322 -0
- package/hooks/scripts/worktree_guard.py +148 -0
- package/hooks/subscriptions/on_gate_decided.json +9 -0
- package/install.mjs +128 -0
- package/package.json +41 -0
- package/pyproject.toml +59 -0
- package/schemas/README.md +32 -0
- package/schemas/assert_contracts.json +37 -0
- package/schemas/health_probe.json +46 -0
- package/schemas/plugin_status.json +37 -0
- package/scripts/_adapters/__init__.py +166 -0
- package/scripts/_adapters/jira_adapter.py +18 -0
- package/scripts/_adapters/linear_adapter.py +18 -0
- package/scripts/_adapters/miro_adapter.py +18 -0
- package/scripts/_adapters/notion_adapter.py +18 -0
- package/scripts/_agents.py +357 -0
- package/scripts/_brain_ingest/__init__.py +2 -0
- package/scripts/_brain_ingest/session_fact_extractor.py +341 -0
- package/scripts/_brain_port.py +163 -0
- package/scripts/_bus.py +1081 -0
- package/scripts/_bus_catalog_gen.py +93 -0
- package/scripts/_bus_consumers.json +46 -0
- package/scripts/_bus_emit.py +43 -0
- package/scripts/_capability_registry.py +334 -0
- package/scripts/_capability_resolver.py +322 -0
- package/scripts/_domain_store.py +559 -0
- package/scripts/_event_log_reader.py +154 -0
- package/scripts/_event_schema.py +305 -0
- package/scripts/_event_store.py +397 -0
- package/scripts/_heavy_cadence.py +324 -0
- package/scripts/_integration_resolver.py +321 -0
- package/scripts/_logger.py +151 -0
- package/scripts/_loom.py +482 -0
- package/scripts/_paths.py +133 -0
- package/scripts/_python.sh +22 -0
- package/scripts/_run.py +137 -0
- package/scripts/_session.py +502 -0
- package/scripts/_validate_registry.py +1042 -0
- package/scripts/_wicked_testing_probe.py +277 -0
- package/scripts/agentic/analyze_agents.py +391 -0
- package/scripts/agentic/detect_framework.py +420 -0
- package/scripts/agentic/issue_taxonomy.py +357 -0
- package/scripts/agentic/pattern_scorer.py +434 -0
- package/scripts/classify/persist.py +169 -0
- package/scripts/compiler/compile.py +552 -0
- package/scripts/compiler/phase0/VERDICT.md +60 -0
- package/scripts/compiler/phase0/detect.py +292 -0
- package/scripts/compiler/phase0/emit.py +228 -0
- package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.bindings.json +30 -0
- package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.lint-output.txt +17 -0
- package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/.wg/evidence/failing-tests.txt +4 -0
- package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/.wg/evidence/honest-tests.txt +2 -0
- package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/fab-fail.build.md +8 -0
- package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/fab-missing.build.md +8 -0
- package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/honest.build.md +8 -0
- package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/wg_check_claims.py +174 -0
- package/scripts/compiler/phase0/evidence/command_iq.bindings.json +45 -0
- package/scripts/compiler/phase0/evidence/command_iq.lint-output.txt +17 -0
- package/scripts/compiler/phase0/evidence/command_iq.stage/.projects/evidence-domain/phase-1-clarify/evidence/failing-tests.txt +4 -0
- package/scripts/compiler/phase0/evidence/command_iq.stage/.projects/evidence-domain/phase-1-clarify/evidence/honest-tests.txt +3 -0
- package/scripts/compiler/phase0/evidence/command_iq.stage/fab-fail.build.md +8 -0
- package/scripts/compiler/phase0/evidence/command_iq.stage/fab-missing.build.md +8 -0
- package/scripts/compiler/phase0/evidence/command_iq.stage/honest.build.md +8 -0
- package/scripts/compiler/phase0/evidence/command_iq.stage/wg_check_claims.py +174 -0
- package/scripts/compiler/phase0/evidence/memos.bindings.json +28 -0
- package/scripts/compiler/phase0/evidence/memos.lint-output.txt +17 -0
- package/scripts/compiler/phase0/evidence/memos.stage/.wg/evidence/failing-tests.txt +4 -0
- package/scripts/compiler/phase0/evidence/memos.stage/.wg/evidence/honest-tests.txt +2 -0
- package/scripts/compiler/phase0/evidence/memos.stage/fab-fail.build.md +8 -0
- package/scripts/compiler/phase0/evidence/memos.stage/fab-missing.build.md +8 -0
- package/scripts/compiler/phase0/evidence/memos.stage/honest.build.md +8 -0
- package/scripts/compiler/phase0/evidence/memos.stage/wg_check_claims.py +174 -0
- package/scripts/compiler/phase0/evidence/verdict.json +104 -0
- package/scripts/compiler/phase0/evidence/wicked-bus.bindings.json +29 -0
- package/scripts/compiler/phase0/evidence/wicked-bus.lint-output.txt +17 -0
- package/scripts/compiler/phase0/evidence/wicked-bus.stage/coverage/failing-tests.txt +4 -0
- package/scripts/compiler/phase0/evidence/wicked-bus.stage/coverage/honest-tests.txt +3 -0
- package/scripts/compiler/phase0/evidence/wicked-bus.stage/fab-fail.build.md +8 -0
- package/scripts/compiler/phase0/evidence/wicked-bus.stage/fab-missing.build.md +8 -0
- package/scripts/compiler/phase0/evidence/wicked-bus.stage/honest.build.md +8 -0
- package/scripts/compiler/phase0/evidence/wicked-bus.stage/wg_check_claims.py +174 -0
- package/scripts/compiler/phase0/evidence/wire-vault-transcript.txt +60 -0
- package/scripts/compiler/phase0/run_probe.py +234 -0
- package/scripts/compiler/phase0/wire_vault.py +310 -0
- package/scripts/crew/__init__.py +0 -0
- package/scripts/crew/_task_audit_writer.py +243 -0
- package/scripts/crew/_task_reader.py +389 -0
- package/scripts/crew/archetypes_v11.py +348 -0
- package/scripts/crew/detectors/__init__.py +12 -0
- package/scripts/crew/flow_compiler.py +121 -0
- package/scripts/crew/phase_manager.py +703 -0
- package/scripts/crew/scope_delta.py +264 -0
- package/scripts/crew/specialist_resolver.py +218 -0
- package/scripts/crew/stack_registry.py +189 -0
- package/scripts/data/data_profiler.py +271 -0
- package/scripts/data/ontology_recommender.py +231 -0
- package/scripts/data/schema_validator.py +267 -0
- package/scripts/delivery/drift.py +739 -0
- package/scripts/delivery/telemetry.py +614 -0
- package/scripts/engineering/patch/codegraph_db.py +125 -0
- package/scripts/engineering/patch/generators/__init__.py +56 -0
- package/scripts/engineering/patch/generators/base.py +373 -0
- package/scripts/engineering/patch/generators/csharp_generator.py +494 -0
- package/scripts/engineering/patch/generators/go_generator.py +430 -0
- package/scripts/engineering/patch/generators/java_generator.py +928 -0
- package/scripts/engineering/patch/generators/jsp_generator.py +454 -0
- package/scripts/engineering/patch/generators/kotlin_generator.py +561 -0
- package/scripts/engineering/patch/generators/perl_generator.py +510 -0
- package/scripts/engineering/patch/generators/php_generator.py +644 -0
- package/scripts/engineering/patch/generators/propagation_engine.py +929 -0
- package/scripts/engineering/patch/generators/python_generator.py +487 -0
- package/scripts/engineering/patch/generators/ruby_generator.py +463 -0
- package/scripts/engineering/patch/generators/rust_generator.py +400 -0
- package/scripts/engineering/patch/generators/sql_generator.py +594 -0
- package/scripts/engineering/patch/generators/typescript_generator.py +439 -0
- package/scripts/engineering/patch/patch.py +800 -0
- package/scripts/engineering/patch/safety.py +429 -0
- package/scripts/jam/__init__.py +0 -0
- package/scripts/jam/_bus_consumers.py +271 -0
- package/scripts/jam/agentic_cli_registry.py +703 -0
- package/scripts/jam/consensus.py +737 -0
- package/scripts/jam/detect_clis.py +409 -0
- package/scripts/jam/jam.py +283 -0
- package/scripts/jam/save_transcript.py +171 -0
- package/scripts/loom/__init__.py +22 -0
- package/scripts/loom/cli.py +170 -0
- package/scripts/loom/compose.py +180 -0
- package/scripts/loom/gate.py +120 -0
- package/scripts/loom/manifest.py +140 -0
- package/scripts/loom/resolve.py +59 -0
- package/scripts/persona/__init__.py +0 -0
- package/scripts/persona/registry.py +688 -0
- package/scripts/platform/guard_pipeline.py +1214 -0
- package/scripts/platform/guard_profiles.py +216 -0
- package/scripts/platform/observability/assert_contracts.py +434 -0
- package/scripts/platform/observability/health_probe.py +915 -0
- package/scripts/platform/observability/ops_log_viewer.py +209 -0
- package/scripts/platform/prereq_doctor.py +567 -0
- package/scripts/qe/conditions_manifest.py +260 -0
- package/scripts/qe/content_sanitizer.py +160 -0
- package/scripts/qe/coverage_tracker.py +535 -0
- package/scripts/qe/discover_scenarios.py +243 -0
- package/scripts/qe/evidence_tracker.py +232 -0
- package/scripts/qe/prove.py +196 -0
- package/scripts/qe/registry_lookup.py +80 -0
- package/scripts/qe/registry_store.py +176 -0
- package/scripts/qe/semantic_review.py +1005 -0
- package/scripts/qe/vault_gate.py +382 -0
- package/scripts/qe/verdict_audit.py +175 -0
- package/scripts/qe/verdict_schema.py +335 -0
- package/scripts/reset.py +220 -0
- package/scripts/resolve_path.py +22 -0
- package/scripts/sentinel/invariants.py +402 -0
- package/scripts/sentinel/pre_push.py +73 -0
- package/scripts/setup/__init__.py +1 -0
- package/scripts/setup/detect_state.py +114 -0
- package/scripts/setup/migrate_legacy.py +67 -0
- package/scripts/setup/migrate_v6_projects.py +232 -0
- package/scripts/setup/onboarding.py +114 -0
- package/scripts/smaht/_bus_consumers.py +98 -0
- package/scripts/smaht/adapters/__init__.py +83 -0
- package/scripts/smaht/adapters/brain_adapter.py +254 -0
- package/scripts/smaht/adapters/context7_adapter.py +438 -0
- package/scripts/smaht/adapters/delegation_adapter.py +104 -0
- package/scripts/smaht/adapters/domain_adapter.py +206 -0
- package/scripts/smaht/adapters/events_adapter.py +231 -0
- package/scripts/smaht/adapters/tools_adapter.py +49 -0
- package/scripts/smaht/cheatsheet_store.py +236 -0
- package/scripts/smaht/context_package.py +386 -0
- package/scripts/smaht/knowledge_graph.py +395 -0
- package/scripts/smaht/propose_skills.py +856 -0
- package/scripts/smaht/test_cheatsheet_store.py +428 -0
- package/scripts/statusline.py +151 -0
- package/scripts/where_am_i.py +236 -0
- package/skills/agentic/agentic-patterns/SKILL.md +91 -0
- package/skills/agentic/agentic-patterns/refs/anti-patterns-design.md +283 -0
- package/skills/agentic/agentic-patterns/refs/anti-patterns-operational.md +216 -0
- package/skills/agentic/agentic-patterns/refs/pattern-catalog.md +329 -0
- package/skills/agentic/context-engineering/SKILL.md +142 -0
- package/skills/agentic/context-engineering/refs/caching-and-optimization.md +251 -0
- package/skills/agentic/context-engineering/refs/compression-techniques.md +171 -0
- package/skills/agentic/context-engineering/refs/cost-calculation-budget.md +250 -0
- package/skills/agentic/context-engineering/refs/cost-optimization-reporting.md +300 -0
- package/skills/agentic/context-engineering/refs/selective-loading.md +179 -0
- package/skills/agentic/frameworks/SKILL.md +191 -0
- package/skills/agentic/frameworks/refs/framework-profiles-1.md +209 -0
- package/skills/agentic/frameworks/refs/framework-profiles-2.md +214 -0
- package/skills/agentic/frameworks/refs/migration-patterns-paths.md +267 -0
- package/skills/agentic/frameworks/refs/migration-patterns-testing.md +208 -0
- package/skills/agentic/refs/audit.md +134 -0
- package/skills/agentic/refs/design.md +137 -0
- package/skills/agentic/refs/frameworks.md +102 -0
- package/skills/agentic/refs/review.md +160 -0
- package/skills/agentic/review-methodology/SKILL.md +186 -0
- package/skills/agentic/review-methodology/refs/deliverable-templates.md +246 -0
- package/skills/agentic/review-methodology/refs/issue-taxonomy-quality-testing.md +277 -0
- package/skills/agentic/review-methodology/refs/issue-taxonomy-reliability-safety.md +253 -0
- package/skills/agentic/trust-and-safety/SKILL.md +177 -0
- package/skills/agentic/trust-and-safety/refs/guardrails-actions.md +246 -0
- package/skills/agentic/trust-and-safety/refs/guardrails-input-output.md +238 -0
- package/skills/agentic/trust-and-safety/refs/guardrails-resources.md +209 -0
- package/skills/agentic/trust-and-safety/refs/safety-checklist-advanced.md +209 -0
- package/skills/agentic/trust-and-safety/refs/safety-checklist-core.md +215 -0
- package/skills/archetype/SKILL.md +104 -0
- package/skills/archetype/refs/build.md +142 -0
- package/skills/archetype/refs/decide.md +117 -0
- package/skills/archetype/refs/explore.md +66 -0
- package/skills/archetype/refs/incident.md +149 -0
- package/skills/archetype/refs/migrate.md +170 -0
- package/skills/archetype/refs/modernize.md +187 -0
- package/skills/archetype/refs/review.md +145 -0
- package/skills/archetype/refs/ship.md +117 -0
- package/skills/archetype/refs/specify.md +108 -0
- package/skills/archetype/refs/triage.md +62 -0
- package/skills/classify/SKILL.md +157 -0
- package/skills/data/analysis/SKILL.md +125 -0
- package/skills/data/analysis/refs/templates.md +170 -0
- package/skills/data/data/SKILL.md +118 -0
- package/skills/data/data/refs/examples.md +235 -0
- package/skills/data/ml/SKILL.md +125 -0
- package/skills/data/ml/refs/templates.md +172 -0
- package/skills/data/pipeline/SKILL.md +136 -0
- package/skills/data/pipeline/refs/templates.md +175 -0
- package/skills/data/refs/analyze.md +123 -0
- package/skills/data/refs/data.md +95 -0
- package/skills/data/refs/ml.md +118 -0
- package/skills/data/refs/pipeline.md +92 -0
- package/skills/deliberate/SKILL.md +125 -0
- package/skills/deliberate/refs/architecture-lens.md +37 -0
- package/skills/deliberate/refs/assumptions-lens.md +43 -0
- package/skills/deliberate/refs/code-lens.md +38 -0
- package/skills/deliberate/refs/content-lens.md +37 -0
- package/skills/deliberate/refs/data-lens.md +43 -0
- package/skills/deliberate/refs/design-lens.md +37 -0
- package/skills/deliberate/refs/opportunity-patterns.md +107 -0
- package/skills/deliberate/refs/ops-lens.md +43 -0
- package/skills/deliberate/refs/product-lens.md +46 -0
- package/skills/deliberate/refs/rethink-framework.md +77 -0
- package/skills/deliberate/refs/security-lens.md +47 -0
- package/skills/deliberate/refs/testing-lens.md +45 -0
- package/skills/deliberate/refs/timing-lens.md +42 -0
- package/skills/engineering/architecture/SKILL.md +177 -0
- package/skills/engineering/architecture/refs/adr-template.md +268 -0
- package/skills/engineering/architecture/refs/architecture-template-deployment.md +176 -0
- package/skills/engineering/architecture/refs/architecture-template-design.md +300 -0
- package/skills/engineering/architecture/refs/examples-ecommerce-analytics.md +299 -0
- package/skills/engineering/architecture/refs/examples-saas-trading.md +291 -0
- package/skills/engineering/architecture/refs/patterns-advanced.md +238 -0
- package/skills/engineering/architecture/refs/patterns-structural.md +303 -0
- package/skills/engineering/backend/SKILL.md +102 -0
- package/skills/engineering/backend/refs/checklists.md +146 -0
- package/skills/engineering/backend/refs/patterns.md +181 -0
- package/skills/engineering/debugging/SKILL.md +99 -0
- package/skills/engineering/debugging/refs/patterns.md +248 -0
- package/skills/engineering/debugging/refs/process.md +203 -0
- package/skills/engineering/docs/SKILL.md +97 -0
- package/skills/engineering/engineering/SKILL.md +88 -0
- package/skills/engineering/engineering/refs/checklists.md +91 -0
- package/skills/engineering/engineering/refs/templates.md +71 -0
- package/skills/engineering/frontend/SKILL.md +92 -0
- package/skills/engineering/frontend/refs/checklists.md +96 -0
- package/skills/engineering/frontend/refs/patterns.md +167 -0
- package/skills/engineering/integration/SKILL.md +183 -0
- package/skills/engineering/integration/refs/error-handling-best-practices.md +139 -0
- package/skills/engineering/integration/refs/error-handling-error-classes-typescript.md +212 -0
- package/skills/engineering/integration/refs/error-handling-error-response-format.md +301 -0
- package/skills/engineering/integration/refs/error-handling-retry-strategies.md +190 -0
- package/skills/engineering/integration/refs/event-schemas-best-practices.md +225 -0
- package/skills/engineering/integration/refs/event-schemas-event-naming-conventions.md +303 -0
- package/skills/engineering/integration/refs/event-schemas-event-structure.md +288 -0
- package/skills/engineering/integration/refs/graphql-best-practices.md +138 -0
- package/skills/engineering/integration/refs/graphql-error-handling.md +198 -0
- package/skills/engineering/integration/refs/graphql-graphql-basics.md +197 -0
- package/skills/engineering/integration/refs/graphql-query-examples.md +226 -0
- package/skills/engineering/integration/refs/graphql-schema-design-patterns.md +280 -0
- package/skills/engineering/integration/refs/grpc-grpc-overview.md +246 -0
- package/skills/engineering/integration/refs/grpc-implementation-examples.md +269 -0
- package/skills/engineering/integration/refs/grpc-metadata-headers.md +304 -0
- package/skills/engineering/integration/refs/grpc-testing.md +49 -0
- package/skills/engineering/integration/refs/openapi-template.yaml +682 -0
- package/skills/engineering/integration/refs/resilience-best-practices.md +109 -0
- package/skills/engineering/integration/refs/resilience-circuit-breaker-pattern.md +302 -0
- package/skills/engineering/integration/refs/resilience-rate-limiting.md +245 -0
- package/skills/engineering/integration/refs/resilience-timeout-pattern.md +212 -0
- package/skills/engineering/integration/refs/rest-api-fundamentals.md +299 -0
- package/skills/engineering/integration/refs/rest-api-responses-security.md +302 -0
- package/skills/engineering/integration/refs/versioning-breaking-changes.md +237 -0
- package/skills/engineering/integration/refs/versioning-migration-strategies.md +257 -0
- package/skills/engineering/integration/refs/versioning-versioning-strategies.md +296 -0
- package/skills/engineering/large-scale-migration/SKILL.md +65 -0
- package/skills/engineering/patch/SKILL.md +184 -0
- package/skills/engineering/refs/arch.md +126 -0
- package/skills/engineering/refs/debug.md +142 -0
- package/skills/engineering/refs/docs.md +190 -0
- package/skills/engineering/refs/plan.md +109 -0
- package/skills/engineering/refs/review.md +138 -0
- package/skills/engineering/system-design/SKILL.md +154 -0
- package/skills/engineering/system-design/refs/anti-patterns-big-ball-of-mud.md +254 -0
- package/skills/engineering/system-design/refs/anti-patterns-circular-dependencies.md +241 -0
- package/skills/engineering/system-design/refs/anti-patterns-feature-envy.md +168 -0
- package/skills/engineering/system-design/refs/anti-patterns-god-object.md +247 -0
- package/skills/engineering/system-design/refs/component-template-lifecycle.md +210 -0
- package/skills/engineering/system-design/refs/component-template-maintenance.md +219 -0
- package/skills/engineering/system-design/refs/component-template-structure.md +276 -0
- package/skills/engineering/system-design/refs/dependencies-best-practices.md +260 -0
- package/skills/engineering/system-design/refs/dependencies-dependency-principles.md +295 -0
- package/skills/engineering/system-design/refs/dependencies-dependency-tracking.md +261 -0
- package/skills/engineering/system-design/refs/interface-template-lifecycle.md +211 -0
- package/skills/engineering/system-design/refs/interface-template-maintenance.md +212 -0
- package/skills/engineering/system-design/refs/interface-template-structure.md +269 -0
- package/skills/engineering/system-design/refs/patterns-dependency-injection.md +151 -0
- package/skills/engineering/system-design/refs/patterns-facade-pattern.md +257 -0
- package/skills/engineering/system-design/refs/patterns-layered-pattern.md +204 -0
- package/skills/engineering/system-design/refs/patterns-plugin-architecture.md +229 -0
- package/skills/engineering/unit-test-quality/SKILL.md +194 -0
- package/skills/ground/SKILL.md +130 -0
- package/skills/integration-discovery/SKILL.md +168 -0
- package/skills/integration-discovery/refs/capabilities.md +282 -0
- package/skills/integration-discovery/refs/cli-detection.md +295 -0
- package/skills/integration-discovery/refs/discovery-sources.md +233 -0
- package/skills/integration-discovery/refs/task-patterns.md +206 -0
- package/skills/jam/SKILL.md +45 -0
- package/skills/jam/refs/facilitation-patterns.md +125 -0
- package/skills/jam/refs/quick.md +64 -0
- package/skills/jam/refs/synthesis-patterns.md +114 -0
- package/skills/multi-model/SKILL.md +168 -0
- package/skills/multi-model/refs/aichat.md +119 -0
- package/skills/multi-model/refs/aider.md +100 -0
- package/skills/multi-model/refs/auditability.md +238 -0
- package/skills/multi-model/refs/codex.md +169 -0
- package/skills/multi-model/refs/context.md +306 -0
- package/skills/multi-model/refs/copilot.md +161 -0
- package/skills/multi-model/refs/examples.md +224 -0
- package/skills/multi-model/refs/gemini.md +185 -0
- package/skills/multi-model/refs/goose.md +112 -0
- package/skills/multi-model/refs/llm.md +124 -0
- package/skills/multi-model/refs/opencode.md +196 -0
- package/skills/multi-model/refs/orchestration.md +188 -0
- package/skills/multi-model/refs/pi.md +208 -0
- package/skills/persona/SKILL.md +144 -0
- package/skills/persona/refs/define.md +133 -0
- package/skills/platform/actions/refs/actions.md +114 -0
- package/skills/platform/audit/SKILL.md +174 -0
- package/skills/platform/audit/refs/audit.md +145 -0
- package/skills/platform/audit/refs/checklists-evidence-operations.md +144 -0
- package/skills/platform/audit/refs/checklists-gdpr-pci-evidence.md +213 -0
- package/skills/platform/audit/refs/checklists-soc2-hipaa.md +120 -0
- package/skills/platform/audit/refs/frameworks-gdpr-pci.md +225 -0
- package/skills/platform/audit/refs/frameworks-soc2-hipaa.md +228 -0
- package/skills/platform/compliance/SKILL.md +169 -0
- package/skills/platform/compliance/refs/checklists.md +303 -0
- package/skills/platform/compliance/refs/compliance.md +117 -0
- package/skills/platform/compliance/refs/frameworks.md +282 -0
- package/skills/platform/errors/SKILL.md +183 -0
- package/skills/platform/errors/refs/patterns.md +271 -0
- package/skills/platform/errors/refs/severity.md +264 -0
- package/skills/platform/gate-benchmark-rebaseline/SKILL.md +108 -0
- package/skills/platform/gh/refs/gh.md +105 -0
- package/skills/platform/gh-cli/SKILL.md +120 -0
- package/skills/platform/gh-cli/refs/automation.md +63 -0
- package/skills/platform/gh-cli/refs/gh-ops.md +103 -0
- package/skills/platform/gh-cli/refs/patterns.md +132 -0
- package/skills/platform/gh-cli/scripts/gh_ops.py +454 -0
- package/skills/platform/github-actions/SKILL.md +159 -0
- package/skills/platform/github-actions/refs/security.md +150 -0
- package/skills/platform/github-actions/refs/templates.md +230 -0
- package/skills/platform/github-actions/refs/troubleshooting.md +174 -0
- package/skills/platform/github-actions/scripts/workflow_gen.py +215 -0
- package/skills/platform/gitlab-ci/SKILL.md +140 -0
- package/skills/platform/gitlab-ci/refs/templates.md +223 -0
- package/skills/platform/gitlab-ci/refs/troubleshooting.md +213 -0
- package/skills/platform/glab-cli/SKILL.md +133 -0
- package/skills/platform/glab-cli/refs/ci-debugging.md +95 -0
- package/skills/platform/glab-cli/refs/glab-ops.md +78 -0
- package/skills/platform/glab-cli/refs/patterns.md +131 -0
- package/skills/platform/glab-cli/scripts/glab_ops.py +313 -0
- package/skills/platform/health/SKILL.md +177 -0
- package/skills/platform/health/refs/health.md +72 -0
- package/skills/platform/health/refs/sources.md +302 -0
- package/skills/platform/incident/refs/incident.md +136 -0
- package/skills/platform/infra/refs/infra.md +104 -0
- package/skills/platform/observability/SKILL.md +128 -0
- package/skills/platform/observability/refs/toolchain-discovery.md +243 -0
- package/skills/platform/prereq-doctor/SKILL.md +57 -0
- package/skills/platform/prereq-doctor/refs/tool-registry.md +58 -0
- package/skills/platform/traces/refs/traces.md +101 -0
- package/skills/product/acceptance-criteria/SKILL.md +193 -0
- package/skills/product/acceptance-criteria/refs/ac-anti-patterns.md +291 -0
- package/skills/product/acceptance-criteria/refs/ac-examples.md +277 -0
- package/skills/product/accessibility/SKILL.md +197 -0
- package/skills/product/accessibility/refs/aria-patterns-basics.md +250 -0
- package/skills/product/accessibility/refs/aria-patterns-dynamic.md +187 -0
- package/skills/product/accessibility/refs/aria-patterns-interactive.md +246 -0
- package/skills/product/accessibility/refs/audit-report-findings.md +248 -0
- package/skills/product/accessibility/refs/audit-report-results.md +276 -0
- package/skills/product/accessibility/refs/common-violations-html-css.md +270 -0
- package/skills/product/accessibility/refs/common-violations-interactive.md +303 -0
- package/skills/product/accessibility/refs/keyboard-testing-basics.md +222 -0
- package/skills/product/accessibility/refs/keyboard-testing-patterns.md +173 -0
- package/skills/product/accessibility/refs/screen-reader-testing-advanced.md +294 -0
- package/skills/product/accessibility/refs/screen-reader-testing-commands.md +255 -0
- package/skills/product/accessibility/refs/wcag-checklist.md +262 -0
- package/skills/product/analyze/SKILL.md +164 -0
- package/skills/product/analyze/refs/algorithms.md +238 -0
- package/skills/product/analyze/refs/sentiment-patterns.md +180 -0
- package/skills/product/imagery/SKILL.md +97 -0
- package/skills/product/imagery/alter/SKILL.md +105 -0
- package/skills/product/imagery/alter/refs/editing-reference.md +146 -0
- package/skills/product/imagery/create/SKILL.md +109 -0
- package/skills/product/imagery/create/refs/prompt-engineering.md +112 -0
- package/skills/product/imagery/create/refs/provider-reference.md +219 -0
- package/skills/product/imagery/review/SKILL.md +101 -0
- package/skills/product/imagery/review/refs/analysis-lenses.md +136 -0
- package/skills/product/imagery/review/refs/quality-gates.md +153 -0
- package/skills/product/imagery/scripts/analyze.sh +23 -0
- package/skills/product/imagery/scripts/edit.sh +14 -0
- package/skills/product/imagery/scripts/generate.sh +13 -0
- package/skills/product/imagery/scripts/provider.py +787 -0
- package/skills/product/listen/SKILL.md +175 -0
- package/skills/product/listen/refs/channels.md +220 -0
- package/skills/product/mockup/SKILL.md +106 -0
- package/skills/product/mockup/refs/templates.md +95 -0
- package/skills/product/refs/a11y.md +109 -0
- package/skills/product/refs/acceptance.md +79 -0
- package/skills/product/refs/align.md +67 -0
- package/skills/product/refs/analyze.md +77 -0
- package/skills/product/refs/elicit.md +67 -0
- package/skills/product/refs/listen.md +58 -0
- package/skills/product/refs/mockup.md +77 -0
- package/skills/product/refs/screenshot.md +59 -0
- package/skills/product/refs/strategy.md +77 -0
- package/skills/product/refs/synthesize.md +54 -0
- package/skills/product/refs/ux-review.md +68 -0
- package/skills/product/refs/ux.md +101 -0
- package/skills/product/requirements-analysis/SKILL.md +136 -0
- package/skills/product/requirements-analysis/refs/requirements-example-auth.md +264 -0
- package/skills/product/requirements-analysis/refs/requirements-example-export-integration.md +88 -0
- package/skills/product/requirements-analysis/refs/requirements-output-format-template.md +247 -0
- package/skills/product/requirements-analysis/refs/user-story-guide.md +296 -0
- package/skills/product/requirements-graph/SKILL.md +155 -0
- package/skills/product/requirements-graph/refs/examples.md +223 -0
- package/skills/product/requirements-graph/refs/schema.md +162 -0
- package/skills/product/requirements-migrate/SKILL.md +90 -0
- package/skills/product/requirements-navigate/SKILL.md +141 -0
- package/skills/product/requirements-navigate/refs/meta-templates.md +141 -0
- package/skills/product/screenshot/SKILL.md +147 -0
- package/skills/product/strategy/SKILL.md +198 -0
- package/skills/product/strategy/refs/frameworks.md +295 -0
- package/skills/product/strategy/refs/templates-competitive-market.md +299 -0
- package/skills/product/strategy/refs/templates-roi-value.md +207 -0
- package/skills/product/synthesize/SKILL.md +116 -0
- package/skills/product/synthesize/refs/journey-mapping.md +212 -0
- package/skills/product/synthesize/refs/prioritization.md +193 -0
- package/skills/product/ux-review/SKILL.md +164 -0
- package/skills/product/visual-direction/SKILL.md +137 -0
- package/skills/product/visual-review/SKILL.md +131 -0
- package/skills/runtime-exec/SKILL.md +138 -0
- package/skills/search/codebase-narrator/SKILL.md +131 -0
- package/skills/search/codebase-narrator/refs/output-template.md +100 -0
- package/skills/smaht/SKILL.md +72 -0
- package/skills/smaht/discovery/SKILL.md +65 -0
- package/skills/smaht/intent/SKILL.md +89 -0
- package/skills/smaht/propose-skills/SKILL.md +142 -0
- package/skills/smaht/refs/state.md +76 -0
- package/skills/swarm/SKILL.md +132 -0
- package/skills/swarm/refs/fan-out.md +104 -0
- package/skills/swarm/refs/independent-verification.md +86 -0
- package/skills/swarm/refs/receipts-and-evidence.md +69 -0
- package/skills/swarm/refs/recon-synthesis.md +87 -0
- package/skills/swarm/refs/ship-discipline.md +90 -0
- package/skills/wickedizer/SKILL.md +147 -0
- package/skills/wickedizer/refs/artifact-types.md +238 -0
- package/skills/wickedizer/refs/complexity.md +278 -0
- package/skills/wickedizer/refs/de-ai-pass.md +140 -0
- package/skills/wickedizer/refs/failure-modes.md +249 -0
- package/skills/wickedizer/refs/patterns.md +282 -0
- package/skills/wickedizer/refs/review.md +221 -0
- package/skills/wickedizer/refs/structure.md +282 -0
- package/skills/wickedizer/refs/voice-profile.md +125 -0
- package/skills/workflow/SKILL.md +132 -0
- package/skills/workflow/refs/archetype-adjustments.md +205 -0
- package/skills/workflow/refs/evidence.md +58 -0
- package/skills/workflow/refs/integration.md +130 -0
- package/skills/workflow/refs/risk-dimension-signals.md +260 -0
- package/skills/workflow/refs/scoring-rubric.md +49 -0
- package/skills/workflow/refs/signal-keywords.md +176 -0
- package/skills/workflow/refs/specialist-routing-rules.md +159 -0
- package/skills/worktrees/SKILL.md +87 -0
- 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()
|