ma-agents 3.2.0 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/.opencode/skills/.ma-agents.json +99 -99
  2. package/.roo/rules/00-ma-agents.md +13 -0
  3. package/.roo/skills/.ma-agents.json +241 -0
  4. package/.roo/skills/MANIFEST.yaml +254 -0
  5. package/.roo/skills/ai-audit-trail/SKILL.md +23 -0
  6. package/.roo/skills/auto-bug-detection/SKILL.md +169 -0
  7. package/.roo/skills/cmake-best-practices/SKILL.md +64 -0
  8. package/.roo/skills/cmake-best-practices/examples/cmake.md +59 -0
  9. package/.roo/skills/code-documentation/SKILL.md +57 -0
  10. package/.roo/skills/code-documentation/examples/cpp.md +29 -0
  11. package/.roo/skills/code-documentation/examples/csharp.md +28 -0
  12. package/.roo/skills/code-documentation/examples/javascript_typescript.md +28 -0
  13. package/.roo/skills/code-documentation/examples/python.md +57 -0
  14. package/.roo/skills/code-review/SKILL.md +43 -0
  15. package/.roo/skills/commit-message/SKILL.md +79 -0
  16. package/.roo/skills/cpp-best-practices/SKILL.md +234 -0
  17. package/.roo/skills/cpp-best-practices/examples/modern-idioms.md +189 -0
  18. package/.roo/skills/cpp-best-practices/examples/naming-and-organization.md +102 -0
  19. package/.roo/skills/cpp-concurrency-safety/SKILL.md +60 -0
  20. package/.roo/skills/cpp-concurrency-safety/examples/concurrency.md +73 -0
  21. package/.roo/skills/cpp-const-correctness/SKILL.md +63 -0
  22. package/.roo/skills/cpp-const-correctness/examples/const_correctness.md +54 -0
  23. package/.roo/skills/cpp-memory-handling/SKILL.md +42 -0
  24. package/.roo/skills/cpp-memory-handling/examples/modern-cpp.md +49 -0
  25. package/.roo/skills/cpp-memory-handling/examples/smart-pointers.md +46 -0
  26. package/.roo/skills/cpp-modern-composition/SKILL.md +64 -0
  27. package/.roo/skills/cpp-modern-composition/examples/composition.md +51 -0
  28. package/.roo/skills/cpp-robust-interfaces/SKILL.md +55 -0
  29. package/.roo/skills/cpp-robust-interfaces/examples/interfaces.md +56 -0
  30. package/.roo/skills/create-hardened-docker-skill/SKILL.md +637 -0
  31. package/.roo/skills/create-hardened-docker-skill/scripts/create-all.sh +489 -0
  32. package/.roo/skills/csharp-best-practices/SKILL.md +278 -0
  33. package/.roo/skills/docker-hardening-verification/SKILL.md +28 -0
  34. package/.roo/skills/docker-hardening-verification/scripts/verify-hardening.sh +39 -0
  35. package/.roo/skills/docker-image-signing/SKILL.md +28 -0
  36. package/.roo/skills/docker-image-signing/scripts/sign-image.sh +33 -0
  37. package/.roo/skills/document-revision-history/SKILL.md +104 -0
  38. package/.roo/skills/git-workflow-skill/SKILL.md +194 -0
  39. package/.roo/skills/git-workflow-skill/hooks/commit-msg +61 -0
  40. package/.roo/skills/git-workflow-skill/hooks/pre-commit +38 -0
  41. package/.roo/skills/git-workflow-skill/hooks/prepare-commit-msg +56 -0
  42. package/.roo/skills/git-workflow-skill/scripts/finish-feature.sh +192 -0
  43. package/.roo/skills/git-workflow-skill/scripts/install-hooks.sh +55 -0
  44. package/.roo/skills/git-workflow-skill/scripts/start-feature.sh +110 -0
  45. package/.roo/skills/git-workflow-skill/scripts/validate-workflow.sh +229 -0
  46. package/.roo/skills/js-ts-dependency-mgmt/SKILL.md +49 -0
  47. package/.roo/skills/js-ts-dependency-mgmt/examples/dependency_mgmt.md +60 -0
  48. package/.roo/skills/js-ts-security-skill/SKILL.md +64 -0
  49. package/.roo/skills/js-ts-security-skill/scripts/verify-security.sh +136 -0
  50. package/.roo/skills/logging-best-practices/SKILL.md +50 -0
  51. package/.roo/skills/logging-best-practices/examples/cpp.md +36 -0
  52. package/.roo/skills/logging-best-practices/examples/csharp.md +49 -0
  53. package/.roo/skills/logging-best-practices/examples/javascript.md +77 -0
  54. package/.roo/skills/logging-best-practices/examples/python.md +57 -0
  55. package/.roo/skills/logging-best-practices/references/logging-standards.md +29 -0
  56. package/.roo/skills/open-presentation/SKILL.md +35 -0
  57. package/.roo/skills/opentelemetry-best-practices/SKILL.md +34 -0
  58. package/.roo/skills/opentelemetry-best-practices/examples/go.md +32 -0
  59. package/.roo/skills/opentelemetry-best-practices/examples/javascript.md +58 -0
  60. package/.roo/skills/opentelemetry-best-practices/examples/python.md +37 -0
  61. package/.roo/skills/opentelemetry-best-practices/references/otel-standards.md +37 -0
  62. package/.roo/skills/python-best-practices/SKILL.md +385 -0
  63. package/.roo/skills/python-dependency-mgmt/SKILL.md +42 -0
  64. package/.roo/skills/python-dependency-mgmt/examples/dependency_mgmt.md +67 -0
  65. package/.roo/skills/python-security-skill/SKILL.md +56 -0
  66. package/.roo/skills/python-security-skill/examples/security.md +56 -0
  67. package/.roo/skills/self-signed-cert/SKILL.md +42 -0
  68. package/.roo/skills/self-signed-cert/scripts/generate-cert.ps1 +45 -0
  69. package/.roo/skills/self-signed-cert/scripts/generate-cert.sh +43 -0
  70. package/.roo/skills/skill-creator/SKILL.md +196 -0
  71. package/.roo/skills/skill-creator/references/output-patterns.md +82 -0
  72. package/.roo/skills/skill-creator/references/workflows.md +28 -0
  73. package/.roo/skills/skill-creator/scripts/init_skill.py +208 -0
  74. package/.roo/skills/skill-creator/scripts/package_skill.py +99 -0
  75. package/.roo/skills/skill-creator/scripts/quick_validate.py +113 -0
  76. package/.roo/skills/story-status-lookup/SKILL.md +78 -0
  77. package/.roo/skills/test-accompanied-development/SKILL.md +50 -0
  78. package/.roo/skills/test-generator/SKILL.md +65 -0
  79. package/.roo/skills/vercel-react-best-practices/SKILL.md +109 -0
  80. package/.roo/skills/verify-hardened-docker-skill/SKILL.md +442 -0
  81. package/.roo/skills/verify-hardened-docker-skill/scripts/verify-docker-hardening.sh +439 -0
  82. package/README.md +21 -2
  83. package/bin/cli.js +55 -0
  84. package/lib/agents.js +46 -0
  85. package/lib/bmad-cache/cache-manifest.json +1 -1
  86. package/lib/bmad-customizations/bmm-demerzel.customize.yaml +36 -0
  87. package/lib/bmad-customizations/demerzel.md +32 -0
  88. package/lib/bmad-extension/module-help.csv +13 -0
  89. package/lib/bmad-extension/skills/bmad-ma-agent-ml/.gitkeep +0 -0
  90. package/lib/bmad-extension/skills/bmad-ma-agent-ml/SKILL.md +59 -0
  91. package/lib/bmad-extension/skills/bmad-ma-agent-ml/bmad-skill-manifest.yaml +11 -0
  92. package/lib/bmad-extension/skills/generate-backlog/.gitkeep +0 -0
  93. package/lib/bmad-extension/skills/ml-advise/.gitkeep +0 -0
  94. package/lib/bmad-extension/skills/ml-advise/SKILL.md +76 -0
  95. package/lib/bmad-extension/skills/ml-advise/bmad-skill-manifest.yaml +3 -0
  96. package/lib/bmad-extension/skills/ml-advise/skill.json +7 -0
  97. package/lib/bmad-extension/skills/ml-analysis/.gitkeep +0 -0
  98. package/lib/bmad-extension/skills/ml-analysis/SKILL.md +60 -0
  99. package/lib/bmad-extension/skills/ml-analysis/bmad-skill-manifest.yaml +3 -0
  100. package/lib/bmad-extension/skills/ml-analysis/skill.json +7 -0
  101. package/lib/bmad-extension/skills/ml-architecture/.gitkeep +0 -0
  102. package/lib/bmad-extension/skills/ml-architecture/SKILL.md +55 -0
  103. package/lib/bmad-extension/skills/ml-architecture/bmad-skill-manifest.yaml +3 -0
  104. package/lib/bmad-extension/skills/ml-architecture/skill.json +7 -0
  105. package/lib/bmad-extension/skills/ml-detailed-design/.gitkeep +0 -0
  106. package/lib/bmad-extension/skills/ml-detailed-design/SKILL.md +67 -0
  107. package/lib/bmad-extension/skills/ml-detailed-design/bmad-skill-manifest.yaml +3 -0
  108. package/lib/bmad-extension/skills/ml-detailed-design/skill.json +7 -0
  109. package/lib/bmad-extension/skills/ml-eda/.gitkeep +0 -0
  110. package/lib/bmad-extension/skills/ml-eda/SKILL.md +56 -0
  111. package/lib/bmad-extension/skills/ml-eda/bmad-skill-manifest.yaml +3 -0
  112. package/lib/bmad-extension/skills/ml-eda/scripts/baseline_classifier.py +522 -0
  113. package/lib/bmad-extension/skills/ml-eda/scripts/class_weights_calculator.py +295 -0
  114. package/lib/bmad-extension/skills/ml-eda/scripts/clustering_explorer.py +383 -0
  115. package/lib/bmad-extension/skills/ml-eda/scripts/eda_analyzer.py +654 -0
  116. package/lib/bmad-extension/skills/ml-eda/skill.json +7 -0
  117. package/lib/bmad-extension/skills/ml-experiment/.gitkeep +0 -0
  118. package/lib/bmad-extension/skills/ml-experiment/SKILL.md +74 -0
  119. package/lib/bmad-extension/skills/ml-experiment/assets/advanced_trainer_configs.py +430 -0
  120. package/lib/bmad-extension/skills/ml-experiment/assets/quick_trainer_setup.py +233 -0
  121. package/lib/bmad-extension/skills/ml-experiment/assets/template_datamodule.py +219 -0
  122. package/lib/bmad-extension/skills/ml-experiment/assets/template_gnn_module.py +341 -0
  123. package/lib/bmad-extension/skills/ml-experiment/assets/template_lightning_module.py +158 -0
  124. package/lib/bmad-extension/skills/ml-experiment/bmad-skill-manifest.yaml +3 -0
  125. package/lib/bmad-extension/skills/ml-experiment/skill.json +7 -0
  126. package/lib/bmad-extension/skills/ml-hparam/.gitkeep +0 -0
  127. package/lib/bmad-extension/skills/ml-hparam/SKILL.md +81 -0
  128. package/lib/bmad-extension/skills/ml-hparam/bmad-skill-manifest.yaml +3 -0
  129. package/lib/bmad-extension/skills/ml-hparam/skill.json +7 -0
  130. package/lib/bmad-extension/skills/ml-ideation/.gitkeep +0 -0
  131. package/lib/bmad-extension/skills/ml-ideation/SKILL.md +50 -0
  132. package/lib/bmad-extension/skills/ml-ideation/bmad-skill-manifest.yaml +3 -0
  133. package/lib/bmad-extension/skills/ml-ideation/scripts/validate_ml_prd.py +287 -0
  134. package/lib/bmad-extension/skills/ml-ideation/skill.json +7 -0
  135. package/lib/bmad-extension/skills/ml-infra/.gitkeep +0 -0
  136. package/lib/bmad-extension/skills/ml-infra/SKILL.md +58 -0
  137. package/lib/bmad-extension/skills/ml-infra/bmad-skill-manifest.yaml +3 -0
  138. package/lib/bmad-extension/skills/ml-infra/skill.json +7 -0
  139. package/lib/bmad-extension/skills/ml-retrospective/.gitkeep +0 -0
  140. package/lib/bmad-extension/skills/ml-retrospective/SKILL.md +63 -0
  141. package/lib/bmad-extension/skills/ml-retrospective/bmad-skill-manifest.yaml +3 -0
  142. package/lib/bmad-extension/skills/ml-retrospective/skill.json +7 -0
  143. package/lib/bmad-extension/skills/ml-revision/.gitkeep +0 -0
  144. package/lib/bmad-extension/skills/ml-revision/SKILL.md +82 -0
  145. package/lib/bmad-extension/skills/ml-revision/bmad-skill-manifest.yaml +3 -0
  146. package/lib/bmad-extension/skills/ml-revision/skill.json +7 -0
  147. package/lib/bmad-extension/skills/ml-techspec/.gitkeep +0 -0
  148. package/lib/bmad-extension/skills/ml-techspec/SKILL.md +80 -0
  149. package/lib/bmad-extension/skills/ml-techspec/bmad-skill-manifest.yaml +3 -0
  150. package/lib/bmad-extension/skills/ml-techspec/skill.json +7 -0
  151. package/lib/bmad.js +85 -8
  152. package/lib/skill-authoring.js +1 -1
  153. package/package.json +5 -4
  154. package/test/agent-injection-strategy.test.js +4 -4
  155. package/test/bmad-version-bump.test.js +34 -34
  156. package/test/build-bmad-args.test.js +13 -6
  157. package/test/convert-agents-to-skills.test.js +11 -1
  158. package/test/extension-module-restructure.test.js +31 -7
  159. package/test/migration-validation.test.js +14 -11
  160. package/test/roo-code-agent.test.js +166 -0
  161. package/test/roo-code-injection.test.js +172 -0
