javi-forge 0.1.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/.gitignore.template +105 -0
- package/.releaserc +44 -0
- package/README.md +45 -0
- package/ai-config/.skillignore +15 -0
- package/ai-config/AUTO_INVOKE.md +300 -0
- package/ai-config/agents/_TEMPLATE.md +93 -0
- package/ai-config/agents/business/api-designer.md +1657 -0
- package/ai-config/agents/business/business-analyst.md +1331 -0
- package/ai-config/agents/business/product-strategist.md +206 -0
- package/ai-config/agents/business/project-manager.md +178 -0
- package/ai-config/agents/business/requirements-analyst.md +1277 -0
- package/ai-config/agents/business/technical-writer.md +1679 -0
- package/ai-config/agents/creative/ux-designer.md +205 -0
- package/ai-config/agents/data-ai/ai-engineer.md +487 -0
- package/ai-config/agents/data-ai/analytics-engineer.md +953 -0
- package/ai-config/agents/data-ai/data-engineer.md +173 -0
- package/ai-config/agents/data-ai/data-scientist.md +672 -0
- package/ai-config/agents/data-ai/mlops-engineer.md +814 -0
- package/ai-config/agents/data-ai/prompt-engineer.md +772 -0
- package/ai-config/agents/development/angular-expert.md +620 -0
- package/ai-config/agents/development/backend-architect.md +795 -0
- package/ai-config/agents/development/database-specialist.md +212 -0
- package/ai-config/agents/development/frontend-specialist.md +686 -0
- package/ai-config/agents/development/fullstack-engineer.md +668 -0
- package/ai-config/agents/development/golang-pro.md +338 -0
- package/ai-config/agents/development/java-enterprise.md +400 -0
- package/ai-config/agents/development/javascript-pro.md +422 -0
- package/ai-config/agents/development/nextjs-pro.md +474 -0
- package/ai-config/agents/development/python-pro.md +570 -0
- package/ai-config/agents/development/react-pro.md +487 -0
- package/ai-config/agents/development/rust-pro.md +246 -0
- package/ai-config/agents/development/spring-boot-4-expert.md +326 -0
- package/ai-config/agents/development/typescript-pro.md +336 -0
- package/ai-config/agents/development/vue-specialist.md +605 -0
- package/ai-config/agents/infrastructure/cloud-architect.md +472 -0
- package/ai-config/agents/infrastructure/deployment-manager.md +358 -0
- package/ai-config/agents/infrastructure/devops-engineer.md +455 -0
- package/ai-config/agents/infrastructure/incident-responder.md +519 -0
- package/ai-config/agents/infrastructure/kubernetes-expert.md +705 -0
- package/ai-config/agents/infrastructure/monitoring-specialist.md +674 -0
- package/ai-config/agents/infrastructure/performance-engineer.md +658 -0
- package/ai-config/agents/orchestrator.md +241 -0
- package/ai-config/agents/quality/accessibility-auditor.md +1204 -0
- package/ai-config/agents/quality/code-reviewer-compact.md +123 -0
- package/ai-config/agents/quality/code-reviewer.md +363 -0
- package/ai-config/agents/quality/dependency-manager.md +743 -0
- package/ai-config/agents/quality/e2e-test-specialist.md +1005 -0
- package/ai-config/agents/quality/performance-tester.md +1086 -0
- package/ai-config/agents/quality/security-auditor.md +133 -0
- package/ai-config/agents/quality/test-engineer.md +453 -0
- package/ai-config/agents/specialists/api-designer.md +87 -0
- package/ai-config/agents/specialists/backend-architect.md +73 -0
- package/ai-config/agents/specialists/code-reviewer.md +77 -0
- package/ai-config/agents/specialists/db-optimizer.md +75 -0
- package/ai-config/agents/specialists/devops-engineer.md +83 -0
- package/ai-config/agents/specialists/documentation-writer.md +78 -0
- package/ai-config/agents/specialists/frontend-developer.md +75 -0
- package/ai-config/agents/specialists/performance-analyst.md +82 -0
- package/ai-config/agents/specialists/refactor-specialist.md +74 -0
- package/ai-config/agents/specialists/security-auditor.md +74 -0
- package/ai-config/agents/specialists/test-engineer.md +81 -0
- package/ai-config/agents/specialists/ux-consultant.md +76 -0
- package/ai-config/agents/specialized/agent-generator.md +1190 -0
- package/ai-config/agents/specialized/blockchain-developer.md +149 -0
- package/ai-config/agents/specialized/code-migrator.md +892 -0
- package/ai-config/agents/specialized/context-manager.md +978 -0
- package/ai-config/agents/specialized/documentation-writer.md +1078 -0
- package/ai-config/agents/specialized/ecommerce-expert.md +1756 -0
- package/ai-config/agents/specialized/embedded-engineer.md +1714 -0
- package/ai-config/agents/specialized/error-detective.md +1034 -0
- package/ai-config/agents/specialized/fintech-specialist.md +1659 -0
- package/ai-config/agents/specialized/freelance-project-planner-v2.md +1988 -0
- package/ai-config/agents/specialized/freelance-project-planner-v3.md +2136 -0
- package/ai-config/agents/specialized/freelance-project-planner-v4.md +4503 -0
- package/ai-config/agents/specialized/freelance-project-planner.md +722 -0
- package/ai-config/agents/specialized/game-developer.md +1963 -0
- package/ai-config/agents/specialized/healthcare-dev.md +1620 -0
- package/ai-config/agents/specialized/mobile-developer.md +188 -0
- package/ai-config/agents/specialized/parallel-plan-executor.md +506 -0
- package/ai-config/agents/specialized/plan-executor.md +485 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/00-INDEX.md +485 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/01-CORE.md +3493 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/02-SELF-CORRECTION.md +778 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/03-PROGRESSIVE-SETUP.md +918 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/04-DEPLOYMENT.md +1537 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/05-TESTING.md +2633 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/06-OPERATIONS.md +5610 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/INSTALL.md +335 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/QUICK-REFERENCE.txt +215 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/README.md +260 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/START-HERE.md +379 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/WORKFLOW-DIAGRAM.md +355 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/solo-dev-planner.md +279 -0
- package/ai-config/agents/specialized/template-writer.md +347 -0
- package/ai-config/agents/specialized/test-runner.md +99 -0
- package/ai-config/agents/specialized/vibekanban-smart-worker.md +244 -0
- package/ai-config/agents/specialized/wave-executor.md +138 -0
- package/ai-config/agents/specialized/workflow-optimizer.md +1114 -0
- package/ai-config/commands/git/changelog.md +32 -0
- package/ai-config/commands/git/ci-local.md +70 -0
- package/ai-config/commands/git/commit.md +35 -0
- package/ai-config/commands/git/fix-issue.md +23 -0
- package/ai-config/commands/git/pr-create.md +42 -0
- package/ai-config/commands/git/pr-review.md +50 -0
- package/ai-config/commands/git/worktree.md +39 -0
- package/ai-config/commands/refactoring/cleanup.md +24 -0
- package/ai-config/commands/refactoring/dead-code.md +40 -0
- package/ai-config/commands/refactoring/extract.md +31 -0
- package/ai-config/commands/testing/e2e.md +30 -0
- package/ai-config/commands/testing/tdd.md +36 -0
- package/ai-config/commands/testing/test-coverage.md +30 -0
- package/ai-config/commands/testing/test-fix.md +24 -0
- package/ai-config/commands/workflow/generate-agents-md.md +85 -0
- package/ai-config/commands/workflow/planning.md +47 -0
- package/ai-config/commands/workflows/compound.md +89 -0
- package/ai-config/commands/workflows/plan.md +77 -0
- package/ai-config/commands/workflows/review.md +78 -0
- package/ai-config/commands/workflows/work.md +75 -0
- package/ai-config/config.yaml +18 -0
- package/ai-config/hooks/_TEMPLATE.md +96 -0
- package/ai-config/hooks/block-dangerous-commands.md +75 -0
- package/ai-config/hooks/commit-guard.md +90 -0
- package/ai-config/hooks/context-loader.md +73 -0
- package/ai-config/hooks/improve-prompt.md +91 -0
- package/ai-config/hooks/learning-log.md +72 -0
- package/ai-config/hooks/model-router.md +86 -0
- package/ai-config/hooks/secret-scanner.md +64 -0
- package/ai-config/hooks/skill-validator.md +102 -0
- package/ai-config/hooks/task-artifact.md +114 -0
- package/ai-config/hooks/validate-workflow.md +100 -0
- package/ai-config/prompts/base.md +71 -0
- package/ai-config/prompts/modes/debug.md +34 -0
- package/ai-config/prompts/modes/deploy.md +40 -0
- package/ai-config/prompts/modes/research.md +32 -0
- package/ai-config/prompts/modes/review.md +33 -0
- package/ai-config/prompts/review-policy.md +79 -0
- package/ai-config/skills/_TEMPLATE.md +157 -0
- package/ai-config/skills/backend/api-gateway/SKILL.md +254 -0
- package/ai-config/skills/backend/bff-concepts/SKILL.md +239 -0
- package/ai-config/skills/backend/bff-spring/SKILL.md +364 -0
- package/ai-config/skills/backend/chi-router/SKILL.md +396 -0
- package/ai-config/skills/backend/error-handling/SKILL.md +255 -0
- package/ai-config/skills/backend/exceptions-spring/SKILL.md +323 -0
- package/ai-config/skills/backend/fastapi/SKILL.md +302 -0
- package/ai-config/skills/backend/gateway-spring/SKILL.md +390 -0
- package/ai-config/skills/backend/go-backend/SKILL.md +457 -0
- package/ai-config/skills/backend/gradle-multimodule/SKILL.md +274 -0
- package/ai-config/skills/backend/graphql-concepts/SKILL.md +352 -0
- package/ai-config/skills/backend/graphql-spring/SKILL.md +398 -0
- package/ai-config/skills/backend/grpc-concepts/SKILL.md +283 -0
- package/ai-config/skills/backend/grpc-spring/SKILL.md +445 -0
- package/ai-config/skills/backend/jwt-auth/SKILL.md +412 -0
- package/ai-config/skills/backend/notifications-concepts/SKILL.md +259 -0
- package/ai-config/skills/backend/recommendations-concepts/SKILL.md +261 -0
- package/ai-config/skills/backend/search-concepts/SKILL.md +263 -0
- package/ai-config/skills/backend/search-spring/SKILL.md +375 -0
- package/ai-config/skills/backend/spring-boot-4/SKILL.md +172 -0
- package/ai-config/skills/backend/websockets/SKILL.md +532 -0
- package/ai-config/skills/data-ai/ai-ml/SKILL.md +423 -0
- package/ai-config/skills/data-ai/analytics-concepts/SKILL.md +195 -0
- package/ai-config/skills/data-ai/analytics-spring/SKILL.md +340 -0
- package/ai-config/skills/data-ai/duckdb-analytics/SKILL.md +440 -0
- package/ai-config/skills/data-ai/langchain/SKILL.md +238 -0
- package/ai-config/skills/data-ai/mlflow/SKILL.md +302 -0
- package/ai-config/skills/data-ai/onnx-inference/SKILL.md +290 -0
- package/ai-config/skills/data-ai/powerbi/SKILL.md +352 -0
- package/ai-config/skills/data-ai/pytorch/SKILL.md +274 -0
- package/ai-config/skills/data-ai/scikit-learn/SKILL.md +321 -0
- package/ai-config/skills/data-ai/vector-db/SKILL.md +301 -0
- package/ai-config/skills/database/graph-databases/SKILL.md +218 -0
- package/ai-config/skills/database/graph-spring/SKILL.md +361 -0
- package/ai-config/skills/database/pgx-postgres/SKILL.md +512 -0
- package/ai-config/skills/database/redis-cache/SKILL.md +343 -0
- package/ai-config/skills/database/sqlite-embedded/SKILL.md +388 -0
- package/ai-config/skills/database/timescaledb/SKILL.md +320 -0
- package/ai-config/skills/docs/api-documentation/SKILL.md +293 -0
- package/ai-config/skills/docs/docs-spring/SKILL.md +377 -0
- package/ai-config/skills/docs/mustache-templates/SKILL.md +190 -0
- package/ai-config/skills/docs/technical-docs/SKILL.md +447 -0
- package/ai-config/skills/frontend/astro-ssr/SKILL.md +441 -0
- package/ai-config/skills/frontend/frontend-design/SKILL.md +54 -0
- package/ai-config/skills/frontend/frontend-web/SKILL.md +368 -0
- package/ai-config/skills/frontend/mantine-ui/SKILL.md +396 -0
- package/ai-config/skills/frontend/tanstack-query/SKILL.md +439 -0
- package/ai-config/skills/frontend/zod-validation/SKILL.md +417 -0
- package/ai-config/skills/frontend/zustand-state/SKILL.md +350 -0
- package/ai-config/skills/infrastructure/chaos-engineering/SKILL.md +244 -0
- package/ai-config/skills/infrastructure/chaos-spring/SKILL.md +378 -0
- package/ai-config/skills/infrastructure/devops-infra/SKILL.md +435 -0
- package/ai-config/skills/infrastructure/docker-containers/SKILL.md +420 -0
- package/ai-config/skills/infrastructure/kubernetes/SKILL.md +456 -0
- package/ai-config/skills/infrastructure/opentelemetry/SKILL.md +546 -0
- package/ai-config/skills/infrastructure/traefik-proxy/SKILL.md +474 -0
- package/ai-config/skills/infrastructure/woodpecker-ci/SKILL.md +315 -0
- package/ai-config/skills/mobile/ionic-capacitor/SKILL.md +504 -0
- package/ai-config/skills/mobile/mobile-ionic/SKILL.md +448 -0
- package/ai-config/skills/prompt-improver/SKILL.md +125 -0
- package/ai-config/skills/quality/ghagga-review/SKILL.md +216 -0
- package/ai-config/skills/references/hooks-patterns/SKILL.md +238 -0
- package/ai-config/skills/references/mcp-servers/SKILL.md +275 -0
- package/ai-config/skills/references/plugins-reference/SKILL.md +110 -0
- package/ai-config/skills/references/skills-reference/SKILL.md +420 -0
- package/ai-config/skills/references/subagent-templates/SKILL.md +193 -0
- package/ai-config/skills/systems-iot/modbus-protocol/SKILL.md +410 -0
- package/ai-config/skills/systems-iot/mqtt-rumqttc/SKILL.md +408 -0
- package/ai-config/skills/systems-iot/rust-systems/SKILL.md +386 -0
- package/ai-config/skills/systems-iot/tokio-async/SKILL.md +324 -0
- package/ai-config/skills/testing/playwright-e2e/SKILL.md +289 -0
- package/ai-config/skills/testing/testcontainers/SKILL.md +299 -0
- package/ai-config/skills/testing/vitest-testing/SKILL.md +381 -0
- package/ai-config/skills/workflow/ci-local-guide/SKILL.md +118 -0
- package/ai-config/skills/workflow/claude-automation-recommender/SKILL.md +299 -0
- package/ai-config/skills/workflow/claude-md-improver/SKILL.md +158 -0
- package/ai-config/skills/workflow/finishing-a-development-branch/SKILL.md +117 -0
- package/ai-config/skills/workflow/git-github/SKILL.md +334 -0
- package/ai-config/skills/workflow/git-github/references/examples.md +160 -0
- package/ai-config/skills/workflow/git-workflow/SKILL.md +214 -0
- package/ai-config/skills/workflow/ide-plugins/SKILL.md +277 -0
- package/ai-config/skills/workflow/ide-plugins-intellij/SKILL.md +401 -0
- package/ai-config/skills/workflow/obsidian-brain-workflow/SKILL.md +199 -0
- package/ai-config/skills/workflow/using-git-worktrees/SKILL.md +100 -0
- package/ai-config/skills/workflow/verification-before-completion/SKILL.md +73 -0
- package/ai-config/skills/workflow/wave-workflow/SKILL.md +178 -0
- package/ci-local/README.md +170 -0
- package/ci-local/ci-local.sh +297 -0
- package/ci-local/hooks/commit-msg +74 -0
- package/ci-local/hooks/pre-commit +162 -0
- package/ci-local/hooks/pre-push +41 -0
- package/ci-local/install.sh +49 -0
- package/ci-local/semgrep.yml +214 -0
- package/dist/commands/analyze.d.ts +9 -0
- package/dist/commands/analyze.d.ts.map +1 -0
- package/dist/commands/analyze.js +55 -0
- package/dist/commands/analyze.js.map +1 -0
- package/dist/commands/analyze.test.d.ts +2 -0
- package/dist/commands/analyze.test.d.ts.map +1 -0
- package/dist/commands/analyze.test.js +145 -0
- package/dist/commands/analyze.test.js.map +1 -0
- package/dist/commands/doctor.d.ts +7 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +158 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/doctor.test.d.ts +2 -0
- package/dist/commands/doctor.test.d.ts.map +1 -0
- package/dist/commands/doctor.test.js +200 -0
- package/dist/commands/doctor.test.js.map +1 -0
- package/dist/commands/init.d.ts +9 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +283 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/init.test.d.ts +2 -0
- package/dist/commands/init.test.d.ts.map +1 -0
- package/dist/commands/init.test.js +271 -0
- package/dist/commands/init.test.js.map +1 -0
- package/dist/commands/sync.d.ts +8 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +201 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/constants.d.ts +21 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +57 -0
- package/dist/constants.js.map +1 -0
- package/dist/e2e/aggressive.e2e.test.d.ts +2 -0
- package/dist/e2e/aggressive.e2e.test.d.ts.map +1 -0
- package/dist/e2e/aggressive.e2e.test.js +350 -0
- package/dist/e2e/aggressive.e2e.test.js.map +1 -0
- package/dist/e2e/commands.e2e.test.d.ts +2 -0
- package/dist/e2e/commands.e2e.test.d.ts.map +1 -0
- package/dist/e2e/commands.e2e.test.js +213 -0
- package/dist/e2e/commands.e2e.test.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +82 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/common.d.ts +17 -0
- package/dist/lib/common.d.ts.map +1 -0
- package/dist/lib/common.js +111 -0
- package/dist/lib/common.js.map +1 -0
- package/dist/lib/common.test.d.ts +2 -0
- package/dist/lib/common.test.d.ts.map +1 -0
- package/dist/lib/common.test.js +316 -0
- package/dist/lib/common.test.js.map +1 -0
- package/dist/lib/frontmatter.d.ts +18 -0
- package/dist/lib/frontmatter.d.ts.map +1 -0
- package/dist/lib/frontmatter.js +61 -0
- package/dist/lib/frontmatter.js.map +1 -0
- package/dist/lib/frontmatter.test.d.ts +2 -0
- package/dist/lib/frontmatter.test.d.ts.map +1 -0
- package/dist/lib/frontmatter.test.js +257 -0
- package/dist/lib/frontmatter.test.js.map +1 -0
- package/dist/lib/template.d.ts +24 -0
- package/dist/lib/template.d.ts.map +1 -0
- package/dist/lib/template.js +78 -0
- package/dist/lib/template.js.map +1 -0
- package/dist/lib/template.test.d.ts +2 -0
- package/dist/lib/template.test.d.ts.map +1 -0
- package/dist/lib/template.test.js +201 -0
- package/dist/lib/template.test.js.map +1 -0
- package/dist/types/index.d.ts +48 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/ui/AnalyzeUI.d.ts +7 -0
- package/dist/ui/AnalyzeUI.d.ts.map +1 -0
- package/dist/ui/AnalyzeUI.js +100 -0
- package/dist/ui/AnalyzeUI.js.map +1 -0
- package/dist/ui/App.d.ts +13 -0
- package/dist/ui/App.d.ts.map +1 -0
- package/dist/ui/App.js +100 -0
- package/dist/ui/App.js.map +1 -0
- package/dist/ui/CIContext.d.ts +9 -0
- package/dist/ui/CIContext.d.ts.map +1 -0
- package/dist/ui/CIContext.js +9 -0
- package/dist/ui/CIContext.js.map +1 -0
- package/dist/ui/CISelector.d.ts +8 -0
- package/dist/ui/CISelector.d.ts.map +1 -0
- package/dist/ui/CISelector.js +45 -0
- package/dist/ui/CISelector.js.map +1 -0
- package/dist/ui/Doctor.d.ts +3 -0
- package/dist/ui/Doctor.d.ts.map +1 -0
- package/dist/ui/Doctor.js +89 -0
- package/dist/ui/Doctor.js.map +1 -0
- package/dist/ui/Header.d.ts +8 -0
- package/dist/ui/Header.d.ts.map +1 -0
- package/dist/ui/Header.js +30 -0
- package/dist/ui/Header.js.map +1 -0
- package/dist/ui/MemorySelector.d.ts +8 -0
- package/dist/ui/MemorySelector.d.ts.map +1 -0
- package/dist/ui/MemorySelector.js +46 -0
- package/dist/ui/MemorySelector.js.map +1 -0
- package/dist/ui/NameInput.d.ts +8 -0
- package/dist/ui/NameInput.d.ts.map +1 -0
- package/dist/ui/NameInput.js +69 -0
- package/dist/ui/NameInput.js.map +1 -0
- package/dist/ui/OptionSelector.d.ts +12 -0
- package/dist/ui/OptionSelector.d.ts.map +1 -0
- package/dist/ui/OptionSelector.js +69 -0
- package/dist/ui/OptionSelector.js.map +1 -0
- package/dist/ui/Progress.d.ts +11 -0
- package/dist/ui/Progress.d.ts.map +1 -0
- package/dist/ui/Progress.js +58 -0
- package/dist/ui/Progress.js.map +1 -0
- package/dist/ui/StackSelector.d.ts +9 -0
- package/dist/ui/StackSelector.d.ts.map +1 -0
- package/dist/ui/StackSelector.js +65 -0
- package/dist/ui/StackSelector.js.map +1 -0
- package/dist/ui/Summary.d.ts +12 -0
- package/dist/ui/Summary.d.ts.map +1 -0
- package/dist/ui/Summary.js +114 -0
- package/dist/ui/Summary.js.map +1 -0
- package/dist/ui/SyncUI.d.ts +10 -0
- package/dist/ui/SyncUI.d.ts.map +1 -0
- package/dist/ui/SyncUI.js +64 -0
- package/dist/ui/SyncUI.js.map +1 -0
- package/dist/ui/Welcome.d.ts +7 -0
- package/dist/ui/Welcome.d.ts.map +1 -0
- package/dist/ui/Welcome.js +45 -0
- package/dist/ui/Welcome.js.map +1 -0
- package/dist/ui/theme.d.ts +10 -0
- package/dist/ui/theme.d.ts.map +1 -0
- package/dist/ui/theme.js +9 -0
- package/dist/ui/theme.js.map +1 -0
- package/modules/engram/.gitignore-snippet.txt +6 -0
- package/modules/engram/.mcp-config-snippet.json +11 -0
- package/modules/engram/README.md +146 -0
- package/modules/engram/install-engram.sh +216 -0
- package/modules/ghagga/.env.example +43 -0
- package/modules/ghagga/README.md +153 -0
- package/modules/ghagga/docker-compose.yml +80 -0
- package/modules/ghagga/setup-ghagga.sh +139 -0
- package/modules/memory-simple/.project/NOTES.md +22 -0
- package/modules/memory-simple/README.md +23 -0
- package/modules/obsidian-brain/.obsidian/app.json +23 -0
- package/modules/obsidian-brain/.obsidian/appearance.json +5 -0
- package/modules/obsidian-brain/.obsidian/bookmarks.json +34 -0
- package/modules/obsidian-brain/.obsidian/community-plugins.json +1 -0
- package/modules/obsidian-brain/.obsidian/core-plugins-migration.json +21 -0
- package/modules/obsidian-brain/.obsidian/core-plugins.json +18 -0
- package/modules/obsidian-brain/.obsidian/daily-notes.json +5 -0
- package/modules/obsidian-brain/.obsidian/graph.json +37 -0
- package/modules/obsidian-brain/.obsidian/hotkeys.json +14 -0
- package/modules/obsidian-brain/.obsidian/plugins/dataview/data.json +25 -0
- package/modules/obsidian-brain/.obsidian/plugins/obsidian-kanban/data.json +29 -0
- package/modules/obsidian-brain/.obsidian/plugins/templater-obsidian/data.json +18 -0
- package/modules/obsidian-brain/.obsidian/snippets/project-memory.css +71 -0
- package/modules/obsidian-brain/.obsidian-gitignore-snippet.txt +8 -0
- package/modules/obsidian-brain/.project/Attachments/.gitkeep +0 -0
- package/modules/obsidian-brain/.project/Memory/BLOCKERS.md +78 -0
- package/modules/obsidian-brain/.project/Memory/CONTEXT.md +102 -0
- package/modules/obsidian-brain/.project/Memory/DASHBOARD.md +73 -0
- package/modules/obsidian-brain/.project/Memory/DECISIONS.md +87 -0
- package/modules/obsidian-brain/.project/Memory/KANBAN.md +15 -0
- package/modules/obsidian-brain/.project/Memory/README.md +61 -0
- package/modules/obsidian-brain/.project/Memory/WAVES.md +78 -0
- package/modules/obsidian-brain/.project/Sessions/TEMPLATE.md +99 -0
- package/modules/obsidian-brain/.project/Templates/ADR.md +33 -0
- package/modules/obsidian-brain/.project/Templates/Blocker.md +21 -0
- package/modules/obsidian-brain/.project/Templates/Session.md +88 -0
- package/modules/obsidian-brain/README.md +268 -0
- package/modules/obsidian-brain/new-wave.sh +182 -0
- package/package.json +51 -0
- package/schemas/agent.schema.json +34 -0
- package/schemas/ai-config.schema.json +28 -0
- package/schemas/skill.schema.json +44 -0
- package/src/commands/analyze.test.ts +145 -0
- package/src/commands/analyze.ts +69 -0
- package/src/commands/doctor.test.ts +208 -0
- package/src/commands/doctor.ts +163 -0
- package/src/commands/init.test.ts +298 -0
- package/src/commands/init.ts +285 -0
- package/src/constants.ts +69 -0
- package/src/e2e/aggressive.e2e.test.ts +557 -0
- package/src/e2e/commands.e2e.test.ts +298 -0
- package/src/index.tsx +106 -0
- package/src/lib/common.test.ts +318 -0
- package/src/lib/common.ts +127 -0
- package/src/lib/frontmatter.test.ts +291 -0
- package/src/lib/frontmatter.ts +77 -0
- package/src/lib/template.test.ts +226 -0
- package/src/lib/template.ts +99 -0
- package/src/types/index.ts +53 -0
- package/src/ui/AnalyzeUI.tsx +133 -0
- package/src/ui/App.tsx +175 -0
- package/src/ui/CIContext.tsx +25 -0
- package/src/ui/CISelector.tsx +72 -0
- package/src/ui/Doctor.tsx +122 -0
- package/src/ui/Header.tsx +48 -0
- package/src/ui/MemorySelector.tsx +73 -0
- package/src/ui/NameInput.tsx +82 -0
- package/src/ui/OptionSelector.tsx +100 -0
- package/src/ui/Progress.tsx +88 -0
- package/src/ui/StackSelector.tsx +101 -0
- package/src/ui/Summary.tsx +134 -0
- package/src/ui/Welcome.tsx +54 -0
- package/src/ui/theme.ts +10 -0
- package/stryker.config.json +19 -0
- package/tasks/_TEMPLATE/files-edited.md +3 -0
- package/tasks/_TEMPLATE/plan.md +3 -0
- package/tasks/_TEMPLATE/research.md +3 -0
- package/tasks/_TEMPLATE/verification.md +5 -0
- package/templates/common/dependabot/cargo.yml +11 -0
- package/templates/common/dependabot/github-actions.yml +16 -0
- package/templates/common/dependabot/gomod.yml +15 -0
- package/templates/common/dependabot/gradle.yml +15 -0
- package/templates/common/dependabot/header.yml +3 -0
- package/templates/common/dependabot/maven.yml +15 -0
- package/templates/common/dependabot/npm.yml +20 -0
- package/templates/common/dependabot/pip.yml +11 -0
- package/templates/dependabot.yml +162 -0
- package/templates/github/ci-go.yml +41 -0
- package/templates/github/ci-java.yml +45 -0
- package/templates/github/ci-monorepo.yml +150 -0
- package/templates/github/ci-node.yml +42 -0
- package/templates/github/ci-python.yml +42 -0
- package/templates/github/ci-rust.yml +42 -0
- package/templates/github/dependabot-automerge.yml +40 -0
- package/templates/gitlab/gitlab-ci-go.yml +88 -0
- package/templates/gitlab/gitlab-ci-java.yml +79 -0
- package/templates/gitlab/gitlab-ci-monorepo.yml +126 -0
- package/templates/gitlab/gitlab-ci-node.yml +63 -0
- package/templates/gitlab/gitlab-ci-python.yml +147 -0
- package/templates/gitlab/gitlab-ci-rust.yml +67 -0
- package/templates/global/claude-settings.json +98 -0
- package/templates/global/codex-config.toml +8 -0
- package/templates/global/copilot-instructions/base-rules.instructions.md +13 -0
- package/templates/global/copilot-instructions/sdd-orchestrator.instructions.md +37 -0
- package/templates/global/gemini-commands/cleanup.toml +20 -0
- package/templates/global/gemini-commands/commit.toml +15 -0
- package/templates/global/gemini-commands/dead-code.toml +22 -0
- package/templates/global/gemini-commands/plan.toml +30 -0
- package/templates/global/gemini-commands/review.toml +17 -0
- package/templates/global/gemini-commands/sdd-apply.toml +22 -0
- package/templates/global/gemini-commands/sdd-ff.toml +14 -0
- package/templates/global/gemini-commands/sdd-new.toml +21 -0
- package/templates/global/gemini-commands/sdd-verify.toml +21 -0
- package/templates/global/gemini-commands/tdd.toml +26 -0
- package/templates/global/gemini-settings.json +8 -0
- package/templates/global/opencode-config.json +44 -0
- package/templates/global/sdd-instructions.md +47 -0
- package/templates/global/sdd-orchestrator-claude.md +46 -0
- package/templates/global/sdd-orchestrator-copilot.md +34 -0
- package/templates/renovate.json +69 -0
- package/templates/woodpecker/monorepo/backend.yml +34 -0
- package/templates/woodpecker/monorepo/frontend.yml +34 -0
- package/templates/woodpecker/monorepo/summary.yml +25 -0
- package/templates/woodpecker/woodpecker-go.yml +51 -0
- package/templates/woodpecker/woodpecker-java.yml +67 -0
- package/templates/woodpecker/woodpecker-node.yml +47 -0
- package/templates/woodpecker/woodpecker-python.yml +108 -0
- package/templates/woodpecker/woodpecker-rust.yml +57 -0
- package/tsconfig.json +19 -0
- package/vitest.config.ts +16 -0
- package/workflows/reusable-build-go.yml +111 -0
- package/workflows/reusable-build-java.yml +120 -0
- package/workflows/reusable-build-node.yml +145 -0
- package/workflows/reusable-build-python.yml +159 -0
- package/workflows/reusable-build-rust.yml +135 -0
- package/workflows/reusable-docker.yml +120 -0
- package/workflows/reusable-ghagga-review.yml +165 -0
- package/workflows/reusable-release.yml +91 -0
|
@@ -0,0 +1,814 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mlops-engineer
|
|
3
|
+
description: MLOps expert specializing in ML pipeline automation, model deployment, experiment tracking, and production ML systems
|
|
4
|
+
trigger: >
|
|
5
|
+
MLOps, ML pipeline, model deployment, MLflow, Kubeflow, experiment tracking,
|
|
6
|
+
model serving, feature store, model monitoring, data drift, model registry,
|
|
7
|
+
SageMaker, Kubernetes ML, CI/CD for ML
|
|
8
|
+
category: data-ai
|
|
9
|
+
color: green
|
|
10
|
+
tools: Write, Read, MultiEdit, Bash, Grep, Glob
|
|
11
|
+
config:
|
|
12
|
+
model: sonnet
|
|
13
|
+
metadata:
|
|
14
|
+
version: "2.0"
|
|
15
|
+
updated: "2026-02"
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
You are an MLOps engineer with expertise in machine learning pipeline automation, model deployment, experiment tracking, and production ML systems.
|
|
19
|
+
|
|
20
|
+
## Core Expertise
|
|
21
|
+
- ML pipeline orchestration and automation
|
|
22
|
+
- Model training, validation, and deployment
|
|
23
|
+
- Experiment tracking and model versioning
|
|
24
|
+
- Feature stores and data lineage
|
|
25
|
+
- Model monitoring and observability
|
|
26
|
+
- A/B testing for ML models
|
|
27
|
+
- Infrastructure as Code for ML workloads
|
|
28
|
+
- CI/CD for machine learning systems
|
|
29
|
+
|
|
30
|
+
## Technical Stack
|
|
31
|
+
- **Orchestration**: Kubeflow, MLflow, Airflow, Prefect, Dagster
|
|
32
|
+
- **Model Serving**: MLflow Model Registry, Seldon Core, KServe, TorchServe
|
|
33
|
+
- **Feature Stores**: Feast, Tecton, Databricks Feature Store
|
|
34
|
+
- **Experiment Tracking**: MLflow, Weights & Biases, Neptune, Comet
|
|
35
|
+
- **Container Platforms**: Docker, Kubernetes, OpenShift
|
|
36
|
+
- **Cloud ML**: AWS SageMaker, Google AI Platform, Azure ML Studio
|
|
37
|
+
- **Monitoring**: Prometheus, Grafana, Evidently AI, Whylabs
|
|
38
|
+
|
|
39
|
+
## MLflow Implementation
|
|
40
|
+
```python
|
|
41
|
+
import mlflow
|
|
42
|
+
import mlflow.sklearn
|
|
43
|
+
import mlflow.tracking
|
|
44
|
+
from mlflow.models.signature import infer_signature
|
|
45
|
+
from mlflow.tracking import MlflowClient
|
|
46
|
+
import pandas as pd
|
|
47
|
+
import numpy as np
|
|
48
|
+
from sklearn.ensemble import RandomForestClassifier
|
|
49
|
+
from sklearn.model_selection import train_test_split
|
|
50
|
+
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
|
|
51
|
+
|
|
52
|
+
class MLflowManager:
|
|
53
|
+
def __init__(self, tracking_uri="http://localhost:5000", experiment_name="default"):
|
|
54
|
+
mlflow.set_tracking_uri(tracking_uri)
|
|
55
|
+
mlflow.set_experiment(experiment_name)
|
|
56
|
+
self.client = MlflowClient()
|
|
57
|
+
|
|
58
|
+
def train_and_log_model(self, X, y, model_params=None, tags=None):
|
|
59
|
+
"""Train model with MLflow tracking"""
|
|
60
|
+
with mlflow.start_run() as run:
|
|
61
|
+
# Split data
|
|
62
|
+
X_train, X_test, y_train, y_test = train_test_split(
|
|
63
|
+
X, y, test_size=0.2, random_state=42
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
# Log dataset info
|
|
67
|
+
mlflow.log_param("dataset_size", len(X))
|
|
68
|
+
mlflow.log_param("features", X.shape[1])
|
|
69
|
+
mlflow.log_param("train_size", len(X_train))
|
|
70
|
+
mlflow.log_param("test_size", len(X_test))
|
|
71
|
+
|
|
72
|
+
# Initialize model
|
|
73
|
+
if model_params is None:
|
|
74
|
+
model_params = {
|
|
75
|
+
'n_estimators': 100,
|
|
76
|
+
'max_depth': 10,
|
|
77
|
+
'random_state': 42
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
model = RandomForestClassifier(**model_params)
|
|
81
|
+
|
|
82
|
+
# Log hyperparameters
|
|
83
|
+
mlflow.log_params(model_params)
|
|
84
|
+
|
|
85
|
+
# Train model
|
|
86
|
+
model.fit(X_train, y_train)
|
|
87
|
+
|
|
88
|
+
# Make predictions
|
|
89
|
+
y_pred = model.predict(X_test)
|
|
90
|
+
|
|
91
|
+
# Calculate metrics
|
|
92
|
+
accuracy = accuracy_score(y_test, y_pred)
|
|
93
|
+
precision = precision_score(y_test, y_pred, average='weighted')
|
|
94
|
+
recall = recall_score(y_test, y_pred, average='weighted')
|
|
95
|
+
f1 = f1_score(y_test, y_pred, average='weighted')
|
|
96
|
+
|
|
97
|
+
# Log metrics
|
|
98
|
+
mlflow.log_metric("accuracy", accuracy)
|
|
99
|
+
mlflow.log_metric("precision", precision)
|
|
100
|
+
mlflow.log_metric("recall", recall)
|
|
101
|
+
mlflow.log_metric("f1_score", f1)
|
|
102
|
+
|
|
103
|
+
# Log model with signature
|
|
104
|
+
signature = infer_signature(X_train, y_pred)
|
|
105
|
+
mlflow.sklearn.log_model(
|
|
106
|
+
sk_model=model,
|
|
107
|
+
artifact_path="model",
|
|
108
|
+
signature=signature,
|
|
109
|
+
registered_model_name="RandomForestClassifier"
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# Log tags
|
|
113
|
+
if tags:
|
|
114
|
+
mlflow.set_tags(tags)
|
|
115
|
+
|
|
116
|
+
# Log feature importance
|
|
117
|
+
if hasattr(model, 'feature_importances_'):
|
|
118
|
+
feature_importance = pd.DataFrame({
|
|
119
|
+
'feature': X.columns,
|
|
120
|
+
'importance': model.feature_importances_
|
|
121
|
+
}).sort_values('importance', ascending=False)
|
|
122
|
+
|
|
123
|
+
feature_importance.to_csv("feature_importance.csv", index=False)
|
|
124
|
+
mlflow.log_artifact("feature_importance.csv")
|
|
125
|
+
|
|
126
|
+
return run.info.run_id, model
|
|
127
|
+
|
|
128
|
+
def promote_model_to_production(self, model_name, version):
|
|
129
|
+
"""Promote model to production stage"""
|
|
130
|
+
self.client.transition_model_version_stage(
|
|
131
|
+
name=model_name,
|
|
132
|
+
version=version,
|
|
133
|
+
stage="Production"
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
return f"Model {model_name} v{version} promoted to Production"
|
|
137
|
+
|
|
138
|
+
def compare_model_versions(self, model_name, metric="accuracy"):
|
|
139
|
+
"""Compare different versions of a model"""
|
|
140
|
+
versions = self.client.search_model_versions(f"name='{model_name}'")
|
|
141
|
+
|
|
142
|
+
comparison = []
|
|
143
|
+
for version in versions:
|
|
144
|
+
run_id = version.run_id
|
|
145
|
+
run = mlflow.get_run(run_id)
|
|
146
|
+
|
|
147
|
+
comparison.append({
|
|
148
|
+
'version': version.version,
|
|
149
|
+
'stage': version.current_stage,
|
|
150
|
+
'run_id': run_id,
|
|
151
|
+
metric: run.data.metrics.get(metric),
|
|
152
|
+
'created_at': version.creation_timestamp
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
return pd.DataFrame(comparison).sort_values('version', ascending=False)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Kubeflow Pipeline
|
|
159
|
+
```python
|
|
160
|
+
import kfp
|
|
161
|
+
from kfp import dsl
|
|
162
|
+
from kfp.components import func_to_container_op, InputPath, OutputPath
|
|
163
|
+
import kfp.components as comp
|
|
164
|
+
|
|
165
|
+
# Define pipeline components
|
|
166
|
+
@func_to_container_op
|
|
167
|
+
def data_preprocessing(
|
|
168
|
+
input_data_path: InputPath(),
|
|
169
|
+
output_data_path: OutputPath(),
|
|
170
|
+
test_size: float = 0.2
|
|
171
|
+
):
|
|
172
|
+
import pandas as pd
|
|
173
|
+
import numpy as np
|
|
174
|
+
from sklearn.model_selection import train_test_split
|
|
175
|
+
from sklearn.preprocessing import StandardScaler
|
|
176
|
+
import joblib
|
|
177
|
+
|
|
178
|
+
# Load data
|
|
179
|
+
data = pd.read_csv(input_data_path)
|
|
180
|
+
|
|
181
|
+
# Preprocessing steps
|
|
182
|
+
# Handle missing values
|
|
183
|
+
data = data.dropna()
|
|
184
|
+
|
|
185
|
+
# Feature engineering
|
|
186
|
+
X = data.drop('target', axis=1)
|
|
187
|
+
y = data['target']
|
|
188
|
+
|
|
189
|
+
# Split data
|
|
190
|
+
X_train, X_test, y_train, y_test = train_test_split(
|
|
191
|
+
X, y, test_size=test_size, random_state=42
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
# Scale features
|
|
195
|
+
scaler = StandardScaler()
|
|
196
|
+
X_train_scaled = scaler.fit_transform(X_train)
|
|
197
|
+
X_test_scaled = scaler.transform(X_test)
|
|
198
|
+
|
|
199
|
+
# Save processed data
|
|
200
|
+
processed_data = {
|
|
201
|
+
'X_train': X_train_scaled,
|
|
202
|
+
'X_test': X_test_scaled,
|
|
203
|
+
'y_train': y_train.values,
|
|
204
|
+
'y_test': y_test.values
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
joblib.dump(processed_data, output_data_path)
|
|
208
|
+
joblib.dump(scaler, output_data_path.replace('.pkl', '_scaler.pkl'))
|
|
209
|
+
|
|
210
|
+
@func_to_container_op
|
|
211
|
+
def train_model(
|
|
212
|
+
processed_data_path: InputPath(),
|
|
213
|
+
model_path: OutputPath(),
|
|
214
|
+
n_estimators: int = 100,
|
|
215
|
+
max_depth: int = 10
|
|
216
|
+
):
|
|
217
|
+
import joblib
|
|
218
|
+
from sklearn.ensemble import RandomForestClassifier
|
|
219
|
+
from sklearn.metrics import accuracy_score
|
|
220
|
+
import mlflow
|
|
221
|
+
import mlflow.sklearn
|
|
222
|
+
|
|
223
|
+
# Load processed data
|
|
224
|
+
data = joblib.load(processed_data_path)
|
|
225
|
+
X_train, y_train = data['X_train'], data['y_train']
|
|
226
|
+
|
|
227
|
+
# Train model
|
|
228
|
+
model = RandomForestClassifier(
|
|
229
|
+
n_estimators=n_estimators,
|
|
230
|
+
max_depth=max_depth,
|
|
231
|
+
random_state=42
|
|
232
|
+
)
|
|
233
|
+
model.fit(X_train, y_train)
|
|
234
|
+
|
|
235
|
+
# Save model
|
|
236
|
+
joblib.dump(model, model_path)
|
|
237
|
+
|
|
238
|
+
# Log to MLflow
|
|
239
|
+
with mlflow.start_run():
|
|
240
|
+
mlflow.log_param("n_estimators", n_estimators)
|
|
241
|
+
mlflow.log_param("max_depth", max_depth)
|
|
242
|
+
mlflow.sklearn.log_model(model, "model")
|
|
243
|
+
|
|
244
|
+
@func_to_container_op
|
|
245
|
+
def evaluate_model(
|
|
246
|
+
processed_data_path: InputPath(),
|
|
247
|
+
model_path: InputPath(),
|
|
248
|
+
metrics_path: OutputPath()
|
|
249
|
+
):
|
|
250
|
+
import joblib
|
|
251
|
+
import json
|
|
252
|
+
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
|
|
253
|
+
import mlflow
|
|
254
|
+
|
|
255
|
+
# Load data and model
|
|
256
|
+
data = joblib.load(processed_data_path)
|
|
257
|
+
model = joblib.load(model_path)
|
|
258
|
+
|
|
259
|
+
X_test, y_test = data['X_test'], data['y_test']
|
|
260
|
+
|
|
261
|
+
# Make predictions
|
|
262
|
+
y_pred = model.predict(X_test)
|
|
263
|
+
|
|
264
|
+
# Calculate metrics
|
|
265
|
+
metrics = {
|
|
266
|
+
'accuracy': accuracy_score(y_test, y_pred),
|
|
267
|
+
'precision': precision_score(y_test, y_pred, average='weighted'),
|
|
268
|
+
'recall': recall_score(y_test, y_pred, average='weighted'),
|
|
269
|
+
'f1_score': f1_score(y_test, y_pred, average='weighted')
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
# Save metrics
|
|
273
|
+
with open(metrics_path, 'w') as f:
|
|
274
|
+
json.dump(metrics, f)
|
|
275
|
+
|
|
276
|
+
# Log metrics to MLflow
|
|
277
|
+
with mlflow.start_run():
|
|
278
|
+
for key, value in metrics.items():
|
|
279
|
+
mlflow.log_metric(key, value)
|
|
280
|
+
|
|
281
|
+
# Define the pipeline
|
|
282
|
+
@dsl.pipeline(
|
|
283
|
+
name='ML Training Pipeline',
|
|
284
|
+
description='End-to-end ML training pipeline'
|
|
285
|
+
)
|
|
286
|
+
def ml_training_pipeline(
|
|
287
|
+
input_data_path: str,
|
|
288
|
+
test_size: float = 0.2,
|
|
289
|
+
n_estimators: int = 100,
|
|
290
|
+
max_depth: int = 10
|
|
291
|
+
):
|
|
292
|
+
# Data preprocessing step
|
|
293
|
+
preprocessing_task = data_preprocessing(
|
|
294
|
+
input_data_path=input_data_path,
|
|
295
|
+
test_size=test_size
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
# Model training step
|
|
299
|
+
training_task = train_model(
|
|
300
|
+
processed_data_path=preprocessing_task.outputs['output_data_path'],
|
|
301
|
+
n_estimators=n_estimators,
|
|
302
|
+
max_depth=max_depth
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
# Model evaluation step
|
|
306
|
+
evaluation_task = evaluate_model(
|
|
307
|
+
processed_data_path=preprocessing_task.outputs['output_data_path'],
|
|
308
|
+
model_path=training_task.outputs['model_path']
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
return evaluation_task
|
|
312
|
+
|
|
313
|
+
# Compile and run pipeline
|
|
314
|
+
if __name__ == "__main__":
|
|
315
|
+
kfp.compiler.Compiler().compile(ml_training_pipeline, 'ml_pipeline.yaml')
|
|
316
|
+
|
|
317
|
+
client = kfp.Client(host='http://localhost:8080')
|
|
318
|
+
client.create_run_from_pipeline_func(
|
|
319
|
+
ml_training_pipeline,
|
|
320
|
+
arguments={
|
|
321
|
+
'input_data_path': '/data/training_data.csv',
|
|
322
|
+
'n_estimators': 200,
|
|
323
|
+
'max_depth': 15
|
|
324
|
+
}
|
|
325
|
+
)
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## Feature Store Implementation
|
|
329
|
+
```python
|
|
330
|
+
import feast
|
|
331
|
+
from feast import Entity, Feature, FeatureView, FileSource, ValueType
|
|
332
|
+
from datetime import timedelta
|
|
333
|
+
import pandas as pd
|
|
334
|
+
import numpy as np
|
|
335
|
+
|
|
336
|
+
class FeatureStoreManager:
|
|
337
|
+
def __init__(self, repo_path="feature_repo"):
|
|
338
|
+
self.repo_path = repo_path
|
|
339
|
+
self.store = feast.FeatureStore(repo_path=repo_path)
|
|
340
|
+
|
|
341
|
+
def define_feature_views(self):
|
|
342
|
+
"""Define feature views and entities"""
|
|
343
|
+
# Define entities
|
|
344
|
+
user_entity = Entity(
|
|
345
|
+
name="user_id",
|
|
346
|
+
value_type=ValueType.INT64,
|
|
347
|
+
description="User identifier"
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
product_entity = Entity(
|
|
351
|
+
name="product_id",
|
|
352
|
+
value_type=ValueType.INT64,
|
|
353
|
+
description="Product identifier"
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
# Define data sources
|
|
357
|
+
user_features_source = FileSource(
|
|
358
|
+
path="/data/user_features.parquet",
|
|
359
|
+
event_timestamp_column="event_timestamp",
|
|
360
|
+
created_timestamp_column="created_timestamp"
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
product_features_source = FileSource(
|
|
364
|
+
path="/data/product_features.parquet",
|
|
365
|
+
event_timestamp_column="event_timestamp"
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
# Define feature views
|
|
369
|
+
user_features_view = FeatureView(
|
|
370
|
+
name="user_features",
|
|
371
|
+
entities=["user_id"],
|
|
372
|
+
ttl=timedelta(days=1),
|
|
373
|
+
features=[
|
|
374
|
+
Feature(name="age", dtype=ValueType.INT64),
|
|
375
|
+
Feature(name="avg_purchase_amount", dtype=ValueType.DOUBLE),
|
|
376
|
+
Feature(name="total_purchases", dtype=ValueType.INT64),
|
|
377
|
+
Feature(name="days_since_last_purchase", dtype=ValueType.INT64)
|
|
378
|
+
],
|
|
379
|
+
online=True,
|
|
380
|
+
batch_source=user_features_source,
|
|
381
|
+
tags={"team": "ml_platform"}
|
|
382
|
+
)
|
|
383
|
+
|
|
384
|
+
product_features_view = FeatureView(
|
|
385
|
+
name="product_features",
|
|
386
|
+
entities=["product_id"],
|
|
387
|
+
ttl=timedelta(hours=6),
|
|
388
|
+
features=[
|
|
389
|
+
Feature(name="price", dtype=ValueType.DOUBLE),
|
|
390
|
+
Feature(name="category", dtype=ValueType.STRING),
|
|
391
|
+
Feature(name="avg_rating", dtype=ValueType.DOUBLE),
|
|
392
|
+
Feature(name="total_reviews", dtype=ValueType.INT64)
|
|
393
|
+
],
|
|
394
|
+
online=True,
|
|
395
|
+
batch_source=product_features_source,
|
|
396
|
+
tags={"team": "ml_platform"}
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
return [user_features_view, product_features_view], [user_entity, product_entity]
|
|
400
|
+
|
|
401
|
+
def materialize_features(self, start_date, end_date):
|
|
402
|
+
"""Materialize features to online store"""
|
|
403
|
+
self.store.materialize(start_date, end_date)
|
|
404
|
+
|
|
405
|
+
return "Features materialized successfully"
|
|
406
|
+
|
|
407
|
+
def get_online_features(self, feature_refs, entity_rows):
|
|
408
|
+
"""Retrieve features for online inference"""
|
|
409
|
+
online_features = self.store.get_online_features(
|
|
410
|
+
features=feature_refs,
|
|
411
|
+
entity_rows=entity_rows
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
return online_features.to_df()
|
|
415
|
+
|
|
416
|
+
def get_historical_features(self, entity_df, feature_refs):
|
|
417
|
+
"""Get historical features for training"""
|
|
418
|
+
training_df = self.store.get_historical_features(
|
|
419
|
+
entity_df=entity_df,
|
|
420
|
+
features=feature_refs
|
|
421
|
+
).to_df()
|
|
422
|
+
|
|
423
|
+
return training_df
|
|
424
|
+
|
|
425
|
+
# Example usage
|
|
426
|
+
def create_training_dataset():
|
|
427
|
+
fs_manager = FeatureStoreManager()
|
|
428
|
+
|
|
429
|
+
# Entity dataframe with user-product pairs and timestamps
|
|
430
|
+
entity_df = pd.DataFrame({
|
|
431
|
+
"user_id": [1001, 1002, 1003, 1004],
|
|
432
|
+
"product_id": [2001, 2002, 2003, 2004],
|
|
433
|
+
"event_timestamp": pd.to_datetime([
|
|
434
|
+
"2023-09-01 10:00:00",
|
|
435
|
+
"2023-09-01 11:00:00",
|
|
436
|
+
"2023-09-01 12:00:00",
|
|
437
|
+
"2023-09-01 13:00:00"
|
|
438
|
+
])
|
|
439
|
+
})
|
|
440
|
+
|
|
441
|
+
# Feature references
|
|
442
|
+
feature_refs = [
|
|
443
|
+
"user_features:age",
|
|
444
|
+
"user_features:avg_purchase_amount",
|
|
445
|
+
"user_features:total_purchases",
|
|
446
|
+
"product_features:price",
|
|
447
|
+
"product_features:category",
|
|
448
|
+
"product_features:avg_rating"
|
|
449
|
+
]
|
|
450
|
+
|
|
451
|
+
# Get historical features
|
|
452
|
+
training_df = fs_manager.get_historical_features(entity_df, feature_refs)
|
|
453
|
+
|
|
454
|
+
return training_df
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
## Model Monitoring and Observability
|
|
458
|
+
```python
|
|
459
|
+
import pandas as pd
|
|
460
|
+
import numpy as np
|
|
461
|
+
from scipy import stats
|
|
462
|
+
from evidently.dashboard import Dashboard
|
|
463
|
+
from evidently.dashboard.tabs import DataDriftTab, CatTargetDriftTab
|
|
464
|
+
from evidently.model_profile import Profile
|
|
465
|
+
from evidently.model_profile.sections import DataDriftProfileSection
|
|
466
|
+
import prometheus_client
|
|
467
|
+
from prometheus_client import Counter, Histogram, Gauge, generate_latest
|
|
468
|
+
|
|
469
|
+
class ModelMonitor:
|
|
470
|
+
def __init__(self, model_name, reference_data):
|
|
471
|
+
self.model_name = model_name
|
|
472
|
+
self.reference_data = reference_data
|
|
473
|
+
|
|
474
|
+
# Prometheus metrics
|
|
475
|
+
self.prediction_counter = Counter(
|
|
476
|
+
f'{model_name}_predictions_total',
|
|
477
|
+
'Total predictions made'
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
self.prediction_latency = Histogram(
|
|
481
|
+
f'{model_name}_prediction_duration_seconds',
|
|
482
|
+
'Prediction latency in seconds'
|
|
483
|
+
)
|
|
484
|
+
|
|
485
|
+
self.data_drift_score = Gauge(
|
|
486
|
+
f'{model_name}_data_drift_score',
|
|
487
|
+
'Data drift score'
|
|
488
|
+
)
|
|
489
|
+
|
|
490
|
+
self.prediction_distribution = Histogram(
|
|
491
|
+
f'{model_name}_prediction_values',
|
|
492
|
+
'Distribution of prediction values',
|
|
493
|
+
buckets=(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0)
|
|
494
|
+
)
|
|
495
|
+
|
|
496
|
+
def detect_data_drift(self, current_data, threshold=0.1):
|
|
497
|
+
"""Detect data drift using statistical tests"""
|
|
498
|
+
drift_results = {}
|
|
499
|
+
|
|
500
|
+
for column in self.reference_data.columns:
|
|
501
|
+
if column in current_data.columns:
|
|
502
|
+
ref_values = self.reference_data[column].dropna()
|
|
503
|
+
curr_values = current_data[column].dropna()
|
|
504
|
+
|
|
505
|
+
if self.reference_data[column].dtype in ['int64', 'float64']:
|
|
506
|
+
# KS test for numerical features
|
|
507
|
+
statistic, p_value = stats.ks_2samp(ref_values, curr_values)
|
|
508
|
+
drift_detected = p_value < threshold
|
|
509
|
+
else:
|
|
510
|
+
# Chi-square test for categorical features
|
|
511
|
+
ref_counts = ref_values.value_counts()
|
|
512
|
+
curr_counts = curr_values.value_counts()
|
|
513
|
+
|
|
514
|
+
# Align indices
|
|
515
|
+
all_categories = set(ref_counts.index) | set(curr_counts.index)
|
|
516
|
+
ref_aligned = ref_counts.reindex(all_categories, fill_value=0)
|
|
517
|
+
curr_aligned = curr_counts.reindex(all_categories, fill_value=0)
|
|
518
|
+
|
|
519
|
+
statistic, p_value = stats.chisquare(curr_aligned, ref_aligned)
|
|
520
|
+
drift_detected = p_value < threshold
|
|
521
|
+
|
|
522
|
+
drift_results[column] = {
|
|
523
|
+
'statistic': statistic,
|
|
524
|
+
'p_value': p_value,
|
|
525
|
+
'drift_detected': drift_detected
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
# Update Prometheus metric
|
|
529
|
+
overall_drift_score = np.mean([r['statistic'] for r in drift_results.values()])
|
|
530
|
+
self.data_drift_score.set(overall_drift_score)
|
|
531
|
+
|
|
532
|
+
return drift_results
|
|
533
|
+
|
|
534
|
+
def generate_drift_report(self, current_data):
|
|
535
|
+
"""Generate Evidently drift report"""
|
|
536
|
+
data_drift_dashboard = Dashboard(tabs=[DataDriftTab()])
|
|
537
|
+
data_drift_dashboard.calculate(self.reference_data, current_data)
|
|
538
|
+
|
|
539
|
+
# Save report
|
|
540
|
+
report_path = f"{self.model_name}_drift_report.html"
|
|
541
|
+
data_drift_dashboard.save(report_path)
|
|
542
|
+
|
|
543
|
+
return report_path
|
|
544
|
+
|
|
545
|
+
def log_prediction(self, features, prediction, latency):
|
|
546
|
+
"""Log prediction metrics"""
|
|
547
|
+
self.prediction_counter.inc()
|
|
548
|
+
self.prediction_latency.observe(latency)
|
|
549
|
+
self.prediction_distribution.observe(prediction)
|
|
550
|
+
|
|
551
|
+
def check_model_performance(self, y_true, y_pred, threshold_metrics=None):
|
|
552
|
+
"""Monitor model performance metrics"""
|
|
553
|
+
if threshold_metrics is None:
|
|
554
|
+
threshold_metrics = {
|
|
555
|
+
'accuracy': 0.8,
|
|
556
|
+
'precision': 0.7,
|
|
557
|
+
'recall': 0.7
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
from sklearn.metrics import accuracy_score, precision_score, recall_score
|
|
561
|
+
|
|
562
|
+
current_metrics = {
|
|
563
|
+
'accuracy': accuracy_score(y_true, y_pred),
|
|
564
|
+
'precision': precision_score(y_true, y_pred, average='weighted'),
|
|
565
|
+
'recall': recall_score(y_true, y_pred, average='weighted')
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
alerts = []
|
|
569
|
+
for metric, value in current_metrics.items():
|
|
570
|
+
if value < threshold_metrics.get(metric, 0):
|
|
571
|
+
alerts.append(f"{metric} ({value:.3f}) below threshold ({threshold_metrics[metric]})")
|
|
572
|
+
|
|
573
|
+
return current_metrics, alerts
|
|
574
|
+
|
|
575
|
+
def export_metrics(self):
|
|
576
|
+
"""Export Prometheus metrics"""
|
|
577
|
+
return generate_latest()
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
## CI/CD Pipeline for ML
|
|
581
|
+
```yaml
|
|
582
|
+
# .github/workflows/ml-pipeline.yml
|
|
583
|
+
name: ML Model CI/CD Pipeline
|
|
584
|
+
|
|
585
|
+
on:
|
|
586
|
+
push:
|
|
587
|
+
branches: [main, develop]
|
|
588
|
+
pull_request:
|
|
589
|
+
branches: [main]
|
|
590
|
+
|
|
591
|
+
env:
|
|
592
|
+
PYTHON_VERSION: 3.9
|
|
593
|
+
MLFLOW_TRACKING_URI: ${{ secrets.MLFLOW_TRACKING_URI }}
|
|
594
|
+
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
595
|
+
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
596
|
+
|
|
597
|
+
jobs:
|
|
598
|
+
data-validation:
|
|
599
|
+
runs-on: ubuntu-latest
|
|
600
|
+
steps:
|
|
601
|
+
- uses: actions/checkout@v3
|
|
602
|
+
|
|
603
|
+
- name: Set up Python
|
|
604
|
+
uses: actions/setup-python@v4
|
|
605
|
+
with:
|
|
606
|
+
python-version: ${{ env.PYTHON_VERSION }}
|
|
607
|
+
|
|
608
|
+
- name: Install dependencies
|
|
609
|
+
run: |
|
|
610
|
+
pip install -r requirements.txt
|
|
611
|
+
pip install great-expectations pandas-profiling
|
|
612
|
+
|
|
613
|
+
- name: Validate data quality
|
|
614
|
+
run: |
|
|
615
|
+
python scripts/data_validation.py
|
|
616
|
+
python scripts/generate_data_profile.py
|
|
617
|
+
|
|
618
|
+
- name: Upload data profile
|
|
619
|
+
uses: actions/upload-artifact@v3
|
|
620
|
+
with:
|
|
621
|
+
name: data-profile
|
|
622
|
+
path: data_profile.html
|
|
623
|
+
|
|
624
|
+
model-training:
|
|
625
|
+
needs: data-validation
|
|
626
|
+
runs-on: ubuntu-latest
|
|
627
|
+
steps:
|
|
628
|
+
- uses: actions/checkout@v3
|
|
629
|
+
|
|
630
|
+
- name: Set up Python
|
|
631
|
+
uses: actions/setup-python@v4
|
|
632
|
+
with:
|
|
633
|
+
python-version: ${{ env.PYTHON_VERSION }}
|
|
634
|
+
|
|
635
|
+
- name: Install dependencies
|
|
636
|
+
run: pip install -r requirements.txt
|
|
637
|
+
|
|
638
|
+
- name: Train model
|
|
639
|
+
run: |
|
|
640
|
+
python scripts/train_model.py \
|
|
641
|
+
--experiment-name "CI-CD-Pipeline" \
|
|
642
|
+
--model-type "RandomForest" \
|
|
643
|
+
--cross-validation
|
|
644
|
+
|
|
645
|
+
- name: Model validation
|
|
646
|
+
run: |
|
|
647
|
+
python scripts/validate_model.py \
|
|
648
|
+
--min-accuracy 0.8 \
|
|
649
|
+
--min-precision 0.7
|
|
650
|
+
|
|
651
|
+
- name: Upload model artifacts
|
|
652
|
+
uses: actions/upload-artifact@v3
|
|
653
|
+
with:
|
|
654
|
+
name: model-artifacts
|
|
655
|
+
path: artifacts/
|
|
656
|
+
|
|
657
|
+
model-deployment:
|
|
658
|
+
needs: model-training
|
|
659
|
+
runs-on: ubuntu-latest
|
|
660
|
+
if: github.ref == 'refs/heads/main'
|
|
661
|
+
steps:
|
|
662
|
+
- uses: actions/checkout@v3
|
|
663
|
+
|
|
664
|
+
- name: Configure AWS credentials
|
|
665
|
+
uses: aws-actions/configure-aws-credentials@v2
|
|
666
|
+
with:
|
|
667
|
+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
668
|
+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
669
|
+
aws-region: us-west-2
|
|
670
|
+
|
|
671
|
+
- name: Deploy to SageMaker
|
|
672
|
+
run: |
|
|
673
|
+
python scripts/deploy_model.py \
|
|
674
|
+
--endpoint-name "ml-model-prod" \
|
|
675
|
+
--instance-type "ml.t2.medium"
|
|
676
|
+
|
|
677
|
+
- name: Run integration tests
|
|
678
|
+
run: |
|
|
679
|
+
python scripts/integration_tests.py \
|
|
680
|
+
--endpoint-name "ml-model-prod"
|
|
681
|
+
|
|
682
|
+
- name: Update model registry
|
|
683
|
+
run: |
|
|
684
|
+
python scripts/update_model_registry.py \
|
|
685
|
+
--stage "Production" \
|
|
686
|
+
--model-version ${{ github.sha }}
|
|
687
|
+
|
|
688
|
+
monitoring-setup:
|
|
689
|
+
needs: model-deployment
|
|
690
|
+
runs-on: ubuntu-latest
|
|
691
|
+
steps:
|
|
692
|
+
- uses: actions/checkout@v3
|
|
693
|
+
|
|
694
|
+
- name: Set up monitoring
|
|
695
|
+
run: |
|
|
696
|
+
kubectl apply -f k8s/monitoring/
|
|
697
|
+
python scripts/setup_drift_detection.py
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
## Model Serving Infrastructure
|
|
701
|
+
```yaml
|
|
702
|
+
# Kubernetes deployment for model serving
|
|
703
|
+
apiVersion: apps/v1
|
|
704
|
+
kind: Deployment
|
|
705
|
+
metadata:
|
|
706
|
+
name: ml-model-server
|
|
707
|
+
labels:
|
|
708
|
+
app: ml-model-server
|
|
709
|
+
spec:
|
|
710
|
+
replicas: 3
|
|
711
|
+
selector:
|
|
712
|
+
matchLabels:
|
|
713
|
+
app: ml-model-server
|
|
714
|
+
template:
|
|
715
|
+
metadata:
|
|
716
|
+
labels:
|
|
717
|
+
app: ml-model-server
|
|
718
|
+
spec:
|
|
719
|
+
containers:
|
|
720
|
+
- name: model-server
|
|
721
|
+
image: mlmodel:latest
|
|
722
|
+
ports:
|
|
723
|
+
- containerPort: 8080
|
|
724
|
+
env:
|
|
725
|
+
- name: MODEL_NAME
|
|
726
|
+
value: "random_forest_classifier"
|
|
727
|
+
- name: MODEL_VERSION
|
|
728
|
+
value: "v1.0.0"
|
|
729
|
+
- name: MLFLOW_TRACKING_URI
|
|
730
|
+
value: "http://mlflow-server:5000"
|
|
731
|
+
resources:
|
|
732
|
+
requests:
|
|
733
|
+
memory: "512Mi"
|
|
734
|
+
cpu: "500m"
|
|
735
|
+
limits:
|
|
736
|
+
memory: "1Gi"
|
|
737
|
+
cpu: "1000m"
|
|
738
|
+
livenessProbe:
|
|
739
|
+
httpGet:
|
|
740
|
+
path: /health
|
|
741
|
+
port: 8080
|
|
742
|
+
initialDelaySeconds: 30
|
|
743
|
+
periodSeconds: 10
|
|
744
|
+
readinessProbe:
|
|
745
|
+
httpGet:
|
|
746
|
+
path: /ready
|
|
747
|
+
port: 8080
|
|
748
|
+
initialDelaySeconds: 5
|
|
749
|
+
periodSeconds: 5
|
|
750
|
+
---
|
|
751
|
+
apiVersion: v1
|
|
752
|
+
kind: Service
|
|
753
|
+
metadata:
|
|
754
|
+
name: ml-model-service
|
|
755
|
+
spec:
|
|
756
|
+
selector:
|
|
757
|
+
app: ml-model-server
|
|
758
|
+
ports:
|
|
759
|
+
- protocol: TCP
|
|
760
|
+
port: 80
|
|
761
|
+
targetPort: 8080
|
|
762
|
+
type: ClusterIP
|
|
763
|
+
---
|
|
764
|
+
apiVersion: networking.k8s.io/v1
|
|
765
|
+
kind: Ingress
|
|
766
|
+
metadata:
|
|
767
|
+
name: ml-model-ingress
|
|
768
|
+
annotations:
|
|
769
|
+
nginx.ingress.kubernetes.io/rewrite-target: /
|
|
770
|
+
spec:
|
|
771
|
+
rules:
|
|
772
|
+
- host: ml-api.example.com
|
|
773
|
+
http:
|
|
774
|
+
paths:
|
|
775
|
+
- path: /predict
|
|
776
|
+
pathType: Prefix
|
|
777
|
+
backend:
|
|
778
|
+
service:
|
|
779
|
+
name: ml-model-service
|
|
780
|
+
port:
|
|
781
|
+
number: 80
|
|
782
|
+
```
|
|
783
|
+
|
|
784
|
+
## Best Practices
|
|
785
|
+
1. **Version Everything**: Models, data, code, and configurations
|
|
786
|
+
2. **Automate Testing**: Unit tests, integration tests, and model validation
|
|
787
|
+
3. **Monitor Continuously**: Model performance, data drift, and system health
|
|
788
|
+
4. **Gradual Rollouts**: Use canary deployments for model updates
|
|
789
|
+
5. **Reproducibility**: Ensure all experiments and deployments are reproducible
|
|
790
|
+
6. **Documentation**: Maintain clear documentation for all processes
|
|
791
|
+
7. **Security**: Implement proper access controls and data privacy measures
|
|
792
|
+
|
|
793
|
+
## Data and Model Governance
|
|
794
|
+
- Implement data lineage tracking
|
|
795
|
+
- Maintain model documentation and metadata
|
|
796
|
+
- Establish approval workflows for production deployments
|
|
797
|
+
- Regular model audits and performance reviews
|
|
798
|
+
- Compliance with data protection regulations
|
|
799
|
+
|
|
800
|
+
## Approach
|
|
801
|
+
- Design end-to-end ML pipelines with automation
|
|
802
|
+
- Implement comprehensive monitoring and alerting
|
|
803
|
+
- Set up proper experiment tracking and model versioning
|
|
804
|
+
- Create robust deployment and rollback procedures
|
|
805
|
+
- Establish data and model governance practices
|
|
806
|
+
- Document all processes and maintain runbooks
|
|
807
|
+
|
|
808
|
+
## Output Format
|
|
809
|
+
- Provide complete pipeline configurations
|
|
810
|
+
- Include monitoring and alerting setups
|
|
811
|
+
- Document deployment procedures
|
|
812
|
+
- Add model governance frameworks
|
|
813
|
+
- Include automation scripts and tools
|
|
814
|
+
- Provide operational runbooks and troubleshooting guides
|