feat(ms-ai-architect): add plugin to open marketplace (v1.5.0 baseline)

Initial addition of ms-ai-architect plugin to the open-source marketplace.
Private content excluded: orchestrator/ (Linear tooling), docs/utredning/
(client investigation), generated test reports and PDF export script.
skill-gen tooling moved from orchestrator/ to scripts/skill-gen/.

Security scan: WARNING (risk 20/100) — no secrets, no injection found.
False positive fixed: added gitleaks:allow to Python variable reference
in output-validation-grounding-verification.md line 109.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-04-07 17:17:17 +02:00
commit 6a7632146e
490 changed files with 213249 additions and 2 deletions

View file

@ -0,0 +1,211 @@
#!/usr/bin/env python3
"""
Generate a professional PDF from a markdown file.
Requirements:
pip install markdown weasyprint
Usage:
python scripts/export-pdf.py <input.md> [output.pdf]
If output is not specified, uses the same name as input with .pdf extension.
"""
import re
import sys
from pathlib import Path
import markdown
from weasyprint import HTML
# --- CSS ---
CSS = """
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
@page {
size: A4;
margin: 25mm 20mm 25mm 20mm;
@bottom-center {
content: counter(page);
font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
font-size: 8pt;
color: #718096;
}
}
@page :first {
@bottom-center { content: none; }
}
* { box-sizing: border-box; }
body {
font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
font-size: 10.5pt;
line-height: 1.6;
color: #1a202c;
max-width: 100%;
}
h1 {
font-size: 20pt;
font-weight: 700;
color: #1a365d;
margin-top: 32px;
margin-bottom: 12px;
page-break-after: avoid;
}
h2 {
font-size: 15pt;
font-weight: 700;
color: #1a365d;
margin-top: 28px;
margin-bottom: 10px;
padding-bottom: 6px;
border-bottom: 2px solid #e2e8f0;
page-break-after: avoid;
}
h3 {
font-size: 12pt;
font-weight: 600;
color: #2b6cb0;
margin-top: 20px;
margin-bottom: 8px;
page-break-after: avoid;
}
h4 {
font-size: 10.5pt;
font-weight: 600;
color: #2d3748;
margin-top: 16px;
margin-bottom: 6px;
}
table {
width: 100%;
border-collapse: collapse;
margin: 12px 0 20px 0;
font-size: 9pt;
page-break-inside: auto;
}
thead { display: table-header-group; }
tr { page-break-inside: avoid; }
th {
background-color: #2b6cb0;
color: white;
font-weight: 600;
text-align: left;
padding: 8px 10px;
font-size: 8.5pt;
text-transform: uppercase;
letter-spacing: 0.3px;
}
td {
padding: 7px 10px;
border-bottom: 1px solid #e2e8f0;
vertical-align: top;
}
tr:nth-child(even) td { background-color: #f7fafc; }
blockquote {
border-left: 3px solid #2b6cb0;
margin: 12px 0;
padding: 8px 16px;
background: #ebf8ff;
color: #2a4365;
font-size: 10pt;
border-radius: 0 4px 4px 0;
}
code {
background: #edf2f7;
padding: 1px 4px;
border-radius: 3px;
font-size: 9pt;
font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
}
hr {
border: none;
border-top: 2px solid #e2e8f0;
margin: 24px 0;
}
ul, ol { margin: 8px 0 12px 0; padding-left: 24px; }
li { margin-bottom: 4px; }
strong { font-weight: 600; color: #1a202c; }
a { color: #2b6cb0; text-decoration: none; }
p { margin: 8px 0; }
.section-break { page-break-before: always; }
.score-high { color: #276749; font-weight: 700; }
.score-medium { color: #d69e2e; font-weight: 700; }
.score-low { color: #c53030; font-weight: 700; }
"""
def postprocess_html(html: str) -> str:
"""Add CSS classes for scores and risk levels."""
# Section breaks on h2 (except first)
h2_count = 0
def add_section_break(match: re.Match) -> str:
nonlocal h2_count
h2_count += 1
if h2_count > 1:
return f'<h2 class="section-break">{match.group(1)}</h2>'
return match.group(0)
html = re.sub(r"<h2>(.*?)</h2>", add_section_break, html)
# Score coloring: 4/5, 5/5 green; 3/5 yellow; 1/5, 2/5 red
html = re.sub(r"<td>([45])/5</td>", r'<td><span class="score-high">\1/5</span></td>', html)
html = re.sub(r"<td>3/5</td>", '<td><span class="score-medium">3/5</span></td>', html)
html = re.sub(r"<td>([12])/5</td>", r'<td><span class="score-low">\1/5</span></td>', html)
return html
def main() -> None:
if len(sys.argv) < 2:
print("Usage: python export-pdf.py <input.md> [output.pdf]")
sys.exit(1)
input_path = Path(sys.argv[1])
if not input_path.exists():
print(f"Error: {input_path} not found")
sys.exit(1)
output_path = Path(sys.argv[2]) if len(sys.argv) > 2 else input_path.with_suffix(".pdf")
md_text = input_path.read_text(encoding="utf-8")
body_html = markdown.markdown(md_text, extensions=["tables", "smarty", "sane_lists"])
body_html = postprocess_html(body_html)
full_html = f"""<!DOCTYPE html>
<html lang="no">
<head>
<meta charset="UTF-8">
<style>{CSS}</style>
</head>
<body>
{body_html}
</body>
</html>"""
HTML(string=full_html).write_pdf(str(output_path))
print(f"PDF generated: {output_path}")
print(f"Size: {output_path.stat().st_size / 1024:.1f} KB")
if __name__ == "__main__":
main()

View file

