ma-agents 2.20.3 → 2.22.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 (149) hide show
  1. package/.opencode/skills/.ma-agents.json +241 -0
  2. package/.opencode/skills/MANIFEST.yaml +254 -0
  3. package/.opencode/skills/ai-audit-trail/SKILL.md +23 -0
  4. package/.opencode/skills/auto-bug-detection/SKILL.md +169 -0
  5. package/.opencode/skills/cmake-best-practices/SKILL.md +64 -0
  6. package/.opencode/skills/cmake-best-practices/examples/cmake.md +59 -0
  7. package/.opencode/skills/code-documentation/SKILL.md +57 -0
  8. package/.opencode/skills/code-documentation/examples/cpp.md +29 -0
  9. package/.opencode/skills/code-documentation/examples/csharp.md +28 -0
  10. package/.opencode/skills/code-documentation/examples/javascript_typescript.md +28 -0
  11. package/.opencode/skills/code-documentation/examples/python.md +57 -0
  12. package/.opencode/skills/code-review/SKILL.md +43 -0
  13. package/.opencode/skills/commit-message/SKILL.md +79 -0
  14. package/.opencode/skills/cpp-best-practices/SKILL.md +234 -0
  15. package/.opencode/skills/cpp-best-practices/examples/modern-idioms.md +189 -0
  16. package/.opencode/skills/cpp-best-practices/examples/naming-and-organization.md +102 -0
  17. package/.opencode/skills/cpp-concurrency-safety/SKILL.md +60 -0
  18. package/.opencode/skills/cpp-concurrency-safety/examples/concurrency.md +73 -0
  19. package/.opencode/skills/cpp-const-correctness/SKILL.md +63 -0
  20. package/.opencode/skills/cpp-const-correctness/examples/const_correctness.md +54 -0
  21. package/.opencode/skills/cpp-memory-handling/SKILL.md +42 -0
  22. package/.opencode/skills/cpp-memory-handling/examples/modern-cpp.md +49 -0
  23. package/.opencode/skills/cpp-memory-handling/examples/smart-pointers.md +46 -0
  24. package/.opencode/skills/cpp-modern-composition/SKILL.md +64 -0
  25. package/.opencode/skills/cpp-modern-composition/examples/composition.md +51 -0
  26. package/.opencode/skills/cpp-robust-interfaces/SKILL.md +55 -0
  27. package/.opencode/skills/cpp-robust-interfaces/examples/interfaces.md +56 -0
  28. package/.opencode/skills/create-hardened-docker-skill/SKILL.md +637 -0
  29. package/.opencode/skills/create-hardened-docker-skill/scripts/create-all.sh +489 -0
  30. package/.opencode/skills/csharp-best-practices/SKILL.md +278 -0
  31. package/.opencode/skills/docker-hardening-verification/SKILL.md +28 -0
  32. package/.opencode/skills/docker-hardening-verification/scripts/verify-hardening.sh +39 -0
  33. package/.opencode/skills/docker-image-signing/SKILL.md +28 -0
  34. package/.opencode/skills/docker-image-signing/scripts/sign-image.sh +33 -0
  35. package/.opencode/skills/document-revision-history/SKILL.md +104 -0
  36. package/.opencode/skills/git-workflow-skill/SKILL.md +194 -0
  37. package/.opencode/skills/git-workflow-skill/hooks/commit-msg +61 -0
  38. package/.opencode/skills/git-workflow-skill/hooks/pre-commit +38 -0
  39. package/.opencode/skills/git-workflow-skill/hooks/prepare-commit-msg +56 -0
  40. package/.opencode/skills/git-workflow-skill/scripts/finish-feature.sh +192 -0
  41. package/.opencode/skills/git-workflow-skill/scripts/install-hooks.sh +55 -0
  42. package/.opencode/skills/git-workflow-skill/scripts/start-feature.sh +110 -0
  43. package/.opencode/skills/git-workflow-skill/scripts/validate-workflow.sh +229 -0
  44. package/.opencode/skills/js-ts-dependency-mgmt/SKILL.md +49 -0
  45. package/.opencode/skills/js-ts-dependency-mgmt/examples/dependency_mgmt.md +60 -0
  46. package/.opencode/skills/js-ts-security-skill/SKILL.md +64 -0
  47. package/.opencode/skills/js-ts-security-skill/scripts/verify-security.sh +136 -0
  48. package/.opencode/skills/logging-best-practices/SKILL.md +50 -0
  49. package/.opencode/skills/logging-best-practices/examples/cpp.md +36 -0
  50. package/.opencode/skills/logging-best-practices/examples/csharp.md +49 -0
  51. package/.opencode/skills/logging-best-practices/examples/javascript.md +77 -0
  52. package/.opencode/skills/logging-best-practices/examples/python.md +57 -0
  53. package/.opencode/skills/logging-best-practices/references/logging-standards.md +29 -0
  54. package/.opencode/skills/open-presentation/SKILL.md +35 -0
  55. package/.opencode/skills/opentelemetry-best-practices/SKILL.md +34 -0
  56. package/.opencode/skills/opentelemetry-best-practices/examples/go.md +32 -0
  57. package/.opencode/skills/opentelemetry-best-practices/examples/javascript.md +58 -0
  58. package/.opencode/skills/opentelemetry-best-practices/examples/python.md +37 -0
  59. package/.opencode/skills/opentelemetry-best-practices/references/otel-standards.md +37 -0
  60. package/.opencode/skills/python-best-practices/SKILL.md +385 -0
  61. package/.opencode/skills/python-dependency-mgmt/SKILL.md +42 -0
  62. package/.opencode/skills/python-dependency-mgmt/examples/dependency_mgmt.md +67 -0
  63. package/.opencode/skills/python-security-skill/SKILL.md +56 -0
  64. package/.opencode/skills/python-security-skill/examples/security.md +56 -0
  65. package/.opencode/skills/self-signed-cert/SKILL.md +42 -0
  66. package/.opencode/skills/self-signed-cert/scripts/generate-cert.ps1 +45 -0
  67. package/.opencode/skills/self-signed-cert/scripts/generate-cert.sh +43 -0
  68. package/.opencode/skills/skill-creator/SKILL.md +196 -0
  69. package/.opencode/skills/skill-creator/references/output-patterns.md +82 -0
  70. package/.opencode/skills/skill-creator/references/workflows.md +28 -0
  71. package/.opencode/skills/skill-creator/scripts/init_skill.py +208 -0
  72. package/.opencode/skills/skill-creator/scripts/package_skill.py +99 -0
  73. package/.opencode/skills/skill-creator/scripts/quick_validate.py +113 -0
  74. package/.opencode/skills/story-status-lookup/SKILL.md +78 -0
  75. package/.opencode/skills/test-accompanied-development/SKILL.md +50 -0
  76. package/.opencode/skills/test-generator/SKILL.md +65 -0
  77. package/.opencode/skills/vercel-react-best-practices/SKILL.md +109 -0
  78. package/.opencode/skills/verify-hardened-docker-skill/SKILL.md +442 -0
  79. package/.opencode/skills/verify-hardened-docker-skill/scripts/verify-docker-hardening.sh +439 -0
  80. package/AiAudit.md +5 -0
  81. package/QUICK_START.md +11 -5
  82. package/README.md +52 -1
  83. package/bin/cli.js +31 -4
  84. package/docs/BMAD_AI_Development_Training.pptx +0 -0
  85. package/docs/technical-notes/context-persistence-research.md +434 -0
  86. package/docs/technical-notes/enforcement-hooks-research.md +415 -0
  87. package/lib/agents.js +34 -0
  88. package/lib/bmad-extension/agents/bmm-architect.customize.yaml +5 -0
  89. package/lib/bmad-extension/agents/bmm-bmad-master.customize.yaml +5 -0
  90. package/lib/bmad-extension/agents/bmm-cyber.customize.yaml +30 -0
  91. package/lib/bmad-extension/agents/bmm-dev.customize.yaml +5 -0
  92. package/lib/bmad-extension/agents/bmm-devops.customize.yaml +30 -0
  93. package/lib/bmad-extension/agents/bmm-mil498.customize.yaml +42 -0
  94. package/lib/bmad-extension/agents/bmm-pm.customize.yaml +5 -0
  95. package/lib/bmad-extension/agents/bmm-qa.customize.yaml +5 -0
  96. package/lib/bmad-extension/agents/bmm-sm.customize.yaml +5 -0
  97. package/lib/bmad-extension/agents/bmm-sre.customize.yaml +30 -0
  98. package/lib/bmad-extension/agents/bmm-tech-writer.customize.yaml +5 -0
  99. package/lib/bmad-extension/agents/bmm-ux-designer.customize.yaml +5 -0
  100. package/lib/bmad-extension/module-help.csv +7 -0
  101. package/lib/bmad-extension/module.yaml +3 -0
  102. package/lib/bmad-extension/workflows/add-sprint/workflow.md +112 -0
  103. package/lib/bmad-extension/workflows/add-to-sprint/workflow.md +206 -0
  104. package/lib/bmad-extension/workflows/create-bug-story/workflow.md +186 -0
  105. package/lib/bmad-extension/workflows/modify-sprint/workflow.md +250 -0
  106. package/lib/bmad-extension/workflows/project-context-expansion/workflow.md +229 -0
  107. package/lib/bmad-extension/workflows/sprint-status-view/workflow.md +193 -0
  108. package/lib/bmad.js +168 -36
  109. package/lib/hooks/claude-code/verify-manifest.js +56 -0
  110. package/lib/installer.js +282 -1
  111. package/lib/methodology/BMAD_AI_Development_Training.pptx +0 -0
  112. package/lib/methodology/version.json +7 -0
  113. package/lib/skill-authoring.js +732 -0
  114. package/lib/templates/project-context.template.md +47 -0
  115. package/opencode.json +8 -0
  116. package/package.json +2 -2
  117. package/skills/auto-bug-detection/SKILL.md +165 -0
  118. package/skills/auto-bug-detection/skill.json +8 -0
  119. package/skills/code-review/SKILL.md +40 -0
  120. package/skills/cpp-best-practices/SKILL.md +230 -0
  121. package/skills/cpp-best-practices/examples/modern-idioms.md +189 -0
  122. package/skills/cpp-best-practices/examples/naming-and-organization.md +102 -0
  123. package/skills/cpp-best-practices/skill.json +25 -0
  124. package/skills/csharp-best-practices/SKILL.md +274 -0
  125. package/skills/csharp-best-practices/skill.json +23 -0
  126. package/skills/git-workflow-skill/skill.json +1 -1
  127. package/skills/open-presentation/SKILL.md +31 -0
  128. package/skills/open-presentation/skill.json +11 -0
  129. package/skills/python-best-practices/SKILL.md +381 -0
  130. package/skills/python-best-practices/skill.json +26 -0
  131. package/skills/story-status-lookup/SKILL.md +74 -0
  132. package/skills/story-status-lookup/skill.json +8 -0
  133. package/test/agent-injection-strategy.test.js +13 -7
  134. package/test/bmad-extension.test.js +237 -0
  135. package/test/bmad-output-policy.test.js +119 -0
  136. package/test/build-bmad-args.test.js +361 -0
  137. package/test/create-agent.test.js +232 -0
  138. package/test/enforcement-hooks.test.js +324 -0
  139. package/test/generate-project-context.test.js +337 -0
  140. package/test/integration-verification.test.js +402 -0
  141. package/test/opencode-agent.test.js +150 -0
  142. package/test/opencode-json-error.test.js +260 -0
  143. package/test/opencode-json-injection.test.js +256 -0
  144. package/test/opencode-json-merge.test.js +299 -0
  145. package/test/skill-authoring.test.js +272 -0
  146. package/test/skill-customize-agent.test.js +253 -0
  147. package/test/skill-mandatory.test.js +235 -0
  148. package/test/skill-validation.test.js +378 -0
  149. package/test/yes-flag.test.js +1 -1
