skilldrop-cli 0.16.3__py3-none-any.whl
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.
- skilldrop_cli/__init__.py +16 -0
- skilldrop_cli/__main__.py +3 -0
- skilldrop_cli/data/LICENSE +9 -0
- skilldrop_cli/data/LICENSE-APACHE +202 -0
- skilldrop_cli/data/LICENSE-MIT +21 -0
- skilldrop_cli/data/agents/README.md +127 -0
- skilldrop_cli/data/agents/code-quality.md +40 -0
- skilldrop_cli/data/agents/devils-advocate.md +40 -0
- skilldrop_cli/data/agents/security-reviewer.md +44 -0
- skilldrop_cli/data/bin/skilldrop.js +2110 -0
- skilldrop_cli/data/catalogue.json +187 -0
- skilldrop_cli/data/contracts/agent.schema.json +28 -0
- skilldrop_cli/data/contracts/catalogue.schema.json +33 -0
- skilldrop_cli/data/contracts/guide.schema.json +18 -0
- skilldrop_cli/data/contracts/loop.schema.json +87 -0
- skilldrop_cli/data/contracts/pack.schema.json +75 -0
- skilldrop_cli/data/contracts/skill.schema.json +110 -0
- skilldrop_cli/data/contracts/terminals.json +33 -0
- skilldrop_cli/data/model-routing.json +474 -0
- skilldrop_cli/data/package.json +46 -0
- skilldrop_cli/data/packs/ai-engineering/pack.json +57 -0
- skilldrop_cli/data/packs/ai-engineering/skills/agent-adoption-stage/SKILL.md +90 -0
- skilldrop_cli/data/packs/ai-engineering/skills/agent-adoption-stage/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/ai-engineering/skills/agent-adoption-stage/evals/evals.json +19 -0
- skilldrop_cli/data/packs/ai-engineering/skills/agent-adoption-stage/manifest.json +39 -0
- skilldrop_cli/data/packs/ai-engineering/skills/agent-budget/SKILL.md +63 -0
- skilldrop_cli/data/packs/ai-engineering/skills/agent-budget/evals/eval_queries.json +11 -0
- skilldrop_cli/data/packs/ai-engineering/skills/agent-budget/evals/evals.json +28 -0
- skilldrop_cli/data/packs/ai-engineering/skills/agent-budget/manifest.json +11 -0
- skilldrop_cli/data/packs/ai-engineering/skills/agent-budget/templates/budget-spec.md +30 -0
- skilldrop_cli/data/packs/ai-engineering/skills/agent-loop-design/SKILL.md +70 -0
- skilldrop_cli/data/packs/ai-engineering/skills/agent-loop-design/evals/eval_queries.json +11 -0
- skilldrop_cli/data/packs/ai-engineering/skills/agent-loop-design/evals/evals.json +28 -0
- skilldrop_cli/data/packs/ai-engineering/skills/agent-loop-design/manifest.json +11 -0
- skilldrop_cli/data/packs/ai-engineering/skills/agent-loop-design/templates/loop-spec.md +46 -0
- skilldrop_cli/data/packs/ai-engineering/skills/agent-threat-model/SKILL.md +89 -0
- skilldrop_cli/data/packs/ai-engineering/skills/agent-threat-model/evals/eval_queries.json +15 -0
- skilldrop_cli/data/packs/ai-engineering/skills/agent-threat-model/evals/evals.json +41 -0
- skilldrop_cli/data/packs/ai-engineering/skills/agent-threat-model/examples/support-triage-agent.md +117 -0
- skilldrop_cli/data/packs/ai-engineering/skills/agent-threat-model/manifest.json +11 -0
- skilldrop_cli/data/packs/ai-engineering/skills/agent-threat-model/reference.md +101 -0
- skilldrop_cli/data/packs/ai-engineering/skills/agent-threat-model/templates/agent-threat-model.md +71 -0
- skilldrop_cli/data/packs/ai-engineering/skills/ai-adoption-rollout/SKILL.md +61 -0
- skilldrop_cli/data/packs/ai-engineering/skills/ai-adoption-rollout/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/ai-engineering/skills/ai-adoption-rollout/evals/evals.json +19 -0
- skilldrop_cli/data/packs/ai-engineering/skills/ai-adoption-rollout/manifest.json +33 -0
- skilldrop_cli/data/packs/ai-engineering/skills/ai-readiness-assessment/SKILL.md +68 -0
- skilldrop_cli/data/packs/ai-engineering/skills/ai-readiness-assessment/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/ai-engineering/skills/ai-readiness-assessment/evals/evals.json +17 -0
- skilldrop_cli/data/packs/ai-engineering/skills/ai-readiness-assessment/manifest.json +35 -0
- skilldrop_cli/data/packs/ai-engineering/skills/ai-usage-policy/SKILL.md +67 -0
- skilldrop_cli/data/packs/ai-engineering/skills/ai-usage-policy/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/ai-engineering/skills/ai-usage-policy/evals/evals.json +19 -0
- skilldrop_cli/data/packs/ai-engineering/skills/ai-usage-policy/manifest.json +33 -0
- skilldrop_cli/data/packs/ai-engineering/skills/ai-usage-report/SKILL.md +111 -0
- skilldrop_cli/data/packs/ai-engineering/skills/ai-usage-report/evals/eval_queries.json +30 -0
- skilldrop_cli/data/packs/ai-engineering/skills/ai-usage-report/evals/evals.json +19 -0
- skilldrop_cli/data/packs/ai-engineering/skills/ai-usage-report/evals/files/1/northwind-ai-events.csv +4213 -0
- skilldrop_cli/data/packs/ai-engineering/skills/ai-usage-report/examples/weekly-engineering-team.md +133 -0
- skilldrop_cli/data/packs/ai-engineering/skills/ai-usage-report/manifest.json +12 -0
- skilldrop_cli/data/packs/ai-engineering/skills/ai-usage-report/scripts/build_report.py +436 -0
- skilldrop_cli/data/packs/ai-engineering/skills/ai-usage-report/templates/report-per-user.md +42 -0
- skilldrop_cli/data/packs/ai-engineering/skills/ai-usage-report/templates/report-team-rollup.md +49 -0
- skilldrop_cli/data/packs/ai-engineering/skills/ai-usage-report/templates/usage-event-schema.md +76 -0
- skilldrop_cli/data/packs/ai-engineering/skills/ai-use-case-triage/SKILL.md +59 -0
- skilldrop_cli/data/packs/ai-engineering/skills/ai-use-case-triage/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/ai-engineering/skills/ai-use-case-triage/evals/evals.json +18 -0
- skilldrop_cli/data/packs/ai-engineering/skills/ai-use-case-triage/manifest.json +34 -0
- skilldrop_cli/data/packs/ai-engineering/skills/llm-eval-harness/SKILL.md +73 -0
- skilldrop_cli/data/packs/ai-engineering/skills/llm-eval-harness/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/ai-engineering/skills/llm-eval-harness/evals/evals.json +19 -0
- skilldrop_cli/data/packs/ai-engineering/skills/llm-eval-harness/manifest.json +11 -0
- skilldrop_cli/data/packs/ai-engineering/skills/llm-eval-harness/reference.md +58 -0
- skilldrop_cli/data/packs/ai-engineering/skills/llm-eval-harness/templates/eval-plan.md +63 -0
- skilldrop_cli/data/packs/ai-engineering/skills/llm-eval-harness/templates/golden-case.jsonl +5 -0
- skilldrop_cli/data/packs/ai-engineering/skills/subagent-design/SKILL.md +69 -0
- skilldrop_cli/data/packs/ai-engineering/skills/subagent-design/evals/eval_queries.json +11 -0
- skilldrop_cli/data/packs/ai-engineering/skills/subagent-design/evals/evals.json +29 -0
- skilldrop_cli/data/packs/ai-engineering/skills/subagent-design/manifest.json +11 -0
- skilldrop_cli/data/packs/ai-engineering/skills/subagent-design/templates/orchestration-plan.md +47 -0
- skilldrop_cli/data/packs/api-builder/pack.json +48 -0
- skilldrop_cli/data/packs/api-builder/skills/eval-harness-generator/SKILL.md +84 -0
- skilldrop_cli/data/packs/api-builder/skills/eval-harness-generator/evals/eval_queries.json +30 -0
- skilldrop_cli/data/packs/api-builder/skills/eval-harness-generator/evals/evals.json +19 -0
- skilldrop_cli/data/packs/api-builder/skills/eval-harness-generator/evals/files/1/SKILL.md +31 -0
- skilldrop_cli/data/packs/api-builder/skills/eval-harness-generator/manifest.json +11 -0
- skilldrop_cli/data/packs/api-builder/skills/prompt-caching-advisor/SKILL.md +90 -0
- skilldrop_cli/data/packs/api-builder/skills/prompt-caching-advisor/evals/eval_queries.json +30 -0
- skilldrop_cli/data/packs/api-builder/skills/prompt-caching-advisor/evals/evals.json +19 -0
- skilldrop_cli/data/packs/api-builder/skills/prompt-caching-advisor/manifest.json +11 -0
- skilldrop_cli/data/packs/api-builder/skills/token-budget-estimator/SKILL.md +75 -0
- skilldrop_cli/data/packs/api-builder/skills/token-budget-estimator/evals/eval_queries.json +30 -0
- skilldrop_cli/data/packs/api-builder/skills/token-budget-estimator/evals/evals.json +18 -0
- skilldrop_cli/data/packs/api-builder/skills/token-budget-estimator/manifest.json +11 -0
- skilldrop_cli/data/packs/api-builder/skills/tool-use-schema-writer/SKILL.md +111 -0
- skilldrop_cli/data/packs/api-builder/skills/tool-use-schema-writer/evals/eval_queries.json +30 -0
- skilldrop_cli/data/packs/api-builder/skills/tool-use-schema-writer/evals/evals.json +18 -0
- skilldrop_cli/data/packs/api-builder/skills/tool-use-schema-writer/manifest.json +11 -0
- skilldrop_cli/data/packs/converters/pack.json +66 -0
- skilldrop_cli/data/packs/converters/skills/file-to-markdown/SKILL.md +103 -0
- skilldrop_cli/data/packs/converters/skills/file-to-markdown/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/converters/skills/file-to-markdown/evals/evals.json +27 -0
- skilldrop_cli/data/packs/converters/skills/file-to-markdown/evals/files/1/northwind-q3.pptx +0 -0
- skilldrop_cli/data/packs/converters/skills/file-to-markdown/evals/files/2/acme-contract-summary.pdf +93 -0
- skilldrop_cli/data/packs/converters/skills/file-to-markdown/examples/inputs/accounts.json +1 -0
- skilldrop_cli/data/packs/converters/skills/file-to-markdown/examples/inputs/fabrikam-status.html +14 -0
- skilldrop_cli/data/packs/converters/skills/file-to-markdown/examples/mixed-inputs.md +306 -0
- skilldrop_cli/data/packs/converters/skills/file-to-markdown/manifest.json +49 -0
- skilldrop_cli/data/packs/converters/skills/file-to-markdown/scripts/to_markdown.py +1299 -0
- skilldrop_cli/data/packs/converters/skills/md-to-docx/SKILL.md +124 -0
- skilldrop_cli/data/packs/converters/skills/md-to-docx/evals/eval_queries.json +10 -0
- skilldrop_cli/data/packs/converters/skills/md-to-docx/evals/evals.json +29 -0
- skilldrop_cli/data/packs/converters/skills/md-to-docx/evals/files/1/brand/brand.json +80 -0
- skilldrop_cli/data/packs/converters/skills/md-to-docx/evals/files/1/brand/logo-white.png +0 -0
- skilldrop_cli/data/packs/converters/skills/md-to-docx/evals/files/1/brand/logo.png +0 -0
- skilldrop_cli/data/packs/converters/skills/md-to-docx/evals/files/1/brand/mark.png +0 -0
- skilldrop_cli/data/packs/converters/skills/md-to-docx/evals/files/1/docs/vendor-onboarding.md +42 -0
- skilldrop_cli/data/packs/converters/skills/md-to-docx/examples/q3-support-review-input.md +54 -0
- skilldrop_cli/data/packs/converters/skills/md-to-docx/examples/q3-support-review.md +80 -0
- skilldrop_cli/data/packs/converters/skills/md-to-docx/examples/tickets-by-region.png +0 -0
- skilldrop_cli/data/packs/converters/skills/md-to-docx/manifest.json +52 -0
- skilldrop_cli/data/packs/converters/skills/md-to-docx/reference.md +89 -0
- skilldrop_cli/data/packs/converters/skills/md-to-docx/scripts/md_to_docx.py +1114 -0
- skilldrop_cli/data/packs/converters/skills/md-to-html/SKILL.md +100 -0
- skilldrop_cli/data/packs/converters/skills/md-to-html/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/converters/skills/md-to-html/evals/evals.json +18 -0
- skilldrop_cli/data/packs/converters/skills/md-to-html/evals/files/1/brand/brand.json +80 -0
- skilldrop_cli/data/packs/converters/skills/md-to-html/evals/files/1/brand/logo-white.png +0 -0
- skilldrop_cli/data/packs/converters/skills/md-to-html/evals/files/1/brand/logo.png +0 -0
- skilldrop_cli/data/packs/converters/skills/md-to-html/evals/files/1/brand/mark.png +0 -0
- skilldrop_cli/data/packs/converters/skills/md-to-html/evals/files/1/docs/q3-review.md +35 -0
- skilldrop_cli/data/packs/converters/skills/md-to-html/evals/files/1/img/dashboard.png +0 -0
- skilldrop_cli/data/packs/converters/skills/md-to-html/examples/inputs/chart.svg +8 -0
- skilldrop_cli/data/packs/converters/skills/md-to-html/examples/inputs/ops-review.md +48 -0
- skilldrop_cli/data/packs/converters/skills/md-to-html/examples/ops-review.md +83 -0
- skilldrop_cli/data/packs/converters/skills/md-to-html/manifest.json +43 -0
- skilldrop_cli/data/packs/converters/skills/md-to-html/reference.md +70 -0
- skilldrop_cli/data/packs/converters/skills/md-to-html/scripts/md_to_html.py +652 -0
- skilldrop_cli/data/packs/converters/skills/md-to-xlsx/SKILL.md +120 -0
- skilldrop_cli/data/packs/converters/skills/md-to-xlsx/evals/eval_queries.json +9 -0
- skilldrop_cli/data/packs/converters/skills/md-to-xlsx/evals/evals.json +28 -0
- skilldrop_cli/data/packs/converters/skills/md-to-xlsx/evals/files/1/exports/northwind-invoices.csv +25 -0
- skilldrop_cli/data/packs/converters/skills/md-to-xlsx/evals/files/2/reports/q3-ops-review.md +32 -0
- skilldrop_cli/data/packs/converters/skills/md-to-xlsx/examples/vendor-review-input.md +28 -0
- skilldrop_cli/data/packs/converters/skills/md-to-xlsx/examples/vendor-review.md +94 -0
- skilldrop_cli/data/packs/converters/skills/md-to-xlsx/manifest.json +33 -0
- skilldrop_cli/data/packs/converters/skills/md-to-xlsx/reference.md +94 -0
- skilldrop_cli/data/packs/converters/skills/md-to-xlsx/scripts/md_to_xlsx.py +667 -0
- skilldrop_cli/data/packs/converters/skills/mermaid-render/SKILL.md +109 -0
- skilldrop_cli/data/packs/converters/skills/mermaid-render/evals/eval_queries.json +30 -0
- skilldrop_cli/data/packs/converters/skills/mermaid-render/evals/evals.json +17 -0
- skilldrop_cli/data/packs/converters/skills/mermaid-render/evals/files/1/docs/contoso-orders.md +23 -0
- skilldrop_cli/data/packs/converters/skills/mermaid-render/examples/broken-diagrams.md +147 -0
- skilldrop_cli/data/packs/converters/skills/mermaid-render/examples/inputs/broken-flowchart.mmd +8 -0
- skilldrop_cli/data/packs/converters/skills/mermaid-render/examples/inputs/broken-sequence.mmd +11 -0
- skilldrop_cli/data/packs/converters/skills/mermaid-render/examples/inputs/checkout-flow.mmd +9 -0
- skilldrop_cli/data/packs/converters/skills/mermaid-render/examples/inputs/design-notes.md +35 -0
- skilldrop_cli/data/packs/converters/skills/mermaid-render/examples/inputs/fixed-flowchart.mmd +9 -0
- skilldrop_cli/data/packs/converters/skills/mermaid-render/examples/inputs/typo.mmd +2 -0
- skilldrop_cli/data/packs/converters/skills/mermaid-render/manifest.json +40 -0
- skilldrop_cli/data/packs/converters/skills/mermaid-render/reference.md +70 -0
- skilldrop_cli/data/packs/converters/skills/mermaid-render/scripts/render_mermaid.py +486 -0
- skilldrop_cli/data/packs/core/loops/ship-a-draft/LOOP.md +77 -0
- skilldrop_cli/data/packs/core/loops/ship-a-draft/evals/eval_queries.json +30 -0
- skilldrop_cli/data/packs/core/loops/ship-a-draft/evals/evals.json +25 -0
- skilldrop_cli/data/packs/core/loops/ship-a-draft/loop.json +41 -0
- skilldrop_cli/data/packs/core/pack.json +50 -0
- skilldrop_cli/data/packs/core/skills/brief-intake/SKILL.md +79 -0
- skilldrop_cli/data/packs/core/skills/brief-intake/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/core/skills/brief-intake/evals/evals.json +16 -0
- skilldrop_cli/data/packs/core/skills/brief-intake/manifest.json +11 -0
- skilldrop_cli/data/packs/core/skills/brief-intake/templates/brief-adr.md +41 -0
- skilldrop_cli/data/packs/core/skills/brief-intake/templates/brief-decision-log.md +35 -0
- skilldrop_cli/data/packs/core/skills/brief-intake/templates/brief-deck.md +43 -0
- skilldrop_cli/data/packs/core/skills/brief-intake/templates/brief-design-doc.md +48 -0
- skilldrop_cli/data/packs/core/skills/brief-intake/templates/brief-exec-summary.md +47 -0
- skilldrop_cli/data/packs/core/skills/brief-intake/templates/brief-generic.md +45 -0
- skilldrop_cli/data/packs/core/skills/brief-intake/templates/brief-runbook.md +44 -0
- skilldrop_cli/data/packs/core/skills/brief-intake/templates/brief-tech-comparison.md +38 -0
- skilldrop_cli/data/packs/core/skills/council-review/SKILL.md +106 -0
- skilldrop_cli/data/packs/core/skills/council-review/evals/eval_queries.json +38 -0
- skilldrop_cli/data/packs/core/skills/council-review/evals/evals.json +18 -0
- skilldrop_cli/data/packs/core/skills/council-review/examples/redis-cache-decision.md +75 -0
- skilldrop_cli/data/packs/core/skills/council-review/manifest.json +11 -0
- skilldrop_cli/data/packs/core/skills/council-review/reference.md +76 -0
- skilldrop_cli/data/packs/core/skills/council-review/seats/architect.md +29 -0
- skilldrop_cli/data/packs/core/skills/council-review/seats/bench.md +39 -0
- skilldrop_cli/data/packs/core/skills/council-review/seats/operator.md +27 -0
- skilldrop_cli/data/packs/core/skills/council-review/seats/pragmatist.md +29 -0
- skilldrop_cli/data/packs/core/skills/council-review/seats/security-engineer.md +29 -0
- skilldrop_cli/data/packs/core/skills/council-review/seats/user-advocate.md +27 -0
- skilldrop_cli/data/packs/core/skills/council-review/templates/council-review.md +59 -0
- skilldrop_cli/data/packs/core/skills/doc-critique/SKILL.md +119 -0
- skilldrop_cli/data/packs/core/skills/doc-critique/evals/eval_queries.json +38 -0
- skilldrop_cli/data/packs/core/skills/doc-critique/evals/evals.json +17 -0
- skilldrop_cli/data/packs/core/skills/doc-critique/examples/design-doc-critique.md +34 -0
- skilldrop_cli/data/packs/core/skills/doc-critique/manifest.json +11 -0
- skilldrop_cli/data/packs/core/skills/doc-critique/rubrics/adr.md +36 -0
- skilldrop_cli/data/packs/core/skills/doc-critique/rubrics/decision-log.md +39 -0
- skilldrop_cli/data/packs/core/skills/doc-critique/rubrics/deck.md +45 -0
- skilldrop_cli/data/packs/core/skills/doc-critique/rubrics/design-doc.md +42 -0
- skilldrop_cli/data/packs/core/skills/doc-critique/rubrics/exec-summary.md +41 -0
- skilldrop_cli/data/packs/core/skills/doc-critique/rubrics/generic.md +40 -0
- skilldrop_cli/data/packs/core/skills/doc-critique/rubrics/runbook.md +42 -0
- skilldrop_cli/data/packs/core/skills/doc-critique/rubrics/tech-comparison.md +40 -0
- skilldrop_cli/data/packs/core/skills/doc-critique/templates/critique.md +49 -0
- skilldrop_cli/data/packs/core/skills/output-hygiene/SKILL.md +97 -0
- skilldrop_cli/data/packs/core/skills/output-hygiene/evals/eval_queries.json +11 -0
- skilldrop_cli/data/packs/core/skills/output-hygiene/evals/evals.json +30 -0
- skilldrop_cli/data/packs/core/skills/output-hygiene/manifest.json +34 -0
- skilldrop_cli/data/packs/core/skills/output-hygiene/reference.md +106 -0
- skilldrop_cli/data/packs/core/skills/output-hygiene/scripts/scrub.py +315 -0
- skilldrop_cli/data/packs/data-analytics/pack.json +57 -0
- skilldrop_cli/data/packs/data-analytics/skills/dashboard-spec/SKILL.md +83 -0
- skilldrop_cli/data/packs/data-analytics/skills/dashboard-spec/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/data-analytics/skills/dashboard-spec/evals/evals.json +19 -0
- skilldrop_cli/data/packs/data-analytics/skills/dashboard-spec/examples/support-staffing.md +84 -0
- skilldrop_cli/data/packs/data-analytics/skills/dashboard-spec/manifest.json +40 -0
- skilldrop_cli/data/packs/data-analytics/skills/dashboard-spec/reference.md +45 -0
- skilldrop_cli/data/packs/data-analytics/skills/dashboard-spec/templates/dashboard-spec.md +55 -0
- skilldrop_cli/data/packs/data-analytics/skills/metric-definition/SKILL.md +84 -0
- skilldrop_cli/data/packs/data-analytics/skills/metric-definition/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/data-analytics/skills/metric-definition/evals/evals.json +19 -0
- skilldrop_cli/data/packs/data-analytics/skills/metric-definition/examples/refund-rate.md +104 -0
- skilldrop_cli/data/packs/data-analytics/skills/metric-definition/manifest.json +41 -0
- skilldrop_cli/data/packs/data-analytics/skills/metric-definition/reference.md +67 -0
- skilldrop_cli/data/packs/data-analytics/skills/metric-definition/templates/metric-spec.md +70 -0
- skilldrop_cli/data/packs/data-analytics/skills/sql-review/SKILL.md +83 -0
- skilldrop_cli/data/packs/data-analytics/skills/sql-review/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/data-analytics/skills/sql-review/evals/evals.json +19 -0
- skilldrop_cli/data/packs/data-analytics/skills/sql-review/examples/revenue-by-region.md +174 -0
- skilldrop_cli/data/packs/data-analytics/skills/sql-review/manifest.json +42 -0
- skilldrop_cli/data/packs/data-analytics/skills/sql-review/reference.md +84 -0
- skilldrop_cli/data/packs/data-analytics/skills/sql-review/scripts/sql_lint.py +461 -0
- skilldrop_cli/data/packs/design/pack.json +60 -0
- skilldrop_cli/data/packs/design/skills/brand-kit/SKILL.md +105 -0
- skilldrop_cli/data/packs/design/skills/brand-kit/evals/eval_queries.json +30 -0
- skilldrop_cli/data/packs/design/skills/brand-kit/evals/evals.json +18 -0
- skilldrop_cli/data/packs/design/skills/brand-kit/evals/files/1/brand/northwind-logo-white.png +0 -0
- skilldrop_cli/data/packs/design/skills/brand-kit/evals/files/1/brand/northwind-logo.png +0 -0
- skilldrop_cli/data/packs/design/skills/brand-kit/examples/northwind-brand.md +48 -0
- skilldrop_cli/data/packs/design/skills/brand-kit/manifest.json +45 -0
- skilldrop_cli/data/packs/design/skills/brand-kit/scripts/check_brand.py +114 -0
- skilldrop_cli/data/packs/design/skills/brand-kit/templates/brand.json +54 -0
- skilldrop_cli/data/packs/design/skills/deck-builder/SKILL.md +201 -0
- skilldrop_cli/data/packs/design/skills/deck-builder/evals/eval_queries.json +14 -0
- skilldrop_cli/data/packs/design/skills/deck-builder/evals/evals.json +40 -0
- skilldrop_cli/data/packs/design/skills/deck-builder/examples/exec-board-update.md +108 -0
- skilldrop_cli/data/packs/design/skills/deck-builder/examples/templated-brand-deck.md +148 -0
- skilldrop_cli/data/packs/design/skills/deck-builder/manifest.json +18 -0
- skilldrop_cli/data/packs/design/skills/deck-builder/reference.md +180 -0
- skilldrop_cli/data/packs/design/skills/deck-builder/requirements.txt +3 -0
- skilldrop_cli/data/packs/design/skills/deck-builder/scripts/build_deck.py +1134 -0
- skilldrop_cli/data/packs/design/skills/deck-builder/templates/deck-spec.json +168 -0
- skilldrop_cli/data/packs/design/skills/deck-builder/templates/palettes.json +59 -0
- skilldrop_cli/data/packs/design/skills/marketing-flyer/SKILL.md +113 -0
- skilldrop_cli/data/packs/design/skills/marketing-flyer/evals/eval_queries.json +30 -0
- skilldrop_cli/data/packs/design/skills/marketing-flyer/evals/evals.json +18 -0
- skilldrop_cli/data/packs/design/skills/marketing-flyer/evals/files/1/brand/brand.json +80 -0
- skilldrop_cli/data/packs/design/skills/marketing-flyer/evals/files/1/brand/logo-white.png +0 -0
- skilldrop_cli/data/packs/design/skills/marketing-flyer/evals/files/1/brand/logo.png +0 -0
- skilldrop_cli/data/packs/design/skills/marketing-flyer/evals/files/1/brand/mark.png +0 -0
- skilldrop_cli/data/packs/design/skills/marketing-flyer/examples/community-health-fair.md +68 -0
- skilldrop_cli/data/packs/design/skills/marketing-flyer/manifest.json +40 -0
- skilldrop_cli/data/packs/design/skills/marketing-flyer/reference.md +54 -0
- skilldrop_cli/data/packs/design/skills/marketing-flyer/scripts/build_flyer.py +323 -0
- skilldrop_cli/data/packs/design/skills/marketing-flyer/templates/flyer-spec.json +26 -0
- skilldrop_cli/data/packs/design/skills/slide-outliner/SKILL.md +58 -0
- skilldrop_cli/data/packs/design/skills/slide-outliner/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/design/skills/slide-outliner/evals/evals.json +16 -0
- skilldrop_cli/data/packs/design/skills/slide-outliner/manifest.json +11 -0
- skilldrop_cli/data/packs/design/skills/slide-outliner/templates/deck-outline.md +131 -0
- skilldrop_cli/data/packs/dev-team/loops/build/LOOP.md +80 -0
- skilldrop_cli/data/packs/dev-team/loops/build/evals/eval_queries.json +30 -0
- skilldrop_cli/data/packs/dev-team/loops/build/evals/evals.json +27 -0
- skilldrop_cli/data/packs/dev-team/loops/build/loop.json +48 -0
- skilldrop_cli/data/packs/dev-team/loops/release/LOOP.md +91 -0
- skilldrop_cli/data/packs/dev-team/loops/release/loop.json +47 -0
- skilldrop_cli/data/packs/dev-team/pack.json +56 -0
- skilldrop_cli/data/packs/dev-team/skills/accessibility-audit/SKILL.md +74 -0
- skilldrop_cli/data/packs/dev-team/skills/accessibility-audit/evals/eval_queries.json +30 -0
- skilldrop_cli/data/packs/dev-team/skills/accessibility-audit/evals/evals.json +19 -0
- skilldrop_cli/data/packs/dev-team/skills/accessibility-audit/examples/login-form.md +76 -0
- skilldrop_cli/data/packs/dev-team/skills/accessibility-audit/manifest.json +11 -0
- skilldrop_cli/data/packs/dev-team/skills/accessibility-audit/reference.md +69 -0
- skilldrop_cli/data/packs/dev-team/skills/agents-md-generator/SKILL.md +82 -0
- skilldrop_cli/data/packs/dev-team/skills/agents-md-generator/evals/eval_queries.json +15 -0
- skilldrop_cli/data/packs/dev-team/skills/agents-md-generator/evals/evals.json +50 -0
- skilldrop_cli/data/packs/dev-team/skills/agents-md-generator/evals/files/1/Makefile +5 -0
- skilldrop_cli/data/packs/dev-team/skills/agents-md-generator/evals/files/1/alembic/versions/0001_create_bookings.py +10 -0
- skilldrop_cli/data/packs/dev-team/skills/agents-md-generator/evals/files/1/booking/__init__.py +0 -0
- skilldrop_cli/data/packs/dev-team/skills/agents-md-generator/evals/files/1/booking/app.py +8 -0
- skilldrop_cli/data/packs/dev-team/skills/agents-md-generator/evals/files/1/pyproject.toml +11 -0
- skilldrop_cli/data/packs/dev-team/skills/agents-md-generator/evals/files/1/tests/test_health.py +5 -0
- skilldrop_cli/data/packs/dev-team/skills/agents-md-generator/evals/files/2/AGENTS.md +3 -0
- skilldrop_cli/data/packs/dev-team/skills/agents-md-generator/evals/files/2/package.json +12 -0
- skilldrop_cli/data/packs/dev-team/skills/agents-md-generator/evals/files/2/src/index.ts +1 -0
- skilldrop_cli/data/packs/dev-team/skills/agents-md-generator/manifest.json +11 -0
- skilldrop_cli/data/packs/dev-team/skills/agents-md-generator/reference.md +89 -0
- skilldrop_cli/data/packs/dev-team/skills/agents-md-generator/templates/agents-md.md +48 -0
- skilldrop_cli/data/packs/dev-team/skills/bug-triage/SKILL.md +67 -0
- skilldrop_cli/data/packs/dev-team/skills/bug-triage/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/dev-team/skills/bug-triage/evals/evals.json +17 -0
- skilldrop_cli/data/packs/dev-team/skills/bug-triage/manifest.json +14 -0
- skilldrop_cli/data/packs/dev-team/skills/bug-triage/templates/bug-ticket.md +86 -0
- skilldrop_cli/data/packs/dev-team/skills/contribution-wizard/SKILL.md +134 -0
- skilldrop_cli/data/packs/dev-team/skills/contribution-wizard/evals/eval_queries.json +30 -0
- skilldrop_cli/data/packs/dev-team/skills/contribution-wizard/evals/evals.json +19 -0
- skilldrop_cli/data/packs/dev-team/skills/contribution-wizard/manifest.json +11 -0
- skilldrop_cli/data/packs/dev-team/skills/devils-advocate/SKILL.md +143 -0
- skilldrop_cli/data/packs/dev-team/skills/devils-advocate/evals/eval_queries.json +38 -0
- skilldrop_cli/data/packs/dev-team/skills/devils-advocate/evals/evals.json +19 -0
- skilldrop_cli/data/packs/dev-team/skills/devils-advocate/examples/rate-limiter-review.md +46 -0
- skilldrop_cli/data/packs/dev-team/skills/devils-advocate/lenses/adversarial-review.md +88 -0
- skilldrop_cli/data/packs/dev-team/skills/devils-advocate/lenses/edge-cases.md +95 -0
- skilldrop_cli/data/packs/dev-team/skills/devils-advocate/lenses/future-proofing.md +75 -0
- skilldrop_cli/data/packs/dev-team/skills/devils-advocate/lenses/test-coverage.md +90 -0
- skilldrop_cli/data/packs/dev-team/skills/devils-advocate/manifest.json +14 -0
- skilldrop_cli/data/packs/dev-team/skills/devils-advocate/templates/challenge.md +118 -0
- skilldrop_cli/data/packs/dev-team/skills/feature-implement-loop/SKILL.md +88 -0
- skilldrop_cli/data/packs/dev-team/skills/feature-implement-loop/evals/eval_queries.json +30 -0
- skilldrop_cli/data/packs/dev-team/skills/feature-implement-loop/evals/evals.json +19 -0
- skilldrop_cli/data/packs/dev-team/skills/feature-implement-loop/manifest.json +14 -0
- skilldrop_cli/data/packs/dev-team/skills/launch-readiness/SKILL.md +95 -0
- skilldrop_cli/data/packs/dev-team/skills/launch-readiness/evals/eval_queries.json +10 -0
- skilldrop_cli/data/packs/dev-team/skills/launch-readiness/evals/evals.json +19 -0
- skilldrop_cli/data/packs/dev-team/skills/launch-readiness/examples/schema-change-revise.md +54 -0
- skilldrop_cli/data/packs/dev-team/skills/launch-readiness/manifest.json +24 -0
- skilldrop_cli/data/packs/dev-team/skills/launch-readiness/templates/readiness-report.md +41 -0
- skilldrop_cli/data/packs/dev-team/skills/migration-plan/SKILL.md +68 -0
- skilldrop_cli/data/packs/dev-team/skills/migration-plan/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/dev-team/skills/migration-plan/evals/evals.json +16 -0
- skilldrop_cli/data/packs/dev-team/skills/migration-plan/manifest.json +11 -0
- skilldrop_cli/data/packs/dev-team/skills/migration-plan/templates/migration-plan.md +68 -0
- skilldrop_cli/data/packs/dev-team/skills/pre-merge-review/SKILL.md +85 -0
- skilldrop_cli/data/packs/dev-team/skills/pre-merge-review/evals/eval_queries.json +11 -0
- skilldrop_cli/data/packs/dev-team/skills/pre-merge-review/evals/evals.json +26 -0
- skilldrop_cli/data/packs/dev-team/skills/pre-merge-review/examples/pre-merge-verdict.md +43 -0
- skilldrop_cli/data/packs/dev-team/skills/pre-merge-review/manifest.json +15 -0
- skilldrop_cli/data/packs/dev-team/skills/pre-merge-review/scripts/gate.py +189 -0
- skilldrop_cli/data/packs/dev-team/skills/release-notes/SKILL.md +61 -0
- skilldrop_cli/data/packs/dev-team/skills/release-notes/evals/eval_queries.json +30 -0
- skilldrop_cli/data/packs/dev-team/skills/release-notes/evals/evals.json +19 -0
- skilldrop_cli/data/packs/dev-team/skills/release-notes/manifest.json +11 -0
- skilldrop_cli/data/packs/dev-team/skills/release-notes/templates/release-notes.md +83 -0
- skilldrop_cli/data/packs/dev-team/skills/sonar-onboard/SKILL.md +170 -0
- skilldrop_cli/data/packs/dev-team/skills/sonar-onboard/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/dev-team/skills/sonar-onboard/evals/evals.json +16 -0
- skilldrop_cli/data/packs/dev-team/skills/sonar-onboard/manifest.json +11 -0
- skilldrop_cli/data/packs/dev-team/skills/sonar-onboard/reference.md +151 -0
- skilldrop_cli/data/packs/dev-team/skills/sonar-onboard/templates/github-actions-sonar-server.yml.tmpl +50 -0
- skilldrop_cli/data/packs/dev-team/skills/sonar-onboard/templates/github-actions-sonarcloud.yml.tmpl +53 -0
- skilldrop_cli/data/packs/dev-team/skills/sonar-onboard/templates/readme-snippet.md +38 -0
- skilldrop_cli/data/packs/dev-team/skills/sonar-onboard/templates/sonar-project.properties.tmpl +31 -0
- skilldrop_cli/data/packs/dev-team/skills/sonar-review/SKILL.md +220 -0
- skilldrop_cli/data/packs/dev-team/skills/sonar-review/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/dev-team/skills/sonar-review/evals/evals.json +16 -0
- skilldrop_cli/data/packs/dev-team/skills/sonar-review/lenses/bugs.md +48 -0
- skilldrop_cli/data/packs/dev-team/skills/sonar-review/lenses/code-smells.md +64 -0
- skilldrop_cli/data/packs/dev-team/skills/sonar-review/lenses/coverage-and-duplication.md +74 -0
- skilldrop_cli/data/packs/dev-team/skills/sonar-review/lenses/security-hotspots.md +56 -0
- skilldrop_cli/data/packs/dev-team/skills/sonar-review/lenses/vulnerabilities.md +52 -0
- skilldrop_cli/data/packs/dev-team/skills/sonar-review/manifest.json +37 -0
- skilldrop_cli/data/packs/dev-team/skills/sonar-review/reference.md +167 -0
- skilldrop_cli/data/packs/dev-team/skills/sonar-review/templates/report.md +84 -0
- skilldrop_cli/data/packs/dev-team/skills/test-plan-generator/SKILL.md +59 -0
- skilldrop_cli/data/packs/dev-team/skills/test-plan-generator/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/dev-team/skills/test-plan-generator/evals/evals.json +16 -0
- skilldrop_cli/data/packs/dev-team/skills/test-plan-generator/manifest.json +11 -0
- skilldrop_cli/data/packs/dev-team/skills/test-plan-generator/templates/test-plan.md +83 -0
- skilldrop_cli/data/packs/dev-team/skills/user-story-splitter/SKILL.md +88 -0
- skilldrop_cli/data/packs/dev-team/skills/user-story-splitter/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/dev-team/skills/user-story-splitter/evals/evals.json +16 -0
- skilldrop_cli/data/packs/dev-team/skills/user-story-splitter/examples/notifications-epic.md +123 -0
- skilldrop_cli/data/packs/dev-team/skills/user-story-splitter/manifest.json +14 -0
- skilldrop_cli/data/packs/dev-team/skills/user-story-splitter/templates/story.md +40 -0
- skilldrop_cli/data/packs/experience-design/pack.json +68 -0
- skilldrop_cli/data/packs/experience-design/skills/content-design/SKILL.md +77 -0
- skilldrop_cli/data/packs/experience-design/skills/content-design/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/experience-design/skills/content-design/evals/evals.json +18 -0
- skilldrop_cli/data/packs/experience-design/skills/content-design/examples/parking-permit-page.md +102 -0
- skilldrop_cli/data/packs/experience-design/skills/content-design/manifest.json +41 -0
- skilldrop_cli/data/packs/experience-design/skills/content-design/scripts/readability.py +115 -0
- skilldrop_cli/data/packs/experience-design/skills/content-design/templates/content-spec.md +45 -0
- skilldrop_cli/data/packs/experience-design/skills/design-system-spec/SKILL.md +79 -0
- skilldrop_cli/data/packs/experience-design/skills/design-system-spec/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/experience-design/skills/design-system-spec/evals/evals.json +19 -0
- skilldrop_cli/data/packs/experience-design/skills/design-system-spec/examples/text-field-spec.md +121 -0
- skilldrop_cli/data/packs/experience-design/skills/design-system-spec/manifest.json +46 -0
- skilldrop_cli/data/packs/experience-design/skills/design-system-spec/reference.md +66 -0
- skilldrop_cli/data/packs/experience-design/skills/design-system-spec/templates/component-spec.md +74 -0
- skilldrop_cli/data/packs/experience-design/skills/information-architecture/SKILL.md +76 -0
- skilldrop_cli/data/packs/experience-design/skills/information-architecture/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/experience-design/skills/information-architecture/evals/evals.json +19 -0
- skilldrop_cli/data/packs/experience-design/skills/information-architecture/examples/payroll-app-nav.md +127 -0
- skilldrop_cli/data/packs/experience-design/skills/information-architecture/manifest.json +46 -0
- skilldrop_cli/data/packs/experience-design/skills/information-architecture/reference.md +54 -0
- skilldrop_cli/data/packs/experience-design/skills/information-architecture/templates/ia-spec.md +77 -0
- skilldrop_cli/data/packs/experience-design/skills/service-blueprint/SKILL.md +76 -0
- skilldrop_cli/data/packs/experience-design/skills/service-blueprint/evals/eval_queries.json +30 -0
- skilldrop_cli/data/packs/experience-design/skills/service-blueprint/evals/evals.json +19 -0
- skilldrop_cli/data/packs/experience-design/skills/service-blueprint/examples/insurance-claim-blueprint.md +107 -0
- skilldrop_cli/data/packs/experience-design/skills/service-blueprint/manifest.json +45 -0
- skilldrop_cli/data/packs/experience-design/skills/service-blueprint/templates/blueprint.md +72 -0
- skilldrop_cli/data/packs/experience-design/skills/ux-writing/SKILL.md +77 -0
- skilldrop_cli/data/packs/experience-design/skills/ux-writing/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/experience-design/skills/ux-writing/evals/evals.json +19 -0
- skilldrop_cli/data/packs/experience-design/skills/ux-writing/examples/team-invite-flow.md +66 -0
- skilldrop_cli/data/packs/experience-design/skills/ux-writing/manifest.json +41 -0
- skilldrop_cli/data/packs/experience-design/skills/ux-writing/templates/string-table.md +22 -0
- skilldrop_cli/data/packs/grc/pack.json +57 -0
- skilldrop_cli/data/packs/grc/skills/dpia/SKILL.md +123 -0
- skilldrop_cli/data/packs/grc/skills/dpia/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/grc/skills/dpia/evals/evals.json +19 -0
- skilldrop_cli/data/packs/grc/skills/dpia/examples/acme-warehouse-performance.md +159 -0
- skilldrop_cli/data/packs/grc/skills/dpia/manifest.json +47 -0
- skilldrop_cli/data/packs/grc/skills/dpia/reference.md +118 -0
- skilldrop_cli/data/packs/grc/skills/dpia/templates/dpia.md +103 -0
- skilldrop_cli/data/packs/grc/skills/risk-register/SKILL.md +139 -0
- skilldrop_cli/data/packs/grc/skills/risk-register/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/grc/skills/risk-register/evals/evals.json +19 -0
- skilldrop_cli/data/packs/grc/skills/risk-register/examples/northwind-register.csv +9 -0
- skilldrop_cli/data/packs/grc/skills/risk-register/examples/northwind-register.md +127 -0
- skilldrop_cli/data/packs/grc/skills/risk-register/manifest.json +43 -0
- skilldrop_cli/data/packs/grc/skills/risk-register/reference.md +99 -0
- skilldrop_cli/data/packs/grc/skills/risk-register/scripts/check_register.py +338 -0
- skilldrop_cli/data/packs/grc/skills/risk-register/templates/risk-register.csv +2 -0
- skilldrop_cli/data/packs/grc/skills/soc2-evidence-map/SKILL.md +117 -0
- skilldrop_cli/data/packs/grc/skills/soc2-evidence-map/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/grc/skills/soc2-evidence-map/evals/evals.json +19 -0
- skilldrop_cli/data/packs/grc/skills/soc2-evidence-map/examples/northwind-evidence-map.csv +17 -0
- skilldrop_cli/data/packs/grc/skills/soc2-evidence-map/examples/northwind-type2-security.md +127 -0
- skilldrop_cli/data/packs/grc/skills/soc2-evidence-map/manifest.json +41 -0
- skilldrop_cli/data/packs/grc/skills/soc2-evidence-map/reference.md +156 -0
- skilldrop_cli/data/packs/grc/skills/soc2-evidence-map/templates/evidence-map.csv +2 -0
- skilldrop_cli/data/packs/infra-as-code/pack.json +51 -0
- skilldrop_cli/data/packs/infra-as-code/skills/terraform-module/SKILL.md +85 -0
- skilldrop_cli/data/packs/infra-as-code/skills/terraform-module/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/infra-as-code/skills/terraform-module/evals/evals.json +31 -0
- skilldrop_cli/data/packs/infra-as-code/skills/terraform-module/examples/s3-log-bucket/README.md +71 -0
- skilldrop_cli/data/packs/infra-as-code/skills/terraform-module/examples/s3-log-bucket/examples/basic/main.tf +30 -0
- skilldrop_cli/data/packs/infra-as-code/skills/terraform-module/examples/s3-log-bucket/main.tf +153 -0
- skilldrop_cli/data/packs/infra-as-code/skills/terraform-module/examples/s3-log-bucket/outputs.tf +14 -0
- skilldrop_cli/data/packs/infra-as-code/skills/terraform-module/examples/s3-log-bucket/variables.tf +71 -0
- skilldrop_cli/data/packs/infra-as-code/skills/terraform-module/examples/s3-log-bucket/versions.tf +10 -0
- skilldrop_cli/data/packs/infra-as-code/skills/terraform-module/examples/s3-log-bucket.md +50 -0
- skilldrop_cli/data/packs/infra-as-code/skills/terraform-module/manifest.json +41 -0
- skilldrop_cli/data/packs/infra-as-code/skills/terraform-module/reference.md +105 -0
- skilldrop_cli/data/packs/infra-as-code/skills/terraform-module/templates/module-readme.md +55 -0
- skilldrop_cli/data/packs/infra-as-code/skills/terraform-plan-review/SKILL.md +87 -0
- skilldrop_cli/data/packs/infra-as-code/skills/terraform-plan-review/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/infra-as-code/skills/terraform-plan-review/evals/evals.json +30 -0
- skilldrop_cli/data/packs/infra-as-code/skills/terraform-plan-review/evals/files/2/plan.json +133 -0
- skilldrop_cli/data/packs/infra-as-code/skills/terraform-plan-review/examples/northwind-orders-plan.json +174 -0
- skilldrop_cli/data/packs/infra-as-code/skills/terraform-plan-review/examples/northwind-orders.md +87 -0
- skilldrop_cli/data/packs/infra-as-code/skills/terraform-plan-review/manifest.json +48 -0
- skilldrop_cli/data/packs/infra-as-code/skills/terraform-plan-review/reference.md +77 -0
- skilldrop_cli/data/packs/infra-as-code/skills/terraform-plan-review/scripts/plan_summary.py +361 -0
- skilldrop_cli/data/packs/product-manager/loops/discover/LOOP.md +81 -0
- skilldrop_cli/data/packs/product-manager/loops/discover/evals/eval_queries.json +30 -0
- skilldrop_cli/data/packs/product-manager/loops/discover/evals/evals.json +26 -0
- skilldrop_cli/data/packs/product-manager/loops/discover/loop.json +41 -0
- skilldrop_cli/data/packs/product-manager/pack.json +61 -0
- skilldrop_cli/data/packs/product-manager/skills/business-case/SKILL.md +64 -0
- skilldrop_cli/data/packs/product-manager/skills/business-case/evals/eval_queries.json +30 -0
- skilldrop_cli/data/packs/product-manager/skills/business-case/evals/evals.json +19 -0
- skilldrop_cli/data/packs/product-manager/skills/business-case/examples/build-vs-buy-flags.md +42 -0
- skilldrop_cli/data/packs/product-manager/skills/business-case/manifest.json +11 -0
- skilldrop_cli/data/packs/product-manager/skills/business-case/templates/business-case.md +60 -0
- skilldrop_cli/data/packs/product-manager/skills/okr-cascade/SKILL.md +59 -0
- skilldrop_cli/data/packs/product-manager/skills/okr-cascade/evals/eval_queries.json +12 -0
- skilldrop_cli/data/packs/product-manager/skills/okr-cascade/evals/evals.json +28 -0
- skilldrop_cli/data/packs/product-manager/skills/okr-cascade/manifest.json +11 -0
- skilldrop_cli/data/packs/product-manager/skills/okr-cascade/templates/okr-cascade.md +46 -0
- skilldrop_cli/data/packs/product-manager/skills/prd-draft/SKILL.md +62 -0
- skilldrop_cli/data/packs/product-manager/skills/prd-draft/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/product-manager/skills/prd-draft/evals/evals.json +17 -0
- skilldrop_cli/data/packs/product-manager/skills/prd-draft/manifest.json +16 -0
- skilldrop_cli/data/packs/product-manager/skills/prd-draft/templates/prd.md +66 -0
- skilldrop_cli/data/packs/product-manager/skills/prfaq/SKILL.md +76 -0
- skilldrop_cli/data/packs/product-manager/skills/prfaq/evals/eval_queries.json +13 -0
- skilldrop_cli/data/packs/product-manager/skills/prfaq/evals/evals.json +32 -0
- skilldrop_cli/data/packs/product-manager/skills/prfaq/manifest.json +11 -0
- skilldrop_cli/data/packs/product-manager/skills/prfaq/templates/prfaq.md +60 -0
- skilldrop_cli/data/packs/product-manager/skills/requirements-interview/SKILL.md +61 -0
- skilldrop_cli/data/packs/product-manager/skills/requirements-interview/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/product-manager/skills/requirements-interview/evals/evals.json +16 -0
- skilldrop_cli/data/packs/product-manager/skills/requirements-interview/manifest.json +14 -0
- skilldrop_cli/data/packs/product-manager/skills/requirements-interview/templates/interview-kit.md +63 -0
- skilldrop_cli/data/packs/product-manager/skills/strategy-analysis/SKILL.md +63 -0
- skilldrop_cli/data/packs/product-manager/skills/strategy-analysis/evals/eval_queries.json +13 -0
- skilldrop_cli/data/packs/product-manager/skills/strategy-analysis/evals/evals.json +36 -0
- skilldrop_cli/data/packs/product-manager/skills/strategy-analysis/examples/market-entry-tows.md +42 -0
- skilldrop_cli/data/packs/product-manager/skills/strategy-analysis/manifest.json +15 -0
- skilldrop_cli/data/packs/product-manager/skills/success-metrics/SKILL.md +65 -0
- skilldrop_cli/data/packs/product-manager/skills/success-metrics/evals/eval_queries.json +11 -0
- skilldrop_cli/data/packs/product-manager/skills/success-metrics/evals/evals.json +27 -0
- skilldrop_cli/data/packs/product-manager/skills/success-metrics/manifest.json +11 -0
- skilldrop_cli/data/packs/product-manager/skills/success-metrics/templates/metrics-plan.md +55 -0
- skilldrop_cli/data/packs/product-manager/skills/user-journey-map/SKILL.md +65 -0
- skilldrop_cli/data/packs/product-manager/skills/user-journey-map/evals/eval_queries.json +12 -0
- skilldrop_cli/data/packs/product-manager/skills/user-journey-map/evals/evals.json +30 -0
- skilldrop_cli/data/packs/product-manager/skills/user-journey-map/examples/b2b-saas-onboarding.md +69 -0
- skilldrop_cli/data/packs/product-manager/skills/user-journey-map/manifest.json +15 -0
- skilldrop_cli/data/packs/product-manager/skills/user-journey-map/templates/journey-map.md +47 -0
- skilldrop_cli/data/packs/research/pack.json +52 -0
- skilldrop_cli/data/packs/research/skills/hypothesis-comparison/SKILL.md +131 -0
- skilldrop_cli/data/packs/research/skills/hypothesis-comparison/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/research/skills/hypothesis-comparison/evals/evals.json +19 -0
- skilldrop_cli/data/packs/research/skills/hypothesis-comparison/examples/conversion-drop.md +132 -0
- skilldrop_cli/data/packs/research/skills/hypothesis-comparison/manifest.json +43 -0
- skilldrop_cli/data/packs/research/skills/hypothesis-comparison/reference.md +107 -0
- skilldrop_cli/data/packs/research/skills/hypothesis-comparison/scripts/ach_matrix.py +204 -0
- skilldrop_cli/data/packs/research/skills/hypothesis-comparison/templates/hypothesis-comparison.md +61 -0
- skilldrop_cli/data/packs/research/skills/hypothesis-comparison/templates/matrix.csv +4 -0
- skilldrop_cli/data/packs/research/skills/research-plan/SKILL.md +122 -0
- skilldrop_cli/data/packs/research/skills/research-plan/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/research/skills/research-plan/evals/evals.json +28 -0
- skilldrop_cli/data/packs/research/skills/research-plan/examples/four-day-week-plan.md +97 -0
- skilldrop_cli/data/packs/research/skills/research-plan/manifest.json +47 -0
- skilldrop_cli/data/packs/research/skills/research-plan/reference.md +88 -0
- skilldrop_cli/data/packs/research/skills/research-plan/templates/research-plan.md +54 -0
- skilldrop_cli/data/packs/research/skills/source-synthesis/SKILL.md +123 -0
- skilldrop_cli/data/packs/research/skills/source-synthesis/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/research/skills/source-synthesis/evals/evals.json +19 -0
- skilldrop_cli/data/packs/research/skills/source-synthesis/examples/four-day-week.md +146 -0
- skilldrop_cli/data/packs/research/skills/source-synthesis/manifest.json +42 -0
- skilldrop_cli/data/packs/research/skills/source-synthesis/reference.md +92 -0
- skilldrop_cli/data/packs/research/skills/source-synthesis/scripts/citations.py +314 -0
- skilldrop_cli/data/packs/research/skills/source-synthesis/templates/synthesis.md +46 -0
- skilldrop_cli/data/packs/skill-engineering/pack.json +46 -0
- skilldrop_cli/data/packs/skill-engineering/skills/skill-author/SKILL.md +139 -0
- skilldrop_cli/data/packs/skill-engineering/skills/skill-author/evals/eval_queries.json +10 -0
- skilldrop_cli/data/packs/skill-engineering/skills/skill-author/evals/evals.json +19 -0
- skilldrop_cli/data/packs/skill-engineering/skills/skill-author/examples/release-notes-skill.md +185 -0
- skilldrop_cli/data/packs/skill-engineering/skills/skill-author/manifest.json +42 -0
- skilldrop_cli/data/packs/skill-engineering/skills/skill-author/reference.md +144 -0
- skilldrop_cli/data/packs/skill-engineering/skills/skill-author/templates/eval_queries.json +9 -0
- skilldrop_cli/data/packs/skill-engineering/skills/skill-author/templates/evals.json +16 -0
- skilldrop_cli/data/packs/skill-engineering/skills/skill-author/templates/skill-template.md +52 -0
- skilldrop_cli/data/packs/skill-engineering/skills/skill-review/SKILL.md +131 -0
- skilldrop_cli/data/packs/skill-engineering/skills/skill-review/evals/eval_queries.json +11 -0
- skilldrop_cli/data/packs/skill-engineering/skills/skill-review/evals/evals.json +19 -0
- skilldrop_cli/data/packs/skill-engineering/skills/skill-review/evals/files/1/skills/changelog-writer/SKILL.md +10 -0
- skilldrop_cli/data/packs/skill-engineering/skills/skill-review/evals/files/1/skills/pr-summary/SKILL.md +12 -0
- skilldrop_cli/data/packs/skill-engineering/skills/skill-review/evals/files/1/skills/pr-summary/references/tone.md +3 -0
- skilldrop_cli/data/packs/skill-engineering/skills/skill-review/evals/files/1/skills/pr-summary/scripts/collect.py +6 -0
- skilldrop_cli/data/packs/skill-engineering/skills/skill-review/examples/meeting-notes-review.md +147 -0
- skilldrop_cli/data/packs/skill-engineering/skills/skill-review/manifest.json +50 -0
- skilldrop_cli/data/packs/skill-engineering/skills/skill-review/reference.md +135 -0
- skilldrop_cli/data/packs/skill-engineering/skills/skill-review/scripts/lint_skill.py +481 -0
- skilldrop_cli/data/packs/skill-engineering/skills/skill-review/templates/review.md +43 -0
- skilldrop_cli/data/packs/solution-architect/loops/design/LOOP.md +83 -0
- skilldrop_cli/data/packs/solution-architect/loops/design/evals/eval_queries.json +30 -0
- skilldrop_cli/data/packs/solution-architect/loops/design/evals/evals.json +26 -0
- skilldrop_cli/data/packs/solution-architect/loops/design/loop.json +47 -0
- skilldrop_cli/data/packs/solution-architect/pack.json +65 -0
- skilldrop_cli/data/packs/solution-architect/skills/adr-generator/SKILL.md +50 -0
- skilldrop_cli/data/packs/solution-architect/skills/adr-generator/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/solution-architect/skills/adr-generator/evals/evals.json +17 -0
- skilldrop_cli/data/packs/solution-architect/skills/adr-generator/manifest.json +11 -0
- skilldrop_cli/data/packs/solution-architect/skills/adr-generator/templates/madr.md +56 -0
- skilldrop_cli/data/packs/solution-architect/skills/adr-generator/templates/nygard.md +19 -0
- skilldrop_cli/data/packs/solution-architect/skills/api-contract-draft/SKILL.md +69 -0
- skilldrop_cli/data/packs/solution-architect/skills/api-contract-draft/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/solution-architect/skills/api-contract-draft/evals/evals.json +18 -0
- skilldrop_cli/data/packs/solution-architect/skills/api-contract-draft/manifest.json +11 -0
- skilldrop_cli/data/packs/solution-architect/skills/api-contract-draft/reference.md +73 -0
- skilldrop_cli/data/packs/solution-architect/skills/api-contract-draft/templates/openapi-skeleton.yaml +148 -0
- skilldrop_cli/data/packs/solution-architect/skills/architecture-diagrams/SKILL.md +66 -0
- skilldrop_cli/data/packs/solution-architect/skills/architecture-diagrams/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/solution-architect/skills/architecture-diagrams/evals/evals.json +16 -0
- skilldrop_cli/data/packs/solution-architect/skills/architecture-diagrams/examples/aws-three-tier.md +44 -0
- skilldrop_cli/data/packs/solution-architect/skills/architecture-diagrams/examples/c4-container-saas.md +51 -0
- skilldrop_cli/data/packs/solution-architect/skills/architecture-diagrams/examples/microservices-sequence.md +49 -0
- skilldrop_cli/data/packs/solution-architect/skills/architecture-diagrams/manifest.json +31 -0
- skilldrop_cli/data/packs/solution-architect/skills/architecture-diagrams/templates/c4-container.puml +31 -0
- skilldrop_cli/data/packs/solution-architect/skills/architecture-diagrams/templates/mermaid-aws.md +52 -0
- skilldrop_cli/data/packs/solution-architect/skills/architecture-diagrams/templates/mermaid-flowchart.md +37 -0
- skilldrop_cli/data/packs/solution-architect/skills/architecture-diagrams/templates/mermaid-sequence.md +39 -0
- skilldrop_cli/data/packs/solution-architect/skills/data-contract/SKILL.md +67 -0
- skilldrop_cli/data/packs/solution-architect/skills/data-contract/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/solution-architect/skills/data-contract/evals/evals.json +16 -0
- skilldrop_cli/data/packs/solution-architect/skills/data-contract/manifest.json +11 -0
- skilldrop_cli/data/packs/solution-architect/skills/data-contract/reference.md +46 -0
- skilldrop_cli/data/packs/solution-architect/skills/data-contract/templates/data-contract.md +69 -0
- skilldrop_cli/data/packs/solution-architect/skills/db-schema-design/SKILL.md +68 -0
- skilldrop_cli/data/packs/solution-architect/skills/db-schema-design/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/solution-architect/skills/db-schema-design/evals/evals.json +16 -0
- skilldrop_cli/data/packs/solution-architect/skills/db-schema-design/manifest.json +11 -0
- skilldrop_cli/data/packs/solution-architect/skills/db-schema-design/reference.md +56 -0
- skilldrop_cli/data/packs/solution-architect/skills/db-schema-design/templates/schema-design.md +75 -0
- skilldrop_cli/data/packs/solution-architect/skills/design-doc/SKILL.md +49 -0
- skilldrop_cli/data/packs/solution-architect/skills/design-doc/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/solution-architect/skills/design-doc/evals/evals.json +17 -0
- skilldrop_cli/data/packs/solution-architect/skills/design-doc/manifest.json +14 -0
- skilldrop_cli/data/packs/solution-architect/skills/design-doc/templates/design-doc.md +98 -0
- skilldrop_cli/data/packs/solution-architect/skills/figma-diagrams/SKILL.md +87 -0
- skilldrop_cli/data/packs/solution-architect/skills/figma-diagrams/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/solution-architect/skills/figma-diagrams/evals/evals.json +15 -0
- skilldrop_cli/data/packs/solution-architect/skills/figma-diagrams/manifest.json +36 -0
- skilldrop_cli/data/packs/solution-architect/skills/figma-diagrams/reference.md +91 -0
- skilldrop_cli/data/packs/solution-architect/skills/figma-diagrams/requirements.txt +3 -0
- skilldrop_cli/data/packs/solution-architect/skills/figma-diagrams/scripts/_figma_client.py +71 -0
- skilldrop_cli/data/packs/solution-architect/skills/figma-diagrams/scripts/frame_to_mermaid.py +102 -0
- skilldrop_cli/data/packs/solution-architect/skills/figma-diagrams/scripts/inspect_file.py +46 -0
- skilldrop_cli/data/packs/solution-architect/skills/figma-diagrams/scripts/list_comments.py +35 -0
- skilldrop_cli/data/packs/solution-architect/skills/figma-diagrams/scripts/post_comment.py +52 -0
- skilldrop_cli/data/packs/solution-architect/skills/figma-diagrams/templates/figjam-import.json +20 -0
- skilldrop_cli/data/packs/solution-architect/skills/nfr-spec/SKILL.md +63 -0
- skilldrop_cli/data/packs/solution-architect/skills/nfr-spec/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/solution-architect/skills/nfr-spec/evals/evals.json +16 -0
- skilldrop_cli/data/packs/solution-architect/skills/nfr-spec/manifest.json +16 -0
- skilldrop_cli/data/packs/solution-architect/skills/nfr-spec/reference.md +74 -0
- skilldrop_cli/data/packs/solution-architect/skills/nfr-spec/templates/nfr-spec.md +56 -0
- skilldrop_cli/data/packs/solution-architect/skills/reverse-architecture/SKILL.md +103 -0
- skilldrop_cli/data/packs/solution-architect/skills/reverse-architecture/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/solution-architect/skills/reverse-architecture/evals/evals.json +16 -0
- skilldrop_cli/data/packs/solution-architect/skills/reverse-architecture/manifest.json +11 -0
- skilldrop_cli/data/packs/solution-architect/skills/reverse-architecture/reference.md +150 -0
- skilldrop_cli/data/packs/solution-architect/skills/reverse-architecture/templates/description.md +52 -0
- skilldrop_cli/data/packs/solution-architect/skills/reverse-architecture/templates/extraction.md +55 -0
- skilldrop_cli/data/packs/solution-architect/skills/tech-comparison-matrix/SKILL.md +56 -0
- skilldrop_cli/data/packs/solution-architect/skills/tech-comparison-matrix/evals/eval_queries.json +30 -0
- skilldrop_cli/data/packs/solution-architect/skills/tech-comparison-matrix/evals/evals.json +18 -0
- skilldrop_cli/data/packs/solution-architect/skills/tech-comparison-matrix/examples/queue-selection.md +41 -0
- skilldrop_cli/data/packs/solution-architect/skills/tech-comparison-matrix/manifest.json +11 -0
- skilldrop_cli/data/packs/solution-architect/skills/tech-comparison-matrix/templates/matrix.md +45 -0
- skilldrop_cli/data/packs/solution-architect/skills/threat-model/SKILL.md +65 -0
- skilldrop_cli/data/packs/solution-architect/skills/threat-model/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/solution-architect/skills/threat-model/evals/evals.json +18 -0
- skilldrop_cli/data/packs/solution-architect/skills/threat-model/examples/document-upload.md +56 -0
- skilldrop_cli/data/packs/solution-architect/skills/threat-model/manifest.json +11 -0
- skilldrop_cli/data/packs/solution-architect/skills/threat-model/reference.md +69 -0
- skilldrop_cli/data/packs/sre-oncall/loops/operate/LOOP.md +84 -0
- skilldrop_cli/data/packs/sre-oncall/loops/operate/evals/eval_queries.json +30 -0
- skilldrop_cli/data/packs/sre-oncall/loops/operate/evals/evals.json +25 -0
- skilldrop_cli/data/packs/sre-oncall/loops/operate/loop.json +41 -0
- skilldrop_cli/data/packs/sre-oncall/pack.json +59 -0
- skilldrop_cli/data/packs/sre-oncall/skills/capacity-cost-model/SKILL.md +65 -0
- skilldrop_cli/data/packs/sre-oncall/skills/capacity-cost-model/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/sre-oncall/skills/capacity-cost-model/evals/evals.json +19 -0
- skilldrop_cli/data/packs/sre-oncall/skills/capacity-cost-model/manifest.json +11 -0
- skilldrop_cli/data/packs/sre-oncall/skills/capacity-cost-model/reference.md +54 -0
- skilldrop_cli/data/packs/sre-oncall/skills/capacity-cost-model/templates/cost-model.md +68 -0
- skilldrop_cli/data/packs/sre-oncall/skills/cloud-cost-review/SKILL.md +121 -0
- skilldrop_cli/data/packs/sre-oncall/skills/cloud-cost-review/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/sre-oncall/skills/cloud-cost-review/evals/evals.json +29 -0
- skilldrop_cli/data/packs/sre-oncall/skills/cloud-cost-review/examples/acme-aws-september.md +247 -0
- skilldrop_cli/data/packs/sre-oncall/skills/cloud-cost-review/examples/acme-cur-2026-08-09.csv +1085 -0
- skilldrop_cli/data/packs/sre-oncall/skills/cloud-cost-review/manifest.json +49 -0
- skilldrop_cli/data/packs/sre-oncall/skills/cloud-cost-review/reference.md +100 -0
- skilldrop_cli/data/packs/sre-oncall/skills/cloud-cost-review/scripts/cost_summary.py +630 -0
- skilldrop_cli/data/packs/sre-oncall/skills/cloud-cost-review/templates/cost-review.md +36 -0
- skilldrop_cli/data/packs/sre-oncall/skills/delivery-metrics-report/SKILL.md +114 -0
- skilldrop_cli/data/packs/sre-oncall/skills/delivery-metrics-report/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/sre-oncall/skills/delivery-metrics-report/evals/evals.json +28 -0
- skilldrop_cli/data/packs/sre-oncall/skills/delivery-metrics-report/evals/files/1/deploys.csv +49 -0
- skilldrop_cli/data/packs/sre-oncall/skills/delivery-metrics-report/evals/files/1/incidents.csv +7 -0
- skilldrop_cli/data/packs/sre-oncall/skills/delivery-metrics-report/evals/files/1/prs.csv +84 -0
- skilldrop_cli/data/packs/sre-oncall/skills/delivery-metrics-report/examples/checkout-api-8-weeks.md +123 -0
- skilldrop_cli/data/packs/sre-oncall/skills/delivery-metrics-report/examples/deployments.csv +49 -0
- skilldrop_cli/data/packs/sre-oncall/skills/delivery-metrics-report/examples/incidents.csv +7 -0
- skilldrop_cli/data/packs/sre-oncall/skills/delivery-metrics-report/examples/prs.csv +84 -0
- skilldrop_cli/data/packs/sre-oncall/skills/delivery-metrics-report/manifest.json +48 -0
- skilldrop_cli/data/packs/sre-oncall/skills/delivery-metrics-report/reference.md +83 -0
- skilldrop_cli/data/packs/sre-oncall/skills/delivery-metrics-report/scripts/delivery_metrics.py +566 -0
- skilldrop_cli/data/packs/sre-oncall/skills/delivery-metrics-report/templates/delivery-report.md +31 -0
- skilldrop_cli/data/packs/sre-oncall/skills/incident-comms/SKILL.md +68 -0
- skilldrop_cli/data/packs/sre-oncall/skills/incident-comms/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/sre-oncall/skills/incident-comms/evals/evals.json +16 -0
- skilldrop_cli/data/packs/sre-oncall/skills/incident-comms/manifest.json +14 -0
- skilldrop_cli/data/packs/sre-oncall/skills/incident-comms/reference.md +43 -0
- skilldrop_cli/data/packs/sre-oncall/skills/incident-comms/templates/messages.md +82 -0
- skilldrop_cli/data/packs/sre-oncall/skills/observability-plan/SKILL.md +70 -0
- skilldrop_cli/data/packs/sre-oncall/skills/observability-plan/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/sre-oncall/skills/observability-plan/evals/evals.json +16 -0
- skilldrop_cli/data/packs/sre-oncall/skills/observability-plan/manifest.json +15 -0
- skilldrop_cli/data/packs/sre-oncall/skills/observability-plan/reference.md +67 -0
- skilldrop_cli/data/packs/sre-oncall/skills/observability-plan/templates/observability-plan.md +62 -0
- skilldrop_cli/data/packs/sre-oncall/skills/postmortem-generator/SKILL.md +66 -0
- skilldrop_cli/data/packs/sre-oncall/skills/postmortem-generator/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/sre-oncall/skills/postmortem-generator/evals/evals.json +17 -0
- skilldrop_cli/data/packs/sre-oncall/skills/postmortem-generator/manifest.json +14 -0
- skilldrop_cli/data/packs/sre-oncall/skills/postmortem-generator/templates/postmortem.md +67 -0
- skilldrop_cli/data/packs/sre-oncall/skills/runbook-generator/SKILL.md +42 -0
- skilldrop_cli/data/packs/sre-oncall/skills/runbook-generator/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/sre-oncall/skills/runbook-generator/evals/evals.json +17 -0
- skilldrop_cli/data/packs/sre-oncall/skills/runbook-generator/manifest.json +11 -0
- skilldrop_cli/data/packs/sre-oncall/skills/runbook-generator/templates/runbook.md +109 -0
- skilldrop_cli/data/packs/stakeholder-comms/pack.json +60 -0
- skilldrop_cli/data/packs/stakeholder-comms/skills/audience-profile/SKILL.md +74 -0
- skilldrop_cli/data/packs/stakeholder-comms/skills/audience-profile/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/stakeholder-comms/skills/audience-profile/evals/evals.json +15 -0
- skilldrop_cli/data/packs/stakeholder-comms/skills/audience-profile/manifest.json +11 -0
- skilldrop_cli/data/packs/stakeholder-comms/skills/audience-profile/reference.md +175 -0
- skilldrop_cli/data/packs/stakeholder-comms/skills/decision-log/SKILL.md +68 -0
- skilldrop_cli/data/packs/stakeholder-comms/skills/decision-log/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/stakeholder-comms/skills/decision-log/evals/evals.json +17 -0
- skilldrop_cli/data/packs/stakeholder-comms/skills/decision-log/manifest.json +11 -0
- skilldrop_cli/data/packs/stakeholder-comms/skills/exec-summary/SKILL.md +45 -0
- skilldrop_cli/data/packs/stakeholder-comms/skills/exec-summary/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/stakeholder-comms/skills/exec-summary/evals/evals.json +17 -0
- skilldrop_cli/data/packs/stakeholder-comms/skills/exec-summary/manifest.json +11 -0
- skilldrop_cli/data/packs/stakeholder-comms/skills/exec-summary/templates/exec-summary.md +48 -0
- skilldrop_cli/data/packs/stakeholder-comms/skills/guide-builder/SKILL.md +77 -0
- skilldrop_cli/data/packs/stakeholder-comms/skills/guide-builder/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/stakeholder-comms/skills/guide-builder/evals/evals.json +18 -0
- skilldrop_cli/data/packs/stakeholder-comms/skills/guide-builder/examples/local-setup-guide.md +127 -0
- skilldrop_cli/data/packs/stakeholder-comms/skills/guide-builder/manifest.json +11 -0
- skilldrop_cli/data/packs/stakeholder-comms/skills/guide-builder/templates/api-reference.md +120 -0
- skilldrop_cli/data/packs/stakeholder-comms/skills/guide-builder/templates/design-walkthrough.md +72 -0
- skilldrop_cli/data/packs/stakeholder-comms/skills/guide-builder/templates/setup-guide.md +109 -0
- skilldrop_cli/data/packs/trackers/pack.json +61 -0
- skilldrop_cli/data/packs/trackers/skills/backlog-triage/SKILL.md +116 -0
- skilldrop_cli/data/packs/trackers/skills/backlog-triage/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/trackers/skills/backlog-triage/evals/evals.json +30 -0
- skilldrop_cli/data/packs/trackers/skills/backlog-triage/evals/files/1/examples/northwind-backlog.csv +28 -0
- skilldrop_cli/data/packs/trackers/skills/backlog-triage/evals/files/2/issues.json +6052 -0
- skilldrop_cli/data/packs/trackers/skills/backlog-triage/examples/northwind-backlog.csv +28 -0
- skilldrop_cli/data/packs/trackers/skills/backlog-triage/examples/northwind-checkout-triage.md +202 -0
- skilldrop_cli/data/packs/trackers/skills/backlog-triage/manifest.json +42 -0
- skilldrop_cli/data/packs/trackers/skills/backlog-triage/reference.md +106 -0
- skilldrop_cli/data/packs/trackers/skills/backlog-triage/scripts/triage_backlog.py +461 -0
- skilldrop_cli/data/packs/trackers/skills/backlog-triage/templates/triage-report.md +42 -0
- skilldrop_cli/data/packs/trackers/skills/team-status-report/SKILL.md +111 -0
- skilldrop_cli/data/packs/trackers/skills/team-status-report/evals/eval_queries.json +30 -0
- skilldrop_cli/data/packs/trackers/skills/team-status-report/evals/evals.json +30 -0
- skilldrop_cli/data/packs/trackers/skills/team-status-report/evals/files/1/examples/northwind-week-40.csv +16 -0
- skilldrop_cli/data/packs/trackers/skills/team-status-report/evals/files/2/issues.json +1212 -0
- skilldrop_cli/data/packs/trackers/skills/team-status-report/examples/northwind-week-40.csv +16 -0
- skilldrop_cli/data/packs/trackers/skills/team-status-report/examples/northwind-weekly-status.md +160 -0
- skilldrop_cli/data/packs/trackers/skills/team-status-report/manifest.json +33 -0
- skilldrop_cli/data/packs/trackers/skills/team-status-report/reference.md +92 -0
- skilldrop_cli/data/packs/trackers/skills/team-status-report/scripts/status_counts.py +486 -0
- skilldrop_cli/data/packs/trackers/skills/team-status-report/templates/status-report.md +42 -0
- skilldrop_cli/data/packs/trackers/skills/tracker-brief-sync/SKILL.md +116 -0
- skilldrop_cli/data/packs/trackers/skills/tracker-brief-sync/evals/eval_queries.json +34 -0
- skilldrop_cli/data/packs/trackers/skills/tracker-brief-sync/evals/evals.json +31 -0
- skilldrop_cli/data/packs/trackers/skills/tracker-brief-sync/evals/files/1/examples/prd-guest-checkout.md +53 -0
- skilldrop_cli/data/packs/trackers/skills/tracker-brief-sync/evals/files/2/examples/prd-guest-checkout.md +53 -0
- skilldrop_cli/data/packs/trackers/skills/tracker-brief-sync/evals/files/2/examples/tracker-after-two-weeks.csv +30 -0
- skilldrop_cli/data/packs/trackers/skills/tracker-brief-sync/examples/guest-checkout-spec.json +98 -0
- skilldrop_cli/data/packs/trackers/skills/tracker-brief-sync/examples/guest-checkout-sync.md +151 -0
- skilldrop_cli/data/packs/trackers/skills/tracker-brief-sync/examples/prd-guest-checkout.md +53 -0
- skilldrop_cli/data/packs/trackers/skills/tracker-brief-sync/examples/tracker-after-two-weeks.csv +30 -0
- skilldrop_cli/data/packs/trackers/skills/tracker-brief-sync/manifest.json +41 -0
- skilldrop_cli/data/packs/trackers/skills/tracker-brief-sync/reference.md +101 -0
- skilldrop_cli/data/packs/trackers/skills/tracker-brief-sync/scripts/brief_sync.py +501 -0
- skilldrop_cli/data/packs/trackers/skills/tracker-brief-sync/templates/issues-spec.json +26 -0
- skilldrop_cli/data/profiles.json +24 -0
- skilldrop_cli-0.16.3.dist-info/METADATA +91 -0
- skilldrop_cli-0.16.3.dist-info/RECORD +757 -0
- skilldrop_cli-0.16.3.dist-info/WHEEL +5 -0
- skilldrop_cli-0.16.3.dist-info/entry_points.txt +2 -0
- skilldrop_cli-0.16.3.dist-info/licenses/LICENSE +9 -0
- skilldrop_cli-0.16.3.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,630 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Summarise a cloud cost export: totals, month-over-month change, untagged
|
|
3
|
+
share, top movers, cost hot spots and commitment coverage.
|
|
4
|
+
|
|
5
|
+
Stdlib only; runs on Python 3.9+. Reads one CSV in long format (one row per
|
|
6
|
+
line item): AWS CUR (legacy or 2.0), a flattened GCP billing export, an Azure
|
|
7
|
+
cost details export, or the generic layout. Column mapping: ../reference.md.
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
python3 cost_summary.py cost.csv [--format auto|aws-cur|aws-cur2|gcp|azure|generic]
|
|
11
|
+
[--tag team --tag env] [--month 2026-09] [--top 10]
|
|
12
|
+
[--out summary.md] [--json summary.json]
|
|
13
|
+
|
|
14
|
+
Exit codes: 0 ok, 2 bad input.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import argparse
|
|
20
|
+
import csv
|
|
21
|
+
import json
|
|
22
|
+
import re
|
|
23
|
+
import sys
|
|
24
|
+
from calendar import monthrange
|
|
25
|
+
from collections import defaultdict
|
|
26
|
+
from datetime import date, datetime
|
|
27
|
+
from pathlib import Path
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class InputError(Exception):
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# --------------------------------------------------------------- formats
|
|
35
|
+
# Each logical field lists candidate headers, matched case-insensitively.
|
|
36
|
+
|
|
37
|
+
FORMATS = {
|
|
38
|
+
"aws-cur": {
|
|
39
|
+
"detect": "lineitem/unblendedcost",
|
|
40
|
+
"date": ["lineItem/UsageStartDate"],
|
|
41
|
+
"cost": ["lineItem/UnblendedCost"],
|
|
42
|
+
"service": ["product/ProductName", "lineItem/ProductCode"],
|
|
43
|
+
"account": ["lineItem/UsageAccountId"],
|
|
44
|
+
"region": ["product/region", "product/regionCode"],
|
|
45
|
+
"usage_type": ["lineItem/UsageType"],
|
|
46
|
+
"resource_id": ["lineItem/ResourceId"],
|
|
47
|
+
"line_type": ["lineItem/LineItemType"],
|
|
48
|
+
"sp_effective": ["savingsPlan/SavingsPlanEffectiveCost"],
|
|
49
|
+
"ri_effective": ["reservation/EffectiveCost"],
|
|
50
|
+
"tag_prefix": ["resourceTags/"],
|
|
51
|
+
"tags_json": [],
|
|
52
|
+
},
|
|
53
|
+
"aws-cur2": {
|
|
54
|
+
"detect": "line_item_unblended_cost",
|
|
55
|
+
"date": ["line_item_usage_start_date"],
|
|
56
|
+
"cost": ["line_item_unblended_cost"],
|
|
57
|
+
"service": ["product_product_name", "line_item_product_code"],
|
|
58
|
+
"account": ["line_item_usage_account_id"],
|
|
59
|
+
"region": ["product_region_code", "product_region"],
|
|
60
|
+
"usage_type": ["line_item_usage_type"],
|
|
61
|
+
"resource_id": ["line_item_resource_id"],
|
|
62
|
+
"line_type": ["line_item_line_item_type"],
|
|
63
|
+
"sp_effective": ["savings_plan_savings_plan_effective_cost"],
|
|
64
|
+
"ri_effective": ["reservation_effective_cost"],
|
|
65
|
+
"tag_prefix": ["resource_tags_"],
|
|
66
|
+
"tags_json": ["resource_tags"],
|
|
67
|
+
},
|
|
68
|
+
"gcp": {
|
|
69
|
+
"detect": "usage_start_time",
|
|
70
|
+
"date": ["usage_start_time"],
|
|
71
|
+
"cost": ["cost"],
|
|
72
|
+
"credits": ["credits_total", "credits"],
|
|
73
|
+
"service": ["service_description", "service.description"],
|
|
74
|
+
"account": ["project_id", "project.id"],
|
|
75
|
+
"region": ["location_region", "location.region"],
|
|
76
|
+
"usage_type": ["sku_description", "sku.description"],
|
|
77
|
+
"resource_id": ["resource_global_name", "resource_name", "resource.name"],
|
|
78
|
+
"line_type": ["cost_type"],
|
|
79
|
+
"tag_prefix": ["label_", "labels_"],
|
|
80
|
+
"tags_json": ["labels"],
|
|
81
|
+
},
|
|
82
|
+
"azure": {
|
|
83
|
+
"detect": "metercategory",
|
|
84
|
+
"date": ["date", "UsageDateTime"],
|
|
85
|
+
"cost": ["costInBillingCurrency", "CostInBillingCurrency", "PreTaxCost", "Cost"],
|
|
86
|
+
"service": ["meterCategory", "ServiceName"],
|
|
87
|
+
"account": ["subscriptionName", "SubscriptionName", "subscriptionId", "SubscriptionGuid"],
|
|
88
|
+
"region": ["resourceLocation", "ResourceLocation"],
|
|
89
|
+
"usage_type": ["meterSubCategory", "MeterSubCategory"],
|
|
90
|
+
"usage_type2": ["meterName", "MeterName"],
|
|
91
|
+
"resource_id": ["resourceId", "ResourceId", "InstanceId"],
|
|
92
|
+
"line_type": ["chargeType", "ChargeType"],
|
|
93
|
+
"pricing": ["pricingModel", "PricingModel"],
|
|
94
|
+
"tag_prefix": [],
|
|
95
|
+
"tags_json": ["tags", "Tags"],
|
|
96
|
+
},
|
|
97
|
+
"generic": {
|
|
98
|
+
"detect": None,
|
|
99
|
+
"date": ["date"],
|
|
100
|
+
"cost": ["cost"],
|
|
101
|
+
"service": ["service"],
|
|
102
|
+
"account": ["account"],
|
|
103
|
+
"region": ["region"],
|
|
104
|
+
"usage_type": ["usage_type"],
|
|
105
|
+
"resource_id": ["resource_id"],
|
|
106
|
+
"line_type": ["line_type"],
|
|
107
|
+
"pricing": ["pricing_model"],
|
|
108
|
+
"tag_prefix": ["tag_"],
|
|
109
|
+
"tags_json": ["tags"],
|
|
110
|
+
},
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
COMPUTE_RE = re.compile(r"BoxUsage|DedicatedUsage|HostUsage|Fargate-(vCPU|GB)-Hours|Lambda-GB-Second|InstanceUsage|NodeUsage|"
|
|
114
|
+
r"Instance Core|Instance Ram|vCPU", re.I)
|
|
115
|
+
GENERIC_COMPUTE_SERVICE_RE = re.compile(r"compute|virtual machine|\bvm\b|ec2|fargate|lambda|functions", re.I)
|
|
116
|
+
HOTSPOTS = [
|
|
117
|
+
("nat_gateway", re.compile(r"NatGateway|NAT Gateway|Cloud NAT", re.I)),
|
|
118
|
+
("data_transfer", re.compile(r"DataTransfer|Data Transfer|Egress|Bandwidth|Inter-?Region|InterZone|Inter Zone|"
|
|
119
|
+
r"Network Internet|Networking", re.I)),
|
|
120
|
+
("idle_address", re.compile(r"IdleAddress|Unused IP|Static IP Charge", re.I)),
|
|
121
|
+
("snapshot", re.compile(r"Snapshot", re.I)),
|
|
122
|
+
("storage", re.compile(r"TimedStorage|VolumeUsage|Storage|Disk|Blob", re.I)),
|
|
123
|
+
("observability", re.compile(r"CloudWatch|Logging|Log Analytics|Azure Monitor|Cloud Monitoring|DataProcessing-Bytes", re.I)),
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def detect_format(headers: list) -> str:
|
|
128
|
+
low = [h.lower() for h in headers]
|
|
129
|
+
for name, spec in FORMATS.items():
|
|
130
|
+
if spec["detect"] and spec["detect"] in low:
|
|
131
|
+
if name == "azure" and "usage_start_time" in low:
|
|
132
|
+
continue
|
|
133
|
+
return name
|
|
134
|
+
if "date" in low and "cost" in low:
|
|
135
|
+
return "generic"
|
|
136
|
+
raise InputError("cannot recognise the export format from its header. Pass --format, or rename columns to "
|
|
137
|
+
"the generic layout (date, cost, service, ...). Header starts: %s" % ", ".join(headers[:8]))
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def resolve(headers: list, spec: dict) -> dict:
|
|
141
|
+
low = {h.lower(): h for h in headers}
|
|
142
|
+
m = {}
|
|
143
|
+
for field, cands in spec.items():
|
|
144
|
+
if field in ("detect", "tag_prefix", "tags_json"):
|
|
145
|
+
continue
|
|
146
|
+
m[field] = next((low[c.lower()] for c in cands if c.lower() in low), None)
|
|
147
|
+
m["tags_json"] = next((low[c.lower()] for c in spec["tags_json"] if c.lower() in low), None)
|
|
148
|
+
m["tag_cols"] = {}
|
|
149
|
+
for pre in spec["tag_prefix"]:
|
|
150
|
+
for h in headers:
|
|
151
|
+
if h.lower().startswith(pre.lower()) and h != m["tags_json"] and len(h) > len(pre):
|
|
152
|
+
key = h[len(pre):]
|
|
153
|
+
key = key[5:] if key.lower().startswith("user:") else key
|
|
154
|
+
key = key[5:] if key.lower().startswith("user_") else key
|
|
155
|
+
m["tag_cols"][key] = h
|
|
156
|
+
for need in ("date", "cost"):
|
|
157
|
+
if not m.get(need):
|
|
158
|
+
raise InputError("no %s column found. Tried: %s" % (need, ", ".join(spec[need])))
|
|
159
|
+
return m
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
# --------------------------------------------------------------- parsing
|
|
163
|
+
|
|
164
|
+
def num(raw, where):
|
|
165
|
+
s = (raw or "").strip().replace(",", "")
|
|
166
|
+
if s == "":
|
|
167
|
+
return 0.0
|
|
168
|
+
try:
|
|
169
|
+
return float(s)
|
|
170
|
+
except ValueError:
|
|
171
|
+
raise InputError("%s: cost value %r is not a number" % (where, raw))
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def day(raw, where):
|
|
175
|
+
s = (raw or "").strip()
|
|
176
|
+
m = re.match(r"(\d{4})-(\d{2})-(\d{2})", s) or re.match(r"(\d{1,2})/(\d{1,2})/(\d{4})", s)
|
|
177
|
+
if not m:
|
|
178
|
+
raise InputError("%s: cannot read date %r (expected YYYY-MM-DD... or MM/DD/YYYY)" % (where, raw))
|
|
179
|
+
try:
|
|
180
|
+
if "/" in m.group(0):
|
|
181
|
+
return date(int(m.group(3)), int(m.group(1)), int(m.group(2)))
|
|
182
|
+
return date(int(m.group(1)), int(m.group(2)), int(m.group(3)))
|
|
183
|
+
except ValueError:
|
|
184
|
+
raise InputError("%s: invalid date %r" % (where, raw))
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def parse_tags(raw):
|
|
188
|
+
s = (raw or "").strip()
|
|
189
|
+
if not s:
|
|
190
|
+
return {}
|
|
191
|
+
for cand in (s, "{" + s + "}"):
|
|
192
|
+
try:
|
|
193
|
+
v = json.loads(cand)
|
|
194
|
+
except ValueError:
|
|
195
|
+
continue
|
|
196
|
+
if isinstance(v, dict):
|
|
197
|
+
return {str(k).replace("user:", ""): str(x) for k, x in v.items()}
|
|
198
|
+
if isinstance(v, list):
|
|
199
|
+
return {str(i.get("key")): str(i.get("value")) for i in v if isinstance(i, dict)}
|
|
200
|
+
return {}
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def credits_value(raw):
|
|
204
|
+
s = (raw or "").strip()
|
|
205
|
+
if not s:
|
|
206
|
+
return 0.0
|
|
207
|
+
try:
|
|
208
|
+
return float(s)
|
|
209
|
+
except ValueError:
|
|
210
|
+
pass
|
|
211
|
+
try:
|
|
212
|
+
v = json.loads(s)
|
|
213
|
+
return sum(float(c.get("amount", 0)) for c in v) if isinstance(v, list) else 0.0
|
|
214
|
+
except ValueError:
|
|
215
|
+
return 0.0
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def classify(fmt, r, m, where):
|
|
219
|
+
"""Return (kind, pricing, cost, od_equiv). kind: usage, commitment_fee, tax, credit, refund, skip."""
|
|
220
|
+
g = lambda f: (r.get(m[f]) or "").strip() if m.get(f) else ""
|
|
221
|
+
cost = num(r.get(m["cost"]), where)
|
|
222
|
+
lt = g("line_type")
|
|
223
|
+
ut = g("usage_type")
|
|
224
|
+
ltl = lt.lower()
|
|
225
|
+
if fmt in ("aws-cur", "aws-cur2"):
|
|
226
|
+
if lt == "SavingsPlanNegation":
|
|
227
|
+
return "skip", None, cost, 0.0
|
|
228
|
+
if lt in ("SavingsPlanRecurringFee", "SavingsPlanUpfrontFee", "RIFee", "Fee"):
|
|
229
|
+
return "commitment_fee", None, cost, 0.0
|
|
230
|
+
if lt == "Tax":
|
|
231
|
+
return "tax", None, cost, 0.0
|
|
232
|
+
if lt in ("Credit", "BundledDiscount", "EdpDiscount", "PrivateRateDiscount", "SppDiscount", "Discount"):
|
|
233
|
+
return "credit", None, cost, 0.0
|
|
234
|
+
if lt == "Refund":
|
|
235
|
+
return "refund", None, cost, 0.0
|
|
236
|
+
if lt == "SavingsPlanCoveredUsage":
|
|
237
|
+
eff = g("sp_effective")
|
|
238
|
+
return "usage", "commitment", num(eff, where) if eff else cost, cost
|
|
239
|
+
if lt == "DiscountedUsage":
|
|
240
|
+
eff = g("ri_effective")
|
|
241
|
+
return "usage", "commitment", num(eff, where) if eff else cost, cost
|
|
242
|
+
return "usage", ("spot" if "SpotUsage" in ut else "on_demand"), cost, cost
|
|
243
|
+
if fmt == "gcp":
|
|
244
|
+
net = cost + (credits_value(r.get(m["credits"])) if m.get("credits") else 0.0)
|
|
245
|
+
if ltl == "tax":
|
|
246
|
+
return "tax", None, cost, 0.0
|
|
247
|
+
if ut.lower().startswith("commitment"):
|
|
248
|
+
return "commitment_fee", None, net, 0.0
|
|
249
|
+
pr = "spot" if re.search(r"spot|preemptible", ut, re.I) else "unknown"
|
|
250
|
+
return "usage", pr, net, net
|
|
251
|
+
if fmt == "azure":
|
|
252
|
+
pm = g("pricing").lower()
|
|
253
|
+
if ltl == "purchase":
|
|
254
|
+
return "commitment_fee", None, cost, 0.0
|
|
255
|
+
if ltl == "refund":
|
|
256
|
+
return "refund", None, cost, 0.0
|
|
257
|
+
if ltl in ("tax",):
|
|
258
|
+
return "tax", None, cost, 0.0
|
|
259
|
+
if ltl.startswith("unused"):
|
|
260
|
+
return "usage", "unused_commitment", cost, 0.0
|
|
261
|
+
pr = {"ondemand": "on_demand", "reservation": "commitment", "savingsplan": "commitment",
|
|
262
|
+
"spot": "spot"}.get(pm.replace(" ", ""), "unknown" if not pm else "on_demand")
|
|
263
|
+
return "usage", pr, cost, cost
|
|
264
|
+
# generic
|
|
265
|
+
kind = ltl if ltl in ("usage", "commitment_fee", "tax", "credit", "refund") else "usage"
|
|
266
|
+
pm = g("pricing").lower().replace("-", "_")
|
|
267
|
+
pr = pm if pm in ("on_demand", "commitment", "spot", "unused_commitment") else "unknown"
|
|
268
|
+
return kind, (pr if kind == "usage" else None), cost, cost
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def load(path: Path, fmt_arg: str):
|
|
272
|
+
if not path.exists():
|
|
273
|
+
raise InputError("file not found: %s" % path)
|
|
274
|
+
with path.open(newline="", encoding="utf-8-sig") as f:
|
|
275
|
+
reader = csv.DictReader(f)
|
|
276
|
+
headers = [h.strip() for h in (reader.fieldnames or [])]
|
|
277
|
+
if not headers:
|
|
278
|
+
raise InputError("%s is empty or has no header row" % path)
|
|
279
|
+
reader.fieldnames = headers
|
|
280
|
+
fmt = detect_format(headers) if fmt_arg == "auto" else fmt_arg
|
|
281
|
+
m = resolve(headers, FORMATS[fmt])
|
|
282
|
+
rows = []
|
|
283
|
+
for i, r in enumerate(reader, start=2):
|
|
284
|
+
where = "line %d" % i
|
|
285
|
+
kind, pricing, cost, od = classify(fmt, r, m, where)
|
|
286
|
+
g = lambda f: (r.get(m[f]) or "").strip() if m.get(f) else ""
|
|
287
|
+
ut = g("usage_type")
|
|
288
|
+
if m.get("usage_type2") and g("usage_type2"):
|
|
289
|
+
ut = (ut + " " + g("usage_type2")).strip()
|
|
290
|
+
tags = parse_tags(r.get(m["tags_json"])) if m["tags_json"] else {}
|
|
291
|
+
for k, col in m["tag_cols"].items():
|
|
292
|
+
v = (r.get(col) or "").strip()
|
|
293
|
+
if v:
|
|
294
|
+
tags[k] = v
|
|
295
|
+
rows.append({"day": day(r.get(m["date"]), where), "kind": kind, "pricing": pricing, "cost": cost,
|
|
296
|
+
"od": od, "service": g("service") or "(none)", "account": g("account") or "(none)",
|
|
297
|
+
"region": g("region") or "(none)", "usage_type": ut or "(none)",
|
|
298
|
+
"resource": g("resource_id"), "tags": tags})
|
|
299
|
+
if not rows:
|
|
300
|
+
raise InputError("%s has a header but no rows" % path)
|
|
301
|
+
used = {k: v for k, v in m.items() if v and k not in ("tag_cols",)}
|
|
302
|
+
used["tag_columns"] = sorted(m["tag_cols"].values())
|
|
303
|
+
return fmt, used, rows
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
# --------------------------------------------------------------- analysis
|
|
307
|
+
|
|
308
|
+
def mkey(d):
|
|
309
|
+
return "%04d-%02d" % (d.year, d.month)
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def r2(x):
|
|
313
|
+
return round(x, 2)
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def change(cur, prev, cur_days, prev_days, normalise):
|
|
317
|
+
if normalise:
|
|
318
|
+
cur_v, prev_v = cur / cur_days if cur_days else 0.0, prev / prev_days if prev_days else 0.0
|
|
319
|
+
else:
|
|
320
|
+
cur_v, prev_v = cur, prev
|
|
321
|
+
delta = cur_v - prev_v
|
|
322
|
+
pct = None if prev_v == 0 else delta / prev_v
|
|
323
|
+
return delta, pct
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
def analyse(rows, tags_wanted, month_arg, top, fmt="generic"):
|
|
327
|
+
months = sorted({mkey(r["day"]) for r in rows})
|
|
328
|
+
cur_m = month_arg or months[-1]
|
|
329
|
+
if cur_m not in months:
|
|
330
|
+
raise InputError("--month %s not in the data (months present: %s)" % (cur_m, ", ".join(months)))
|
|
331
|
+
idx = months.index(cur_m)
|
|
332
|
+
prev_m = months[idx - 1] if idx > 0 else None
|
|
333
|
+
notes = []
|
|
334
|
+
days_seen = defaultdict(set)
|
|
335
|
+
for r in rows:
|
|
336
|
+
days_seen[mkey(r["day"])].add(r["day"])
|
|
337
|
+
|
|
338
|
+
def coverage_of(m):
|
|
339
|
+
y, mo = int(m[:4]), int(m[5:])
|
|
340
|
+
n = monthrange(y, mo)[1]
|
|
341
|
+
return len(days_seen[m]), n
|
|
342
|
+
|
|
343
|
+
cur_days, cur_cal = coverage_of(cur_m)
|
|
344
|
+
prev_days, prev_cal = coverage_of(prev_m) if prev_m else (0, 0)
|
|
345
|
+
monthly_grain = all(len(v) == 1 for v in days_seen.values())
|
|
346
|
+
partial = (not monthly_grain) and (cur_days < cur_cal or (prev_m is not None and prev_days < prev_cal))
|
|
347
|
+
if monthly_grain:
|
|
348
|
+
notes.append("Each month has a single date, so the export looks monthly. Totals are compared as they are; "
|
|
349
|
+
"the script cannot tell whether a month is complete.")
|
|
350
|
+
if partial:
|
|
351
|
+
notes.append("At least one month is partial (%s: %d of %d days%s). Month-over-month change is computed on "
|
|
352
|
+
"average daily spend, not totals." % (cur_m, cur_days, cur_cal,
|
|
353
|
+
"; %s: %d of %d days" % (prev_m, prev_days, prev_cal) if prev_m else ""))
|
|
354
|
+
if prev_m is None:
|
|
355
|
+
notes.append("No month before %s in the data, so there is no month-over-month change or movers list." % cur_m)
|
|
356
|
+
elif (int(cur_m[:4]) * 12 + int(cur_m[5:])) - (int(prev_m[:4]) * 12 + int(prev_m[5:])) != 1:
|
|
357
|
+
notes.append("The comparison month %s is not the calendar month before %s; a month is missing from the data." % (prev_m, cur_m))
|
|
358
|
+
|
|
359
|
+
usage = [r for r in rows if r["kind"] == "usage"]
|
|
360
|
+
in_m = lambda r, m: m is not None and mkey(r["day"]) == m
|
|
361
|
+
|
|
362
|
+
def total(rs, m):
|
|
363
|
+
return sum(r["cost"] for r in rs if in_m(r, m))
|
|
364
|
+
|
|
365
|
+
# non-usage lines
|
|
366
|
+
other = {}
|
|
367
|
+
for kind in ("commitment_fee", "tax", "credit", "refund", "skip"):
|
|
368
|
+
other[kind] = {"current": r2(total([r for r in rows if r["kind"] == kind], cur_m)),
|
|
369
|
+
"previous": r2(total([r for r in rows if r["kind"] == kind], prev_m)) if prev_m else None}
|
|
370
|
+
|
|
371
|
+
cur_total, prev_total = total(usage, cur_m), total(usage, prev_m) if prev_m else 0.0
|
|
372
|
+
d, p = change(cur_total, prev_total, cur_days, prev_days, partial) if prev_m else (None, None)
|
|
373
|
+
headline = {"usage_cost_current": r2(cur_total), "usage_cost_previous": r2(prev_total) if prev_m else None,
|
|
374
|
+
"change": r2(d) if d is not None else None, "change_pct": round(p, 4) if p is not None else None,
|
|
375
|
+
"basis": "average daily spend (change columns are per day)" if partial else "monthly totals"}
|
|
376
|
+
|
|
377
|
+
def group(keyf, rs=None):
|
|
378
|
+
rs = usage if rs is None else rs
|
|
379
|
+
acc = defaultdict(lambda: [0.0, 0.0])
|
|
380
|
+
for r in rs:
|
|
381
|
+
if in_m(r, cur_m):
|
|
382
|
+
acc[keyf(r)][0] += r["cost"]
|
|
383
|
+
elif in_m(r, prev_m):
|
|
384
|
+
acc[keyf(r)][1] += r["cost"]
|
|
385
|
+
out = []
|
|
386
|
+
for k, (c, pv) in acc.items():
|
|
387
|
+
dd, pp = change(c, pv, cur_days, prev_days, partial) if prev_m else (None, None)
|
|
388
|
+
out.append({"key": k, "current": r2(c), "previous": r2(pv) if prev_m else None,
|
|
389
|
+
"change": r2(dd) if dd is not None else None,
|
|
390
|
+
"change_pct": round(pp, 4) if pp is not None else None,
|
|
391
|
+
"share_of_current": round(c / cur_total, 4) if cur_total else None,
|
|
392
|
+
"status": ("new" if prev_m and pv == 0 and c != 0 else "gone" if prev_m and c == 0 and pv != 0 else "")})
|
|
393
|
+
return out
|
|
394
|
+
|
|
395
|
+
by_service = sorted(group(lambda r: r["service"]), key=lambda x: -x["current"])
|
|
396
|
+
by_account = sorted(group(lambda r: r["account"]), key=lambda x: -x["current"])
|
|
397
|
+
by_region = sorted(group(lambda r: r["region"]), key=lambda x: -x["current"])
|
|
398
|
+
lines = group(lambda r: "%s / %s" % (r["service"], r["usage_type"]))
|
|
399
|
+
movers = sorted([x for x in lines if x["change"] is not None], key=lambda x: -abs(x["change"]))[:top] if prev_m else []
|
|
400
|
+
res_rows = [r for r in usage if r["resource"]]
|
|
401
|
+
top_resources = sorted(group(lambda r: "%s / %s / %s" % (r["resource"], r["service"], r["usage_type"]), res_rows),
|
|
402
|
+
key=lambda x: -x["current"])[:top]
|
|
403
|
+
|
|
404
|
+
# tags
|
|
405
|
+
tag_report = {}
|
|
406
|
+
for t in tags_wanted:
|
|
407
|
+
per = {}
|
|
408
|
+
for m in [x for x in (prev_m, cur_m) if x]:
|
|
409
|
+
tot = total(usage, m)
|
|
410
|
+
un = sum(r["cost"] for r in usage if in_m(r, m) and not r["tags"].get(t))
|
|
411
|
+
taggable = [r for r in usage if in_m(r, m) and r["resource"]]
|
|
412
|
+
ttot = sum(r["cost"] for r in taggable)
|
|
413
|
+
tun = sum(r["cost"] for r in taggable if not r["tags"].get(t))
|
|
414
|
+
per[m] = {"untagged_cost": r2(un), "untagged_share": round(un / tot, 4) if tot else None,
|
|
415
|
+
"untagged_share_of_taggable": round(tun / ttot, 4) if ttot else None,
|
|
416
|
+
"spend_without_resource_id": r2(tot - ttot)}
|
|
417
|
+
values = sorted(group(lambda r: r["tags"].get(t) or "(untagged)"), key=lambda x: -x["current"])
|
|
418
|
+
untagged_svcs = sorted(group(lambda r: r["service"], [r for r in usage if not r["tags"].get(t)]),
|
|
419
|
+
key=lambda x: -x["current"])[:5]
|
|
420
|
+
tag_report[t] = {"by_month": per, "by_value": values, "top_untagged_services": untagged_svcs}
|
|
421
|
+
all_keys = sorted({k for r in usage for k in r["tags"]})
|
|
422
|
+
if tags_wanted and not any(t in all_keys for t in tags_wanted):
|
|
423
|
+
notes.append("None of the requested tag keys (%s) appear in the data. Tag keys found: %s."
|
|
424
|
+
% (", ".join(tags_wanted), ", ".join(all_keys) or "none"))
|
|
425
|
+
|
|
426
|
+
# hot spots
|
|
427
|
+
def category(r):
|
|
428
|
+
for name, rx in HOTSPOTS:
|
|
429
|
+
if rx.search(r["usage_type"]) or rx.search(r["service"]):
|
|
430
|
+
return name
|
|
431
|
+
return None
|
|
432
|
+
|
|
433
|
+
hot = {}
|
|
434
|
+
for name, _rx in HOTSPOTS:
|
|
435
|
+
sel = [r for r in usage if category(r) == name]
|
|
436
|
+
c, pv = total(sel, cur_m), total(sel, prev_m) if prev_m else 0.0
|
|
437
|
+
top_lines = sorted(group(lambda r: "%s / %s / %s / %s" % (r["account"], r["region"], r["service"], r["usage_type"]), sel),
|
|
438
|
+
key=lambda x: -x["current"])[:5]
|
|
439
|
+
hot[name] = {"current": r2(c), "previous": r2(pv) if prev_m else None,
|
|
440
|
+
"share_of_current": round(c / cur_total, 4) if cur_total else None, "top_lines": top_lines}
|
|
441
|
+
|
|
442
|
+
# commitments
|
|
443
|
+
comp = [r for r in usage if in_m(r, cur_m) and (COMPUTE_RE.search(r["usage_type"]) or r["service"] == "Virtual Machines"
|
|
444
|
+
or (fmt == "generic" and GENERIC_COMPUTE_SERVICE_RE.search(r["service"]))
|
|
445
|
+
or r["pricing"] == "commitment")]
|
|
446
|
+
covered_od = sum(r["od"] for r in comp if r["pricing"] == "commitment")
|
|
447
|
+
covered_eff = sum(r["cost"] for r in comp if r["pricing"] == "commitment")
|
|
448
|
+
on_demand = sum(r["od"] for r in comp if r["pricing"] == "on_demand")
|
|
449
|
+
spot = sum(r["cost"] for r in comp if r["pricing"] == "spot")
|
|
450
|
+
unknown = sum(r["cost"] for r in comp if r["pricing"] == "unknown")
|
|
451
|
+
unused = sum(r["cost"] for r in usage if in_m(r, cur_m) and r["pricing"] == "unused_commitment")
|
|
452
|
+
od_by_svc = defaultdict(float)
|
|
453
|
+
for r in comp:
|
|
454
|
+
if r["pricing"] == "on_demand":
|
|
455
|
+
od_by_svc[r["service"]] += r["od"]
|
|
456
|
+
commit = {"compute_on_demand": r2(on_demand),
|
|
457
|
+
"on_demand_by_service": {k: r2(v) for k, v in sorted(od_by_svc.items(), key=lambda kv: -kv[1])}, "compute_covered_on_demand_equivalent": r2(covered_od),
|
|
458
|
+
"compute_covered_effective_cost": r2(covered_eff), "compute_spot": r2(spot),
|
|
459
|
+
"compute_pricing_unknown": r2(unknown), "unused_commitment_lines": r2(unused),
|
|
460
|
+
"coverage": round(covered_od / (covered_od + on_demand), 4) if (covered_od + on_demand) and not unknown else None,
|
|
461
|
+
"commitment_fees": other["commitment_fee"]["current"]}
|
|
462
|
+
fees = other["commitment_fee"]["current"]
|
|
463
|
+
if fees and covered_eff:
|
|
464
|
+
commit["utilisation_estimate"] = round(min(covered_eff / fees, 9.99), 4)
|
|
465
|
+
if unknown and not (covered_od + on_demand):
|
|
466
|
+
notes.append("Commitment coverage not computed: this export does not mark which compute usage is on demand "
|
|
467
|
+
"and which is covered. Use the provider's coverage report, or add a pricing_model column.")
|
|
468
|
+
# steady on-demand floor
|
|
469
|
+
daily = defaultdict(float)
|
|
470
|
+
for r in comp:
|
|
471
|
+
if r["pricing"] == "on_demand":
|
|
472
|
+
daily[r["day"]] += r["od"]
|
|
473
|
+
if cur_days >= 20 and daily:
|
|
474
|
+
vals = sorted(daily.get(d, 0.0) for d in days_seen[cur_m])
|
|
475
|
+
k = max(0, int(round(0.10 * (len(vals) - 1))))
|
|
476
|
+
commit["daily_on_demand_compute_min"] = r2(vals[0])
|
|
477
|
+
commit["daily_on_demand_compute_p10"] = r2(vals[k])
|
|
478
|
+
commit["daily_on_demand_compute_median"] = r2(vals[len(vals) // 2])
|
|
479
|
+
per = defaultdict(lambda: defaultdict(float))
|
|
480
|
+
for r in comp:
|
|
481
|
+
if r["pricing"] == "on_demand":
|
|
482
|
+
per[r["service"]][r["day"]] += r["od"]
|
|
483
|
+
commit["daily_on_demand_min_by_service"] = {
|
|
484
|
+
k: r2(min(v.get(d, 0.0) for d in days_seen[cur_m])) for k, v in per.items()}
|
|
485
|
+
elif daily and not monthly_grain:
|
|
486
|
+
notes.append("The data is not daily (or the month has under 20 days), so no steady on-demand floor is computed.")
|
|
487
|
+
|
|
488
|
+
neg = [r for r in usage if in_m(r, cur_m) and r["cost"] < 0]
|
|
489
|
+
if neg:
|
|
490
|
+
notes.append("%d usage line(s) in %s have negative cost; check for credits recorded as usage." % (len(neg), cur_m))
|
|
491
|
+
|
|
492
|
+
return {"current_month": cur_m, "previous_month": prev_m, "months_in_data": months,
|
|
493
|
+
"days_with_data": {cur_m: cur_days, **({prev_m: prev_days} if prev_m else {})},
|
|
494
|
+
"headline": headline, "non_usage_lines": other, "by_service": by_service, "by_account": by_account,
|
|
495
|
+
"by_region": by_region, "top_movers": movers, "top_resources": top_resources, "tags": tag_report,
|
|
496
|
+
"tag_keys_in_data": all_keys, "hot_spots": hot, "commitments": commit, "notes": notes}
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
# --------------------------------------------------------------- render
|
|
500
|
+
|
|
501
|
+
def money(x):
|
|
502
|
+
if x is None:
|
|
503
|
+
return "n/a"
|
|
504
|
+
return ("-$%s" if x < 0 else "$%s") % "{:,.2f}".format(abs(x))
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
def pc(x):
|
|
508
|
+
return "n/a" if x is None else "%+.1f%%" % (x * 100)
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
def share(x):
|
|
512
|
+
return "n/a" if x is None else "%.1f%%" % (x * 100)
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
CHANGE_LABEL = ["Change"]
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
def table(items, label, limit=None):
|
|
519
|
+
out = ["| %s | Current | Previous | %s | Change %% | Share |" % (label, CHANGE_LABEL[0]), "|---|---:|---:|---:|---:|---:|"]
|
|
520
|
+
for x in items[:limit] if limit else items:
|
|
521
|
+
st = " (%s)" % x["status"] if x["status"] else ""
|
|
522
|
+
out.append("| %s%s | %s | %s | %s | %s | %s |" % (str(x["key"]).replace("|", "\\|"), st, money(x["current"]), money(x["previous"]),
|
|
523
|
+
money(x["change"]), pc(x["change_pct"]), share(x["share_of_current"])))
|
|
524
|
+
return out
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
def render(fmt, used, a, top):
|
|
528
|
+
h = a["headline"]
|
|
529
|
+
CHANGE_LABEL[0] = "Change per day" if h["basis"].startswith("average") else "Change"
|
|
530
|
+
o = ["# Cloud cost summary: %s vs %s" % (a["current_month"], a["previous_month"] or "n/a"), ""]
|
|
531
|
+
o.append("Format: %s. Days with data: %s. Change basis: %s. Amounts are usage line items at effective cost; "
|
|
532
|
+
"tax, credits, refunds and commitment fees are listed separately." %
|
|
533
|
+
(fmt, ", ".join("%s=%d" % kv for kv in a["days_with_data"].items()), h["basis"]))
|
|
534
|
+
o.append("")
|
|
535
|
+
o.append("| | %s | %s | %s |" % (a["current_month"], a["previous_month"] or "previous", CHANGE_LABEL[0]))
|
|
536
|
+
o.append("|---|---:|---:|---:|")
|
|
537
|
+
o.append("| Usage cost | %s | %s | %s (%s) |" % (money(h["usage_cost_current"]), money(h["usage_cost_previous"]),
|
|
538
|
+
money(h["change"]), pc(h["change_pct"])))
|
|
539
|
+
for k, lab in (("commitment_fee", "Commitment fees"), ("tax", "Tax"), ("credit", "Credits and discounts"),
|
|
540
|
+
("refund", "Refunds"), ("skip", "Excluded (savings plan negation)")):
|
|
541
|
+
v = a["non_usage_lines"][k]
|
|
542
|
+
if v["current"] or v["previous"]:
|
|
543
|
+
o.append("| %s | %s | %s | |" % (lab, money(v["current"]), money(v["previous"])))
|
|
544
|
+
o += ["", "## By service", ""] + table(a["by_service"], "Service", top)
|
|
545
|
+
o += ["", "## By account / project / subscription", ""] + table(a["by_account"], "Account", top)
|
|
546
|
+
o += ["", "## By region", ""] + table(a["by_region"], "Region", top)
|
|
547
|
+
if a["top_movers"]:
|
|
548
|
+
o += ["", "## Top movers (service / usage type)", ""] + table(a["top_movers"], "Line")
|
|
549
|
+
o += ["", "## Top resources by current cost", ""] + table(a["top_resources"], "Resource / service / usage type")
|
|
550
|
+
for t, rep in a["tags"].items():
|
|
551
|
+
o += ["", "## Tag `%s`" % t, ""]
|
|
552
|
+
o.append("| Month | Untagged cost | Untagged share | Untagged share of spend with a resource id | Spend with no resource id |")
|
|
553
|
+
o.append("|---|---:|---:|---:|---:|")
|
|
554
|
+
for m, v in rep["by_month"].items():
|
|
555
|
+
o.append("| %s | %s | %s | %s | %s |" % (m, money(v["untagged_cost"]), share(v["untagged_share"]),
|
|
556
|
+
share(v["untagged_share_of_taggable"]), money(v["spend_without_resource_id"])))
|
|
557
|
+
o += [""] + table(rep["by_value"], "Value of %s" % t, top)
|
|
558
|
+
o += ["", "Top services with no `%s` tag:" % t, ""] + table(rep["top_untagged_services"], "Service")
|
|
559
|
+
o += ["", "## Hot spots", "", "| Category | Current | Previous | Share of usage |", "|---|---:|---:|---:|"]
|
|
560
|
+
for name, v in a["hot_spots"].items():
|
|
561
|
+
o.append("| %s | %s | %s | %s |" % (name.replace("_", " "), money(v["current"]), money(v["previous"]), share(v["share_of_current"])))
|
|
562
|
+
for name, v in a["hot_spots"].items():
|
|
563
|
+
if v["current"] > 0 and v["top_lines"]:
|
|
564
|
+
o += ["", "Top %s lines (account / region / service / usage type):" % name.replace("_", " "), ""]
|
|
565
|
+
o += table(v["top_lines"], "Line")
|
|
566
|
+
c = a["commitments"]
|
|
567
|
+
o += ["", "## Commitments (%s, compute usage)" % a["current_month"], "", "| Measure | Value |", "|---|---:|"]
|
|
568
|
+
for k in ("compute_on_demand", "compute_covered_on_demand_equivalent", "compute_covered_effective_cost",
|
|
569
|
+
"compute_spot", "compute_pricing_unknown", "commitment_fees", "unused_commitment_lines"):
|
|
570
|
+
o.append("| %s | %s |" % (k.replace("_", " "), money(c[k])))
|
|
571
|
+
for svc_name, v in c["on_demand_by_service"].items():
|
|
572
|
+
o.append("| on demand: %s | %s |" % (svc_name, money(v)))
|
|
573
|
+
o.append("| coverage (covered / covered + on demand, on-demand-equivalent basis) | %s |" % share(c["coverage"]))
|
|
574
|
+
if "utilisation_estimate" in c:
|
|
575
|
+
o.append("| utilisation estimate (covered effective cost / commitment fees) | %s |" % share(c["utilisation_estimate"]))
|
|
576
|
+
for k in ("daily_on_demand_compute_min", "daily_on_demand_compute_p10", "daily_on_demand_compute_median"):
|
|
577
|
+
if k in c:
|
|
578
|
+
o.append("| %s | %s |" % (k.replace("_", " "), money(c[k])))
|
|
579
|
+
for svc_name, v in c.get("daily_on_demand_min_by_service", {}).items():
|
|
580
|
+
o.append("| daily on demand min: %s | %s |" % (svc_name, money(v)))
|
|
581
|
+
o += ["", "## Column mapping used", ""]
|
|
582
|
+
for k, v in used.items():
|
|
583
|
+
o.append("- %s: %s" % (k, ", ".join(v) if isinstance(v, list) else v))
|
|
584
|
+
if a["tag_keys_in_data"]:
|
|
585
|
+
o.append("- tag keys found: %s" % ", ".join(a["tag_keys_in_data"]))
|
|
586
|
+
if a["notes"]:
|
|
587
|
+
o += ["", "## Notes", ""] + ["- " + n for n in a["notes"]]
|
|
588
|
+
return "\n".join(o) + "\n"
|
|
589
|
+
|
|
590
|
+
|
|
591
|
+
def main(argv=None):
|
|
592
|
+
ap = argparse.ArgumentParser(description="Summarise a cloud cost export CSV.")
|
|
593
|
+
ap.add_argument("csv")
|
|
594
|
+
ap.add_argument("--format", default="auto", choices=["auto"] + list(FORMATS))
|
|
595
|
+
ap.add_argument("--tag", action="append", default=[], help="tag/label key to report untagged share for (repeatable)")
|
|
596
|
+
ap.add_argument("--month", help="month to analyse, YYYY-MM (default: latest in data)")
|
|
597
|
+
ap.add_argument("--top", type=int, default=10)
|
|
598
|
+
ap.add_argument("--out")
|
|
599
|
+
ap.add_argument("--json")
|
|
600
|
+
args = ap.parse_args(argv)
|
|
601
|
+
try:
|
|
602
|
+
if args.month and not re.fullmatch(r"\d{4}-(0[1-9]|1[0-2])", args.month):
|
|
603
|
+
raise InputError("--month must be YYYY-MM, got %r" % args.month)
|
|
604
|
+
if args.top < 1:
|
|
605
|
+
raise InputError("--top must be at least 1")
|
|
606
|
+
fmt, used, rows = load(Path(args.csv), args.format)
|
|
607
|
+
a = analyse(rows, args.tag, args.month, args.top, fmt)
|
|
608
|
+
except InputError as e:
|
|
609
|
+
print("error: %s" % e, file=sys.stderr)
|
|
610
|
+
return 2
|
|
611
|
+
report = render(fmt, used, a, args.top)
|
|
612
|
+
if args.out:
|
|
613
|
+
Path(args.out).parent.mkdir(parents=True, exist_ok=True)
|
|
614
|
+
Path(args.out).write_text(report, encoding="utf-8")
|
|
615
|
+
print("wrote %s" % args.out, file=sys.stderr)
|
|
616
|
+
else:
|
|
617
|
+
sys.stdout.write(report)
|
|
618
|
+
if args.json:
|
|
619
|
+
payload = json.dumps({"format": fmt, "columns": used, **a}, indent=2, default=str)
|
|
620
|
+
if args.json == "-":
|
|
621
|
+
print(payload)
|
|
622
|
+
else:
|
|
623
|
+
Path(args.json).parent.mkdir(parents=True, exist_ok=True)
|
|
624
|
+
Path(args.json).write_text(payload + "\n", encoding="utf-8")
|
|
625
|
+
print("wrote %s" % args.json, file=sys.stderr)
|
|
626
|
+
return 0
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
if __name__ == "__main__":
|
|
630
|
+
sys.exit(main())
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Cloud cost review: <org or account set>, <month> vs <previous month>
|
|
2
|
+
|
|
3
|
+
**Export:** <provider and export type, granularity, date pulled>
|
|
4
|
+
**Basis:** usage at effective cost. Tax, credits, refunds and commitment fees are listed separately.
|
|
5
|
+
**Assumptions to confirm:** <[assumption] lines, or "none">
|
|
6
|
+
|
|
7
|
+
## What changed
|
|
8
|
+
|
|
9
|
+
<One paragraph: the usage total and its change, then the 2–3 named movers that explain it, with amounts.>
|
|
10
|
+
|
|
11
|
+
## Ranked findings
|
|
12
|
+
|
|
13
|
+
| # | Finding | Monthly saving | Confidence | Ease | Rank score | Action |
|
|
14
|
+
|---|---|---:|---|---:|---:|---|
|
|
15
|
+
| 1 | <short noun phrase> | $<n> | High/Medium/Low | 3/2/1 | <saving × ease> | <verb + object + owner> |
|
|
16
|
+
|
|
17
|
+
### 1. <Finding>
|
|
18
|
+
|
|
19
|
+
- **Evidence:** <the lines from the script output: account, usage type, resource, amounts>
|
|
20
|
+
- **Arithmetic:** <the formula with numbers, and the source of any rate>
|
|
21
|
+
- **Check before acting:** <the fact to confirm, and the command or report>
|
|
22
|
+
- **Action:** <what to change, who owns it>
|
|
23
|
+
|
|
24
|
+
## Evidence needed (no saving figure yet)
|
|
25
|
+
|
|
26
|
+
| Candidate | Bill signal | Evidence to collect | How |
|
|
27
|
+
|---|---|---|---|
|
|
28
|
+
| <instance or line> | <cost, trend> | <utilisation, flow logs, access pattern> | <tool or command> |
|
|
29
|
+
|
|
30
|
+
## Untagged spend
|
|
31
|
+
|
|
32
|
+
<Untagged share for each key, against all spend and against spend with a resource id; the top untagged services; and who should own them.>
|
|
33
|
+
|
|
34
|
+
## Excluded from the analysis
|
|
35
|
+
|
|
36
|
+
<Tax, credits, refunds, commitment fees and savings plan negation amounts, from the script.>
|