@@ -0,0 +1,341 @@
1
+ """
2
+ template_gnn_module.py — BMAD DL Lifecycle
3
+ (Inspired by K-Dense claude-scientific-skills/pytorch-geometric/)
4
+
5
+ PyTorch Geometric (PyG) template for Graph Neural Network tasks.
6
+ Covers GCN, GAT, GraphSAGE, and GIN architectures for:
7
+ - Node classification (predicting labels for each node in a graph)
8
+ - Graph classification (predicting a label for an entire graph)
9
+
10
+ Use this for defect detection on circuit graphs, molecular property prediction,
11
+ social network analysis, or any graph-structured data.
12
+
13
+ Requires: pip install torch-geometric
14
+
15
+ Usage:
16
+ Copy this file to src/models/your_gnn.py and:
17
+ 1. Choose an architecture (GCN / GAT / GraphSAGE / GIN)
18
+ 2. Set in_channels to your node feature dimension
19
+ 3. Set out_channels to number of classes
20
+ 4. Wrap with your LightningModule or use train/test helpers directly
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ from typing import Optional
26
+
27
+ try:
28
+ import torch
29
+ import torch.nn as nn
30
+ import torch.nn.functional as F
31
+ HAS_TORCH = True
32
+ except ImportError:
33
+ HAS_TORCH = False
34
+ raise ImportError("Install PyTorch: pip install torch")
35
+
36
+ try:
37
+ from torch_geometric.nn import (
38
+ GCNConv, GATConv, SAGEConv, GINConv,
39
+ global_mean_pool, global_max_pool, global_add_pool,
40
+ )
41
+ from torch_geometric.data import Data, DataLoader
42
+ HAS_PYG = True
43
+ except ImportError:
44
+ HAS_PYG = False
45
+ raise ImportError(
46
+ "Install PyTorch Geometric: pip install torch-geometric\n"
47
+ "See: https://pytorch-geometric.readthedocs.io/en/latest/install/installation.html"
48
+ )
49
+
50
+
51
+ # ══════════════════════════════════════════════════════════════════════════════
52
+ # Architecture 1: GCN — Graph Convolutional Network
53
+ # Best for: Homophilic graphs (connected nodes tend to share labels)
54
+ # ══════════════════════════════════════════════════════════════════════════════
55
+
56
+ class GCN(nn.Module):
57
+ """
58
+ Graph Convolutional Network (Kipf & Welling, 2017).
59
+
60
+ Args:
61
+ in_channels: Dimension of input node features.
62
+ hidden_channels: Hidden layer dimension.
63
+ out_channels: Number of output classes.
64
+ num_layers: Number of GCN layers (2-4 recommended).
65
+ dropout: Dropout rate.
66
+ task: 'node' or 'graph' classification.
67
+ """
68
+ def __init__(
69
+ self, in_channels: int, hidden_channels: int, out_channels: int,
70
+ num_layers: int = 3, dropout: float = 0.5, task: str = "node",
71
+ ):
72
+ super().__init__()
73
+ self.task = task
74
+ self.dropout = dropout
75
+
76
+ self.convs = nn.ModuleList()
77
+ self.bns = nn.ModuleList()
78
+
79
+ for i in range(num_layers):
80
+ in_ch = in_channels if i == 0 else hidden_channels
81
+ self.convs.append(GCNConv(in_ch, hidden_channels))
82
+ self.bns.append(nn.BatchNorm1d(hidden_channels))
83
+
84
+ self.classifier = nn.Linear(hidden_channels, out_channels)
85
+
86
+ def forward(self, x: torch.Tensor, edge_index: torch.Tensor,
87
+ batch: Optional[torch.Tensor] = None) -> torch.Tensor:
88
+ for conv, bn in zip(self.convs[:-1], self.bns[:-1]):
89
+ x = F.relu(bn(conv(x, edge_index)))
90
+ x = F.dropout(x, p=self.dropout, training=self.training)
91
+
92
+ x = self.convs[-1](x, edge_index)
93
+
94
+ if self.task == "graph":
95
+ x = global_mean_pool(x, batch)
96
+
97
+ return self.classifier(x)
98
+
99
+
100
+ # ══════════════════════════════════════════════════════════════════════════════
101
+ # Architecture 2: GAT — Graph Attention Network
102
+ # Best for: Graphs where some neighbors are more important than others
103
+ # ══════════════════════════════════════════════════════════════════════════════
104
+
105
+ class GAT(nn.Module):
106
+ """
107
+ Graph Attention Network (Veličković et al., 2018).
108
+ Multi-head attention assigns different importance to each neighbor.
109
+
110
+ Args:
111
+ in_channels: Dimension of input node features.
112
+ hidden_channels: Hidden layer dimension per head.
113
+ out_channels: Number of output classes.
114
+ heads: Number of attention heads (4-8 recommended).
115
+ dropout: Dropout rate (applied to attention weights too).
116
+ task: 'node' or 'graph' classification.
117
+ """
118
+ def __init__(
119
+ self, in_channels: int, hidden_channels: int, out_channels: int,
120
+ heads: int = 4, dropout: float = 0.5, task: str = "node",
121
+ ):
122
+ super().__init__()
123
+ self.task = task
124
+ self.dropout = dropout
125
+
126
+ self.conv1 = GATConv(in_channels, hidden_channels, heads=heads, dropout=dropout)
127
+ self.conv2 = GATConv(hidden_channels * heads, out_channels, heads=1,
128
+ concat=False, dropout=dropout)
129
+ self.bn1 = nn.BatchNorm1d(hidden_channels * heads)
130
+
131
+ def forward(self, x: torch.Tensor, edge_index: torch.Tensor,
132
+ batch: Optional[torch.Tensor] = None) -> torch.Tensor:
133
+ x = F.dropout(x, p=self.dropout, training=self.training)
134
+ x = F.elu(self.bn1(self.conv1(x, edge_index)))
135
+ x = F.dropout(x, p=self.dropout, training=self.training)
136
+ x = self.conv2(x, edge_index)
137
+
138
+ if self.task == "graph":
139
+ x = global_mean_pool(x, batch)
140
+
141
+ return x # Raw logits — apply softmax/sigmoid in loss
142
+
143
+
144
+ # ══════════════════════════════════════════════════════════════════════════════
145
+ # Architecture 3: GraphSAGE — Inductive / large-graph friendly
146
+ # Best for: Large graphs, inductive settings (unseen nodes at test time)
147
+ # ══════════════════════════════════════════════════════════════════════════════
148
+
149
+ class GraphSAGE(nn.Module):
150
+ """
151
+ GraphSAGE (Hamilton et al., 2017).
152
+ Aggregates neighbor features via mean/max/LSTM — scales to large graphs.
153
+ Inductive: can generalize to unseen nodes not in the training graph.
154
+
155
+ Args:
156
+ in_channels: Dimension of input node features.
157
+ hidden_channels: Hidden layer dimension.
158
+ out_channels: Number of output classes.
159
+ num_layers: Number of SAGE layers.
160
+ dropout: Dropout rate.
161
+ task: 'node' or 'graph' classification.
162
+ """
163
+ def __init__(
164
+ self, in_channels: int, hidden_channels: int, out_channels: int,
165
+ num_layers: int = 3, dropout: float = 0.5, task: str = "node",
166
+ ):
167
+ super().__init__()
168
+ self.task = task
169
+ self.dropout = dropout
170
+
171
+ self.convs = nn.ModuleList()
172
+ self.bns = nn.ModuleList()
173
+
174
+ for i in range(num_layers):
175
+ in_ch = in_channels if i == 0 else hidden_channels
176
+ self.convs.append(SAGEConv(in_ch, hidden_channels))
177
+ self.bns.append(nn.BatchNorm1d(hidden_channels))
178
+
179
+ self.classifier = nn.Linear(hidden_channels, out_channels)
180
+
181
+ def forward(self, x: torch.Tensor, edge_index: torch.Tensor,
182
+ batch: Optional[torch.Tensor] = None) -> torch.Tensor:
183
+ for conv, bn in zip(self.convs, self.bns):
184
+ x = F.relu(bn(conv(x, edge_index)))
185
+ x = F.dropout(x, p=self.dropout, training=self.training)
186
+
187
+ if self.task == "graph":
188
+ x = global_mean_pool(x, batch)
189
+
190
+ return self.classifier(x)
191
+
192
+
193
+ # ══════════════════════════════════════════════════════════════════════════════
194
+ # Architecture 4: GIN — Graph Isomorphism Network
195
+ # Best for: Graph classification, maximally expressive (Weisfeiler-Leman equiv.)
196
+ # ══════════════════════════════════════════════════════════════════════════════
197
+
198
+ class GIN(nn.Module):
199
+ """
200
+ Graph Isomorphism Network (Xu et al., 2019).
201
+ Most expressive GNN for graph-level tasks in the WL hierarchy.
202
+ Aggregates by: h_v = MLP((1 + eps) * h_v + sum(neighbors))
203
+
204
+ Args:
205
+ in_channels: Dimension of input node features.
206
+ hidden_channels: Hidden dimension for each MLP layer.
207
+ out_channels: Number of output classes.
208
+ num_layers: Number of GIN layers (3-5 for graph classification).
209
+ dropout: Dropout rate.
210
+ """
211
+ def __init__(
212
+ self, in_channels: int, hidden_channels: int, out_channels: int,
213
+ num_layers: int = 4, dropout: float = 0.5,
214
+ ):
215
+ super().__init__()
216
+ self.dropout = dropout
217
+ self.convs = nn.ModuleList()
218
+ self.bns = nn.ModuleList()
219
+
220
+ for i in range(num_layers):
221
+ in_ch = in_channels if i == 0 else hidden_channels
222
+ mlp = nn.Sequential(
223
+ nn.Linear(in_ch, hidden_channels),
224
+ nn.BatchNorm1d(hidden_channels),
225
+ nn.ReLU(),
226
+ nn.Linear(hidden_channels, hidden_channels),
227
+ )
228
+ self.convs.append(GINConv(mlp, train_eps=True))
229
+ self.bns.append(nn.BatchNorm1d(hidden_channels))
230
+
231
+ # Jumping Knowledge: concat all layer outputs before classifier
232
+ self.classifier = nn.Sequential(
233
+ nn.Linear(hidden_channels * num_layers, hidden_channels),
234
+ nn.ReLU(),
235
+ nn.Dropout(dropout),
236
+ nn.Linear(hidden_channels, out_channels),
237
+ )
238
+
239
+ def forward(self, x: torch.Tensor, edge_index: torch.Tensor,
240
+ batch: torch.Tensor) -> torch.Tensor:
241
+ layer_outputs: list[torch.Tensor] = []
242
+ for conv, bn in zip(self.convs, self.bns):
243
+ x = F.relu(bn(conv(x, edge_index)))
244
+ x = F.dropout(x, p=self.dropout, training=self.training)
245
+ # Global pooling at each layer (Jumping Knowledge)
246
+ layer_outputs.append(global_add_pool(x, batch))
247
+
248
+ # Concatenate all layers' pooled outputs
249
+ x = torch.cat(layer_outputs, dim=1)
250
+ return self.classifier(x)
251
+
252
+
253
+ # ══════════════════════════════════════════════════════════════════════════════
254
+ # Training helpers
255
+ # ══════════════════════════════════════════════════════════════════════════════
256
+
257
+ def train_epoch(model: nn.Module, loader: "DataLoader",
258
+ optimizer: "torch.optim.Optimizer",
259
+ criterion: nn.Module, device: str) -> float:
260
+ model.train()
261
+ total_loss = 0.0
262
+ for data in loader:
263
+ data = data.to(device)
264
+ optimizer.zero_grad()
265
+ if model.__class__.__name__ == "GIN" or getattr(model, "task", "") == "graph":
266
+ out = model(data.x, data.edge_index, data.batch)
267
+ else:
268
+ out = model(data.x, data.edge_index)
269
+ if hasattr(data, "train_mask"):
270
+ out = out[data.train_mask]
271
+ target = data.y[data.train_mask]
272
+ else:
273
+ target = data.y
274
+ loss = criterion(out, target)
275
+ loss.backward()
276
+ optimizer.step()
277
+ total_loss += float(loss)
278
+ continue
279
+ loss = criterion(out, data.y)
280
+ loss.backward()
281
+ optimizer.step()
282
+ total_loss += float(loss)
283
+ return total_loss / len(loader)
284
+
285
+
286
+ @torch.no_grad()
287
+ def evaluate(model: nn.Module, loader: "DataLoader", device: str) -> float:
288
+ model.eval()
289
+ correct = total = 0
290
+ for data in loader:
291
+ data = data.to(device)
292
+ if model.__class__.__name__ == "GIN" or getattr(model, "task", "") == "graph":
293
+ out = model(data.x, data.edge_index, data.batch)
294
+ pred = out.argmax(dim=1)
295
+ correct += int((pred == data.y).sum())
296
+ total += data.y.size(0)
297
+ else:
298
+ out = model(data.x, data.edge_index)
299
+ if hasattr(data, "test_mask"):
300
+ pred = out[data.test_mask].argmax(dim=1)
301
+ correct += int((pred == data.y[data.test_mask]).sum())
302
+ total += int(data.test_mask.sum())
303
+ else:
304
+ pred = out.argmax(dim=1)
305
+ correct += int((pred == data.y).sum())
306
+ total += data.y.size(0)
307
+ return correct / total if total > 0 else 0.0
308
+
309
+
310
+ # ══════════════════════════════════════════════════════════════════════════════
311
+ # Architecture selection guide
312
+ # ══════════════════════════════════════════════════════════════════════════════
313
+
314
+ ARCHITECTURE_GUIDE = """
315
+ GNN Architecture Selection Guide — BMAD DL Lifecycle
316
+ ─────────────────────────────────────────────────────
317
+ Task: Node classification
318
+ Homophilic graph (similar nodes connected) → GCN
319
+ Attention needed (noisy neighbors) → GAT
320
+ Large / dynamic / inductive graph → GraphSAGE
321
+
322
+ Task: Graph classification
323
+ Standard accuracy → GraphSAGE or GCN + global pool
324
+ Maximum expressiveness → GIN (recommended)
325
+ Edge features matter → GAT with edge_attr
326
+
327
+ Quick model size guide:
328
+ Small dataset (<1K graphs) → 2 layers, hidden=64
329
+ Medium dataset (1K–50K) → 3 layers, hidden=128
330
+ Large dataset (50K+) → 4-5 layers, hidden=256, mini-batch DataLoader
331
+
332
+ Typical hyperparameter ranges:
333
+ hidden_channels: 64, 128, 256
334
+ num_layers: 2, 3, 4
335
+ dropout: 0.3 – 0.6
336
+ heads (GAT): 4, 8
337
+ learning_rate: 0.001 – 0.01
338
+ """
339
+
340
+ if __name__ == "__main__":
341
+ print(ARCHITECTURE_GUIDE)
@@ -0,0 +1,158 @@
1
+ """
2
+ template_lightning_module.py — BMAD DL Lifecycle
3
+ PyTorch Lightning LightningModule template for supervised classification/regression.
4
+
5
+ Drop this file into your project and fill in the TODO sections.
6
+
7
+ Usage:
8
+ Copy to src/models/your_model.py and implement:
9
+ - __init__: define layers
10
+ - forward: define forward pass
11
+ - _shared_step: compute loss + metrics for any split
12
+ The training/validation/test steps call _shared_step automatically.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ from typing import Any
18
+
19
+ import torch
20
+ import torch.nn as nn
21
+ import torch.nn.functional as F
22
+
23
+ try:
24
+ import lightning as L
25
+ LightningModule = L.LightningModule
26
+ except ImportError:
27
+ try:
28
+ import pytorch_lightning as pl
29
+ LightningModule = pl.LightningModule
30
+ except ImportError:
31
+ raise ImportError(
32
+ "Install PyTorch Lightning: pip install lightning\n"
33
+ " or: pip install pytorch-lightning"
34
+ )
35
+
36
+
37
+ class YourModel(LightningModule):
38
+ """
39
+ Template LightningModule for image/tabular classification or regression.
40
+
41
+ Replace 'YourModel' with a descriptive name (e.g. DefectClassifier, FruitNet).
42
+
43
+ Args:
44
+ num_classes: Number of output classes (use 1 for binary/regression).
45
+ learning_rate: Initial learning rate for the optimizer.
46
+ weight_decay: L2 regularization weight.
47
+ """
48
+
49
+ def __init__(
50
+ self,
51
+ num_classes: int = 2,
52
+ learning_rate: float = 1e-3,
53
+ weight_decay: float = 1e-4,
54
+ ):
55
+ super().__init__()
56
+ # Saves all __init__ args to self.hparams (enables checkpointing)
57
+ self.save_hyperparameters()
58
+
59
+ # ── TODO: Define your model architecture ──────────────────────────────
60
+ # Example: simple two-layer MLP for tabular data
61
+ self.encoder = nn.Sequential(
62
+ nn.Linear(128, 64), # TODO: replace 128 with your input dim
63
+ nn.BatchNorm1d(64),
64
+ nn.ReLU(),
65
+ nn.Dropout(0.3),
66
+ )
67
+ self.classifier = nn.Linear(64, num_classes)
68
+ # ── END TODO ──────────────────────────────────────────────────────────
69
+
70
+ # Loss function
71
+ if num_classes == 1:
72
+ self.loss_fn = nn.BCEWithLogitsLoss()
73
+ else:
74
+ self.loss_fn = nn.CrossEntropyLoss()
75
+
76
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
77
+ """
78
+ Forward pass.
79
+
80
+ Args:
81
+ x: Input tensor, shape depends on your architecture.
82
+ Returns:
83
+ Logits tensor of shape (batch, num_classes) or (batch, 1).
84
+ """
85
+ # ── TODO: Implement forward pass ──────────────────────────────────────
86
+ features = self.encoder(x)
87
+ logits = self.classifier(features)
88
+ return logits
89
+ # ── END TODO ──────────────────────────────────────────────────────────
90
+
91
+ def _shared_step(self, batch: Any, stage: str) -> torch.Tensor:
92
+ """
93
+ Common logic for train/val/test.
94
+
95
+ Args:
96
+ batch: Tuple of (inputs, labels) from your DataLoader.
97
+ stage: One of "train", "val", "test".
98
+ Returns:
99
+ Loss tensor.
100
+ """
101
+ # ── TODO: Unpack batch to match your DataLoader output ────────────────
102
+ x, y = batch # e.g. (images, labels) or (features, targets)
103
+ # ── END TODO ──────────────────────────────────────────────────────────
104
+
105
+ logits = self(x)
106
+
107
+ if self.hparams.num_classes == 1:
108
+ loss = self.loss_fn(logits.squeeze(1), y.float())
109
+ preds = (torch.sigmoid(logits.squeeze(1)) > 0.5).long()
110
+ else:
111
+ loss = self.loss_fn(logits, y.long())
112
+ preds = logits.argmax(dim=1)
113
+
114
+ acc = (preds == y).float().mean()
115
+
116
+ # Log metrics — appears in TensorBoard / W&B / CSV logger
117
+ self.log(f"{stage}/loss", loss, prog_bar=(stage == "val"), on_step=False, on_epoch=True)
118
+ self.log(f"{stage}/acc", acc, prog_bar=True, on_step=False, on_epoch=True)
119
+
120
+ return loss
121
+
122
+ # ── Lightning hooks (do not rename these) ─────────────────────────────────
123
+
124
+ def training_step(self, batch: Any, batch_idx: int) -> torch.Tensor:
125
+ loss = self._shared_step(batch, "train")
126
+ if torch.cuda.is_available():
127
+ self.log("gpu/memory_allocated_gb", torch.cuda.memory_allocated() / 1e9,
128
+ on_step=True, on_epoch=False, prog_bar=False)
129
+ return loss
130
+
131
+ def validation_step(self, batch: Any, batch_idx: int) -> None:
132
+ self._shared_step(batch, "val")
133
+
134
+ def test_step(self, batch: Any, batch_idx: int) -> None:
135
+ self._shared_step(batch, "test")
136
+
137
+ def configure_optimizers(self) -> dict:
138
+ """
139
+ Set up optimizer and learning rate scheduler.
140
+ Swap optimizer or scheduler as needed.
141
+ """
142
+ optimizer = torch.optim.AdamW(
143
+ self.parameters(),
144
+ lr=self.hparams.learning_rate,
145
+ weight_decay=self.hparams.weight_decay,
146
+ )
147
+ scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(
148
+ optimizer,
149
+ T_max=10, # TODO: set to your total_epochs
150
+ eta_min=1e-6,
151
+ )
152
+ return {
153
+ "optimizer": optimizer,
154
+ "lr_scheduler": {
155
+ "scheduler": scheduler,
156
+ "monitor": "val/loss",
157
+ },
158
+ }
@@ -0,0 +1,3 @@
1
+ type: skill
2
+ name: ml-experiment
3
+ module: ma-skills
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "ML Experiment Execution",
3
+ "description": "Executes training runs against a locked TECHSPEC and logs metrics to W&B/MLflow/ClearML.",
4
+ "version": "1.0.0",
5
+ "author": "Demerzel (ML Scientist)",
6
+ "tags": ["Machine Learning", "Experiment", "Training", "Logging", "Demerzel"]
7
+ }
File without changes
@@ -0,0 +1,81 @@
1
+ ---
2
+
3
+ name: ml-hparam
4
+
5
+ description: Acts as Demerzel (Machine Learning Scientist) to run structured hyperparameter optimization after a baseline architecture is confirmed to work. Uses Optuna, W&B Sweeps, or Ray Tune. Produces a validated best-parameter configuration for the next tuned experiment run.
6
+
7
+ ---
8
+
9
+ # Machine Learning Workflow: Hyperparameter Optimization (Conditional) — Demerzel
10
+
11
+ ## 1. Operating Instructions
12
+
13
+ You are **Demerzel**, an expert Machine Learning Scientist running structured hyperparameter search. **This stage is conditional.** Run it only after `ml-analysis` confirms the baseline architecture meets at least the "Worst case (alive)" tier in the TECHSPEC.
14
+
15
+ Your goal is to find the optimal parameter configuration within the search space defined in the TECHSPEC, then hand off validated parameters to the next `ml-experiment` run.
16
+
17
+ 1. **Verify the prerequisite:** Read the latest `ml-analysis-exp-[id].md`. Confirm: "Worst case (alive)" tier or better was reached. If not, recommend running `ml-revision` instead.
18
+
19
+ 2. **Read the TECHSPEC:** `_bmad-output/planning-artifacts/techspecs/ml-techspec-exp-[id].md` — use Section C as the HPO search space.
20
+
21
+ 3. **Run the advisor:** `/ml-advise` — check if any past HPO runs exist.
22
+
23
+ 4. **Run the HPO search:** (Optuna, W&B Sweeps, or Ray Tune).
24
+ - Define objective: Maximize the primary metric from the PRD.
25
+ - Use early stopping to save budget.
26
+ - Example (Optuna):
27
+ ```python
28
+ import optuna
29
+ def objective(trial):
30
+ lr = trial.suggest_float("lr", 1e-5, 1e-2, log=True)
31
+ # train and return f1
32
+ return f1
33
+ study = optuna.create_study(direction="maximize")
34
+ study.optimize(objective, n_trials=50)
35
+ ```
36
+
37
+ 5. **CRITICAL:** Do not write the HPO report yet. Present the top-5 parameter configurations to the user and ask for sign-off. Halt and wait.
38
+
39
+ 6. Upon confirmation, write `_bmad-output/planning-artifacts/techspecs/ml-hparam-exp-[id].md` with the validated best configuration and update the original TECHSPEC.
40
+
41
+ 7. **Commit the HPO artifact:**
42
+ ```bash
43
+ git add _bmad-output/planning-artifacts/techspecs/ml-hparam-exp-[id].md
44
+ git commit -m "docs(ml-hparam): validated best config for EXP-[id] val/f1=[score]"
45
+ ```
46
+
47
+ ## 2. Expected Output Template
48
+
49
+ ### Template A: `_bmad-output/planning-artifacts/techspecs/ml-hparam-exp-[id].md`
50
+
51
+ ```markdown
52
+ # HPO Results: EXP-[ID]
53
+
54
+ ## A. Search Summary
55
+ * **Linked Experiment:** EXP-[ID]
56
+ * **HPO Tool:** [Optuna / W&B Sweeps / Ray Tune]
57
+ * **Sweep URL:** [link]
58
+
59
+ ## B. Top Configurations
60
+ | Rank | lr | batch_size | dropout | val/f1 | Run URL |
61
+ | :--- | :--- | :--- | :--- | :--- | :--- |
62
+ | 1 (best) | 2.3e-4 | 1024 | 0.22 | 0.94 | [link] |
63
+
64
+ ## C. Parameter Importance
65
+ * [Which params had highest impact from study analysis.]
66
+
67
+ ## D. Validated Best Configuration (copy-paste ready)
68
+ ```yaml
69
+ learning_rate: 2.3e-4
70
+ batch_size: 1024
71
+ dropout: 0.22
72
+ ```
73
+
74
+ ## E. Scientist Sign-off
75
+ * [ ] Best params are within real-world acceptable ranges.
76
+ * [ ] No anomalous values.
77
+ * **Signed off by:** [Demerzel / Date]
78
+
79
+ ## F. Next Step
80
+ * Run `/ml-experiment` with run_type="tuned" using the above config.
81
+ ```
@@ -0,0 +1,3 @@
1
+ type: skill
2
+ name: ml-hparam
3
+ module: ma-skills
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "ML Hyperparameter Optimization",
3
+ "description": "Runs structured HPO using Optuna, W&B Sweeps, or Ray Tune after a baseline is confirmed.",
4
+ "version": "1.0.0",
5
+ "author": "Demerzel (ML Scientist)",
6
+ "tags": ["Machine Learning", "HPO", "Optimization", "Optuna", "Sweeps", "Demerzel"]
7
+ }
File without changes
@@ -0,0 +1,50 @@
1
+ ---
2
+ name: ml-ideation
3
+ description: ML Ideation — Frame the research problem, define success criteria, and produce a Machine Learning PRD
4
+ ---
5
+
6
+ # ML Stage 1 — Ideation & PRD
7
+
8
+ Frame the ML problem rigorously before any data or modelling work begins.
9
+
10
+ ## Instructions
11
+
12
+ ### 1. Elicit Problem Context
13
+ Ask the user for (or extract from context):
14
+ - **Business problem**: What decision or process will the model improve?
15
+ - **Target variable**: What are we predicting? (classification / regression / ranking / generation)
16
+ - **Failure cost asymmetry**: What is the cost of a false negative vs a false positive in this domain?
17
+ - **Success definition**: What metric threshold constitutes a production-ready model?
18
+ - **Data availability**: What raw datasets exist and where are they located?
19
+
20
+ ### 2. Produce Research Thesis
21
+ Write `_bmad-output/planning-artifacts/research-thesis.md` with:
22
+ - **Hypothesis**: A single falsifiable statement (e.g. "We can predict X with >Y recall using features A, B, C")
23
+ - **Assumptions**: List all assumptions that must hold for the hypothesis to be testable
24
+ - **Risks**: Top 3 risks that could invalidate the hypothesis (data quality, label noise, distribution shift)
25
+ - **Null Hypothesis**: The baseline we must beat (random, heuristic, or existing system)
26
+
27
+ ### 3. Produce ML PRD
28
+ Write `_bmad-output/planning-artifacts/ml-prd.md` with sections:
29
+ - **Problem Statement** (1 paragraph)
30
+ - **Stakeholders & Users**
31
+ - **Success Metrics** (primary metric, secondary metrics, guardrail metrics)
32
+ - **Failure Cost Matrix** (FP cost vs FN cost with domain justification)
33
+ - **Data Requirements** (source, volume, freshness, labelling)
34
+ - **Out of Scope** (explicit non-goals)
35
+ - **Dependencies** (upstream data pipelines, external APIs)
36
+
37
+ ### 4. Surface Dilemmas & Commit Gate
38
+
39
+ Before presenting and **before any git commit**:
40
+
41
+ - Identify every framing choice where two or more reasonable options existed (metric threshold, failure cost ratio, scope boundary, two-stage vs single-stage, etc.)
42
+ - Format each as: **Dilemma [Letter] — Title** / **Context** / **Options (a/b)** / **Recommendation** / **Your decision:** [blank]
43
+ - If all choices were unambiguous, state explicitly: "No open dilemmas."
44
+ - **Do NOT commit any artifact until the user has responded and given explicit approval.**
45
+
46
+ ### 5. Confirm & Advance
47
+ - Present both documents to the user for review
48
+ - Ask: "Do you approve this framing, or would you like to adjust the hypothesis or success criteria?"
49
+ - On approval: commit artifacts, then say "Stage 1 complete. When ready, proceed to **Stage 2 — /ml-eda** to analyze the raw data."
50
+ - STOP and WAIT for user confirmation before advancing
@@ -0,0 +1,3 @@
1
+ type: skill
2
+ name: ml-ideation
3
+ module: ma-skills