@@ -0,0 +1,439 @@
1
+ #!/bin/bash
2
+ #
3
+ # verify-docker-hardening.sh
4
+ # Comprehensive Docker security verification script
5
+ # Checks Dockerfile, docker-compose.yml, and running containers
6
+ # against CIS, OWASP, and NIST standards
7
+ #
8
+
9
+ set -e
10
+
11
+ # Colors for output
12
+ RED='\033[0;31m'
13
+ GREEN='\033[0;32m'
14
+ YELLOW='\033[1;33m'
15
+ BLUE='\033[0;34m'
16
+ NC='\033[0m' # No Color
17
+
18
+ # Configuration
19
+ IMAGE_NAME="${1:-contacts-app}"
20
+ CONTAINER_NAME="${2:-contacts-app}"
21
+ EXIT_CODE=0
22
+
23
+ # Counters
24
+ TOTAL_CHECKS=0
25
+ PASSED_CHECKS=0
26
+ FAILED_CHECKS=0
27
+ WARNING_CHECKS=0
28
+
29
+ # Helper functions
30
+ print_header() {
31
+ echo ""
32
+ echo -e "${BLUE}========================================${NC}"
33
+ echo -e "${BLUE}$1${NC}"
34
+ echo -e "${BLUE}========================================${NC}"
35
+ }
36
+
37
+ print_check() {
38
+ TOTAL_CHECKS=$((TOTAL_CHECKS + 1))
39
+ echo -ne " [$TOTAL_CHECKS] $1... "
40
+ }
41
+
42
+ pass() {
43
+ PASSED_CHECKS=$((PASSED_CHECKS + 1))
44
+ echo -e "${GREEN}✅ PASS${NC}"
45
+ }
46
+
47
+ fail() {
48
+ FAILED_CHECKS=$((FAILED_CHECKS + 1))
49
+ EXIT_CODE=2
50
+ echo -e "${RED}❌ FAIL${NC}"
51
+ [ -n "$1" ] && echo -e " ${RED}→ $1${NC}"
52
+ }
53
+
54
+ warn() {
55
+ WARNING_CHECKS=$((WARNING_CHECKS + 1))
56
+ echo -e "${YELLOW}⚠️ WARN${NC}"
57
+ [ -n "$1" ] && echo -e " ${YELLOW}→ $1${NC}"
58
+ }
59
+
60
+ critical() {
61
+ FAILED_CHECKS=$((FAILED_CHECKS + 1))
62
+ EXIT_CODE=1
63
+ echo -e "${RED}🚨 CRITICAL${NC}"
64
+ [ -n "$1" ] && echo -e " ${RED}→ $1${NC}"
65
+ }
66
+
67
+ # Start verification
68
+ echo -e "${BLUE}🔍 Docker Security Verification${NC}"
69
+ echo -e "${BLUE}================================${NC}"
70
+ echo "Image: $IMAGE_NAME"
71
+ echo "Container: $CONTAINER_NAME"
72
+
73
+ # ============================================================================
74
+ # 1. Dockerfile Verification
75
+ # ============================================================================
76
+ print_header "1. Dockerfile Security"
77
+
78
+ if [ ! -f "Dockerfile" ]; then
79
+ print_check "Dockerfile exists"
80
+ critical "Dockerfile not found in current directory"
81
+ EXIT_CODE=5
82
+ exit $EXIT_CODE
83
+ fi
84
+
85
+ # Check for specific version tags
86
+ print_check "Specific version tags (no :latest)"
87
+ if grep -qE "^FROM.*:(latest|alpine)$" Dockerfile; then
88
+ fail "Using :latest or unversioned :alpine tag"
89
+ else
90
+ pass
91
+ fi
92
+
93
+ # Check for non-root user
94
+ print_check "Non-root user configured"
95
+ if grep -qE "^USER (root|[0-9]+)" Dockerfile; then
96
+ if grep -qE "^USER root" Dockerfile; then
97
+ fail "Running as root user"
98
+ else
99
+ pass
100
+ fi
101
+ elif grep -qE "^USER [a-zA-Z]" Dockerfile; then
102
+ pass
103
+ else
104
+ fail "No USER directive found"
105
+ fi
106
+
107
+ # Check for HEALTHCHECK
108
+ print_check "HEALTHCHECK instruction"
109
+ if grep -q "^HEALTHCHECK" Dockerfile; then
110
+ pass
111
+ else
112
+ warn "Missing HEALTHCHECK instruction"
113
+ fi
114
+
115
+ # Check for hardcoded secrets
116
+ print_check "No hardcoded secrets in ENV/ARG"
117
+ if grep -iE "^(ENV|ARG).*(SECRET|PASSWORD|KEY|TOKEN|CLIENT_ID)=" Dockerfile | grep -v "REACT_APP_API_BASE_URL" > /dev/null; then
118
+ fail "Potential hardcoded secrets found"
119
+ else
120
+ pass
121
+ fi
122
+
123
+ # Check for multi-stage build
124
+ print_check "Multi-stage build pattern"
125
+ if [ $(grep -c "^FROM" Dockerfile) -ge 2 ]; then
126
+ pass
127
+ else
128
+ warn "Not using multi-stage build"
129
+ fi
130
+
131
+ # Check for Alpine base images
132
+ print_check "Minimal Alpine base images"
133
+ if grep -qE "^FROM.*alpine" Dockerfile; then
134
+ pass
135
+ else
136
+ warn "Not using Alpine base images"
137
+ fi
138
+
139
+ # ============================================================================
140
+ # 2. docker-compose.yml Verification
141
+ # ============================================================================
142
+ print_header "2. docker-compose.yml Security"
143
+
144
+ if [ ! -f "docker-compose.yml" ]; then
145
+ print_check "docker-compose.yml exists"
146
+ warn "docker-compose.yml not found (optional)"
147
+ else
148
+ # Check for read-only filesystem
149
+ print_check "Read-only root filesystem"
150
+ if grep -q "read_only: true" docker-compose.yml; then
151
+ pass
152
+ else
153
+ fail "Missing read_only: true"
154
+ fi
155
+
156
+ # Check for no-new-privileges
157
+ print_check "No new privileges"
158
+ if grep -q "no-new-privileges:true" docker-compose.yml; then
159
+ pass
160
+ else
161
+ fail "Missing security_opt: no-new-privileges:true"
162
+ fi
163
+
164
+ # Check for capability dropping
165
+ print_check "Capabilities dropped"
166
+ if grep -q "cap_drop:" docker-compose.yml; then
167
+ pass
168
+ else
169
+ fail "Missing cap_drop configuration"
170
+ fi
171
+
172
+ # Check for tmpfs mounts
173
+ print_check "Tmpfs mounts for writable dirs"
174
+ if grep -q "tmpfs:" docker-compose.yml; then
175
+ pass
176
+ else
177
+ fail "Missing tmpfs mounts"
178
+ fi
179
+
180
+ # Check for resource limits
181
+ print_check "Memory limits configured"
182
+ if grep -q "memory:" docker-compose.yml; then
183
+ pass
184
+ else
185
+ warn "Missing memory limits"
186
+ fi
187
+
188
+ print_check "CPU limits configured"
189
+ if grep -q "cpus:" docker-compose.yml; then
190
+ pass
191
+ else
192
+ warn "Missing CPU limits"
193
+ fi
194
+
195
+ # Check for health check
196
+ print_check "Healthcheck configured"
197
+ if grep -q "healthcheck:" docker-compose.yml; then
198
+ pass
199
+ else
200
+ warn "Missing healthcheck configuration"
201
+ fi
202
+
203
+ # Check for privileged mode
204
+ print_check "Not running in privileged mode"
205
+ if grep -q "privileged: true" docker-compose.yml; then
206
+ critical "Running in privileged mode"
207
+ else
208
+ pass
209
+ fi
210
+ fi
211
+
212
+ # ============================================================================
213
+ # 3. .dockerignore Verification
214
+ # ============================================================================
215
+ print_header "3. .dockerignore Configuration"
216
+
217
+ if [ ! -f ".dockerignore" ]; then
218
+ print_check ".dockerignore exists"
219
+ warn ".dockerignore not found"
220
+ else
221
+ print_check ".env excluded from Docker context"
222
+ if grep -qE "^\.env$" .dockerignore; then
223
+ pass
224
+ else
225
+ critical ".env not in .dockerignore - secret leakage risk!"
226
+ fi
227
+
228
+ print_check "node_modules excluded"
229
+ if grep -q "node_modules" .dockerignore; then
230
+ pass
231
+ else
232
+ warn "node_modules not excluded"
233
+ fi
234
+
235
+ print_check ".git excluded"
236
+ if grep -qE "^\.git" .dockerignore; then
237
+ pass
238
+ else
239
+ warn ".git not excluded"
240
+ fi
241
+ fi
242
+
243
+ # ============================================================================
244
+ # 4. Image Security Scanning
245
+ # ============================================================================
246
+ print_header "4. Image Vulnerability Scanning"
247
+
248
+ # Check if image exists
249
+ if ! docker images --format "{{.Repository}}" | grep -q "^${IMAGE_NAME}$"; then
250
+ print_check "Docker image exists"
251
+ warn "Image '$IMAGE_NAME' not found locally. Skipping image scans."
252
+ echo " Run 'docker build -t $IMAGE_NAME .' to build the image."
253
+ else
254
+ # Check if trivy is installed
255
+ if ! command -v trivy &> /dev/null; then
256
+ print_check "Trivy scanner installed"
257
+ warn "Trivy not installed. Skipping vulnerability scans."
258
+ echo " Install: brew install aquasecurity/trivy/trivy (macOS)"
259
+ echo " : apt-get install trivy (Linux)"
260
+ else
261
+ # Scan for CRITICAL vulnerabilities
262
+ print_check "No CRITICAL vulnerabilities"
263
+ if trivy image --quiet --severity CRITICAL --exit-code 1 "$IMAGE_NAME" > /dev/null 2>&1; then
264
+ pass
265
+ else
266
+ critical "CRITICAL vulnerabilities found. Run: trivy image --severity CRITICAL $IMAGE_NAME"
267
+ fi
268
+
269
+ # Scan for HIGH vulnerabilities
270
+ print_check "No HIGH vulnerabilities"
271
+ if trivy image --quiet --severity HIGH --exit-code 1 "$IMAGE_NAME" > /dev/null 2>&1; then
272
+ pass
273
+ else
274
+ fail "HIGH vulnerabilities found. Run: trivy image --severity HIGH $IMAGE_NAME"
275
+ fi
276
+
277
+ # Scan for leaked secrets
278
+ print_check "No leaked secrets in image"
279
+ if trivy image --quiet --scanners secret --exit-code 1 "$IMAGE_NAME" > /dev/null 2>&1; then
280
+ pass
281
+ else
282
+ critical "Secrets detected in image! Run: trivy image --scanners secret $IMAGE_NAME"
283
+ fi
284
+ fi
285
+
286
+ # Check image size
287
+ print_check "Optimized image size (< 100MB)"
288
+ IMAGE_SIZE=$(docker images --format "{{.Size}}" "$IMAGE_NAME" | head -1 | sed 's/MB//' | sed 's/GB/*1024/' | bc 2>/dev/null || echo "0")
289
+ if [ -n "$IMAGE_SIZE" ] && [ "$IMAGE_SIZE" != "0" ]; then
290
+ if (( $(echo "$IMAGE_SIZE < 100" | bc -l) )); then
291
+ pass
292
+ else
293
+ warn "Image size is ${IMAGE_SIZE}MB (recommended < 100MB)"
294
+ fi
295
+ else
296
+ warn "Could not determine image size"
297
+ fi
298
+
299
+ # Check for .env in image
300
+ print_check ".env file not baked into image"
301
+ if docker run --rm "$IMAGE_NAME" sh -c "ls -la / 2>/dev/null | grep -q .env"; then
302
+ critical ".env file found in image! Secrets leaked!"
303
+ else
304
+ pass
305
+ fi
306
+ fi
307
+
308
+ # ============================================================================
309
+ # 5. Runtime Security (if container is running)
310
+ # ============================================================================
311
+ print_header "5. Runtime Security Verification"
312
+
313
+ if ! docker ps --filter "name=$CONTAINER_NAME" --format "{{.Names}}" | grep -q "^$CONTAINER_NAME$"; then
314
+ echo -e "${YELLOW} Container '$CONTAINER_NAME' is not running.${NC}"
315
+ echo -e "${YELLOW} Run 'docker-compose up -d' to enable runtime checks.${NC}"
316
+ else
317
+ # Check container runs as non-root
318
+ print_check "Container runs as non-root"
319
+ CONTAINER_USER=$(docker exec "$CONTAINER_NAME" whoami 2>/dev/null || echo "root")
320
+ if [ "$CONTAINER_USER" != "root" ]; then
321
+ pass
322
+ else
323
+ critical "Container running as root user!"
324
+ fi
325
+
326
+ # Check user ID is not 0
327
+ print_check "User ID is not 0 (root)"
328
+ USER_ID=$(docker exec "$CONTAINER_NAME" id -u 2>/dev/null || echo "0")
329
+ if [ "$USER_ID" != "0" ]; then
330
+ pass
331
+ else
332
+ critical "Container running with UID 0 (root)!"
333
+ fi
334
+
335
+ # Check read-only filesystem
336
+ print_check "Root filesystem is read-only"
337
+ if docker exec "$CONTAINER_NAME" sh -c "touch /test 2>/dev/null"; then
338
+ fail "Root filesystem is writable"
339
+ docker exec "$CONTAINER_NAME" sh -c "rm /test 2>/dev/null" || true
340
+ else
341
+ pass
342
+ fi
343
+
344
+ # Check tmpfs is writable
345
+ print_check "Tmpfs mount is writable"
346
+ if docker exec "$CONTAINER_NAME" sh -c "touch /tmp/test 2>/dev/null && rm /tmp/test 2>/dev/null"; then
347
+ pass
348
+ else
349
+ warn "Tmpfs mount /tmp is not writable"
350
+ fi
351
+
352
+ # Check health status
353
+ print_check "Container is healthy"
354
+ HEALTH_STATUS=$(docker inspect --format='{{.State.Health.Status}}' "$CONTAINER_NAME" 2>/dev/null || echo "none")
355
+ if [ "$HEALTH_STATUS" = "healthy" ]; then
356
+ pass
357
+ elif [ "$HEALTH_STATUS" = "none" ]; then
358
+ warn "No health check configured"
359
+ else
360
+ fail "Container health status: $HEALTH_STATUS"
361
+ fi
362
+
363
+ # Check capabilities
364
+ print_check "Capabilities dropped"
365
+ CAPS_DROPPED=$(docker inspect --format='{{.HostConfig.CapDrop}}' "$CONTAINER_NAME" 2>/dev/null || echo "[]")
366
+ if echo "$CAPS_DROPPED" | grep -q "ALL"; then
367
+ pass
368
+ else
369
+ warn "Not all capabilities dropped"
370
+ fi
371
+
372
+ # Check memory limit
373
+ print_check "Memory limit enforced"
374
+ MEMORY_LIMIT=$(docker inspect --format='{{.HostConfig.Memory}}' "$CONTAINER_NAME" 2>/dev/null || echo "0")
375
+ if [ "$MEMORY_LIMIT" != "0" ]; then
376
+ pass
377
+ else
378
+ warn "No memory limit set"
379
+ fi
380
+ fi
381
+
382
+ # ============================================================================
383
+ # 6. Git Secret Protection
384
+ # ============================================================================
385
+ print_header "6. Git Secret Protection"
386
+
387
+ if [ -d ".git" ]; then
388
+ # Check .env in .gitignore
389
+ print_check ".env in .gitignore"
390
+ if [ -f ".gitignore" ] && grep -qE "^\.env$" .gitignore; then
391
+ pass
392
+ else
393
+ critical ".env not in .gitignore! Secrets may be committed!"
394
+ fi
395
+
396
+ # Check .env.example exists
397
+ print_check ".env.example exists (template)"
398
+ if [ -f ".env.example" ]; then
399
+ pass
400
+ else
401
+ warn ".env.example not found"
402
+ fi
403
+
404
+ # Check if .env is committed
405
+ print_check ".env not committed to git"
406
+ if git ls-files --error-unmatch .env > /dev/null 2>&1; then
407
+ critical ".env is tracked by git! Remove immediately!"
408
+ else
409
+ pass
410
+ fi
411
+ else
412
+ echo -e "${YELLOW} Not a git repository. Skipping git checks.${NC}"
413
+ fi
414
+
415
+ # ============================================================================
416
+ # Summary
417
+ # ============================================================================
418
+ print_header "Verification Summary"
419
+
420
+ echo ""
421
+ echo " Total checks: $TOTAL_CHECKS"
422
+ echo -e " ${GREEN}Passed: $PASSED_CHECKS${NC}"
423
+ echo -e " ${YELLOW}Warnings: $WARNING_CHECKS${NC}"
424
+ echo -e " ${RED}Failed: $FAILED_CHECKS${NC}"
425
+ echo ""
426
+
427
+ if [ $FAILED_CHECKS -eq 0 ]; then
428
+ echo -e "${GREEN}✅ All critical security checks passed!${NC}"
429
+ if [ $WARNING_CHECKS -gt 0 ]; then
430
+ echo -e "${YELLOW}⚠️ $WARNING_CHECKS warning(s) - consider addressing these.${NC}"
431
+ fi
432
+ else
433
+ echo -e "${RED}❌ $FAILED_CHECKS security check(s) failed!${NC}"
434
+ echo -e "${RED} Please fix the issues above before deploying.${NC}"
435
+ fi
436
+
437
+ echo ""
438
+
439
+ exit $EXIT_CODE
package/AiAudit.md ADDED
@@ -0,0 +1,5 @@
1
+ # AI Audit Trail
2
+
3
+ | Date | Task | Tokens (est.) |
4
+ |------|------|---------------|
5
+ | 2026-03-18 | Story 9.2: JSON Injection — Create opencode.json When Absent. Added MA_AGENTS_SOURCE constant, json-merge branch in updateAgentInstructions(), and 12-test fixture suite. | In: ~18K / Out: ~6K |
package/QUICK_START.md CHANGED
@@ -7,14 +7,14 @@ Get started with AI Agent Skills in 2 minutes!
7
7
  No installation needed! Just run:
