@ketecode/loom 0.0.0-stage → 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/LICENSE +21 -0
- package/README.md +516 -2
- package/agents/accessibility-reviewer/AGENT.md +70 -0
- package/agents/accessibility-reviewer/evals/triggers.json +15 -0
- package/agents/agent-evaluator/AGENT.md +74 -0
- package/agents/agent-evaluator/evals/triggers.json +15 -0
- package/agents/architect/AGENT.md +82 -0
- package/agents/architect/evals/triggers.json +17 -0
- package/agents/billing-reviewer/AGENT.md +68 -0
- package/agents/billing-reviewer/evals/triggers.json +16 -0
- package/agents/code-reviewer/AGENT.md +51 -0
- package/agents/code-reviewer/evals/triggers.json +14 -0
- package/agents/code-simplifier/AGENT.md +74 -0
- package/agents/code-simplifier/evals/triggers.json +15 -0
- package/agents/cpp-build-resolver/AGENT.md +73 -0
- package/agents/cpp-build-resolver/evals/triggers.json +16 -0
- package/agents/cpp-reviewer/AGENT.md +59 -0
- package/agents/cpp-reviewer/evals/triggers.json +16 -0
- package/agents/csharp-build-resolver/AGENT.md +84 -0
- package/agents/csharp-build-resolver/evals/triggers.json +17 -0
- package/agents/csharp-reviewer/AGENT.md +88 -0
- package/agents/csharp-reviewer/evals/triggers.json +17 -0
- package/agents/dart-build-resolver/AGENT.md +80 -0
- package/agents/dart-build-resolver/evals/triggers.json +17 -0
- package/agents/dart-reviewer/AGENT.md +66 -0
- package/agents/dart-reviewer/evals/triggers.json +17 -0
- package/agents/database-reviewer/AGENT.md +72 -0
- package/agents/database-reviewer/evals/triggers.json +16 -0
- package/agents/django-reviewer/AGENT.md +61 -0
- package/agents/django-reviewer/evals/triggers.json +15 -0
- package/agents/doc-updater/AGENT.md +92 -0
- package/agents/doc-updater/evals/triggers.json +14 -0
- package/agents/e2e-runner/AGENT.md +88 -0
- package/agents/e2e-runner/evals/triggers.json +16 -0
- package/agents/fastapi-reviewer/AGENT.md +63 -0
- package/agents/fastapi-reviewer/evals/triggers.json +15 -0
- package/agents/flutter-reviewer/AGENT.md +70 -0
- package/agents/flutter-reviewer/evals/triggers.json +15 -0
- package/agents/fsharp-build-resolver/AGENT.md +81 -0
- package/agents/fsharp-build-resolver/evals/triggers.json +15 -0
- package/agents/fsharp-reviewer/AGENT.md +77 -0
- package/agents/fsharp-reviewer/evals/triggers.json +15 -0
- package/agents/go-build-resolver/AGENT.md +85 -0
- package/agents/go-build-resolver/evals/triggers.json +16 -0
- package/agents/go-reviewer/AGENT.md +66 -0
- package/agents/go-reviewer/evals/triggers.json +16 -0
- package/agents/healthcare-reviewer/AGENT.md +65 -0
- package/agents/healthcare-reviewer/evals/triggers.json +16 -0
- package/agents/i18n-reviewer/AGENT.md +64 -0
- package/agents/i18n-reviewer/evals/triggers.json +16 -0
- package/agents/infra-reviewer/AGENT.md +93 -0
- package/agents/infra-reviewer/evals/triggers.json +15 -0
- package/agents/java-build-resolver/AGENT.md +82 -0
- package/agents/java-build-resolver/evals/triggers.json +16 -0
- package/agents/java-reviewer/AGENT.md +64 -0
- package/agents/java-reviewer/evals/triggers.json +16 -0
- package/agents/kotlin-build-resolver/AGENT.md +89 -0
- package/agents/kotlin-build-resolver/evals/triggers.json +16 -0
- package/agents/kotlin-reviewer/AGENT.md +75 -0
- package/agents/kotlin-reviewer/evals/triggers.json +16 -0
- package/agents/mle-reviewer/AGENT.md +68 -0
- package/agents/mle-reviewer/evals/triggers.json +16 -0
- package/agents/network-config-reviewer/AGENT.md +68 -0
- package/agents/network-config-reviewer/evals/triggers.json +17 -0
- package/agents/payments-reviewer/AGENT.md +64 -0
- package/agents/payments-reviewer/evals/triggers.json +16 -0
- package/agents/performance-optimizer/AGENT.md +86 -0
- package/agents/performance-optimizer/evals/triggers.json +16 -0
- package/agents/perl-build-resolver/AGENT.md +84 -0
- package/agents/perl-build-resolver/evals/triggers.json +15 -0
- package/agents/perl-reviewer/AGENT.md +77 -0
- package/agents/perl-reviewer/evals/triggers.json +15 -0
- package/agents/php-build-resolver/AGENT.md +88 -0
- package/agents/php-build-resolver/evals/triggers.json +16 -0
- package/agents/php-reviewer/AGENT.md +61 -0
- package/agents/php-reviewer/evals/triggers.json +15 -0
- package/agents/planner/AGENT.md +75 -0
- package/agents/planner/evals/triggers.json +17 -0
- package/agents/pr-test-analyzer/AGENT.md +82 -0
- package/agents/pr-test-analyzer/evals/triggers.json +16 -0
- package/agents/python-build-resolver/AGENT.md +87 -0
- package/agents/python-build-resolver/evals/triggers.json +16 -0
- package/agents/python-reviewer/AGENT.md +63 -0
- package/agents/python-reviewer/evals/triggers.json +15 -0
- package/agents/rag-reviewer/AGENT.md +71 -0
- package/agents/rag-reviewer/evals/triggers.json +16 -0
- package/agents/react-reviewer/AGENT.md +70 -0
- package/agents/react-reviewer/evals/triggers.json +16 -0
- package/agents/refactor-cleaner/AGENT.md +82 -0
- package/agents/refactor-cleaner/evals/triggers.json +16 -0
- package/agents/ruby-build-resolver/AGENT.md +93 -0
- package/agents/ruby-build-resolver/evals/triggers.json +16 -0
- package/agents/ruby-reviewer/AGENT.md +62 -0
- package/agents/ruby-reviewer/evals/triggers.json +16 -0
- package/agents/rust-build-resolver/AGENT.md +98 -0
- package/agents/rust-build-resolver/evals/triggers.json +16 -0
- package/agents/rust-reviewer/AGENT.md +78 -0
- package/agents/rust-reviewer/evals/triggers.json +15 -0
- package/agents/security-reviewer/AGENT.md +84 -0
- package/agents/security-reviewer/evals/triggers.json +16 -0
- package/agents/silent-failure-hunter/AGENT.md +66 -0
- package/agents/silent-failure-hunter/evals/triggers.json +16 -0
- package/agents/solidity-reviewer/AGENT.md +70 -0
- package/agents/solidity-reviewer/evals/triggers.json +16 -0
- package/agents/swift-build-resolver/AGENT.md +85 -0
- package/agents/swift-build-resolver/evals/triggers.json +15 -0
- package/agents/swift-reviewer/AGENT.md +75 -0
- package/agents/swift-reviewer/evals/triggers.json +15 -0
- package/agents/typescript-build-resolver/AGENT.md +76 -0
- package/agents/typescript-build-resolver/evals/triggers.json +15 -0
- package/agents/typescript-reviewer/AGENT.md +76 -0
- package/agents/typescript-reviewer/evals/triggers.json +15 -0
- package/agents/vue-reviewer/AGENT.md +75 -0
- package/agents/vue-reviewer/evals/triggers.json +15 -0
- package/bin/kete-loom.js +683 -0
- package/commands/aside.md +19 -0
- package/commands/build-fix.md +26 -0
- package/commands/campaign.md +19 -0
- package/commands/changelog.md +36 -0
- package/commands/checkpoint.md +26 -0
- package/commands/codemap.md +25 -0
- package/commands/commit.md +26 -0
- package/commands/deps-audit.md +32 -0
- package/commands/epic-decompose.md +21 -0
- package/commands/explain.md +37 -0
- package/commands/feature-dev.md +22 -0
- package/commands/hookify.md +23 -0
- package/commands/i18n-check.md +39 -0
- package/commands/issue-sync.md +22 -0
- package/commands/jira.md +19 -0
- package/commands/learn.md +23 -0
- package/commands/loom.md +21 -0
- package/commands/loop.md +20 -0
- package/commands/model-route.md +27 -0
- package/commands/onboard.md +35 -0
- package/commands/orchestrate.md +21 -0
- package/commands/plan-feature.md +36 -0
- package/commands/postmortem.md +42 -0
- package/commands/pr-describe.md +39 -0
- package/commands/pr.md +22 -0
- package/commands/prd.md +41 -0
- package/commands/project-init.md +21 -0
- package/commands/refactor-clean.md +24 -0
- package/commands/resume-session.md +22 -0
- package/commands/review.md +35 -0
- package/commands/save-session.md +37 -0
- package/commands/security-scan.md +32 -0
- package/commands/sessions.md +21 -0
- package/commands/skill-create.md +21 -0
- package/commands/tdd.md +36 -0
- package/commands/test-coverage.md +24 -0
- package/commands/threat-model.md +36 -0
- package/commands/update-docs.md +25 -0
- package/commands/verify.md +21 -0
- package/hooks/block-dangerous-commands/HOOK.md +30 -0
- package/hooks/block-dangerous-commands/cases.json +50 -0
- package/hooks/block-dangerous-commands/hook.js +75 -0
- package/hooks/block-no-verify/HOOK.md +25 -0
- package/hooks/block-no-verify/cases.json +30 -0
- package/hooks/block-no-verify/hook.js +43 -0
- package/hooks/format-on-edit/HOOK.md +24 -0
- package/hooks/format-on-edit/hook.js +89 -0
- package/hooks/guard-secrets/HOOK.md +19 -0
- package/hooks/guard-secrets/cases.json +110 -0
- package/hooks/guard-secrets/hook.js +44 -0
- package/hooks/load-session-context/HOOK.md +20 -0
- package/hooks/load-session-context/hook.js +56 -0
- package/hooks/protect-files/HOOK.md +24 -0
- package/hooks/protect-files/cases.json +27 -0
- package/hooks/protect-files/hook.js +39 -0
- package/hooks/run.js +132 -0
- package/mcp/atlassian.json +11 -0
- package/mcp/chrome-devtools.json +18 -0
- package/mcp/cloudflare.json +11 -0
- package/mcp/context7.json +11 -0
- package/mcp/fetch.json +17 -0
- package/mcp/figma.json +11 -0
- package/mcp/git.json +17 -0
- package/mcp/github.json +11 -0
- package/mcp/linear.json +11 -0
- package/mcp/memory.json +18 -0
- package/mcp/notion.json +11 -0
- package/mcp/playwright.json +18 -0
- package/mcp/sentry.json +11 -0
- package/mcp/stripe.json +11 -0
- package/mcp/supabase.json +11 -0
- package/mcp/time.json +17 -0
- package/package.json +59 -4
- package/profiles.json +165 -0
- package/rules/common.md +21 -0
- package/rules/cpp.md +29 -0
- package/rules/csharp.md +25 -0
- package/rules/dart.md +29 -0
- package/rules/fsharp.md +28 -0
- package/rules/git.md +26 -0
- package/rules/go.md +29 -0
- package/rules/java.md +29 -0
- package/rules/kotlin.md +27 -0
- package/rules/perl.md +26 -0
- package/rules/php.md +28 -0
- package/rules/python.md +30 -0
- package/rules/ruby.md +27 -0
- package/rules/rust.md +26 -0
- package/rules/security.md +29 -0
- package/rules/swift.md +28 -0
- package/rules/testing.md +25 -0
- package/rules/typescript.md +29 -0
- package/schemas/skill-frontmatter.schema.json +52 -0
- package/scripts/lib/audit.js +96 -0
- package/scripts/lib/frontmatter.js +65 -0
- package/scripts/lib/hooks-install.js +292 -0
- package/scripts/lib/i18n.js +51 -0
- package/scripts/lib/inventory.js +85 -0
- package/scripts/lib/lint.js +158 -0
- package/scripts/lib/mcp-install.js +284 -0
- package/scripts/lib/profiles.js +128 -0
- package/scripts/lib/render.js +86 -0
- package/scripts/lib/rules-install.js +118 -0
- package/scripts/lib/skills.js +86 -0
- package/scripts/lib/targets.js +113 -0
- package/skills/accounting-api-integration/SKILL.md +81 -0
- package/skills/accounting-api-integration/evals/triggers.json +17 -0
- package/skills/accounting-api-integration/references/quickbooks.md +48 -0
- package/skills/accounting-api-integration/references/xero.md +45 -0
- package/skills/agent-harness-design/SKILL.md +125 -0
- package/skills/agent-harness-design/evals/triggers.json +21 -0
- package/skills/ai-media-generation/SKILL.md +89 -0
- package/skills/ai-media-generation/evals/triggers.json +16 -0
- package/skills/ai-media-generation/references/job-pipeline.md +76 -0
- package/skills/angular-patterns/SKILL.md +122 -0
- package/skills/angular-patterns/evals/triggers.json +16 -0
- package/skills/api-design/SKILL.md +96 -0
- package/skills/api-design/evals/triggers.json +18 -0
- package/skills/api-design/references/conventions.md +133 -0
- package/skills/architecture-decision-records/SKILL.md +98 -0
- package/skills/architecture-decision-records/evals/triggers.json +17 -0
- package/skills/article-writing/SKILL.md +108 -0
- package/skills/article-writing/evals/triggers.json +16 -0
- package/skills/aspnet-core-patterns/SKILL.md +149 -0
- package/skills/aspnet-core-patterns/evals/triggers.json +16 -0
- package/skills/auth-patterns/SKILL.md +104 -0
- package/skills/auth-patterns/evals/triggers.json +17 -0
- package/skills/auth-patterns/references/oauth-oidc.md +64 -0
- package/skills/autonomous-loops/SKILL.md +99 -0
- package/skills/autonomous-loops/evals/triggers.json +14 -0
- package/skills/aws-patterns/SKILL.md +91 -0
- package/skills/aws-patterns/evals/triggers.json +16 -0
- package/skills/azure-patterns/SKILL.md +86 -0
- package/skills/azure-patterns/evals/triggers.json +16 -0
- package/skills/benchmark-methodology/SKILL.md +88 -0
- package/skills/benchmark-methodology/evals/triggers.json +16 -0
- package/skills/benchmark-methodology/references/language-harnesses.md +130 -0
- package/skills/bgp-diagnostics/SKILL.md +84 -0
- package/skills/bgp-diagnostics/evals/triggers.json +18 -0
- package/skills/bgp-diagnostics/references/bgp-reference.md +81 -0
- package/skills/bioinformatics-workflows/SKILL.md +108 -0
- package/skills/bioinformatics-workflows/evals/triggers.json +16 -0
- package/skills/bioinformatics-workflows/references/commands.md +71 -0
- package/skills/bioinformatics-workflows/references/formats.md +24 -0
- package/skills/bioinformatics-workflows/references/workflow-managers.md +107 -0
- package/skills/brand-voice/SKILL.md +112 -0
- package/skills/brand-voice/evals/triggers.json +16 -0
- package/skills/browser-qa/SKILL.md +99 -0
- package/skills/browser-qa/evals/triggers.json +16 -0
- package/skills/bun-runtime/SKILL.md +93 -0
- package/skills/bun-runtime/evals/triggers.json +16 -0
- package/skills/cisco-ios-config/SKILL.md +101 -0
- package/skills/cisco-ios-config/evals/triggers.json +18 -0
- package/skills/cisco-ios-config/references/verification.md +63 -0
- package/skills/clickhouse-patterns/SKILL.md +101 -0
- package/skills/clickhouse-patterns/evals/triggers.json +18 -0
- package/skills/clickhouse-patterns/references/engines-and-views.md +138 -0
- package/skills/clinical-decision-support/SKILL.md +90 -0
- package/skills/clinical-decision-support/evals/triggers.json +16 -0
- package/skills/clinical-decision-support/references/cds-hooks.md +76 -0
- package/skills/clinical-decision-support/references/regulatory-boundaries.md +37 -0
- package/skills/code-tour/SKILL.md +97 -0
- package/skills/code-tour/evals/triggers.json +14 -0
- package/skills/codebase-onboarding/SKILL.md +112 -0
- package/skills/codebase-onboarding/evals/triggers.json +14 -0
- package/skills/cold-outreach-sequences/SKILL.md +90 -0
- package/skills/cold-outreach-sequences/evals/triggers.json +16 -0
- package/skills/content-repurposing/SKILL.md +82 -0
- package/skills/content-repurposing/evals/triggers.json +16 -0
- package/skills/context-budget/SKILL.md +84 -0
- package/skills/context-budget/evals/triggers.json +14 -0
- package/skills/conventional-commits/SKILL.md +144 -0
- package/skills/conventional-commits/evals/triggers.json +16 -0
- package/skills/cpp-patterns/SKILL.md +129 -0
- package/skills/cpp-patterns/evals/triggers.json +16 -0
- package/skills/cpp-patterns/references/cmake-and-tooling.md +88 -0
- package/skills/cpp-patterns/references/undefined-behaviour.md +75 -0
- package/skills/cpp-testing/SKILL.md +131 -0
- package/skills/cpp-testing/evals/triggers.json +16 -0
- package/skills/csharp-patterns/SKILL.md +110 -0
- package/skills/csharp-patterns/evals/triggers.json +17 -0
- package/skills/csharp-patterns/references/analyzers.md +59 -0
- package/skills/csharp-testing/SKILL.md +85 -0
- package/skills/csharp-testing/evals/triggers.json +17 -0
- package/skills/csharp-testing/references/integration-tests.md +77 -0
- package/skills/css-architecture/SKILL.md +143 -0
- package/skills/css-architecture/evals/triggers.json +16 -0
- package/skills/customs-trade-compliance/SKILL.md +95 -0
- package/skills/customs-trade-compliance/evals/triggers.json +16 -0
- package/skills/customs-trade-compliance/references/incoterms-2020.md +42 -0
- package/skills/dart-patterns/SKILL.md +157 -0
- package/skills/dart-patterns/evals/triggers.json +18 -0
- package/skills/dart-testing/SKILL.md +164 -0
- package/skills/dart-testing/evals/triggers.json +18 -0
- package/skills/data-analysis-notebooks/SKILL.md +113 -0
- package/skills/data-analysis-notebooks/evals/triggers.json +16 -0
- package/skills/data-analysis-notebooks/references/dataframe-pitfalls.md +49 -0
- package/skills/data-analysis-notebooks/references/statistics-pitfalls.md +24 -0
- package/skills/data-pipelines/SKILL.md +90 -0
- package/skills/data-pipelines/evals/triggers.json +16 -0
- package/skills/data-pipelines/references/orchestrators.md +64 -0
- package/skills/database-migrations/SKILL.md +102 -0
- package/skills/database-migrations/evals/triggers.json +16 -0
- package/skills/database-migrations/references/recipes.md +98 -0
- package/skills/database-migrations/references/tools.md +21 -0
- package/skills/dbt-patterns/SKILL.md +96 -0
- package/skills/dbt-patterns/evals/triggers.json +16 -0
- package/skills/dbt-patterns/references/yaml-examples.md +114 -0
- package/skills/deep-research/SKILL.md +107 -0
- package/skills/deep-research/evals/triggers.json +14 -0
- package/skills/dependency-audit/SKILL.md +103 -0
- package/skills/dependency-audit/evals/triggers.json +16 -0
- package/skills/dependency-audit/references/tools.md +124 -0
- package/skills/deployment-strategies/SKILL.md +108 -0
- package/skills/deployment-strategies/evals/triggers.json +16 -0
- package/skills/django-patterns/SKILL.md +123 -0
- package/skills/django-patterns/evals/triggers.json +16 -0
- package/skills/docker-patterns/SKILL.md +132 -0
- package/skills/docker-patterns/evals/triggers.json +16 -0
- package/skills/docker-patterns/references/dockerfiles.md +105 -0
- package/skills/e2e-testing-playwright/SKILL.md +94 -0
- package/skills/e2e-testing-playwright/evals/triggers.json +16 -0
- package/skills/e2e-testing-playwright/references/config-and-ci.md +129 -0
- package/skills/ef-core-patterns/SKILL.md +117 -0
- package/skills/ef-core-patterns/evals/triggers.json +16 -0
- package/skills/email-deliverability/SKILL.md +99 -0
- package/skills/email-deliverability/evals/triggers.json +17 -0
- package/skills/email-deliverability/references/dns-records.md +85 -0
- package/skills/error-handling-patterns/SKILL.md +112 -0
- package/skills/error-handling-patterns/evals/triggers.json +18 -0
- package/skills/error-handling-patterns/references/language-idioms.md +49 -0
- package/skills/estimation-and-scoping/SKILL.md +97 -0
- package/skills/estimation-and-scoping/evals/triggers.json +14 -0
- package/skills/evm-dapp-integration/SKILL.md +73 -0
- package/skills/evm-dapp-integration/evals/triggers.json +16 -0
- package/skills/fastapi-patterns/SKILL.md +127 -0
- package/skills/fastapi-patterns/evals/triggers.json +16 -0
- package/skills/ffmpeg-media-processing/SKILL.md +94 -0
- package/skills/ffmpeg-media-processing/evals/triggers.json +16 -0
- package/skills/ffmpeg-media-processing/references/recipes.md +112 -0
- package/skills/fhir-integration/SKILL.md +81 -0
- package/skills/fhir-integration/evals/triggers.json +16 -0
- package/skills/fhir-integration/references/search-and-bundles.md +73 -0
- package/skills/fhir-integration/references/smart-on-fhir.md +50 -0
- package/skills/flask-patterns/SKILL.md +132 -0
- package/skills/flask-patterns/evals/triggers.json +16 -0
- package/skills/flutter-patterns/SKILL.md +99 -0
- package/skills/flutter-patterns/evals/triggers.json +16 -0
- package/skills/flutterwave-integration/SKILL.md +75 -0
- package/skills/flutterwave-integration/evals/triggers.json +16 -0
- package/skills/flutterwave-integration/references/api.md +73 -0
- package/skills/flutterwave-integration/references/webhooks.md +49 -0
- package/skills/fsharp-patterns/SKILL.md +133 -0
- package/skills/fsharp-patterns/evals/triggers.json +16 -0
- package/skills/fsharp-testing/SKILL.md +136 -0
- package/skills/fsharp-testing/evals/triggers.json +16 -0
- package/skills/gcp-patterns/SKILL.md +86 -0
- package/skills/gcp-patterns/evals/triggers.json +16 -0
- package/skills/git-workflow/SKILL.md +114 -0
- package/skills/git-workflow/evals/triggers.json +16 -0
- package/skills/github-actions-ci/SKILL.md +117 -0
- package/skills/github-actions-ci/evals/triggers.json +16 -0
- package/skills/github-api-automation/SKILL.md +101 -0
- package/skills/github-api-automation/evals/triggers.json +17 -0
- package/skills/go-patterns/SKILL.md +118 -0
- package/skills/go-patterns/evals/triggers.json +17 -0
- package/skills/go-patterns/references/concurrency.md +162 -0
- package/skills/go-testing/SKILL.md +154 -0
- package/skills/go-testing/evals/triggers.json +17 -0
- package/skills/hexagonal-architecture/SKILL.md +89 -0
- package/skills/hexagonal-architecture/evals/triggers.json +17 -0
- package/skills/hipaa-compliance/SKILL.md +91 -0
- package/skills/hipaa-compliance/evals/triggers.json +18 -0
- package/skills/hipaa-compliance/references/safeguards.md +68 -0
- package/skills/hl7v2-integration/SKILL.md +69 -0
- package/skills/hl7v2-integration/evals/triggers.json +16 -0
- package/skills/hl7v2-integration/references/messages-and-ack.md +78 -0
- package/skills/homelab-network-setup/SKILL.md +125 -0
- package/skills/homelab-network-setup/evals/triggers.json +18 -0
- package/skills/homelab-network-setup/references/firewall-and-dns.md +45 -0
- package/skills/homelab-network-setup/references/wireguard.md +72 -0
- package/skills/hubtel-integration/SKILL.md +77 -0
- package/skills/hubtel-integration/evals/triggers.json +16 -0
- package/skills/hubtel-integration/references/api.md +92 -0
- package/skills/i18n-localization/SKILL.md +114 -0
- package/skills/i18n-localization/evals/triggers.json +16 -0
- package/skills/i18n-localization/references/libraries.md +52 -0
- package/skills/incident-postmortem/SKILL.md +118 -0
- package/skills/incident-postmortem/evals/triggers.json +14 -0
- package/skills/inventory-demand-planning/SKILL.md +89 -0
- package/skills/inventory-demand-planning/evals/triggers.json +16 -0
- package/skills/inventory-demand-planning/references/formulas.md +62 -0
- package/skills/investor-materials/SKILL.md +127 -0
- package/skills/investor-materials/evals/triggers.json +16 -0
- package/skills/investor-materials/references/templates.md +74 -0
- package/skills/invoicing-and-tax/SKILL.md +84 -0
- package/skills/invoicing-and-tax/evals/triggers.json +17 -0
- package/skills/invoicing-and-tax/references/e-invoicing.md +24 -0
- package/skills/invoicing-and-tax/references/invoice-fields.md +38 -0
- package/skills/invoicing-and-tax/references/rounding.md +26 -0
- package/skills/java-patterns/SKILL.md +141 -0
- package/skills/java-patterns/evals/triggers.json +17 -0
- package/skills/java-testing/SKILL.md +142 -0
- package/skills/java-testing/evals/triggers.json +16 -0
- package/skills/jetpack-compose-patterns/SKILL.md +88 -0
- package/skills/jetpack-compose-patterns/evals/triggers.json +16 -0
- package/skills/jira-integration/SKILL.md +92 -0
- package/skills/jira-integration/evals/triggers.json +17 -0
- package/skills/jpa-hibernate/SKILL.md +92 -0
- package/skills/jpa-hibernate/evals/triggers.json +18 -0
- package/skills/jpa-hibernate/references/mapping.md +99 -0
- package/skills/kotlin-multiplatform/SKILL.md +97 -0
- package/skills/kotlin-multiplatform/evals/triggers.json +16 -0
- package/skills/kotlin-patterns/SKILL.md +128 -0
- package/skills/kotlin-patterns/evals/triggers.json +16 -0
- package/skills/kotlin-testing/SKILL.md +117 -0
- package/skills/kotlin-testing/evals/triggers.json +16 -0
- package/skills/ktor-patterns/SKILL.md +135 -0
- package/skills/ktor-patterns/evals/triggers.json +18 -0
- package/skills/kubernetes-patterns/SKILL.md +106 -0
- package/skills/kubernetes-patterns/evals/triggers.json +16 -0
- package/skills/kubernetes-patterns/references/manifests.md +115 -0
- package/skills/laravel-patterns/SKILL.md +136 -0
- package/skills/laravel-patterns/evals/triggers.json +16 -0
- package/skills/linear-integration/SKILL.md +98 -0
- package/skills/linear-integration/evals/triggers.json +17 -0
- package/skills/literature-review/SKILL.md +109 -0
- package/skills/literature-review/evals/triggers.json +16 -0
- package/skills/literature-review/references/appraisal.md +41 -0
- package/skills/literature-review/references/search-sources.md +39 -0
- package/skills/llm-app-patterns/SKILL.md +97 -0
- package/skills/llm-app-patterns/evals/triggers.json +17 -0
- package/skills/llm-evals/SKILL.md +98 -0
- package/skills/llm-evals/evals/triggers.json +16 -0
- package/skills/llm-evals/references/graders.md +66 -0
- package/skills/logistics-exception-management/SKILL.md +90 -0
- package/skills/logistics-exception-management/evals/triggers.json +16 -0
- package/skills/manim-animations/SKILL.md +106 -0
- package/skills/manim-animations/evals/triggers.json +16 -0
- package/skills/market-research/SKILL.md +117 -0
- package/skills/market-research/evals/triggers.json +16 -0
- package/skills/marketing-campaign/SKILL.md +111 -0
- package/skills/marketing-campaign/evals/triggers.json +16 -0
- package/skills/mcp-server-patterns/SKILL.md +127 -0
- package/skills/mcp-server-patterns/evals/triggers.json +18 -0
- package/skills/mcp-server-patterns/references/protocol-notes.md +68 -0
- package/skills/metrics-dashboards/SKILL.md +113 -0
- package/skills/metrics-dashboards/evals/triggers.json +16 -0
- package/skills/ml-experiment-workflow/SKILL.md +125 -0
- package/skills/ml-experiment-workflow/evals/triggers.json +16 -0
- package/skills/mongodb-patterns/SKILL.md +115 -0
- package/skills/mongodb-patterns/evals/triggers.json +18 -0
- package/skills/mongodb-patterns/references/indexes-and-aggregation.md +94 -0
- package/skills/mpesa-daraja-integration/SKILL.md +70 -0
- package/skills/mpesa-daraja-integration/evals/triggers.json +16 -0
- package/skills/mpesa-daraja-integration/references/api.md +103 -0
- package/skills/mpesa-daraja-integration/references/callbacks.md +74 -0
- package/skills/mtn-momo-integration/SKILL.md +66 -0
- package/skills/mtn-momo-integration/evals/triggers.json +16 -0
- package/skills/mtn-momo-integration/references/api.md +153 -0
- package/skills/mtn-momo-integration/references/callbacks.md +92 -0
- package/skills/mtn-momo-integration/references/sandbox-and-go-live.md +51 -0
- package/skills/mtn-momo-integration/scripts/sandbox-setup.js +79 -0
- package/skills/mysql-patterns/SKILL.md +96 -0
- package/skills/mysql-patterns/evals/triggers.json +16 -0
- package/skills/mysql-patterns/references/explain.md +34 -0
- package/skills/mysql-patterns/references/online-ddl.md +41 -0
- package/skills/nestjs-patterns/SKILL.md +114 -0
- package/skills/nestjs-patterns/evals/triggers.json +16 -0
- package/skills/nestjs-patterns/references/testing.md +68 -0
- package/skills/network-automation/SKILL.md +107 -0
- package/skills/network-automation/evals/triggers.json +18 -0
- package/skills/network-automation/references/tool-snippets.md +153 -0
- package/skills/network-troubleshooting/SKILL.md +152 -0
- package/skills/network-troubleshooting/evals/triggers.json +18 -0
- package/skills/network-troubleshooting/references/commands.md +33 -0
- package/skills/nextjs-patterns/SKILL.md +150 -0
- package/skills/nextjs-patterns/evals/triggers.json +18 -0
- package/skills/nextjs-patterns/references/caching.md +87 -0
- package/skills/node-backend-patterns/SKILL.md +103 -0
- package/skills/node-backend-patterns/evals/triggers.json +16 -0
- package/skills/node-backend-patterns/references/templates.md +122 -0
- package/skills/nuxt-patterns/SKILL.md +103 -0
- package/skills/nuxt-patterns/evals/triggers.json +16 -0
- package/skills/parallel-agent-orchestration/SKILL.md +106 -0
- package/skills/parallel-agent-orchestration/evals/triggers.json +14 -0
- package/skills/paystack-integration/SKILL.md +59 -0
- package/skills/paystack-integration/evals/triggers.json +14 -0
- package/skills/paystack-integration/references/api.md +73 -0
- package/skills/paystack-integration/references/mobile-money.md +50 -0
- package/skills/paystack-integration/references/webhooks.md +80 -0
- package/skills/pci-dss-scope/SKILL.md +103 -0
- package/skills/pci-dss-scope/evals/triggers.json +18 -0
- package/skills/pci-dss-scope/references/saq-and-data.md +36 -0
- package/skills/perl-patterns/SKILL.md +135 -0
- package/skills/perl-patterns/evals/triggers.json +18 -0
- package/skills/perl-testing/SKILL.md +126 -0
- package/skills/perl-testing/evals/triggers.json +17 -0
- package/skills/php-patterns/SKILL.md +116 -0
- package/skills/php-patterns/evals/triggers.json +16 -0
- package/skills/php-testing/SKILL.md +123 -0
- package/skills/php-testing/evals/triggers.json +16 -0
- package/skills/postgres-patterns/SKILL.md +103 -0
- package/skills/postgres-patterns/evals/triggers.json +17 -0
- package/skills/postgres-patterns/references/explain.md +59 -0
- package/skills/postgres-patterns/references/locks.md +53 -0
- package/skills/prd-writing/SKILL.md +124 -0
- package/skills/prd-writing/evals/triggers.json +15 -0
- package/skills/prisma-patterns/SKILL.md +83 -0
- package/skills/prisma-patterns/evals/triggers.json +18 -0
- package/skills/prisma-patterns/references/prisma-8.md +46 -0
- package/skills/prisma-patterns/references/workflow.md +50 -0
- package/skills/privacy-compliance/SKILL.md +121 -0
- package/skills/privacy-compliance/evals/triggers.json +18 -0
- package/skills/privacy-compliance/references/jurisdictions.md +51 -0
- package/skills/production-scheduling/SKILL.md +98 -0
- package/skills/production-scheduling/evals/triggers.json +16 -0
- package/skills/prompt-engineering/SKILL.md +92 -0
- package/skills/prompt-engineering/evals/triggers.json +16 -0
- package/skills/python-patterns/SKILL.md +107 -0
- package/skills/python-patterns/evals/triggers.json +16 -0
- package/skills/python-patterns/references/tooling.md +101 -0
- package/skills/python-testing/SKILL.md +126 -0
- package/skills/python-testing/evals/triggers.json +16 -0
- package/skills/python-testing/references/mocking.md +71 -0
- package/skills/pytorch-patterns/SKILL.md +139 -0
- package/skills/pytorch-patterns/evals/triggers.json +16 -0
- package/skills/pytorch-patterns/references/debugging.md +39 -0
- package/skills/quarkus-patterns/SKILL.md +93 -0
- package/skills/quarkus-patterns/evals/triggers.json +18 -0
- package/skills/rag-pipeline-patterns/SKILL.md +117 -0
- package/skills/rag-pipeline-patterns/evals/triggers.json +18 -0
- package/skills/rag-pipeline-patterns/references/evaluation.md +37 -0
- package/skills/rag-pipeline-patterns/references/retrieval-recipes.md +78 -0
- package/skills/rails-patterns/SKILL.md +132 -0
- package/skills/rails-patterns/evals/triggers.json +16 -0
- package/skills/react-native-patterns/SKILL.md +101 -0
- package/skills/react-native-patterns/evals/triggers.json +16 -0
- package/skills/react-patterns/SKILL.md +140 -0
- package/skills/react-patterns/evals/triggers.json +18 -0
- package/skills/react-performance/SKILL.md +107 -0
- package/skills/react-performance/evals/triggers.json +18 -0
- package/skills/redis-patterns/SKILL.md +109 -0
- package/skills/redis-patterns/evals/triggers.json +18 -0
- package/skills/redis-patterns/references/operations.md +61 -0
- package/skills/refactoring-safely/SKILL.md +107 -0
- package/skills/refactoring-safely/evals/triggers.json +17 -0
- package/skills/release-management/SKILL.md +141 -0
- package/skills/release-management/evals/triggers.json +16 -0
- package/skills/remotion-video/SKILL.md +91 -0
- package/skills/remotion-video/evals/triggers.json +16 -0
- package/skills/remotion-video/references/lambda.md +66 -0
- package/skills/returns-reverse-logistics/SKILL.md +97 -0
- package/skills/returns-reverse-logistics/evals/triggers.json +16 -0
- package/skills/ruby-patterns/SKILL.md +127 -0
- package/skills/ruby-patterns/evals/triggers.json +18 -0
- package/skills/ruby-testing/SKILL.md +113 -0
- package/skills/ruby-testing/evals/triggers.json +18 -0
- package/skills/runbook-writing/SKILL.md +101 -0
- package/skills/runbook-writing/evals/triggers.json +14 -0
- package/skills/rust-patterns/SKILL.md +118 -0
- package/skills/rust-patterns/evals/triggers.json +16 -0
- package/skills/rust-patterns/references/cargo-and-clippy.md +105 -0
- package/skills/rust-patterns/references/errors-and-traits.md +97 -0
- package/skills/rust-testing/SKILL.md +148 -0
- package/skills/rust-testing/evals/triggers.json +16 -0
- package/skills/rust-testing/references/fakes-proptest-async.md +113 -0
- package/skills/search-first/SKILL.md +73 -0
- package/skills/search-first/evals/triggers.json +14 -0
- package/skills/security-review/SKILL.md +58 -0
- package/skills/security-review/evals/triggers.json +14 -0
- package/skills/security-review/references/checklist.md +54 -0
- package/skills/security-review/scripts/scan-secrets.js +79 -0
- package/skills/seo-audit/SKILL.md +111 -0
- package/skills/seo-audit/evals/triggers.json +16 -0
- package/skills/seo-audit/references/checks.md +65 -0
- package/skills/session-handoff/SKILL.md +101 -0
- package/skills/session-handoff/evals/triggers.json +14 -0
- package/skills/skill-authoring/SKILL.md +87 -0
- package/skills/skill-authoring/evals/triggers.json +14 -0
- package/skills/skill-authoring/references/frontmatter.md +40 -0
- package/skills/slack-app-integration/SKILL.md +108 -0
- package/skills/slack-app-integration/evals/triggers.json +17 -0
- package/skills/smart-contract-security/SKILL.md +110 -0
- package/skills/smart-contract-security/evals/triggers.json +16 -0
- package/skills/smart-contract-security/references/vulnerability-checklist.md +79 -0
- package/skills/social-media-publishing/SKILL.md +84 -0
- package/skills/social-media-publishing/evals/triggers.json +17 -0
- package/skills/social-media-publishing/references/platform-apis.md +116 -0
- package/skills/solidity-patterns/SKILL.md +95 -0
- package/skills/solidity-patterns/evals/triggers.json +16 -0
- package/skills/spring-boot-patterns/SKILL.md +128 -0
- package/skills/spring-boot-patterns/evals/triggers.json +18 -0
- package/skills/spring-boot-patterns/references/testing.md +72 -0
- package/skills/stripe-integration/SKILL.md +69 -0
- package/skills/stripe-integration/evals/triggers.json +16 -0
- package/skills/stripe-integration/references/api.md +71 -0
- package/skills/stripe-integration/references/billing.md +58 -0
- package/skills/stripe-integration/references/webhooks.md +76 -0
- package/skills/subscription-billing-ops/SKILL.md +118 -0
- package/skills/subscription-billing-ops/evals/triggers.json +17 -0
- package/skills/subscription-billing-ops/references/proration.md +47 -0
- package/skills/subscription-billing-ops/references/revenue-metrics.md +38 -0
- package/skills/svelte-patterns/SKILL.md +122 -0
- package/skills/svelte-patterns/evals/triggers.json +16 -0
- package/skills/swift-patterns/SKILL.md +113 -0
- package/skills/swift-patterns/evals/triggers.json +16 -0
- package/skills/swift-patterns/references/concurrency-migration.md +40 -0
- package/skills/swift-testing/SKILL.md +121 -0
- package/skills/swift-testing/evals/triggers.json +16 -0
- package/skills/swift-testing/references/swift-testing-cheatsheet.md +81 -0
- package/skills/swiftui-patterns/SKILL.md +102 -0
- package/skills/swiftui-patterns/evals/triggers.json +16 -0
- package/skills/tdd-workflow/SKILL.md +67 -0
- package/skills/tdd-workflow/evals/triggers.json +14 -0
- package/skills/technical-writing/SKILL.md +95 -0
- package/skills/technical-writing/evals/triggers.json +14 -0
- package/skills/terraform-patterns/SKILL.md +122 -0
- package/skills/terraform-patterns/evals/triggers.json +16 -0
- package/skills/terraform-patterns/references/backends.md +67 -0
- package/skills/test-coverage-improvement/SKILL.md +107 -0
- package/skills/test-coverage-improvement/evals/triggers.json +16 -0
- package/skills/threat-modeling/SKILL.md +113 -0
- package/skills/threat-modeling/evals/triggers.json +16 -0
- package/skills/typescript-patterns/SKILL.md +122 -0
- package/skills/typescript-patterns/evals/triggers.json +16 -0
- package/skills/typescript-testing/SKILL.md +101 -0
- package/skills/typescript-testing/evals/triggers.json +16 -0
- package/skills/verification-loop/SKILL.md +70 -0
- package/skills/verification-loop/evals/triggers.json +14 -0
- package/skills/verification-loop/scripts/detect-checks.js +102 -0
- package/skills/vite-patterns/SKILL.md +117 -0
- package/skills/vite-patterns/evals/triggers.json +16 -0
- package/skills/vue-patterns/SKILL.md +104 -0
- package/skills/vue-patterns/evals/triggers.json +16 -0
- package/skills/web-accessibility/SKILL.md +119 -0
- package/skills/web-accessibility/evals/triggers.json +16 -0
- package/skills/web-performance/SKILL.md +107 -0
- package/skills/web-performance/evals/triggers.json +16 -0
- package/skills/web-scraping/SKILL.md +80 -0
- package/skills/web-scraping/evals/triggers.json +16 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# MySQL online DDL
|
|
2
|
+
|
|
3
|
+
Always name the algorithm and lock level so the server errors instead of silently falling back to a blocking table copy:
|
|
4
|
+
|
|
5
|
+
```sql
|
|
6
|
+
ALTER TABLE orders ADD COLUMN note VARCHAR(200) NULL, ALGORITHM=INSTANT;
|
|
7
|
+
ALTER TABLE orders ADD INDEX orders_status_idx (status, created_at), ALGORITHM=INPLACE, LOCK=NONE;
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## What the InnoDB online DDL table says (MySQL 8.4 manual)
|
|
11
|
+
|
|
12
|
+
| Change | Algorithm | Concurrent DML |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| Add column (any position) | INSTANT (default) | yes |
|
|
15
|
+
| Drop column | INSTANT (default) | yes |
|
|
16
|
+
| Add secondary index | INPLACE, no rebuild | yes |
|
|
17
|
+
| Drop index | INPLACE | yes |
|
|
18
|
+
| Extend `VARCHAR` within the same length-prefix size (both under 256 bytes, or both 256+) | INPLACE | yes |
|
|
19
|
+
| Extend `VARCHAR` across 255 to 256+ bytes, or shrink it | COPY | no |
|
|
20
|
+
| Change column data type (for example `INT` to `BIGINT`) | COPY | no |
|
|
21
|
+
| Convert table character set (`CONVERT TO CHARACTER SET`) | COPY (rebuild) | no |
|
|
22
|
+
|
|
23
|
+
Limits on INSTANT: not for `ROW_FORMAT=COMPRESSED` tables, tables with a `FULLTEXT` index, temporary tables or tables in the data dictionary tablespace. Each instant add or drop creates a row version; when the per-table limit is reached (64 in 8.4, 255 as of MySQL 9.1) instant changes fail with error 4092 and the table must be rebuilt. Check `INFORMATION_SCHEMA.INNODB_TABLES.TOTAL_ROW_VERSIONS`.
|
|
24
|
+
|
|
25
|
+
MariaDB has its own instant and online rules; check its `ALTER TABLE` and InnoDB online DDL docs for the server version.
|
|
26
|
+
|
|
27
|
+
Source: https://dev.mysql.com/doc/refman/8.4/en/innodb-online-ddl-operations.html
|
|
28
|
+
|
|
29
|
+
## Metadata locks
|
|
30
|
+
|
|
31
|
+
Even INSTANT and INPLACE DDL need a brief exclusive metadata lock at start and end. If a long transaction holds a shared metadata lock on the table, the `ALTER` waits, and every new query on the table queues behind it. Before DDL:
|
|
32
|
+
|
|
33
|
+
```sql
|
|
34
|
+
SET SESSION lock_wait_timeout = 5; -- seconds to wait for the metadata lock
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Check for long transactions first: `SELECT * FROM information_schema.innodb_trx ORDER BY trx_started;`.
|
|
38
|
+
|
|
39
|
+
## When to use an external tool
|
|
40
|
+
|
|
41
|
+
Use `gh-ost` or `pt-online-schema-change` when the change needs COPY on a large, busy table (type changes, charset conversion). Both build a shadow table, copy rows in chunks with replica-lag throttling, then swap. They need a primary key or unique key, extra disk for a full copy, and testing on staging first. `pt-online-schema-change` uses triggers; `gh-ost` reads the binary log (row format) instead.
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nestjs-patterns
|
|
3
|
+
description: NestJS application structure and conventions, covering feature modules, providers and dependency-injection scopes, ValidationPipe with class-validator DTOs, guards, interceptors, exception filters, ConfigModule, database modules (TypeORM, Prisma, Mongoose) and Test.createTestingModule unit and e2e tests. Use when building or restructuring a NestJS API, wiring a new module or provider, fixing a circular dependency or "Nest can't resolve dependencies" error, adding auth guards, or writing NestJS tests.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: Any Agent Skills host. Needs Node.js and the project's package manager. Check the project's @nestjs/core major version and its migration guide before using version-specific APIs.
|
|
6
|
+
metadata:
|
|
7
|
+
kete-loom/version: "0.1.0"
|
|
8
|
+
kete-loom/category: coding
|
|
9
|
+
kete-loom/risk: writes-files
|
|
10
|
+
kete-loom/requires: "node"
|
|
11
|
+
kete-loom/owner: "Kete-org"
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# NestJS patterns
|
|
15
|
+
|
|
16
|
+
Keep a Nest app boring: one feature per module, thin controllers, logic in providers, validation at the edge, and tests that swap providers instead of patching imports.
|
|
17
|
+
|
|
18
|
+
## First, look at the project
|
|
19
|
+
|
|
20
|
+
1. Read `package.json` for the `@nestjs/core` major, the HTTP adapter (`@nestjs/platform-express` or `@nestjs/platform-fastify`) and the ORM.
|
|
21
|
+
2. Read `src/main.ts` and `src/app.module.ts` to see global pipes, filters, prefixes and versioning already set.
|
|
22
|
+
3. Match existing conventions (folder layout, DTO library, error shape). Do not introduce a second ORM, validation library or config style.
|
|
23
|
+
|
|
24
|
+
Stop and ask the user before switching HTTP adapter, ORM, or moving from class-validator to a schema library: these touch every module.
|
|
25
|
+
|
|
26
|
+
## Module layout
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
src/
|
|
30
|
+
main.ts
|
|
31
|
+
app.module.ts
|
|
32
|
+
orders/
|
|
33
|
+
orders.module.ts
|
|
34
|
+
orders.controller.ts # HTTP only: route, DTO in, DTO out
|
|
35
|
+
orders.service.ts # business rules
|
|
36
|
+
orders.repository.ts # optional: data access behind an injectable
|
|
37
|
+
dto/create-order.dto.ts
|
|
38
|
+
orders.service.spec.ts
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Rules:
|
|
42
|
+
|
|
43
|
+
- A module exports only the providers other modules need. Everything else stays private.
|
|
44
|
+
- Import a module to use its exported providers; never list another module's provider in your own `providers` array (that creates a second instance).
|
|
45
|
+
- Use `@Global()` only for true cross-cutting infrastructure (config, logger, database). Feature modules are never global.
|
|
46
|
+
- Controllers never touch the ORM directly.
|
|
47
|
+
- Use the CLI to scaffold (`nest g resource orders`) when the project already uses it.
|
|
48
|
+
|
|
49
|
+
## Providers and scopes
|
|
50
|
+
|
|
51
|
+
| Scope | Lifetime | Use for |
|
|
52
|
+
|---|---|---|
|
|
53
|
+
| `Scope.DEFAULT` | one instance per app | almost everything |
|
|
54
|
+
| `Scope.REQUEST` | one per request | per-request tenant or user context you cannot pass as an argument |
|
|
55
|
+
| `Scope.TRANSIENT` | one per consumer | stateful helpers each consumer must own, such as a logger with a context name |
|
|
56
|
+
|
|
57
|
+
- Request scope bubbles up: anything that injects a request-scoped provider becomes request-scoped too, which costs performance. Prefer passing the user or tenant as a method argument, or use `AsyncLocalStorage` (for example via `nestjs-cls`).
|
|
58
|
+
- Custom providers: `useValue` for constants and test doubles, `useClass` for swapping implementations, `useFactory` with `inject: [...]` for config-driven construction. Use a string or symbol token plus `@Inject(TOKEN)` for non-class dependencies.
|
|
59
|
+
- **"Nest can't resolve dependencies of X (?)"**: the `?` position names the missing dependency. Check, in order: the provider is in the module's `providers` or imported from a module that `exports` it; the import is not a type-only import (`import type` erases the token); there is no circular file import producing `undefined`.
|
|
60
|
+
- **Circular dependency**: first try to extract the shared logic into a third provider. Use `forwardRef(() => OtherModule)` / `@Inject(forwardRef(() => OtherService))` only when the cycle is genuine, and say so in a comment.
|
|
61
|
+
|
|
62
|
+
## Request pipeline
|
|
63
|
+
|
|
64
|
+
Order for each request: middleware, guards, interceptors (before), pipes, handler, interceptors (after), exception filters (on error).
|
|
65
|
+
|
|
66
|
+
- **Validation**: register one global pipe in `main.ts`:
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
app.useGlobalPipes(new ValidationPipe({ whitelist: true, forbidNonWhitelisted: true, transform: true }));
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`whitelist` strips unknown properties, `forbidNonWhitelisted` rejects them, `transform` turns the payload into the DTO class and converts primitive params. DTOs are classes (interfaces vanish at runtime) decorated with `class-validator`; nested objects need `@ValidateNested()` plus `@Type(() => Child)` from `class-transformer`.
|
|
73
|
+
- **Params**: use `ParseIntPipe`, `ParseUUIDPipe`, `ParseEnumPipe` on `@Param`/`@Query` instead of manual parsing.
|
|
74
|
+
- **Guards** answer "may this request run?" (`CanActivate`). Read route metadata with `Reflector` (for example a `@Roles()` or `@Public()` decorator). Register auth guards globally with `{ provide: APP_GUARD, useClass: AuthGuard }` so new routes are protected by default, and opt out with `@Public()`.
|
|
75
|
+
- **Interceptors** wrap the handler (`NestInterceptor`, RxJS `next.handle().pipe(...)`): response mapping, timing, caching, timeouts. They are not for authorization.
|
|
76
|
+
- **Exception filters**: throw built-in `HttpException` subclasses (`NotFoundException`, `ConflictException`) from services only when the service is HTTP-specific; otherwise throw domain errors and map them to HTTP in one `@Catch(DomainError)` filter. Register with `APP_FILTER` so it can inject providers. Never leak stack traces or ORM messages in the response body.
|
|
77
|
+
|
|
78
|
+
## Configuration
|
|
79
|
+
|
|
80
|
+
- `ConfigModule.forRoot({ isGlobal: true, validationSchema })` once in `AppModule`; validate env at boot so a missing variable fails startup, not the first request. The accepted schema libraries vary by major version; check the config docs for the installed version.
|
|
81
|
+
- Read values with `configService.getOrThrow<string>('DATABASE_URL')`. Group related settings with `registerAs('db', () => ({ ... }))` and inject the typed namespace.
|
|
82
|
+
- Never read `process.env` scattered through services.
|
|
83
|
+
|
|
84
|
+
## Database integration
|
|
85
|
+
|
|
86
|
+
- Use the official module for the chosen ORM (`TypeOrmModule.forRootAsync`, `MongooseModule.forRootAsync`) with `useFactory` + `inject: [ConfigService]`, or a small `PrismaService` that extends `PrismaClient` and connects in `onModuleInit`.
|
|
87
|
+
- Register entities or models per feature module (`TypeOrmModule.forFeature([Order])`).
|
|
88
|
+
- Wrap multi-write operations in a transaction from the ORM; do not rely on sequential awaits.
|
|
89
|
+
- Never use TypeORM `synchronize: true` outside local development; use migrations.
|
|
90
|
+
|
|
91
|
+
## Lifecycle and shutdown
|
|
92
|
+
|
|
93
|
+
- Call `app.enableShutdownHooks()` in `main.ts` so `onModuleDestroy` / `beforeApplicationShutdown` / `onApplicationShutdown` run on SIGTERM; close pools and consumers there.
|
|
94
|
+
- Hooks run in module dependency order; do not depend on ordering between unrelated modules.
|
|
95
|
+
|
|
96
|
+
## Testing
|
|
97
|
+
|
|
98
|
+
Follow `references/testing.md` for unit and e2e templates. The rules:
|
|
99
|
+
|
|
100
|
+
1. Unit-test services with `Test.createTestingModule({ providers: [OrdersService, { provide: OrdersRepository, useValue: fakeRepo }] })`.
|
|
101
|
+
2. E2E-test through HTTP: build the real `AppModule`, `.overrideProvider(...)` only external services, and apply the same global pipes/filters as `main.ts` (extract a `configureApp(app)` function and call it in both places).
|
|
102
|
+
3. Close the app in `afterAll` (`await app.close()`) or the test runner hangs.
|
|
103
|
+
|
|
104
|
+
## Never
|
|
105
|
+
|
|
106
|
+
- Put business logic in controllers, guards or interceptors.
|
|
107
|
+
- Use `any`-typed `@Body() body` without a DTO.
|
|
108
|
+
- Make a provider request-scoped "just in case".
|
|
109
|
+
- Catch an exception in a controller only to rethrow a generic 500.
|
|
110
|
+
- Disable `whitelist` to silence a validation error; fix the DTO.
|
|
111
|
+
|
|
112
|
+
## Before you finish
|
|
113
|
+
|
|
114
|
+
Run the project's build (`nest build` or `tsc --noEmit`), lint and test commands. Report: modules or providers added or changed, any new global pipe/guard/filter, any env variable the user must set, and test results.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"should_trigger": [
|
|
3
|
+
"Nest can't resolve dependencies of the OrdersService (?), please fix it",
|
|
4
|
+
"Add a global JWT guard to our NestJS API with a @Public() decorator to opt out",
|
|
5
|
+
"Set up a ValidationPipe so our Nest DTOs reject unknown fields",
|
|
6
|
+
"Write an e2e test for the users module in NestJS that overrides the email provider",
|
|
7
|
+
"How should I split this NestJS app into feature modules with a shared Prisma service?"
|
|
8
|
+
],
|
|
9
|
+
"should_not_trigger": [
|
|
10
|
+
"Add graceful shutdown and pino logging to our plain Express server",
|
|
11
|
+
"Design the REST resource naming and pagination for our public API",
|
|
12
|
+
"Write a Prisma migration that adds a status column to orders",
|
|
13
|
+
"Review this TypeScript pull request for type safety problems",
|
|
14
|
+
"Our Vite dev server can't find env variables in the React app"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# NestJS test templates
|
|
2
|
+
|
|
3
|
+
Use the project's existing runner (Jest is the CLI default; Vitest needs SWC or a decorator-aware transform because Nest relies on `emitDecoratorMetadata`).
|
|
4
|
+
|
|
5
|
+
## Unit test a service
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { Test } from '@nestjs/testing';
|
|
9
|
+
import { OrdersService } from './orders.service';
|
|
10
|
+
import { OrdersRepository } from './orders.repository';
|
|
11
|
+
|
|
12
|
+
describe('OrdersService', () => {
|
|
13
|
+
let service: OrdersService;
|
|
14
|
+
const repo = { findById: jest.fn(), save: jest.fn() };
|
|
15
|
+
|
|
16
|
+
beforeEach(async () => {
|
|
17
|
+
const moduleRef = await Test.createTestingModule({
|
|
18
|
+
providers: [OrdersService, { provide: OrdersRepository, useValue: repo }],
|
|
19
|
+
}).compile();
|
|
20
|
+
service = moduleRef.get(OrdersService);
|
|
21
|
+
jest.clearAllMocks();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('rejects an order for a missing customer', async () => {
|
|
25
|
+
repo.findById.mockResolvedValue(null);
|
|
26
|
+
await expect(service.place({ customerId: 'c1', items: [] })).rejects.toThrow('customer');
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
- For request- or transient-scoped providers use `await moduleRef.resolve(Token)` instead of `get`.
|
|
32
|
+
- Test guards directly: construct with a fake `Reflector` and pass a hand-built `ExecutionContext` (`switchToHttp().getRequest()` returning a plain object).
|
|
33
|
+
|
|
34
|
+
## E2E test through HTTP
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { Test } from '@nestjs/testing';
|
|
38
|
+
import { INestApplication } from '@nestjs/common';
|
|
39
|
+
import request from 'supertest';
|
|
40
|
+
import { AppModule } from '../src/app.module';
|
|
41
|
+
import { configureApp } from '../src/configure-app'; // same pipes/filters/prefix as main.ts
|
|
42
|
+
import { PaymentsClient } from '../src/payments/payments.client';
|
|
43
|
+
|
|
44
|
+
describe('Orders (e2e)', () => {
|
|
45
|
+
let app: INestApplication;
|
|
46
|
+
|
|
47
|
+
beforeAll(async () => {
|
|
48
|
+
const moduleRef = await Test.createTestingModule({ imports: [AppModule] })
|
|
49
|
+
.overrideProvider(PaymentsClient)
|
|
50
|
+
.useValue({ charge: async () => ({ id: 'ch_test', status: 'succeeded' }) })
|
|
51
|
+
.compile();
|
|
52
|
+
app = moduleRef.createNestApplication();
|
|
53
|
+
configureApp(app);
|
|
54
|
+
await app.init();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
afterAll(async () => {
|
|
58
|
+
await app.close();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('rejects unknown fields', () =>
|
|
62
|
+
request(app.getHttpServer()).post('/orders').send({ items: [], admin: true }).expect(400));
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
- With the Fastify adapter, create the app with `createNestApplication<NestFastifyApplication>(new FastifyAdapter())` and call `await app.getHttpAdapter().getInstance().ready()` after `init()`.
|
|
67
|
+
- Point e2e tests at a disposable database (container or schema per run); never at a shared dev database.
|
|
68
|
+
- Other override helpers: `overrideGuard`, `overrideInterceptor`, `overridePipe`, `overrideFilter`, `overrideModule`.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: network-automation
|
|
3
|
+
description: Automates configuration of routers, switches and firewalls with Netmiko, NAPALM, Nornir or Ansible network collections, building a source-of-truth inventory, idempotent templates and resource modules, dry runs that show a diff before any push, commit-confirm style rollback, vaulted credentials, and testing against a containerlab or CML lab before production. Use when writing or fixing a Python or Ansible script that pushes config to many network devices, choosing between these tools, adding a check-mode diff or automatic revert to a device rollout, or moving device passwords out of an inventory file.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: Any Agent Skills host. Needs Python 3 with netmiko, napalm or nornir, or ansible-core with the vendor collection (for example cisco.ios), plus SSH reach to a lab or devices.
|
|
6
|
+
metadata:
|
|
7
|
+
kete-loom/version: "0.1.0"
|
|
8
|
+
kete-loom/category: devops
|
|
9
|
+
kete-loom/risk: network
|
|
10
|
+
kete-loom/requires: "python3"
|
|
11
|
+
kete-loom/owner: "Kete-org"
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Network automation
|
|
15
|
+
|
|
16
|
+
Push configuration to network devices so that every run shows its diff first, does nothing when nothing changed, can be undone without console access, and never leaks a credential.
|
|
17
|
+
|
|
18
|
+
For per-tool code shapes (inventory files, tasks, playbooks), read `references/tool-snippets.md`.
|
|
19
|
+
|
|
20
|
+
## 0. Before you start
|
|
21
|
+
|
|
22
|
+
1. Find what exists: search the repo for `inventory/`, `hosts.yaml`, `group_vars/`, `ansible.cfg`, `config.yaml` (Nornir), `requirements.txt`, Jinja2 templates (`*.j2`), and any NetBox or Nautobot URL.
|
|
23
|
+
2. Ask the user, if not stated:
|
|
24
|
+
- Which platforms and OS versions (`ios`, `iosxe`, `nxos`, `eos`, `junos`, `iosxr`)? Behaviour differs per driver.
|
|
25
|
+
- Is there a lab (containerlab, Cisco Modeling Labs, GNS3, EVE-NG) or only production?
|
|
26
|
+
- What is the change window, and who approves a production push?
|
|
27
|
+
3. **Stop and ask** before running anything against a production device. Default target is the lab or one named canary device.
|
|
28
|
+
|
|
29
|
+
## 1. Pick the tool
|
|
30
|
+
|
|
31
|
+
| Situation | Use |
|
|
32
|
+
|---|---|
|
|
33
|
+
| A few show commands or a one-off push, any vendor with SSH | Netmiko (`ConnectHandler`, `send_command`, `send_config_set`) |
|
|
34
|
+
| Diff before push, merge or full replace, commit and rollback across vendors | NAPALM (`load_merge_candidate`, `load_replace_candidate`, `compare_config`, `commit_config`, `rollback`) |
|
|
35
|
+
| Python, many devices in parallel, inventory filtering | Nornir with `nornir_napalm` / `nornir_netmiko` |
|
|
36
|
+
| Team already on Ansible, declarative desired state | Ansible with `ansible.netcommon.network_cli` and vendor resource modules (`cisco.ios.ios_vlans`, `ios_interfaces`, `ios_l3_interfaces` ...) |
|
|
37
|
+
|
|
38
|
+
Prefer what the repo already uses. Do not add a second framework for one task.
|
|
39
|
+
|
|
40
|
+
## 2. Inventory and source of truth
|
|
41
|
+
|
|
42
|
+
1. One inventory: hosts with `platform`/`ansible_network_os`, management IP, site and role. Group variables hold shared settings; hosts hold only what differs.
|
|
43
|
+
2. If NetBox or Nautobot exists, read the inventory from it (the `nornir-netbox` package's `NetBoxInventory2` plugin, or Ansible's `netbox.netbox.nb_inventory`) instead of copying data into YAML.
|
|
44
|
+
3. Intended config is data plus templates. Variables in YAML, rendering in Jinja2, no hand-edited per-device files.
|
|
45
|
+
|
|
46
|
+
## 3. Secrets
|
|
47
|
+
|
|
48
|
+
- Never put passwords, enable secrets, SNMP communities or API tokens in inventory, templates, playbooks or git history.
|
|
49
|
+
- Use `ansible-vault` (`ansible-vault encrypt_string`), environment variables read at runtime, or the team's secret manager. Nornir: set `username`/`password` in a transform function from `os.environ`.
|
|
50
|
+
- Mark Ansible tasks that handle secrets with `no_log: true`. Do not print rendered configs that contain secrets; redact before logging diffs.
|
|
51
|
+
- If you find a committed secret, tell the user it must be rotated. Removing it from the file is not enough.
|
|
52
|
+
|
|
53
|
+
## 4. Make every change idempotent
|
|
54
|
+
|
|
55
|
+
1. Declarative first: Ansible resource modules with `state: merged` (add/update only) or `state: replaced` (this resource exactly). Treat `state: overridden` and NAPALM `load_replace_candidate` as high risk: anything not in your data is removed. Confirm with the user before using them.
|
|
56
|
+
2. With `ios_config`/`*_config` line modules, give `parents` and `lines` that match the running config exactly as the device prints it, or every run reports a change.
|
|
57
|
+
3. Netmiko is not idempotent: `send_config_set` sends whatever you give it. Fetch the running config first, compute what is missing, and send only that.
|
|
58
|
+
4. A second run against an unchanged device must report zero changes. Test this in the lab.
|
|
59
|
+
|
|
60
|
+
## 5. Dry run and diff
|
|
61
|
+
|
|
62
|
+
- Ansible: `ansible-playbook site.yml --check --diff --limit <canary>`.
|
|
63
|
+
- NAPALM: `load_*_candidate`, print `compare_config()`, then `discard_config()`.
|
|
64
|
+
- Nornir: `napalm_configure(dry_run=True)` or `InitNornir(dry_run=True)`; print `result.diff`.
|
|
65
|
+
- Netmiko: show the computed command list and the current running section side by side.
|
|
66
|
+
|
|
67
|
+
Show the diff to the user. **Stop and ask** before committing if the diff touches management access (VTY lines, ACLs on the management interface, AAA, SSH, routing toward the management network) or deletes anything.
|
|
68
|
+
|
|
69
|
+
## 6. Rollback
|
|
70
|
+
|
|
71
|
+
1. Take a backup of the running config before every push (`ios_config: backup: true`, NAPALM `get_config()`, or `show running-config` saved per host with a timestamp).
|
|
72
|
+
2. Use the platform's confirmed commit so a change that cuts you off reverts on its own:
|
|
73
|
+
- NAPALM: `commit_config(revert_in=300)` then `confirm_commit()` after checks pass. On IOS this needs the `archive` feature; the driver rounds down to whole minutes and accepts 60 to 7200 seconds (IOS `revert timer` is 1 to 120 minutes).
|
|
74
|
+
- Junos: `commit confirmed <minutes>` then `commit` to confirm. IOS-XR: `commit confirmed <seconds>` (or `commit confirmed minutes <n>`; the bare number is seconds, and the allowed range differs by release, so check that release's command reference) then `commit`. Cisco IOS by hand: see the `cisco-ios-config` skill.
|
|
75
|
+
3. Rollback plan in the change ticket: the command or playbook that restores the backup, tested in the lab.
|
|
76
|
+
|
|
77
|
+
## 7. Rollout
|
|
78
|
+
|
|
79
|
+
1. Lab first, then one canary, then batches: Ansible `serial: [1, 5, "25%"]` with `max_fail_percentage: 0` (the percentage must be exceeded, so any failure in a batch stops the play); Nornir: filter to a small group per run.
|
|
80
|
+
2. Capture state before and after: interfaces up, neighbors (`get_lldp_neighbors`, OSPF/BGP neighbor counts), route counts. Compare; any drop stops the rollout.
|
|
81
|
+
3. Save to startup only after verification (`save_when: modified`, Netmiko `save_config()`).
|
|
82
|
+
4. Stop on the first unexpected failure. Do not retry a failed push in a loop.
|
|
83
|
+
|
|
84
|
+
## 8. Test
|
|
85
|
+
|
|
86
|
+
- Lab: containerlab topology (`clab deploy -t lab.clab.yml`) with vendor images the user is licensed for, or CML/GNS3/EVE-NG.
|
|
87
|
+
- Offline: render templates in CI and run `ansible-playbook --syntax-check`, `ansible-lint`, or unit tests on the rendering. Batfish can check reachability and ACL behaviour on rendered configs without devices.
|
|
88
|
+
- State checks: `napalm_validate` with a validation YAML, or pyATS/Genie parsers.
|
|
89
|
+
|
|
90
|
+
## Never
|
|
91
|
+
|
|
92
|
+
- Run against `all` hosts without a `--limit` or filter on the first run.
|
|
93
|
+
- Disable SSH host key checking permanently in shared config. Accepting keys in a lab is fine; say so in the file.
|
|
94
|
+
- Push to production without a diff the user has seen, a backup, and a rollback path.
|
|
95
|
+
- Store device output containing secrets in CI logs or artifacts.
|
|
96
|
+
|
|
97
|
+
## Report back
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
Targets: <hosts/groups>, platform(s)
|
|
101
|
+
Tool and mode: <tool>, <merge|replace|resource state>
|
|
102
|
+
Dry-run diff: <summary, lines added/removed per host>
|
|
103
|
+
Applied: <yes/no>, rollback mechanism: <revert timer / backup path>
|
|
104
|
+
Verification: <checks run, before/after counts>
|
|
105
|
+
Idempotency: second run changed = <0 or list>
|
|
106
|
+
Open risks: <anything not tested in the lab>
|
|
107
|
+
```
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"should_trigger": [
|
|
3
|
+
"Write a Nornir script that pushes our NTP and syslog template to 200 IOS-XE switches with a dry run first",
|
|
4
|
+
"My Ansible ios_config task reports changed on every run even though nothing is different, why?",
|
|
5
|
+
"Should we use NAPALM or plain Netmiko to roll out ACL updates across Arista and Cisco boxes?",
|
|
6
|
+
"Add an automatic revert to our NAPALM deploy so a bad push doesn't strand us without SSH",
|
|
7
|
+
"Our network inventory YAML has device passwords in plaintext, move them to vault or env vars",
|
|
8
|
+
"Set up a containerlab topology so we can test our Ansible network playbooks before production"
|
|
9
|
+
],
|
|
10
|
+
"should_not_trigger": [
|
|
11
|
+
"Our eBGP session to the transit provider keeps flapping between Active and Idle",
|
|
12
|
+
"Write the IOS commands to make Gi1/0/5 an access port in VLAN 30 with portfast",
|
|
13
|
+
"Review this OPNsense config.xml for anything exposed on the WAN side",
|
|
14
|
+
"Traceroute from the app server dies at the second hop, help me find where packets drop",
|
|
15
|
+
"Write a Terraform module for an Azure virtual network with two subnets",
|
|
16
|
+
"Write an Ansible playbook that installs nginx and certbot on Ubuntu servers"
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Tool snippets
|
|
2
|
+
|
|
3
|
+
Minimal, working shapes. Adapt names to the repo; keep secrets out of every file shown.
|
|
4
|
+
|
|
5
|
+
## Netmiko
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
import os
|
|
9
|
+
from netmiko import ConnectHandler
|
|
10
|
+
|
|
11
|
+
device = {
|
|
12
|
+
"device_type": "cisco_ios", # cisco_xe, cisco_nxos, arista_eos, juniper_junos ...
|
|
13
|
+
"host": "10.0.0.11",
|
|
14
|
+
"username": os.environ["NET_USER"],
|
|
15
|
+
"password": os.environ["NET_PASS"],
|
|
16
|
+
"secret": os.environ.get("NET_ENABLE", ""),
|
|
17
|
+
}
|
|
18
|
+
with ConnectHandler(**device) as conn:
|
|
19
|
+
conn.enable()
|
|
20
|
+
# Read only the interface you change, so a match elsewhere cannot hide a missing line.
|
|
21
|
+
running = conn.send_command("show running-config interface GigabitEthernet1/0/10")
|
|
22
|
+
wanted = ["interface GigabitEthernet1/0/10", " description uplink-core1"]
|
|
23
|
+
# Send only what is missing; Netmiko does not diff for you.
|
|
24
|
+
if not any(line.strip() == "description uplink-core1" for line in running.splitlines()):
|
|
25
|
+
print(conn.send_config_set(wanted))
|
|
26
|
+
conn.save_config()
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`send_command(..., use_textfsm=True)` returns parsed data when a TextFSM (ntc-templates) template exists for that command.
|
|
30
|
+
|
|
31
|
+
## NAPALM
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
from napalm import get_network_driver
|
|
35
|
+
|
|
36
|
+
driver = get_network_driver("ios") # eos, junos, nxos, nxos_ssh, iosxr ...
|
|
37
|
+
with driver("10.0.0.11", user, password, optional_args={"secret": enable}) as dev:
|
|
38
|
+
dev.load_merge_candidate(config=rendered) # or load_replace_candidate(filename=...)
|
|
39
|
+
diff = dev.compare_config()
|
|
40
|
+
if not diff:
|
|
41
|
+
dev.discard_config()
|
|
42
|
+
elif approved(diff):
|
|
43
|
+
dev.commit_config(revert_in=300) # seconds; IOS rounds to minutes, needs archive
|
|
44
|
+
if checks_pass(dev):
|
|
45
|
+
dev.confirm_commit()
|
|
46
|
+
else:
|
|
47
|
+
dev.rollback()
|
|
48
|
+
else:
|
|
49
|
+
dev.discard_config()
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
IOS driver prerequisites: `ip scp server enable` on the device, `archive` configured with a local path for revert and replace, and a replace file that matches IOS indentation and ends with `end`.
|
|
53
|
+
|
|
54
|
+
## Nornir (3.x)
|
|
55
|
+
|
|
56
|
+
`config.yaml`:
|
|
57
|
+
|
|
58
|
+
```yaml
|
|
59
|
+
inventory:
|
|
60
|
+
plugin: SimpleInventory
|
|
61
|
+
options:
|
|
62
|
+
host_file: inventory/hosts.yaml
|
|
63
|
+
group_file: inventory/groups.yaml
|
|
64
|
+
defaults_file: inventory/defaults.yaml
|
|
65
|
+
runner:
|
|
66
|
+
plugin: threaded
|
|
67
|
+
options:
|
|
68
|
+
num_workers: 10
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
import os
|
|
73
|
+
from nornir import InitNornir
|
|
74
|
+
from nornir.core.filter import F
|
|
75
|
+
from nornir_napalm.plugins.tasks import napalm_configure
|
|
76
|
+
from nornir_utils.plugins.functions import print_result
|
|
77
|
+
|
|
78
|
+
nr = InitNornir(config_file="config.yaml")
|
|
79
|
+
nr.inventory.defaults.username = os.environ["NET_USER"]
|
|
80
|
+
nr.inventory.defaults.password = os.environ["NET_PASS"]
|
|
81
|
+
|
|
82
|
+
def push(task):
|
|
83
|
+
# napalm_configure does not expand {host} in filename; build the path per host.
|
|
84
|
+
return task.run(task=napalm_configure, filename=f"out/{task.host.name}.cfg", dry_run=True)
|
|
85
|
+
|
|
86
|
+
canary = nr.filter(F(site="lab") & F(role="access"))
|
|
87
|
+
result = canary.run(task=push)
|
|
88
|
+
print_result(result)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`napalm_configure` (signature in the nornir_napalm repo) takes `dry_run`, `filename`, `configuration`, `replace`, `commit_message` and `revert_in`. Render per-host files first, or pass `configuration=` from a task that renders the template.
|
|
92
|
+
|
|
93
|
+
## Ansible
|
|
94
|
+
|
|
95
|
+
`inventory/group_vars/ios.yml`:
|
|
96
|
+
|
|
97
|
+
```yaml
|
|
98
|
+
ansible_connection: ansible.netcommon.network_cli
|
|
99
|
+
ansible_network_os: cisco.ios.ios
|
|
100
|
+
ansible_user: "{{ vault_net_user }}"
|
|
101
|
+
ansible_password: "{{ vault_net_pass }}"
|
|
102
|
+
ansible_become: true
|
|
103
|
+
ansible_become_method: enable
|
|
104
|
+
ansible_become_password: "{{ vault_net_enable }}"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Playbook:
|
|
108
|
+
|
|
109
|
+
```yaml
|
|
110
|
+
- hosts: ios
|
|
111
|
+
gather_facts: false
|
|
112
|
+
serial: [1, 5, "25%"]
|
|
113
|
+
max_fail_percentage: 0
|
|
114
|
+
tasks:
|
|
115
|
+
- name: Backup running config
|
|
116
|
+
cisco.ios.ios_config:
|
|
117
|
+
backup: true
|
|
118
|
+
backup_options:
|
|
119
|
+
dir_path: backups/
|
|
120
|
+
- name: VLANs as data
|
|
121
|
+
cisco.ios.ios_vlans:
|
|
122
|
+
config: "{{ vlans }}"
|
|
123
|
+
state: merged # replaced / overridden remove what is not listed
|
|
124
|
+
- name: Save if running differs from startup
|
|
125
|
+
cisco.ios.ios_config:
|
|
126
|
+
save_when: modified
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Run: `ansible-playbook site.yml --check --diff --limit lab-sw1`, then without `--check` on the same limit, then widen.
|
|
130
|
+
|
|
131
|
+
`state: rendered` prints the commands a resource module would send without connecting; `state: gathered` reads current state as structured data, useful for before/after checks.
|
|
132
|
+
|
|
133
|
+
## containerlab
|
|
134
|
+
|
|
135
|
+
```yaml
|
|
136
|
+
name: lab
|
|
137
|
+
topology:
|
|
138
|
+
nodes:
|
|
139
|
+
sw1: { kind: arista_ceos, image: ceos:<version you have> }
|
|
140
|
+
sw2: { kind: arista_ceos, image: ceos:<version you have> }
|
|
141
|
+
links:
|
|
142
|
+
- endpoints: ["sw1:eth1", "sw2:eth1"]
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
`clab deploy -t lab.clab.yml`, `clab inspect`, `clab destroy -t lab.clab.yml`. Vendor images (cEOS for `arista_ceos`, `cisco_iol`, `cisco_c8000v` built with vrnetlab) must be obtained under the vendor's licence. Kind names: https://containerlab.dev/manual/kinds/
|
|
146
|
+
|
|
147
|
+
## Sources
|
|
148
|
+
|
|
149
|
+
- NAPALM base API (`commit_config(revert_in=seconds)`): https://napalm.readthedocs.io/en/latest/base.html ; IOS caveats (archive, `ip scp server enable`, replace file format): https://napalm.readthedocs.io/en/latest/support/ios.html
|
|
150
|
+
- Ansible `serial` lists: https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_strategies.html ; `max_fail_percentage`: https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_error_handling.html
|
|
151
|
+
- `cisco.ios.ios_config` (`backup_options`, `save_when`) and `ios_vlans` states: https://github.com/ansible-collections/cisco.ios
|
|
152
|
+
- IOS-XR `commit confirmed`: https://www.cisco.com/c/en/us/td/docs/iosxr/cisco8000/system-management/b-system-management/m-conf-mgmt-commands.html
|
|
153
|
+
- containerlab deploy: https://containerlab.dev/cmd/deploy/
|