@ -0,0 +1,235 @@
#!/bin/bash
# kb-staleness-check.sh — Scan knowledge base files for staleness
# Usage: bash scripts/kb-staleness-check.sh [--days N] [--priority-only] [--verbose] [--json] [--output FILE]
#
# Default threshold: 90 days
# Priority order: prices > compliance > features > architecture
set -euo pipefail
PLUGIN_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
# Scan all skill reference directories
KB_ROOTS=(
"$PLUGIN_ROOT/skills/ms-ai-advisor/references"
"$PLUGIN_ROOT/skills/ms-ai-governance/references"
"$PLUGIN_ROOT/skills/ms-ai-security/references"
"$PLUGIN_ROOT/skills/ms-ai-engineering/references"
"$PLUGIN_ROOT/skills/ms-ai-infrastructure/references"
)
# Defaults
THRESHOLD_DAYS=90
PRIORITY_ONLY=false
VERBOSE=false
JSON_OUTPUT=false
OUTPUT_FILE=""
# Parse arguments
while [[ $# -gt 0 ]]; do
case "$1" in
--days)
THRESHOLD_DAYS="$2"
shift 2
;;
--priority-only)
PRIORITY_ONLY=true
shift
;;
--verbose)
VERBOSE=true
shift
;;
--json)
JSON_OUTPUT=true
shift
;;
--output)
OUTPUT_FILE="$2"
shift 2
;;
*)
echo "Unknown option: $1"
echo "Usage: bash scripts/kb-staleness-check.sh [--days N] [--priority-only] [--verbose] [--json] [--output FILE]"
exit 1
;;
esac
done
for kb_dir in "${KB_ROOTS[@]}"; do
if [ ! -d "$kb_dir" ]; then
echo "WARNING: Knowledge base directory not found: $kb_dir" >&2
fi
done
NOW=$(date +%s)
TOTAL=0
FRESH=0
STALE=0
STALE_CRITICAL=0
STALE_HIGH=0
STALE_MEDIUM=0
STALE_LOW=0
# Collect stale files for sorted summary
declare -a STALE_ENTRIES=()
get_priority() {
local filepath="$1"
local lower_path
lower_path=$(echo "$filepath" | tr '[:upper:]' '[:lower:]')
# Critical (30 days): cost, pricing, pris
if echo "$lower_path" | grep -qE '(cost|pricing|pris)'; then
echo "Critical:30"
return
fi
# High (60 days): compliance, security, governance
if echo "$lower_path" | grep -qE '(responsible-ai|norwegian-public-sector-governance|ai-security-engineering)'; then
echo "High:60"
return
fi
# Medium (90 days): platforms, features, extensibility
if echo "$lower_path" | grep -qE '(platforms|copilot-extensibility|azure-ai-services|multi-modal|performance-scalability|monitoring-observability|agent-orchestration|data-engineering|api-management|hybrid-edge|bcdr|rag-architecture|mlops-genaiops|prompt-engineering)'; then
echo "Medium:90"
return
fi
# Low (180 days): architecture, development, patterns
echo "Low:180"
}
for KB_ROOT in "${KB_ROOTS[@]}"; do
[ -d "$KB_ROOT" ] || continue
while IFS= read -r -d '' file; do
TOTAL=$((TOTAL + 1))
# macOS-compatible stat for modification time
MOD_EPOCH=$(stat -f '%m' "$file" 2>/dev/null || stat -c '%Y' "$file" 2>/dev/null)
DAYS_OLD=$(( (NOW - MOD_EPOCH) / 86400 ))
REL_PATH="${file#"$KB_ROOT/"}"
PRIORITY_INFO=$(get_priority "$REL_PATH")
PRIORITY="${PRIORITY_INFO%%:*}"
PRIORITY_THRESHOLD="${PRIORITY_INFO##*:}"
if [ "$DAYS_OLD" -gt "$PRIORITY_THRESHOLD" ]; then
STALE=$((STALE + 1))
case "$PRIORITY" in
Critical) STALE_CRITICAL=$((STALE_CRITICAL + 1)) ;;
High) STALE_HIGH=$((STALE_HIGH + 1)) ;;
Medium) STALE_MEDIUM=$((STALE_MEDIUM + 1)) ;;
Low) STALE_LOW=$((STALE_LOW + 1)) ;;
esac
FULL_REL="${file#"$PLUGIN_ROOT/"}"
if [ "$JSON_OUTPUT" = true ]; then
echo "[STALE] $REL_PATH${DAYS_OLD} days old (threshold: ${PRIORITY_THRESHOLD}) — Priority: $PRIORITY" >&2
else
echo "[STALE] $REL_PATH${DAYS_OLD} days old (threshold: ${PRIORITY_THRESHOLD}) — Priority: $PRIORITY"
fi
STALE_ENTRIES+=("${DAYS_OLD}:${PRIORITY}:${FULL_REL}")
else
FRESH=$((FRESH + 1))
if [ "$VERBOSE" = true ] && [ "$PRIORITY_ONLY" = false ]; then
if [ "$JSON_OUTPUT" = true ]; then
echo "[FRESH] $REL_PATH${DAYS_OLD} days old (threshold: ${PRIORITY_THRESHOLD}) — Priority: $PRIORITY" >&2
else
echo "[FRESH] $REL_PATH${DAYS_OLD} days old (threshold: ${PRIORITY_THRESHOLD}) — Priority: $PRIORITY"
fi
fi
fi
done < <(find "$KB_ROOT" -name '*.md' -type f -print0)
done
# JSON output mode
if [ "$JSON_OUTPUT" = true ]; then
JSON="{"
JSON+="\"generated_at\":\"$(date -Iseconds)\","
JSON+="\"total\":$TOTAL,"
JSON+="\"fresh\":$FRESH,"
JSON+="\"stale\":$STALE,"
JSON+="\"stale_by_priority\":{\"critical\":$STALE_CRITICAL,\"high\":$STALE_HIGH,\"medium\":$STALE_MEDIUM,\"low\":$STALE_LOW},"
JSON+="\"files\":["
FIRST=true
for entry in "${STALE_ENTRIES[@]}"; do
days="${entry%%:*}"
rest="${entry#*:}"
priority="${rest%%:*}"
filepath="${rest#*:}"
# Determine skill from path
skill="unknown"
case "$filepath" in
*ms-ai-advisor*) skill="ms-ai-advisor" ;;
*ms-ai-engineering*) skill="ms-ai-engineering" ;;
*ms-ai-governance*) skill="ms-ai-governance" ;;
*ms-ai-security*) skill="ms-ai-security" ;;
*ms-ai-infrastructure*) skill="ms-ai-infrastructure" ;;
esac
# Determine category from path
category=$(echo "$filepath" | sed -E 's|.*/references/([^/]+)/.*|\1|')
if [ "$FIRST" = true ]; then
FIRST=false
else
JSON+=","
fi
JSON+="{\"path\":\"$filepath\",\"skill\":\"$skill\",\"category\":\"$category\",\"age_days\":$days,\"priority\":\"$priority\"}"
done
JSON+="]}"
if [ -n "$OUTPUT_FILE" ]; then
echo "$JSON" > "$OUTPUT_FILE"
echo "JSON written to: $OUTPUT_FILE" >&2
else
echo "$JSON"
fi
exit 0
fi
echo ""
echo "=== KB Freshness Report ==="
echo "Total files: $TOTAL"
echo "Fresh: $FRESH"
echo "Stale: $STALE (Critical: $STALE_CRITICAL, High: $STALE_HIGH, Medium: $STALE_MEDIUM, Low: $STALE_LOW)"
if [ "$STALE" -gt 0 ]; then
echo ""
echo "Recommended update order:"
# Sort stale entries: Critical first, then High, Medium, Low; within priority by age descending
PRIORITY_ORDER="Critical High Medium Low"
INDEX=1
for prio in $PRIORITY_ORDER; do
# Collect entries for this priority, sort by age descending
PRIO_ENTRIES=()
for entry in "${STALE_ENTRIES[@]}"; do
entry_prio="${entry#*:}"
entry_prio="${entry_prio%%:*}"
if [ "$entry_prio" = "$prio" ]; then
PRIO_ENTRIES+=("$entry")
fi
done
# Sort by days (first field) descending
if [ ${#PRIO_ENTRIES[@]} -gt 0 ]; then
SORTED=$(printf '%s\n' "${PRIO_ENTRIES[@]}" | sort -t: -k1 -nr)
while IFS= read -r sorted_entry; do
days="${sorted_entry%%:*}"
rest="${sorted_entry#*:}"
rest="${rest#*:}"
echo " ${INDEX}. [$prio] $rest (${days} days)"
INDEX=$((INDEX + 1))
done <<< "$SORTED"
fi
done
fi
echo ""
echo "Run with --verbose to see fresh files. Use --days N to override threshold. Use --json for machine-readable output."

View file

@ -0,0 +1,406 @@
{
"version": "1.0",
"created": "2026-02-03",
"target_dir": "skills/ms-ai-engineering/references",
"total_estimated_skills": "300-350",
"waves": [
{
"wave": 1,
"priority": "HIGH",
"description": "Kritisk manglende kunnskap for enterprise AI-arkitektur",
"categories": [
"azure-ai-services",
"rag-architecture",
"responsible-ai",
"copilot-extensibility",
"prompt-engineering",
"cost-optimization",
"mlops-genaiops"
]
},
{
"wave": 1.5,
"priority": "HIGH",
"description": "Utredningsstøtte: norsk offentlig sektor, AI-sikkerhet og observerbarhet",
"categories": [
"norwegian-public-sector-governance",
"ai-security-engineering",
"monitoring-observability"
]
},
{
"wave": 2,
"priority": "MEDIUM",
"description": "Verdifulle tillegg for komplett arkitekturdekning",
"categories": [
"agent-orchestration",
"bcdr",
"data-engineering",
"api-management",
"hybrid-edge",
"multi-modal",
"performance-scalability"
]
}
],
"categories": {
"azure-ai-services": {
"name": "Azure AI Services (Foundry Tools)",
"dir": "azure-ai-services",
"priority": "HIGH",
"description": "Pre-bygde AI-tjenester: Vision, Speech, Language, Document Intelligence, Translator, Content Understanding. Fundamentale byggeblokker for enterprise AI.",
"estimated_skills": 20,
"examples": [
"azure-ai-vision-overview",
"document-intelligence-models",
"speech-services-architecture",
"language-services-text-analytics",
"content-understanding-multimodal",
"translator-custom-models",
"azure-ai-search-indexing",
"custom-vision-vs-florence",
"ai-services-networking-security",
"ai-services-pricing-optimization"
],
"existing_overlap": ["platforms/azure-ai-foundry.md"],
"notes": "Foundry Tools er ny branding (2025). Unngå duplikering med azure-ai-foundry.md som dekker overordnet plattform."
},
"rag-architecture": {
"name": "RAG Architecture & Semantic Search",
"dir": "rag-architecture",
"priority": "HIGH",
"description": "Retrieval-Augmented Generation med Azure AI Search. Vektorindeksering, embedding, hybrid search, reranking, chunking, citation tracking.",
"estimated_skills": 22,
"examples": [
"rag-architecture-patterns",
"azure-ai-search-vector-indexing",
"embedding-model-selection",
"chunking-strategies",
"hybrid-search-configuration",
"semantic-ranker-optimization",
"rag-evaluation-metrics",
"multi-index-federation",
"rag-security-rbac",
"graphrag-knowledge-graphs"
],
"existing_overlap": ["architecture/decision-trees.md"],
"notes": "RAG er det vanligste mønsteret for enterprise AI. Detaljer er planlagt som ms-rag-architect plugin men grunnleggende arkitektur dekkes her."
},
"responsible-ai": {
"name": "Responsible AI & Governance",
"dir": "responsible-ai",
"priority": "HIGH",
"description": "Microsofts Responsible AI-rammeverk, AI-etikk, bias-deteksjon, forklarbarhet, GDPR/AI Act compliance, AI governance for offentlig sektor.",
"estimated_skills": 22,
"examples": [
"responsible-ai-framework-overview",
"ai-act-compliance-guide",
"bias-detection-mitigation",
"model-explainability-techniques",
"ai-governance-structure",
"ai-center-of-excellence",
"red-teaming-ai-models",
"content-safety-implementation",
"ai-impact-assessment",
"transparency-documentation"
],
"existing_overlap": ["architecture/security.md", "architecture/public-sector-checklist.md"],
"notes": "Utfyller security.md (teknisk sikkerhet) med governance og compliance. Spesielt viktig for offentlig sektor etter AI Act."
},
"copilot-extensibility": {
"name": "Copilot Extensibility & Integration",
"dir": "copilot-extensibility",
"priority": "HIGH",
"description": "Utvidelse av M365 Copilot og Copilot Studio: declarative agents, custom engine agents, plugins, connectors, Graph API, MCP.",
"estimated_skills": 22,
"examples": [
"declarative-agents-overview",
"custom-engine-agents",
"copilot-studio-topics-entities",
"graph-api-for-copilot",
"copilot-connectors-patterns",
"mcp-integration-copilot-studio",
"copilot-analytics-usage",
"teams-copilot-extensions",
"sharepoint-agents",
"copilot-studio-dlp-governance"
],
"existing_overlap": ["platforms/copilot-studio.md", "platforms/m365-copilot.md"],
"notes": "Går dypere enn eksisterende plattformfiler. Fokus på implementeringsmønstre, ikke overordnet arkitektur."
},
"prompt-engineering": {
"name": "Prompt Engineering & LLM Optimization",
"dir": "prompt-engineering",
"priority": "HIGH",
"description": "System message design, few-shot/zero-shot teknikker, chain-of-thought, reasoning-modeller (O1/O3), grounding, output-formatering.",
"estimated_skills": 18,
"examples": [
"system-message-design-patterns",
"few-shot-learning-techniques",
"chain-of-thought-prompting",
"reasoning-models-o1-o3",
"structured-output-json-mode",
"function-calling-patterns",
"grounding-with-search",
"temperature-and-sampling",
"token-optimization-techniques",
"prompt-testing-evaluation"
],
"existing_overlap": [],
"notes": "Helt nytt område. Direkte påvirkning på kvaliteten av alle AI-løsninger."
},
"cost-optimization": {
"name": "Cost Optimization & FinOps for AI",
"dir": "cost-optimization",
"priority": "HIGH",
"description": "Token-optimalisering, caching, reserved capacity, modellvalg, Azure Cost Management, chargeback, budsjettplanlegging for AI.",
"estimated_skills": 20,
"examples": [
"token-cost-optimization",
"semantic-caching-patterns",
"reserved-capacity-planning",
"model-selection-price-performance",
"azure-cost-management-ai",
"ptu-vs-paygo-decision",
"ai-builder-credits-transition",
"cost-allocation-chargeback",
"budget-forecasting-ai",
"small-language-models-cost"
],
"existing_overlap": ["architecture/cost-models.md"],
"notes": "Utfyller cost-models.md med dypere strategier. cost-models.md dekker prislister, dette dekker optimaliseringsteknikker."
},
"mlops-genaiops": {
"name": "MLOps & GenAIOps",
"dir": "mlops-genaiops",
"priority": "HIGH",
"description": "CI/CD for AI, modellmonitorering, versjonshåndtering, A/B-testing, retraining, evaluering, Azure ML pipelines for produksjon.",
"estimated_skills": 22,
"examples": [
"genaiops-overview",
"azure-ml-pipelines",
"model-versioning-registry",
"llm-evaluation-framework",
"ab-testing-ai-models",
"data-drift-monitoring",
"automated-retraining",
"ci-cd-ai-models",
"prompt-flow-production",
"model-deployment-strategies"
],
"existing_overlap": [],
"notes": "Helt nytt område. Kritisk for å gå fra prototyp til produksjon."
},
"data-engineering": {
"name": "Data Engineering for AI",
"dir": "data-engineering",
"priority": "MEDIUM",
"description": "Dataintegrasjon med Microsoft Fabric, Data Factory, OneLake, Databricks. Zero-ETL, lakehouse-arkitektur, AI-drevet dataintegrering.",
"estimated_skills": 22,
"examples": [
"microsoft-fabric-for-ai",
"onelake-data-strategy",
"data-factory-ai-pipelines",
"zero-etl-patterns",
"data-quality-for-ai",
"real-time-streaming-ai",
"dataverse-ai-integration",
"data-lakehouse-architecture",
"data-governance-purview",
"synthetic-data-generation"
],
"existing_overlap": [],
"notes": "Datakvalitet er #1 årsak til AI-prosjektfeil. Microsoft Fabric er raskt voksende."
},
"api-management": {
"name": "API Management & AI Gateway",
"dir": "api-management",
"priority": "MEDIUM",
"description": "Azure API Management som AI-gateway: rate limiting, token quota, load balancing, circuit breaker, autentisering, multi-region.",
"estimated_skills": 18,
"examples": [
"apim-ai-gateway-overview",
"token-rate-limiting",
"load-balancing-openai",
"circuit-breaker-patterns",
"multi-region-gateway",
"apim-authentication-patterns",
"backend-pool-management",
"streaming-support-apim",
"cost-tracking-apim",
"apim-vs-direct-access"
],
"existing_overlap": [],
"notes": "Viktig for enterprise-skalering. APIM AI Gateway er relativt nytt (2024-2025)."
},
"hybrid-edge": {
"name": "Hybrid Cloud & Edge AI",
"dir": "hybrid-edge",
"priority": "MEDIUM",
"description": "Azure Arc, Azure Local, IoT Operations, edge AI inferencing, disconnected scenarios, datasuverenitet for offentlig sektor.",
"estimated_skills": 18,
"examples": [
"azure-arc-ai-management",
"azure-local-ai-workloads",
"edge-ai-inferencing",
"disconnected-ai-scenarios",
"data-sovereignty-patterns",
"iot-operations-ai",
"hybrid-rag-architecture",
"on-premises-llm-deployment",
"azure-confidential-computing",
"sovereign-cloud-norway"
],
"existing_overlap": [],
"notes": "Spesielt relevant for norsk offentlig sektor med suverenitetskrav og sikkerhetsgradert informasjon."
},
"bcdr": {
"name": "Business Continuity & Disaster Recovery",
"dir": "bcdr",
"priority": "MEDIUM",
"description": "HA, DR og BCDR for AI: multi-region, backup, failover, RTO/RPO for Azure OpenAI og AI Foundry.",
"estimated_skills": 16,
"examples": [
"multi-region-azure-openai",
"ai-foundry-dr-planning",
"backup-recovery-strategies",
"failover-testing-ai",
"rto-rpo-ai-services",
"data-replication-patterns",
"geo-redundancy-search",
"incident-response-ai",
"capacity-planning-dr",
"compliance-bcdr-requirements"
],
"existing_overlap": [],
"notes": "Nødvendig for kritiske produksjonssystemer i offentlig sektor."
},
"multi-modal": {
"name": "Multi-Modal AI",
"dir": "multi-modal",
"priority": "MEDIUM",
"description": "Tekst + bilde + tale + video: GPT-4V/GPT-5 vision, Video Indexer, Speech-integrasjon, multi-modal RAG, aksessibilitet.",
"estimated_skills": 18,
"examples": [
"gpt-vision-architecture",
"video-indexer-ai",
"multi-modal-rag",
"speech-to-ai-pipelines",
"image-generation-dall-e",
"document-vision-processing",
"accessibility-multi-modal",
"real-time-audio-api",
"video-analysis-patterns",
"multi-modal-evaluation"
],
"existing_overlap": [],
"notes": "Økende etterspørsel etter multi-modale løsninger. GPT-5 styrker vision-kapabiliteter."
},
"agent-orchestration": {
"name": "Agent Orchestration & Automation",
"dir": "agent-orchestration",
"priority": "MEDIUM",
"description": "Multi-agent systemer, orkesteringsmønstre, agent-kommunikasjon, Agent 365, Semantic Kernel/Agent Framework-mønstre.",
"estimated_skills": 20,
"examples": [
"multi-agent-patterns",
"agent-orchestration-topologies",
"agent-to-agent-communication",
"agent-365-governance",
"semantic-kernel-agents",
"agent-memory-patterns",
"tool-use-patterns",
"agent-evaluation-testing",
"human-in-the-loop-agents",
"autonomous-workflow-patterns"
],
"existing_overlap": ["development/agent-framework.md"],
"notes": "Utfyller agent-framework.md med orkestrerings- og designmønstre."
},
"performance-scalability": {
"name": "Performance & Scalability",
"dir": "performance-scalability",
"priority": "MEDIUM",
"description": "Latency-reduksjon, throughput, caching, batching, streaming, auto-scaling, CDN for AI-workloads.",
"estimated_skills": 18,
"examples": [
"latency-optimization-openai",
"streaming-responses-patterns",
"batch-api-usage",
"auto-scaling-ai-infra",
"cdn-edge-caching-ai",
"connection-pooling-patterns",
"throughput-optimization",
"model-distillation-perf",
"async-processing-patterns",
"load-testing-ai-services"
],
"existing_overlap": [],
"notes": "Viktig for brukeropplevelse. Komplementerer cost-optimization."
},
"monitoring-observability": {
"name": "Monitoring & Observability",
"dir": "monitoring-observability",
"priority": "HIGH",
"description": "Azure Monitor, Application Insights, Log Analytics for AI. Token tracking, anomaly detection, dashboards, alerting.",
"estimated_skills": 18,
"examples": [
"azure-monitor-ai-workloads",
"application-insights-llm",
"token-usage-tracking",
"anomaly-detection-ai",
"custom-ai-dashboards",
"alerting-strategies-ai",
"distributed-tracing-ai",
"log-analytics-ai-queries",
"sla-monitoring-ai",
"cost-attribution-monitoring"
],
"existing_overlap": [],
"notes": "Nødvendig for produksjonsoperasjoner. Komplementerer MLOps."
},
"norwegian-public-sector-governance": {
"name": "Norwegian Public Sector AI Governance",
"dir": "norwegian-public-sector-governance",
"priority": "HIGH",
"description": "Norsk lovverk, Digdir-rammeverk og forvaltningsmetodikk anvendt på AI. Utredningsinstruksen, Digdirs 7 arkitekturprinsipper, rammeverk for digital samhandling (EIF), DPIA, ROS-analyse, NSM grunnprinsipper, anskaffelser og gevinstrealisering for AI i offentlig sektor.",
"estimated_skills": 20,
"research_sources": ["websearch", "regjeringen.no", "lovdata.no", "digdir.no", "nsm.no", "datatilsynet.no"],
"examples": [
"utredningsinstruksen-methodology",
"forvaltningsloven-ai-decisions",
"digdir-principle-1-user-centric",
"digdir-principle-4-trust",
"digital-samhandling-5-layers",
"dpia-norwegian-methodology",
"ros-analyse-ai-systems",
"nsm-grunnprinsipper-ai-mapping",
"anskaffelser-ai-procurement",
"gevinstrealisering-ai-projects"
],
"existing_overlap": ["architecture/public-sector-checklist.md", "architecture/ai-utredning-template.md"],
"notes": "Fundamentalt annerledes enn øvrige kategorier: primærkilder er regjeringen.no, lovdata.no, digdir.no, nsm.no — IKKE microsoft-learn. Innhold er regulatorisk/juridisk, ikke teknisk produktdokumentasjon. Prompt-template må bruke WebSearch for norske kilder i tillegg til microsoft-learn MCP."
},
"ai-security-engineering": {
"name": "AI Security Engineering",
"dir": "ai-security-engineering",
"priority": "HIGH",
"description": "Operasjonell AI-sikkerhet: prompt injection forsvar, jailbreak-prevention, content safety kalibrering, PII-deteksjon, trusselmodellering, sikkerhetsscoring, hendelseshåndtering, output-validering, zero trust for AI, datalekkasjeforebygging og red teaming.",
"estimated_skills": 15,
"examples": [
"prompt-injection-defense-patterns",
"jailbreak-prevention-production",
"content-safety-filter-calibration",
"pii-detection-norwegian-text",
"ai-threat-modeling-stride",
"security-scoring-rubric-6dimensions",
"ai-incident-response-procedures",
"output-validation-grounding-verification",
"zero-trust-ai-services",
"ai-red-team-operations-practical"
],
"existing_overlap": ["architecture/security.md", "responsible-ai/red-teaming-ai-models.md", "responsible-ai/content-safety-implementation.md", "prompt-engineering/adversarial-prompting-and-jailbreaks.md"],
"notes": "Komplementerer responsible-ai (governance/teori) og prompt-engineering (angrepsteknikker) med OPERASJONELLE forsvarsmønstre. Fokus: forsvar, deteksjon, respons — ikke policy eller angrep."
}
}
}

View file

@ -0,0 +1,32 @@
{
"version": "1.0",
"description": "Maps KB categories to their target skill directories",
"mapping": {
"rag-architecture": "ms-ai-engineering",
"azure-ai-services": "ms-ai-engineering",
"copilot-extensibility": "ms-ai-engineering",
"prompt-engineering": "ms-ai-engineering",
"data-engineering": "ms-ai-engineering",
"api-management": "ms-ai-engineering",
"agent-orchestration": "ms-ai-engineering",
"multi-modal": "ms-ai-engineering",
"mlops-genaiops": "ms-ai-engineering",
"performance-scalability": "ms-ai-engineering",
"monitoring-observability": "ms-ai-engineering",
"responsible-ai": "ms-ai-governance",
"norwegian-public-sector-governance": "ms-ai-governance",
"cost-optimization": "ms-ai-security",
"ai-security-engineering": "ms-ai-security",
"security-scoring": "ms-ai-security",
"hybrid-edge": "ms-ai-infrastructure",
"bcdr": "ms-ai-infrastructure",
"platforms": "ms-ai-advisor",
"architecture": "ms-ai-advisor"
},
"priority_thresholds": {
"critical": 30,
"high": 60,
"medium": 90,
"low": 180
}
}

View file

@ -0,0 +1,301 @@
#!/bin/bash
# expand-categories.sh — Expand skill categories into full manifest
#
# Uses claude --print to expand each category in categories.json
# into 15-25 individual skill titles, producing manifest.json
#
# Usage:
# ./expand-categories.sh # Expand all categories
# ./expand-categories.sh azure-ai-services # Expand single category
# ./expand-categories.sh --wave 1 # Expand wave 1 only
#
# Prerequisites:
# - claude CLI installed and authenticated
# - jq installed
# - categories.json in same directory
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PLUGIN_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
CATEGORIES_FILE="$SCRIPT_DIR/categories.json"
MANIFEST_FILE="$SCRIPT_DIR/manifest.json"
LOG_DIR="$SCRIPT_DIR/logs"
# Model for expansion (haiku is sufficient for generating titles)
MODEL="${MODEL:-haiku}"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log() { echo -e "${BLUE}[expand]${NC} $1" >&2; }
success() { echo -e "${GREEN}[expand]${NC} $1" >&2; }
warn() { echo -e "${YELLOW}[expand]${NC} $1" >&2; }
error() { echo -e "${RED}[expand]${NC} $1" >&2; }
# Check prerequisites
check_prereqs() {
if ! command -v claude &>/dev/null; then
error "claude CLI not found. Install: npm install -g @anthropic-ai/claude-code"
exit 1
fi
if ! command -v jq &>/dev/null; then
error "jq not found. Install: brew install jq"
exit 1
fi
if [[ ! -f "$CATEGORIES_FILE" ]]; then
error "categories.json not found at $CATEGORIES_FILE"
exit 1
fi
}
# Get list of existing reference files for context
get_existing_refs() {
local category_dir="$1"
local refs_dir="$PLUGIN_DIR/skills/ms-ai-engineering/references"
# List all existing reference files
find "$refs_dir" -name "*.md" -type f 2>/dev/null | while read -r f; do
basename "$f" .md
done | sort | tr '\n' ', '
}
# Expand a single category
expand_category() {
local category_key="$1"
local name description estimated examples existing_overlap notes
name=$(jq -r ".categories[\"$category_key\"].name" "$CATEGORIES_FILE")
description=$(jq -r ".categories[\"$category_key\"].description" "$CATEGORIES_FILE")
estimated=$(jq -r ".categories[\"$category_key\"].estimated_skills" "$CATEGORIES_FILE")
examples=$(jq -r ".categories[\"$category_key\"].examples | join(\", \")" "$CATEGORIES_FILE")
existing_overlap=$(jq -r ".categories[\"$category_key\"].existing_overlap | join(\", \")" "$CATEGORIES_FILE")
notes=$(jq -r ".categories[\"$category_key\"].notes" "$CATEGORIES_FILE")
local existing_refs
existing_refs=$(get_existing_refs "$category_key")
log "Expanding: $name ($estimated skills estimated)"
local prompt
prompt="Du er en Microsoft AI Solution Architect som planlegger en kunnskapsbase.
Kategorien **${name}** trenger individuelle kunnskapsfiler (skills).
## Kategori-beskrivelse
${description}
## Eksisterende filer i kunnskapsbasen (unngå duplikering)
${existing_refs}
## Eksisterende overlapp å ta hensyn til
${existing_overlap}
## Eksempel-titler (for inspirasjon, ikke begrens deg til disse)
${examples}
## Notater
${notes}
## Oppgave
Generer en JSON-array med NØYAKTIG ${estimated} skills for denne kategorien.
Hver skill skal ha:
- \`id\`: kebab-case filnavn (uten .md)
- \`title\`: Engelsk tittel (kortfattet, beskrivende)
- \`description\`: 1-2 setninger på norsk om hva filen dekker
- \`subtopics\`: 3-5 viktige undertemaer som array
Regler:
1. Ikke dupliser emner som allerede finnes i eksisterende filer
2. Sørg for bred dekning uten overlapp mellom skills
3. Titler skal være spesifikke (\"Azure AI Vision OCR and Document Processing\", ikke bare \"Vision\")
4. Prioriter mest nyttige emner for enterprise AI-arkitekter i norsk offentlig sektor
5. Returner KUN valid JSON-array, ingen annen tekst
Eksempel-format:
[
{
\"id\": \"example-skill-name\",
\"title\": \"Example Skill - Full Descriptive Title\",
\"description\": \"Beskrivelse av hva denne kunnskapsfilen dekker.\",
\"subtopics\": [\"subtopic-1\", \"subtopic-2\", \"subtopic-3\"]
}
]"
local output
output=$(claude --print --model "$MODEL" "$prompt" 2>"$LOG_DIR/expand-${category_key}.err")
# Extract JSON array from response (handles markdown code blocks, plain JSON, etc.)
local json_output
json_output=$(python3 -c "
import sys, json, re
text = sys.stdin.read()
# Try to find JSON array in code blocks first
m = re.search(r'\`\`\`(?:json)?\s*(\[[\s\S]*?\])\s*\`\`\`', text)
if m:
arr = json.loads(m.group(1))
print(json.dumps(arr))
sys.exit(0)
# Try to find bare JSON array
m = re.search(r'(\[[\s\S]*\])', text)
if m:
try:
arr = json.loads(m.group(1))
print(json.dumps(arr))
sys.exit(0)
except: pass
# Nothing found
sys.exit(1)
" <<< "$output" 2>/dev/null)
# Validate JSON
if ! echo "$json_output" | jq . &>/dev/null; then
error "Invalid JSON for $category_key. Raw output saved to $LOG_DIR/expand-${category_key}.raw"
echo "$output" > "$LOG_DIR/expand-${category_key}.raw"
return 1
fi
local count
count=$(echo "$json_output" | jq 'length')
success "$name: $count skills generated"
# Return the JSON
echo "$json_output"
}
# Build or update manifest
build_manifest() {
local categories_to_expand=("$@")
# Initialize manifest if it doesn't exist
if [[ ! -f "$MANIFEST_FILE" ]]; then
echo '{"version":"1.0","created":"'"$(date +%Y-%m-%d)"'","categories":{}}' | jq . > "$MANIFEST_FILE"
fi
local total=0
local failed=0
for category_key in "${categories_to_expand[@]}"; do
local skills_json
if skills_json=$(expand_category "$category_key"); then
# Add to manifest
local dir
dir=$(jq -r ".categories[\"$category_key\"].dir" "$CATEGORIES_FILE")
local name
name=$(jq -r ".categories[\"$category_key\"].name" "$CATEGORIES_FILE")
local priority
priority=$(jq -r ".categories[\"$category_key\"].priority" "$CATEGORIES_FILE")
local category_obj
category_obj=$(jq -n \
--arg name "$name" \
--arg dir "$dir" \
--arg priority "$priority" \
--argjson skills "$skills_json" \
'{name: $name, dir: $dir, priority: $priority, skills: $skills}')
# Merge into manifest
jq --arg key "$category_key" --argjson cat "$category_obj" \
'.categories[$key] = $cat' "$MANIFEST_FILE" > "$MANIFEST_FILE.tmp" \
&& mv "$MANIFEST_FILE.tmp" "$MANIFEST_FILE"
local count
count=$(echo "$skills_json" | jq 'length')
total=$((total + count))
else
failed=$((failed + 1))
fi
# Rate limiting: pause between API calls
sleep 2
done
echo "" >&2
log "═══════════════════════════════════════"
success "Total skills in manifest: $total"
[[ $failed -gt 0 ]] && error "Failed categories: $failed"
log "Manifest: $MANIFEST_FILE"
log "═══════════════════════════════════════"
}
# Parse arguments
parse_args() {
local wave=""
local single_category=""
while [[ $# -gt 0 ]]; do
case "$1" in
--wave)
wave="$2"
shift 2
;;
--model)
MODEL="$2"
shift 2
;;
--help|-h)
echo "Usage: $0 [category-key] [--wave N] [--model MODEL]"
echo ""
echo "Options:"
echo " category-key Expand single category"
echo " --wave N Expand all categories in wave N (1 or 2)"
echo " --model MODEL Claude model to use (default: haiku)"
echo ""
echo "Examples:"
echo " $0 # Expand all categories"
echo " $0 azure-ai-services # Expand single category"
echo " $0 --wave 1 # Expand HIGH priority only"
exit 0
;;
*)
single_category="$1"
shift
;;
esac
done
# Determine which categories to expand
if [[ -n "$single_category" ]]; then
echo "$single_category"
elif [[ -n "$wave" ]]; then
jq -r ".waves[] | select(.wave == $wave) | .categories[]" "$CATEGORIES_FILE"
else
jq -r '.categories | keys[]' "$CATEGORIES_FILE"
fi
}
# Main
main() {
check_prereqs
mkdir -p "$LOG_DIR"
log "Skill Category Expansion"
log "Model: $MODEL | Categories file: $CATEGORIES_FILE"
echo "" >&2
local categories=()
while IFS= read -r line; do
categories+=("$line")
done < <(parse_args "$@")
if [[ ${#categories[@]} -eq 0 ]]; then
error "No categories to expand"
exit 1
fi
log "Categories to expand: ${#categories[@]}"
for cat in "${categories[@]}"; do
log " - $cat"
done
echo "" >&2
build_manifest "${categories[@]}"
}
main "$@"

View file

@ -0,0 +1,610 @@
#!/bin/bash
# generate-skills.sh — Generate knowledge reference files from manifest
#
# Reads manifest.json and generates each skill file using claude --print
# with the prompt template. Supports resuming from where it left off.
#
# Usage:
# ./generate-skills.sh # Generate all pending skills
# ./generate-skills.sh --category rag-architecture # Generate single category
# ./generate-skills.sh --skill azure-ai-vision-overview # Generate single skill
# ./generate-skills.sh --wave 1 # Generate wave 1 (HIGH) only
# ./generate-skills.sh --dry-run # Show what would be generated
# ./generate-skills.sh --pilot 5 # Generate first N skills only
#
# Prerequisites:
# - claude CLI installed and authenticated
# - jq installed
# - manifest.json (run expand-categories.sh first)
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PLUGIN_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
REFS_DIR="$PLUGIN_DIR/skills/ms-ai-engineering/references"
MANIFEST_FILE="$SCRIPT_DIR/manifest.json"
STATE_FILE="$SCRIPT_DIR/state.json"
PROMPT_TEMPLATE="$SCRIPT_DIR/prompt-template.md"
CATEGORIES_FILE="$SCRIPT_DIR/categories.json"
LOG_DIR="$SCRIPT_DIR/logs"
# Model for generation (sonnet for quality, haiku for speed)
MODEL="${MODEL:-sonnet}"
# Limits
PARALLEL="${PARALLEL:-1}" # Sequential by default for reliability
DELAY="${DELAY:-3}" # Seconds between API calls
MIN_SIZE="${MIN_SIZE:-5000}" # Minimum file size in bytes (quality gate)
MAX_RETRIES="${MAX_RETRIES:-2}" # Retries for failed/small files
# Flags
DRY_RUN=false
PILOT=0
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
log() { echo -e "${BLUE}[gen]${NC} $1" >&2; }
success() { echo -e "${GREEN}[gen]${NC} $1" >&2; }
warn() { echo -e "${YELLOW}[gen]${NC} $1" >&2; }
error() { echo -e "${RED}[gen]${NC} $1" >&2; }
detail() { echo -e "${CYAN}[gen]${NC} $1" >&2; }
# Check prerequisites
check_prereqs() {
if ! command -v claude &>/dev/null; then
error "claude CLI not found"
exit 1
fi
if ! command -v jq &>/dev/null; then
error "jq not found"
exit 1
fi
if [[ ! -f "$MANIFEST_FILE" ]]; then
error "manifest.json not found. Run expand-categories.sh first."
exit 1
fi
}
# Initialize or load state
init_state() {
if [[ ! -f "$STATE_FILE" ]]; then
jq -n '{
"started": "'$(date -Iseconds)'",
"completed": [],
"failed": [],
"skipped": [],
"stats": {
"total_generated": 0,
"total_failed": 0,
"total_skipped": 0,
"total_bytes": 0
}
}' > "$STATE_FILE"
fi
}
# Check if skill is already completed
is_completed() {
local skill_id="$1"
jq -e --arg id "$skill_id" '.completed | index($id) != null' "$STATE_FILE" &>/dev/null
}
# Mark skill as completed
mark_completed() {
local skill_id="$1"
local file_size="$2"
jq --arg id "$skill_id" --arg size "$file_size" '
.completed += [$id] |
.stats.total_generated += 1 |
.stats.total_bytes += ($size | tonumber)
' "$STATE_FILE" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"
}
# Mark skill as failed
mark_failed() {
local skill_id="$1"
local reason="$2"
jq --arg id "$skill_id" --arg reason "$reason" '
.failed += [{"id": $id, "reason": $reason, "time": (now | todate)}] |
.stats.total_failed += 1
' "$STATE_FILE" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"
}
# Get existing context for a category (overlap files content summary)
get_existing_context() {
local category_key="$1"
local overlaps
overlaps=$(jq -r ".categories[\"$category_key\"].existing_overlap // [] | .[]" "$CATEGORIES_FILE" 2>/dev/null)
if [[ -z "$overlaps" ]]; then
echo "Ingen direkte overlapp med eksisterende filer."
return
fi
local context=""
for overlap in $overlaps; do
local filepath="$REFS_DIR/$overlap"
if [[ -f "$filepath" ]]; then
# Extract just the header and section titles
local summary
summary=$(head -50 "$filepath" | grep -E '^#{1,3} ' | head -10)
context+="**$overlap:** $summary"$'\n'
fi
done
echo "${context:-Ingen direkte overlapp med eksisterende filer.}"
}
# Get related skills in same category
get_related_skills() {
local category_key="$1"
local current_skill="$2"
jq -r --arg key "$category_key" --arg current "$current_skill" '
.categories[$key].skills[]
| select(.id != $current)
| "- \(.title): \(.description)"
' "$MANIFEST_FILE" | head -20
}
# Build the prompt for a specific skill
build_prompt() {
local category_key="$1"
local skill_id="$2"
local title description subtopics
title=$(jq -r --arg key "$category_key" --arg id "$skill_id" \
'.categories[$key].skills[] | select(.id == $id) | .title' "$MANIFEST_FILE")
description=$(jq -r --arg key "$category_key" --arg id "$skill_id" \
'.categories[$key].skills[] | select(.id == $id) | .description' "$MANIFEST_FILE")
subtopics=$(jq -r --arg key "$category_key" --arg id "$skill_id" \
'.categories[$key].skills[] | select(.id == $id) | .subtopics | join(", ")' "$MANIFEST_FILE")
local category_name category_description
category_name=$(jq -r --arg key "$category_key" '.categories[$key].name' "$MANIFEST_FILE")
category_description=$(jq -r --arg key "$category_key" '.categories[$key].name' "$CATEGORIES_FILE")
local existing_context
existing_context=$(get_existing_context "$category_key")
local related_skills
related_skills=$(get_related_skills "$category_key" "$skill_id")
# Build the full prompt from template
cat <<PROMPT
Du er Cosmo Skyberg, en senior Microsoft AI Solution Architect som skriver kunnskapsreferanser for et Claude Code-plugin. Referansene brukes av en AI-arkitekt persona som hjelper norske organisasjoner (spesielt offentlig sektor) med Microsoft AI-løsninger.
## Oppgave
Skriv en komplett kunnskapsreferanse om: **${title}**
Skill-beskrivelse: ${description}
Viktige undertemaer å dekke: ${subtopics}
Denne filen tilhører kategorien **${category_name}**.
## Format-krav (STRENGT)
### Header
\`\`\`markdown
# ${title}
**Last updated:** 2026-02
**Status:** [GA | Preview | Announced]
**Category:** ${category_name}
---
\`\`\`
### Innhold (7-15 KB, alle seksjoner påkrevd)
1. **Introduksjon** (2-3 avsnitt)
- Hva er dette? Hvorfor er det viktig for enterprise AI?
- Plassering i Microsoft-økosystemet
- Norsk prosa, engelske tekniske termer
2. **Kjernekomponenter / Nøkkelegenskaper**
- Bruk tabeller for sammenligninger
- Bullet points for egenskaper
- Kodeeksempler der relevant (korte, illustrative)
3. **Arkitekturmønstre**
- 2-3 typiske bruksmønstre
- Når bruke hvert mønster
- Fordeler og ulemper
4. **Beslutningsveiledning**
- "Velg X når..." beslutningstabell
- Vanlige feil og misforståelser
- Røde flagg arkitekten bør se etter
5. **Integrasjon med Microsoft-stakken**
- Hvordan dette kobles til andre Azure/M365-tjenester
- Typiske integrasjonsmønstre
6. **Offentlig sektor (Norge)**
- GDPR, Schrems II, AI Act, Forvaltningsloven
- Datasuverenitet og residency
7. **Kostnad og lisensiering**
- Prismodell (oversikt)
- Kostnadsoptimaliseringstips
8. **For arkitekten (Cosmo)**
- 5-8 nøkkelspørsmål å stille kunden
- Vanlige fallgruver
- Anbefalinger per modenhetsnivå
9. **Kilder og verifisering**
- Microsoft Learn-referanser
- Konfidensnivå (Verified / Baseline / Assumed)
## Regler
1. Norsk prosa, engelske tekniske termer
2. Tabeller over tekst for sammenligninger
3. Konkret over vagt — spesifikke tall og tjenester
4. Balansert — vis fordeler OG ulemper
5. Oppdatert — 2025-2026 informasjon
6. Størrelse: 7-15 KB (200-400 linjer)
7. Ikke dupliser: ${existing_context}
## Relaterte skills (for kryssreferanser)
${related_skills}
Skriv KUN markdown-innholdet. Ingen innledende forklaring eller avsluttende kommentar.
PROMPT
}
# Generate a single skill file
generate_skill() {
local category_key="$1"
local skill_id="$2"
local attempt="${3:-1}"
local category_dir
category_dir=$(jq -r --arg key "$category_key" '.categories[$key].dir' "$MANIFEST_FILE")
local output_dir="$REFS_DIR/$category_dir"
local output_file="$output_dir/$skill_id.md"
local title
title=$(jq -r --arg key "$category_key" --arg id "$skill_id" \
'.categories[$key].skills[] | select(.id == $id) | .title' "$MANIFEST_FILE")
# Skip if already completed
if is_completed "$skill_id"; then
detail " Skipping (already completed): $skill_id"
return 0
fi
# Skip if file already exists and is large enough
if [[ -f "$output_file" ]]; then
local existing_size
existing_size=$(wc -c < "$output_file" | tr -d ' ')
if [[ $existing_size -ge $MIN_SIZE ]]; then
detail " Skipping (file exists, ${existing_size}B): $skill_id"
mark_completed "$skill_id" "$existing_size"
return 0
fi
warn " File exists but too small (${existing_size}B < ${MIN_SIZE}B), regenerating: $skill_id"
fi
if $DRY_RUN; then
log " [DRY RUN] Would generate: $output_file"
log " Title: $title"
return 0
fi
log " Generating ($attempt/$((MAX_RETRIES+1))): $title"
# Create output directory
mkdir -p "$output_dir"
# Build prompt
local prompt
prompt=$(build_prompt "$category_key" "$skill_id")
# Generate with claude --print
local output
if ! output=$(claude --print --model "$MODEL" "$prompt" 2>"$LOG_DIR/gen-${skill_id}.err"); then
error " Claude CLI failed for $skill_id"
if [[ $attempt -le $MAX_RETRIES ]]; then
warn " Retrying in ${DELAY}s..."
sleep "$DELAY"
generate_skill "$category_key" "$skill_id" $((attempt + 1))
return $?
fi
mark_failed "$skill_id" "claude CLI error"
return 1
fi
# Write output
echo "$output" > "$output_file"
# Quality gate: check file size
local file_size
file_size=$(wc -c < "$output_file" | tr -d ' ')
if [[ $file_size -lt $MIN_SIZE ]]; then
warn " File too small: ${file_size}B (min: ${MIN_SIZE}B)"
if [[ $attempt -le $MAX_RETRIES ]]; then
warn " Retrying with stronger prompt..."
sleep "$DELAY"
generate_skill "$category_key" "$skill_id" $((attempt + 1))
return $?
fi
error " Giving up on $skill_id (still too small after retries)"
mark_failed "$skill_id" "file too small: ${file_size}B"
return 1
fi
# Quality gate: check that file starts with # (markdown header)
if ! head -1 "$output_file" | grep -q '^# '; then
warn " File doesn't start with markdown header"
# Try to fix by removing leading content before first header
local temp_file="$output_file.tmp"
sed -n '/^# /,$p' "$output_file" > "$temp_file"
if [[ -s "$temp_file" ]]; then
mv "$temp_file" "$output_file"
file_size=$(wc -c < "$output_file" | tr -d ' ')
else
rm -f "$temp_file"
fi
fi
mark_completed "$skill_id" "$file_size"
success " Generated: $skill_id (${file_size}B)"
# Rate limiting
sleep "$DELAY"
}
# Generate all skills in a category
generate_category() {
local category_key="$1"
local category_name
category_name=$(jq -r --arg key "$category_key" '.categories[$key].name' "$MANIFEST_FILE")
local skill_count
skill_count=$(jq --arg key "$category_key" '.categories[$key].skills | length' "$MANIFEST_FILE")
log ""
log "═══════════════════════════════════════"
log "Category: $category_name ($skill_count skills)"
log "═══════════════════════════════════════"
local skill_ids=()
while IFS= read -r line; do
skill_ids+=("$line")
done < <(jq -r --arg key "$category_key" \
'.categories[$key].skills[].id' "$MANIFEST_FILE")
local generated=0
for skill_id in "${skill_ids[@]}"; do
if generate_skill "$category_key" "$skill_id"; then
generated=$((generated + 1))
fi
# Pilot mode: stop after N skills total
if [[ $PILOT -gt 0 ]]; then
local total_completed
total_completed=$(jq '.stats.total_generated' "$STATE_FILE")
if [[ $total_completed -ge $PILOT ]]; then
warn "Pilot limit reached ($PILOT skills)"
return 0
fi
fi
done
success "Category complete: $generated/$skill_count generated"
}
# Print summary
print_summary() {
local total_generated total_failed total_bytes
total_generated=$(jq '.stats.total_generated' "$STATE_FILE")
total_failed=$(jq '.stats.total_failed' "$STATE_FILE")
total_bytes=$(jq '.stats.total_bytes' "$STATE_FILE")
local total_kb=$((total_bytes / 1024))
echo ""
log "═══════════════════════════════════════"
log " GENERATION SUMMARY "
log "═══════════════════════════════════════"
success "Generated: $total_generated files ($total_kb KB)"
[[ $total_failed -gt 0 ]] && error "Failed: $total_failed files"
log "State: $STATE_FILE"
log "Output: $REFS_DIR/"
log "═══════════════════════════════════════"
# List failed skills if any
if [[ $total_failed -gt 0 ]]; then
echo ""
warn "Failed skills:"
jq -r '.failed[] | " - \(.id): \(.reason)"' "$STATE_FILE"
fi
}
# Parse arguments
parse_args() {
local category=""
local skill=""
local wave=""
while [[ $# -gt 0 ]]; do
case "$1" in
--category|-c)
category="$2"
shift 2
;;
--skill|-s)
skill="$2"
shift 2
;;
--wave|-w)
wave="$2"
shift 2
;;
--model|-m)
MODEL="$2"
shift 2
;;
--dry-run)
DRY_RUN=true
shift
;;
--pilot)
PILOT="$2"
shift 2
;;
--delay)
DELAY="$2"
shift 2
;;
--min-size)
MIN_SIZE="$2"
shift 2
;;
--max-retries)
MAX_RETRIES="$2"
shift 2
;;
--reset)
rm -f "$STATE_FILE"
log "State reset"
shift
;;
--help|-h)
cat <<EOF
Usage: $0 [OPTIONS]
Options:
--category, -c KEY Generate single category
--skill, -s ID Generate single skill
--wave, -w N Generate wave N (1=HIGH, 2=MEDIUM)
--model, -m MODEL Claude model (default: sonnet)
--dry-run Show what would be generated
--pilot N Generate only first N skills (for testing)
--delay N Seconds between API calls (default: 3)
--min-size N Minimum file size in bytes (default: 5000)
--max-retries N Max retries per skill (default: 2)
--reset Clear state and start fresh
Environment:
MODEL=sonnet Override default model
MAX_BUDGET_USD=5 Max dollar amount per run
PARALLEL=1 Parallel generation (experimental)
DELAY=3 Delay between calls
Examples:
$0 --pilot 3 # Test with 3 skills
$0 --category rag-architecture # Generate one category
$0 --wave 1 --model sonnet # Generate all HIGH priority
$0 --dry-run # Preview without generating
MODEL=haiku $0 --wave 2 # MEDIUM priority with haiku
EOF
exit 0
;;
*)
error "Unknown option: $1"
exit 1
;;
esac
done
# Return mode and target
if [[ -n "$skill" ]]; then
echo "skill:$skill"
elif [[ -n "$category" ]]; then
echo "category:$category"
elif [[ -n "$wave" ]]; then
echo "wave:$wave"
else
echo "all"
fi
}
# Find which category a skill belongs to
find_skill_category() {
local skill_id="$1"
jq -r --arg id "$skill_id" '
.categories | to_entries[] |
select(.value.skills | map(.id) | index($id) != null) |
.key
' "$MANIFEST_FILE"
}
# Main
main() {
check_prereqs
init_state
mkdir -p "$LOG_DIR"
local mode
mode=$(parse_args "$@")
log "Skill Generation Pipeline"
log "Model: $MODEL | Min size: ${MIN_SIZE}B | Delay: ${DELAY}s"
$DRY_RUN && warn "DRY RUN MODE — no files will be generated"
[[ $PILOT -gt 0 ]] && warn "PILOT MODE — only $PILOT skills"
echo ""
case "$mode" in
skill:*)
local skill_id="${mode#skill:}"
local category_key
category_key=$(find_skill_category "$skill_id")
if [[ -z "$category_key" ]]; then
error "Skill not found in manifest: $skill_id"
exit 1
fi
generate_skill "$category_key" "$skill_id"
;;
category:*)
local category_key="${mode#category:}"
generate_category "$category_key"
;;
wave:*)
local wave_num="${mode#wave:}"
local categories=()
while IFS= read -r line; do
categories+=("$line")
done < <(jq -r --argjson w "$wave_num" \
'.waves[] | select(.wave == $w) | .categories[]' "$CATEGORIES_FILE")
for cat in "${categories[@]}"; do
generate_category "$cat"
if [[ $PILOT -gt 0 ]]; then
local total
total=$(jq '.stats.total_generated' "$STATE_FILE")
[[ $total -ge $PILOT ]] && break
fi
done
;;
all)
local all_categories=()
while IFS= read -r line; do
all_categories+=("$line")
done < <(jq -r '.categories | keys[]' "$MANIFEST_FILE")
for cat in "${all_categories[@]}"; do
generate_category "$cat"
if [[ $PILOT -gt 0 ]]; then
local total
total=$(jq '.stats.total_generated' "$STATE_FILE")
[[ $total -ge $PILOT ]] && break
fi
done
;;
esac
print_summary
}
main "$@"

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,102 @@
# Skill Generation Prompt Template
This template is used by `generate-skills.sh` to produce knowledge reference files for the architect plugin.
## Variables
- `{{SKILL_TITLE}}` — English title (e.g., "Azure AI Vision - Overview and Architecture")
- `{{SKILL_FILENAME}}` — Kebab-case filename without extension (e.g., "azure-ai-vision-overview")
- `{{CATEGORY_NAME}}` — Category name (e.g., "Azure AI Services (Foundry Tools)")
- `{{CATEGORY_DIR}}` — Directory name (e.g., "azure-ai-services")
- `{{CATEGORY_DESCRIPTION}}` — Category context
- `{{RELATED_SKILLS}}` — Other skills in same category (for cross-referencing)
- `{{EXISTING_CONTEXT}}` — Summary of existing reference files that overlap
## Prompt
```
Du er Cosmo Skyberg, en senior Microsoft AI Solution Architect som skriver kunnskapsreferanser for et Claude Code-plugin. Referansene brukes av en AI-arkitekt persona som hjelper norske organisasjoner (spesielt offentlig sektor) med Microsoft AI-løsninger.
## Oppgave
Skriv en komplett kunnskapsreferanse om: **{{SKILL_TITLE}}**
Denne filen tilhører kategorien **{{CATEGORY_NAME}}**: {{CATEGORY_DESCRIPTION}}
## Format-krav (STRENGT)
Filen MÅ følge dette eksakte formatet:
### Header
```markdown
# {{SKILL_TITLE}}
**Last updated:** 2026-02
**Status:** [GA | Preview | Announced]
**Category:** {{CATEGORY_NAME}}
---
```
### Innhold (7-15 KB, alle seksjoner påkrevd)
1. **Introduksjon** (2-3 avsnitt)
- Hva er dette? Hvorfor er det viktig for enterprise AI?
- Plassering i Microsoft-økosystemet
- Norsk prosa, engelske tekniske termer
2. **Kjernekomponenter / Nøkkelegenskaper**
- Bruk tabeller for sammenligninger
- Bullet points for egenskaper
- Kodeeksempler der relevant (korte, illustrative)
3. **Arkitekturmønstre**
- 2-3 typiske bruksmønstre med ASCII-diagrammer der det hjelper
- Når bruke hvert mønster
- Fordeler og ulemper
4. **Beslutningsveiledning**
- "Velg X når..." beslutningstabell
- Vanlige feil og misforståelser
- Røde flagg arkitekten bør se etter
5. **Integrasjon med Microsoft-stakken**
- Hvordan dette kobles til andre Azure/M365-tjenester
- Typiske integrasjonsmønstre
6. **Offentlig sektor (Norge)**
- Spesielle hensyn for norsk offentlig sektor
- GDPR, Schrems II, AI Act, Forvaltningsloven
- Datasuverenitet og residency
7. **Kostnad og lisensiering**
- Prismodell (oversikt, ikke detaljerte tall)
- Inkludert i hvilke lisenser
- Kostnadsoptimaliseringstips
8. **For arkitekten (Cosmo)**
- 5-8 nøkkelspørsmål å stille kunden
- Vanlige fallgruver
- Anbefalinger per modenhetsnivå (starter/intermediate/advanced)
9. **Kilder og verifisering**
- Referanser til Microsoft Learn-artikler
- Sist verifisert dato
- Konfidensnivå per seksjon (Verified / Baseline / Assumed)
## Regler
1. **Norsk prosa, engelske tekniske termer** — Skriv forklaringer på norsk, behold engelske termer for tjenester, konsepter og API-er
2. **Tabeller over tekst** — Bruk tabeller for sammenligninger, beslutninger, oversikter
3. **Konkret over vagt** — Spesifikke tall, konkrete eksempler, navngitte tjenester
4. **Balansert** — Vis både fordeler og ulemper, ikke bare markedsføringssnakk
5. **Oppdatert** — Bruk 2025-2026 informasjon, nevn GPT-5, AI Act, Foundry Tools (ny branding)
6. **Confidence markers** — Merk usikre påstander med (anslått) eller (uverifisert)
7. **Størrelse** — Mål: 7-15 KB (200-400 linjer). Ikke for kort (overfladisk) eller for langt (bloat)
8. **Ingen duplikering** — Ikke gjenta informasjon som allerede finnes i: {{EXISTING_CONTEXT}}
## Relaterte skills i samme kategori
{{RELATED_SKILLS}}
Skriv KUN markdown-innholdet. Ingen innledende forklaring eller avsluttende kommentar.
```

View file

@ -0,0 +1,227 @@
{
"started": "2026-02-03T15:13:03+01:00",
"completed": [
"rag-core-patterns",
"azure-ai-search-setup",
"embedding-models-selection",
"vector-indexing-techniques",
"chunking-strategies",
"hybrid-search-configuration",
"semantic-ranker-reranking",
"citation-tracking",
"rag-evaluation-frameworks",
"multi-index-federation",
"rag-security-rbac",
"rag-caching-optimization",
"metadata-management-filtering",
"graphrag-knowledge-graphs",
"rag-query-understanding",
"rag-context-windows",
"streaming-rag-responses",
"rag-iterative-refinement",
"rag-enterprise-scale",
"rag-document-preprocessing",
"rag-hallucination-mitigation",
"rag-cost-optimization",
"azure-ai-vision-ocr-processing",
"azure-ai-vision-image-analysis",
"document-intelligence-prebuilt-models",
"document-intelligence-custom-models",
"speech-services-speech-to-text",
"speech-services-text-to-speech",
"speech-services-speaker-recognition",
"language-services-text-analytics",
"language-services-question-answering",
"language-services-custom-text-classification",
"translator-document-translation",
"translator-custom-neural-models",
"content-understanding-multimodal-analysis",
"ai-services-networking-security",
"ai-services-monitoring-logging",
"ai-services-api-best-practices",
"ai-services-governance-compliance",
"ai-services-cost-optimization",
"ai-services-enterprise-architecture",
"ai-services-vs-foundry-tools-selection",
"responsible-ai-framework-overview",
"ai-act-compliance-guide",
"bias-detection-mitigation-strategies",
"ai-governance-structure-framework",
"ai-center-of-excellence-setup",
"red-teaming-ai-models",
"model-explainability-interpretability",
"content-safety-implementation",
"ai-impact-assessment-framework",
"transparency-documentation-standards",
"gdpr-compliance-ai-systems",
"algorithmic-accountability-auditability",
"fairness-testing-measurement",
"ai-ethics-in-public-sector",
"model-monitoring-drift-detection",
"stakeholder-communication-ai-decisions",
"ai-risk-taxonomy-classification",
"responsible-ai-policy-development",
"data-quality-responsible-ai",
"human-in-the-loop-oversight",
"responsible-ai-training-awareness",
"continuous-improvement-feedback-loops",
"declarative-agents-fundamentals",
"custom-engine-agents-development",
"copilot-studio-topics-and-entities",
"microsoft-graph-api-copilot-integration",
"copilot-connectors-design-patterns",
"mcp-protocol-copilot-studio",
"teams-copilot-message-extensions",
"sharepoint-copilot-agents",
"m365-copilot-plugins-ecosystem",
"copilot-orchestration-multi-agent",
"copilot-dlp-and-governance",
"copilot-analytics-and-usage-insights",
"copilot-prompt-engineering-governance",
"declarative-agents-grounding-strategies",
"copilot-studio-nlp-configuration",
"copilot-extensibility-security-patterns",
"power-automate-copilot-integration",
"copilot-context-window-optimization",
"adaptive-cards-copilot-responses",
"copilot-api-rate-limiting-resilience",
"copilot-studio-localization-globalization",
"enterprise-governance-copilot-deployment",
"system-message-design-patterns",
"few-shot-learning-techniques",
"chain-of-thought-prompting",
"reasoning-models-o1-o3-optimization",
"structured-output-formatting",
"function-calling-and-tool-use",
"grounding-and-knowledge-injection",
"temperature-sampling-and-parameters",
"token-optimization-and-efficiency",
"prompt-testing-and-evaluation",
"adversarial-prompting-and-jailbreaks",
"multi-turn-conversation-management",
"role-playing-and-persona-techniques",
"error-handling-and-fallback-prompting",
"domain-specific-prompt-optimization",
"multimodal-prompt-design",
"real-time-reasoning-performance",
"regulatory-and-compliance-prompting",
"token-counting-optimization",
"semantic-caching-patterns",
"reserved-capacity-planning",
"model-selection-price-performance",
"ptu-vs-paygo-economics",
"batch-processing-cost-reduction",
"azure-cost-management-ai",
"request-batching-aggregation",
"prompt-engineering-cost-reduction",
"vector-storage-cost-optimization",
"ai-builder-credits-transition",
"cost-allocation-chargeback",
"budget-forecasting-ai-projects",
"small-language-models-economics",
"rag-query-cost-reduction",
"azure-ai-foundry-cost-governance",
"multi-model-strategy-costs",
"inference-endpoint-cost-optimization",
"licensing-compliance-cost-avoidance",
"observability-cost-reduction",
"mlops-fundamentals-overview",
"azure-ml-pipelines-orchestration",
"model-versioning-registry-management",
"ci-cd-for-ml-models",
"contextual-retrieval",
"late-chunking-patterns",
"hierarchical-rag-patterns",
"agentic-rag-patterns",
"self-reflective-rag",
"multimodal-rag",
"model-evaluation-frameworks",
"ab-testing-llm-applications",
"data-drift-monitoring-detection",
"model-drift-performance-degradation",
"automated-retraining-pipelines",
"prompt-flow-production-deployment",
"model-deployment-strategies-azure",
"inferencing-optimization-caching",
"llm-evaluation-production",
"monitoring-observability-ml-systems",
"governance-audit-ml-operations",
"genaiops-llm-specific-practices",
"cost-optimization-mlops-pipelines",
"infrastructure-as-code-mlops",
"mlops-security-access-control",
"feedback-loops-continuous-improvement",
"responsible-ai-mlops-integration",
"mlops-teams-collaboration-tools",
"utredningsinstruksen-ai-methodology",
"forvaltningsloven-ai-decisions",
"digdir-principle-1-user-centric-design",
"digdir-principle-2-interoperability",
"digdir-principle-4-trust-security",
"digital-samhandling-eif-5-layers",
"dpia-norwegian-methodology-ai",
"ros-analyse-ai-systems",
"nsm-grunnprinsipper-ai-mapping",
"anskaffelser-ai-procurement-framework",
"gevinstrealisering-ai-projects",
"norge-ai-strategy-government",
"digdir-ai-governance-structure",
"statistical-ethics-ssa-methodology",
"public-sector-ai-ethics-framework",
"accessibility-requirements-wcag-norway",
"copyright-ai-training-data-norway",
"budget-and-accounting-ai-costs",
"digital-accessibility-action-plan",
"citizen-communication-ai-decisions",
"prompt-injection-defense-patterns",
"jailbreak-prevention-production",
"content-safety-filter-calibration",
"pii-detection-norwegian-context",
"ai-threat-modeling-stride",
"ai-security-scoring-framework",
"ai-incident-response-procedures",
"output-validation-grounding-verification",
"zero-trust-ai-services",
"data-leakage-prevention-ai",
"adversarial-input-robustness-testing",
"model-fingerprinting-watermarking",
"secure-model-deployment-hardening",
"ai-red-team-operations-practical",
"supply-chain-security-ai-models",
"azure-monitor-setup-ai-workloads",
"application-insights-llm-monitoring",
"token-usage-tracking-attribution",
"anomaly-detection-ai-systems",
"custom-dashboards-ai-operations",
"log-analytics-kql-ai-queries",
"distributed-tracing-ai-pipelines",
"sla-monitoring-ai-services",
"model-performance-drift-detection",
"security-and-audit-logging-ai",
"cost-monitoring-cost-attribution",
"response-quality-metrics-rag",
"endpoint-health-and-capacity-planning",
"real-time-streaming-monitoring",
"compliance-monitoring-ai-governance",
"alerting-strategies-escalation",
"observability-for-copilot-extensions",
"data-residency-audit-monitoring",
"multi-agent-orchestration-patterns",
"agent-to-agent-communication",
"semantic-kernel-agents-implementation",
"agent-memory-and-context-management",
"tool-use-and-function-calling-patterns",
"agent-autonomy-and-control-governance",
"agent-365-governance-and-deployment",
"agent-evaluation-testing-frameworks",
"autonomous-workflow-automation-patterns"
],
"failed": [],
"skipped": [],
"stats": {
"total_generated": 214,
"total_failed": 0,
"total_skipped": 0,
"total_bytes": 4673862
}
}