8
8
 
9
9
  ```bash
10
- npx ai-agent-skills
10
+ npx ma-agents
11
11
  ```
12
12
 
13
13
  ## Using the CLI
14
14
 
15
15
  1. **Run the tool:**
16
16
  ```bash
17
- npx ai-agent-skills
17
+ npx ma-agents
18
18
  ```
19
19
 
20
20
  2. **Select "Install a skill"**
@@ -38,23 +38,29 @@ npx ai-agent-skills
38
38
 
39
39
  6. **Done!** The skill is now available in your selected agents.
40
40
 
41
+ > **Project-level install also generates `_bmad-output/project-context.md`** — a constitutional
42
+ > document that tells AI agents which skills to load and how to run missions in this project.
43
+ > It is never overwritten on reinstall, and its MANIFEST paths are kept up to date on every
44
+ > subsequent install. See [Project Context](README.md#project-context) in the README for details
45
+ > on what it contains and how to expand it over time.
46
+
41
47
  ## Quick Examples
42
48
 
43
49
  ### List all available skills
44
50
  ```bash
45
- npx ai-agent-skills
51
+ npx ma-agents
46
52
  # Select: List available skills
47
53
  ```
48
54
 
49
55
  ### List supported agents
50
56
  ```bash
51
- npx ai-agent-skills
57
+ npx ma-agents
52
58
  # Select: List supported agents
53
59
  ```
54
60
 
55
61
  ### Install a skill
56
62
  ```bash
57
- npx ai-agent-skills
63
+ npx ma-agents
58
64
  # Select: Install a skill
59
65
  # Choose: code-review
60
66
  # Select agents: claude-code, cline
package/README.md CHANGED
@@ -51,6 +51,56 @@ skills/code-review/
51
51
  + Updated Agent Instructions (CLAUDE.md, etc.)
52
52
  ```
53
53
 
54
+ ## Project Knowledge: _bmad-output/
55
+
56
+ The `_bmad-output/` folder is **intentionally tracked in version control** as project knowledge. Do not add `_bmad-output/` to your `.gitignore`.
57
+
58
+ ### What it contains
59
+
60
+ `_bmad-output/` holds all AI-generated planning artifacts produced by BMAD agents:
61
+
62
+ - **`planning-artifacts/`** — PRDs, architecture documents, UX designs
63
+ - **`implementation-artifacts/`** — Epics, user stories, sprint status
64
+ - **`methodology/`** — BMAD-METHOD training materials and onboarding presentation
65
+
66
+ ### Why it is version-controlled
67
+
68
+ 1. **Team alignment** — all team members see the same AI-generated plans and decisions
69
+ 2. **AI context continuity** — AI agents need prior context across sessions to maintain consistency
70
+ 3. **Decision history** — preserves the rationale and evolution of architectural and product decisions
71
+
72
+ ### Installer behaviour
73
+
74
+ The `ma-agents` installer automatically removes `_bmad-output/` from `.gitignore` if it finds it there. This is intentional — if your IDE or tooling suggests adding `_bmad-output/` to `.gitignore`, you should decline. The folder is project knowledge, not build artefacts.
75
+
76
+ > **Do not add `_bmad-output/` to your `.gitignore`** — the installer will remove it automatically if it appears there.
77
+
78
+ ---
79
+
80
+ ## Project Context
81
+
82
+ When you run `npx ma-agents install` at the project level, ma-agents automatically generates
83
+ `_bmad-output/project-context.md` — a constitutional document that governs how AI agents
84
+ behave in this project.
85
+
86
+ **What it contains:**
87
+ - Mandatory pre-task rules: which MANIFEST.yaml files to read, which skills to load
88
+ - Git workflow mandate: fresh worktrees per mission (not just branches)
89
+ - Agent mission lifecycle: 8-step sequence from pre-flight to post-mission cleanup
90
+
91
+ **It is safe to edit.** The installer never regenerates the file from scratch once it exists.
92
+ On reinstall, only the `## AI Agent Mandatory Rules` MANIFEST paths section is updated
93
+ if new agents have been added — all your custom edits are preserved. Edit it freely — it belongs to your project.
94
+
95
+ **Expand it over time:**
96
+ - After architecture phase: run `/bmad-generate-project-context` to auto-detect your stack
97
+ - After each sprint: run `/bmad-retrospective`, then `/project-context-expansion`
98
+ - Manually: add conventions you notice agents getting wrong
99
+
100
+ The file is version-controlled as part of `_bmad-output/` project knowledge. Commit it.
101
+
102
+ ---
103
+
54
104
  ## Supported Agents
55
105
 
56
106
  | Agent | Project Path | Template | Instruction File |
@@ -67,7 +117,7 @@ skills/code-review/
67
117
  | Joseph (MIL-STD-498) | `_bmad/skills/` | `generic` | `_bmad/bmm/agents/mil498.md` |
68
118
  | Antigravity | `_bmad/skills/` | `generic` | `_bmad/bmm/agents/antigravity.md` |
69
119
 
70
- ## Available Skills (27)
120
+ ## Available Skills (28)
71
121
 
72
122
  | Skill ID | Domain | Description |
73
123
  | :--- | :--- | :--- |
@@ -80,6 +130,7 @@ skills/code-review/
80
130
  | `skill-creator` | Meta | Guide for creating new skills to extend agent capabilities |
81
131
  | `document-revision-history` | Documentation | Manages revision history tables at the beginning of generated documents |
82
132
  | `ai-audit-trail` | Audit | Tracks AI agent session activity, time spent, and token usage |
133
+ | `open-presentation` | Methodology | Opens the BMAD-METHOD AI Development Training presentation (`/open-presentation`) |
83
134
  | **Security** | | |
84
135
  | `python-security-skill` | Python | OWASP Top 10 2025 aligned guardrails for Python |
85
136
  | `js-ts-security-skill` | JS/TS | Security verification for JS/TS codebases (OWASP aligned) |
package/bin/cli.js CHANGED
@@ -5,6 +5,7 @@ const chalk = require('chalk');
5
5
  const path = require('path');
6
6
  const { installSkill, uninstallSkill, getStatus, listSkills, listAgents } = require('../lib/installer');
7
7
  const bmad = require('../lib/bmad');
8
+ const { handleCreateSkill, handleValidateSkill, handleSetMandatory, handleCustomizeAgent, handleCreateAgent } = require('../lib/skill-authoring');
8
9
 
9
10
  const PKG = require('../package.json');
10
11
  const NAME = PKG.name;
@@ -22,6 +23,11 @@ ${chalk.bold('Usage:')}
22
23
  ${chalk.cyan(`npx ${NAME} status`)} Show installed skills
23
24
  ${chalk.cyan(`npx ${NAME} list`)} List available skills
24
25
  ${chalk.cyan(`npx ${NAME} agents`)} List supported agents
26
+ ${chalk.cyan(`npx ${NAME} create-skill`)} <name> Scaffold a new skill directory
27
+ ${chalk.cyan(`npx ${NAME} validate-skill`)} <name> Validate a skill against the schema
28
+ ${chalk.cyan(`npx ${NAME} set-mandatory`)} <name> [--off] Mark a skill as always-load (or remove)
29
+ ${chalk.cyan(`npx ${NAME} customize-agent`)} <agent> Customize a BMAD agent persona and actions
30
+ ${chalk.cyan(`npx ${NAME} create-agent`)} <name> Create a new specialized BMAD agent
25
31
  ${chalk.cyan(`npx ${NAME} help`)} Show this help
26
32
 
27
33
  ${chalk.bold('Install options:')}
@@ -44,9 +50,15 @@ ${chalk.bold('Examples:')}
44
50
  `);
45
51
  }
46
52
 
47
- function showSkills() {
48
- const skills = listSkills();
49
- console.log(chalk.bold('\n Available Skills:\n'));
53
+ function showSkills(args) {
54
+ const mandatoryOnly = args && args.includes('--mandatory');
55
+ let skills = listSkills();
56
+ if (mandatoryOnly) {
57
+ skills = skills.filter(s => s.always_load === true);
58
+ console.log(chalk.bold('\n Mandatory Skills (always_load: true):\n'));
59
+ } else {
60
+ console.log(chalk.bold('\n Available Skills:\n'));
61
+ }
50
62
  skills.forEach(skill => {
51
63
  console.log(chalk.cyan(` ${skill.id.padEnd(35)}`) + chalk.white(`${skill.name}`) + chalk.gray(` v${skill.version}`));
52
64
  console.log(chalk.gray(` ${''.padEnd(35)}${skill.description}\n`));
@@ -632,12 +644,27 @@ async function main() {
632
644
  break;
633
645
  case 'list':
634
646
  case 'list-skills':
635
- showSkills();
647
+ showSkills(args.slice(1));
636
648
  break;
637
649
  case 'agents':
638
650
  case 'list-agents':
639
651
  showAgents();
640
652
  break;
653
+ case 'create-skill':
654
+ await handleCreateSkill(args.slice(1));
655
+ break;
656
+ case 'validate-skill':
657
+ await handleValidateSkill(args.slice(1));
658
+ break;
659
+ case 'set-mandatory':
660
+ await handleSetMandatory(args.slice(1));
661
+ break;
662
+ case 'customize-agent':
663
+ await handleCustomizeAgent(args.slice(1));
664
+ break;
665
+ case 'create-agent':
666
+ await handleCreateAgent(args.slice(1));
667
+ break;
641
668
  case 'help':
642
669
  case '--help':
643
670
  case '-h':