@hybridlabor-api/aos 4.2.0 → 4.3.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 (54) hide show
  1. package/CLAUDE.md +37 -84
  2. package/CODEX.md +31 -12
  3. package/GEMINI.md +51 -58
  4. package/README.de.md +13 -12
  5. package/README.md +13 -12
  6. package/README.pt.md +13 -12
  7. package/THIRD_PARTY_NOTICES.md +54 -0
  8. package/installer.js +12 -10
  9. package/package.json +6 -1
  10. package/scripts/validate-skills.mjs +402 -0
  11. package/skills/basic/godmode-engineering/SKILL.md +1 -1
  12. package/skills/basic/godmode-shipping/SKILL.md +1 -1
  13. package/skills/github-repo/SKILL.md +1 -0
  14. package/skills/global_config/agent-tool-builder/SKILL.md +5 -4
  15. package/skills/global_config/ai-product/SKILL.md +3 -2
  16. package/skills/global_config/ask-tim/SKILL.md +3 -1
  17. package/skills/global_config/{bdb-adobe-suite-mcp.md → bdb-adobe-suite-mcp/SKILL.md} +1 -0
  18. package/skills/global_config/{bdb-after-effects-mcp.md → bdb-after-effects-mcp/SKILL.md} +1 -0
  19. package/skills/global_config/{bdb-blender-mcp.md → bdb-blender-mcp/SKILL.md} +1 -0
  20. package/skills/global_config/{bdb-computer-use-mcp.md → bdb-computer-use-mcp/SKILL.md} +1 -0
  21. package/skills/global_config/{bdb-davinci-mcp.md → bdb-davinci-mcp/SKILL.md} +1 -0
  22. package/skills/global_config/bdb-ecosystem-health/SKILL.md +3 -3
  23. package/skills/global_config/{bdb-grandma3-mcp.md → bdb-grandma3-mcp/SKILL.md} +1 -0
  24. package/skills/global_config/{bdb-memb-mcp.md → bdb-memb-mcp/SKILL.md} +10 -0
  25. package/skills/global_config/{bdb-resolume-mcp.md → bdb-resolume-mcp/SKILL.md} +1 -0
  26. package/skills/global_config/{bdb-rhino-mcp.md → bdb-rhino-mcp/SKILL.md} +1 -0
  27. package/skills/global_config/{bdb-touchdesigner-mcp.md → bdb-touchdesigner-mcp/SKILL.md} +1 -0
  28. package/skills/global_config/{bdb-unreal-mcp.md → bdb-unreal-mcp/SKILL.md} +1 -0
  29. package/skills/global_config/{bdb-vectorworks-mcp.md → bdb-vectorworks-mcp/SKILL.md} +1 -0
  30. package/skills/global_config/bdbsaashost/SKILL.md +50 -50
  31. package/skills/global_config/browser-automation/SKILL.md +4 -4
  32. package/skills/global_config/crewai/SKILL.md +3 -2
  33. package/skills/global_config/debugger/SKILL.md +3 -6
  34. package/skills/global_config/git-advanced-workflows/SKILL.md +0 -1
  35. package/skills/global_config/github-actions-templates/SKILL.md +0 -2
  36. package/skills/global_config/google-sheets-automation/SKILL.md +2 -2
  37. package/skills/global_config/neon-postgres/SKILL.md +3 -2
  38. package/skills/global_config/playwright-skill/SKILL.md +1 -1
  39. package/skills/global_config/posix-shell-pro/SKILL.md +0 -1
  40. package/skills/global_config/postgres-best-practices/SKILL.md +1 -1
  41. package/skills/global_config/prompt-engineering-patterns/SKILL.md +0 -1
  42. package/skills/global_config/rag-engineer/SKILL.md +4 -3
  43. package/skills/global_config/react-best-practices/SKILL.md +1 -1
  44. package/skills/global_config/remotion/SKILL.md +0 -1
  45. package/skills/global_config/seo/SKILL.md +6 -41
  46. package/skills/global_config/systematic-debugging/CREATION-LOG.md +1 -1
  47. package/skills/global_config/systematic-debugging/root-cause-tracing.md +1 -1
  48. package/skills/global_config/turborepo-caching/SKILL.md +0 -1
  49. package/skills/global_config/using-neon/SKILL.md +1 -47
  50. package/skills/global_config/vector-database-engineer/SKILL.md +0 -1
  51. package/skills/global_config/web-artifacts-builder/LICENSE.txt +1 -1
  52. package/skills/global_config/web-artifacts-builder/SKILL.md +1 -1
  53. package/skills/global_config/webapp-testing/LICENSE.txt +1 -1
  54. package/skills/global_config/webapp-testing/SKILL.md +1 -1
@@ -0,0 +1,402 @@
1
+ #!/usr/bin/env node
2
+ // Validates every skill in skills/ against the contract in AGENTS.md.
3
+ // Zero dependencies on purpose: CI runs this with no install step, and it must
4
+ // work on any harness, not just the one that happens to ship a hook runner.
5
+
6
+ import { readFileSync, readdirSync, statSync, existsSync } from 'node:fs';
7
+ import { join, dirname, basename, relative, resolve } from 'node:path';
8
+ import { fileURLToPath } from 'node:url';
9
+ import assert from 'node:assert/strict';
10
+
11
+ const REPO = resolve(dirname(fileURLToPath(import.meta.url)), '..');
12
+ const SKILLS = join(REPO, 'skills');
13
+
14
+ const CATEGORIES = new Set([
15
+ 'design-ui-ux', 'engineering-method', 'media-eventtech',
16
+ 'bdb-core', 'saas-ops', 'library',
17
+ ]);
18
+ const REQUIRED = ['name', 'description', 'category'];
19
+
20
+ // Names that are stand-ins or service accounts rather than a person. The rule
21
+ // is about leaking a human's username; `/home/agent` on the SaaS fleet is a
22
+ // role account and is meant to be written down.
23
+ const PLACEHOLDER_USERS = new Set([
24
+ 'username', '<username>', '{username}', '$USER', 'USER', 'user', 'you', 'your-username',
25
+ 'john', 'jane', 'example', 'me', 'name', '<user>', 'ubuntu', 'runner', 'YOUR_NAME',
26
+ 'agent', 'root', 'admin', 'deploy', 'app', 'node', 'git', 'www-data', 'service',
27
+ ]);
28
+
29
+ // ---------------------------------------------------------------- YAML scanner
30
+ // Not a general YAML parser — it resolves scalar boundaries, which is the only
31
+ // thing needed to tell a real key from text absorbed into the value above it.
32
+ // That distinction is the whole point: a `grep "^category:"` says these files
33
+ // are fine, because the line is physically present and semantically swallowed.
34
+
35
+ function findClosingQuote(s, from, q) {
36
+ for (let i = from; i < s.length; i++) {
37
+ if (s[i] !== q) continue;
38
+ if (q === "'" && s[i + 1] === "'") { i++; continue; } // '' escapes a quote
39
+ if (q === '"' && s[i - 1] === '\\') continue;
40
+ return i;
41
+ }
42
+ return -1;
43
+ }
44
+
45
+ const indentOf = (l) => l.length - l.trimStart().length;
46
+ const KEY_RE = /^([A-Za-z_][\w.-]*)\s*:(.*)$/;
47
+
48
+ export function scanFrontmatter(text) {
49
+ const lines = text.split(/\r?\n/);
50
+ if (lines[0]?.trim() !== '---') return { ok: false, reason: 'missing', keys: [], issues: [] };
51
+
52
+ let close = -1;
53
+ for (let i = 1; i < lines.length; i++) {
54
+ if (lines[i].trim() === '---') { close = i; break; }
55
+ }
56
+ if (close === -1) return { ok: false, reason: 'unterminated', keys: [], issues: [] };
57
+
58
+ const body = lines.slice(1, close);
59
+ const keys = [];
60
+ const issues = [];
61
+ let i = 0;
62
+
63
+ while (i < body.length) {
64
+ const line = body[i];
65
+ if (line.trim() === '' || line.trimStart().startsWith('#')) { i++; continue; }
66
+ if (indentOf(line) > 0) { i++; continue; }
67
+
68
+ const m = KEY_RE.exec(line);
69
+ if (!m) { i++; continue; }
70
+
71
+ const key = m[1];
72
+ const rest = m[2];
73
+ const restT = rest.trim();
74
+ const start = i;
75
+ const consumed = [rest];
76
+ let swallowed = [];
77
+
78
+ const eatIndented = (allowBlank) => {
79
+ i++;
80
+ while (i < body.length) {
81
+ const l = body[i];
82
+ if (l.trim() === '') { if (!allowBlank) break; consumed.push(l); i++; continue; }
83
+ if (indentOf(l) === 0) break;
84
+ consumed.push(l); i++;
85
+ }
86
+ };
87
+
88
+ if (/^[|>][-+]?\d*$/.test(restT)) {
89
+ eatIndented(true); // block scalar
90
+ } else if (restT === '') {
91
+ eatIndented(true); // nested mapping / empty
92
+ } else if (restT[0] === "'" || restT[0] === '"') {
93
+ const q = restT[0];
94
+ const offset = rest.indexOf(q);
95
+ if (findClosingQuote(rest, offset + 1, q) !== -1) {
96
+ i++; // closes on its own line
97
+ } else {
98
+ i++;
99
+ let closed = false;
100
+ while (i < body.length) {
101
+ const l = body[i];
102
+ consumed.push(l);
103
+ i++;
104
+ if (indentOf(l) === 0 && KEY_RE.test(l)) swallowed.push(KEY_RE.exec(l)[1]);
105
+ if (findClosingQuote(l, 0, q) !== -1) { closed = true; break; }
106
+ }
107
+ if (!closed) issues.push({ code: 'E-YAML02', key, msg: `quoted value for \`${key}\` is never closed` });
108
+ }
109
+ } else {
110
+ eatIndented(false); // plain scalar
111
+ }
112
+
113
+ if (swallowed.length) {
114
+ issues.push({
115
+ code: 'E-YAML03', key,
116
+ msg: `the quoted value of \`${key}\` swallows ${swallowed.map((k) => `\`${k}\``).join(', ')} — ` +
117
+ `${swallowed.length > 1 ? 'those keys are' : 'that key is'} not parsed at all`,
118
+ });
119
+ }
120
+
121
+ keys.push({
122
+ key,
123
+ line: start + 2, // +1 for the opening ---, +1 for 1-indexing
124
+ multiline: consumed.length > 1,
125
+ value: consumed.join(' ').trim().replace(/\s+/g, ' '),
126
+ });
127
+ }
128
+
129
+ return { ok: true, keys, issues, endLine: close + 1 };
130
+ }
131
+
132
+ function unquote(v) {
133
+ const t = v.trim();
134
+ if (t.length > 1 && (t[0] === '"' || t[0] === "'") && t.at(-1) === t[0]) return t.slice(1, -1).trim();
135
+ return t;
136
+ }
137
+
138
+ // ------------------------------------------------------------------ collectors
139
+
140
+ function walk(dir, out = []) {
141
+ for (const e of readdirSync(dir, { withFileTypes: true })) {
142
+ if (e.name === 'node_modules' || e.name.startsWith('.')) continue;
143
+ const p = join(dir, e.name);
144
+ if (e.isDirectory()) walk(p, out);
145
+ else out.push(p);
146
+ }
147
+ return out;
148
+ }
149
+
150
+ function collect() {
151
+ const files = walk(SKILLS);
152
+ const skills = files.filter((f) => basename(f) === 'SKILL.md');
153
+ // A .md sitting directly in a category dir is a skill nobody can load: every
154
+ // harness discovers skills as <dir>/SKILL.md.
155
+ const strays = files.filter((f) => {
156
+ if (basename(f) === 'SKILL.md' || !f.endsWith('.md')) return false;
157
+ const rel = relative(SKILLS, f);
158
+ return rel.split('/').length === 2;
159
+ });
160
+ return { skills, strays };
161
+ }
162
+
163
+ // ---------------------------------------------------------------------- checks
164
+
165
+ // A skill that documents the no-usernames rule has to be able to show a
166
+ // counter-example. `<!-- validate-skills-ignore -->` on the line, or the line
167
+ // above, says this one is deliberate.
168
+ const IGNORE = 'validate-skills-ignore';
169
+
170
+ function checkLeakedPaths(text, file, findings) {
171
+ const patterns = [/\/Users\/([^/\s`'")\],]+)/g, /\/home\/([^/\s`'")\],]+)/g, /C:\\Users\\([^\\\s`'")\],]+)/g];
172
+ const lines = text.split(/\r?\n/);
173
+ for (const re of patterns) {
174
+ for (let n = 0; n < lines.length; n++) {
175
+ if (lines[n].includes(IGNORE) || (n > 0 && lines[n - 1].includes(IGNORE))) continue;
176
+ for (const m of lines[n].matchAll(re)) {
177
+ const who = m[1].replace(/[<>{}]/g, '');
178
+ if (PLACEHOLDER_USERS.has(m[1]) || PLACEHOLDER_USERS.has(who)) continue;
179
+ findings.push({
180
+ level: 'error', code: 'E-PATH01', file, line: n + 1,
181
+ msg: `absolute home path leaks a username: \`${m[0]}\` — use \`~\` or \`$HOME\``,
182
+ });
183
+ }
184
+ }
185
+ }
186
+ }
187
+
188
+ function checkLocalRefs(text, skillDir, file, findings) {
189
+ const re = /`([a-zA-Z0-9_@-]+\/[a-zA-Z0-9_./@-]+\.(?:md|py|mjs|js|ts|sh|json))`/g;
190
+ const seen = new Set();
191
+ for (const m of text.matchAll(re)) {
192
+ const p = m[1];
193
+ if (seen.has(p) || p.startsWith('~') || p.startsWith('.') || p.includes('://')) continue;
194
+ if (!/^(references|scripts|assets|rules|contracts|resources|templates)\//.test(p)) continue;
195
+ seen.add(p);
196
+ if (!existsSync(join(skillDir, p))) {
197
+ findings.push({ level: 'warn', code: 'W-REF01', file, msg: `references \`${p}\`, which does not exist in this skill` });
198
+ }
199
+ }
200
+ }
201
+
202
+ // Only hyphenated `/slash-names` are checked. Single words in that position are
203
+ // nearly always something else — a route, a temp path, a pipeline stage in
204
+ // prose, a harness builtin — and flagging them buries the real hits.
205
+ const HARNESS_BUILTINS = new Set([
206
+ 'code-review', 'plan-mode', 'add-dir', 'bug-report', 'output-style', 'export-conversation',
207
+ ]);
208
+
209
+ function checkSkillRefs(text, file, known, self, findings) {
210
+ const seen = new Set();
211
+ for (const m of text.matchAll(/`\/([a-z][a-z0-9]*(?:-[a-z0-9]+)+)`/g)) {
212
+ const name = m[1];
213
+ if (seen.has(name) || name === self || known.has(name) || HARNESS_BUILTINS.has(name)) continue;
214
+ seen.add(name);
215
+ findings.push({ level: 'warn', code: 'W-REF02', file, msg: `references skill \`/${name}\`, which does not exist` });
216
+ }
217
+ }
218
+
219
+ function validate() {
220
+ const { skills, strays } = collect();
221
+ const known = new Set(skills.map((f) => basename(dirname(f))));
222
+ const findings = [];
223
+
224
+ for (const file of skills) {
225
+ const rel = relative(REPO, file);
226
+ const dir = dirname(file);
227
+ const dirName = basename(dir);
228
+ const text = readFileSync(file, 'utf8');
229
+ const fm = scanFrontmatter(text);
230
+
231
+ if (!fm.ok) {
232
+ findings.push({
233
+ level: 'error', code: 'E-FM01', file: rel,
234
+ msg: fm.reason === 'missing' ? 'no YAML frontmatter block' : 'frontmatter block is never closed',
235
+ });
236
+ continue;
237
+ }
238
+
239
+ for (const iss of fm.issues) findings.push({ level: 'error', code: iss.code, file: rel, msg: iss.msg });
240
+
241
+ const byKey = new Map(fm.keys.map((k) => [k.key, k]));
242
+
243
+ for (const req of REQUIRED) {
244
+ if (!byKey.has(req)) {
245
+ findings.push({ level: 'error', code: 'E-FM02', file: rel, msg: `missing required key \`${req}\`` });
246
+ }
247
+ }
248
+
249
+ const name = byKey.get('name');
250
+ if (name && unquote(name.value) !== dirName) {
251
+ findings.push({
252
+ level: 'error', code: 'E-FM04', file: rel, line: name.line,
253
+ msg: `\`name: ${unquote(name.value)}\` does not match its directory \`${dirName}\``,
254
+ });
255
+ }
256
+
257
+ const desc = byKey.get('description');
258
+ if (desc && unquote(desc.value) === '') {
259
+ findings.push({ level: 'error', code: 'E-FM05', file: rel, line: desc.line, msg: 'description is empty' });
260
+ }
261
+
262
+ const cat = byKey.get('category');
263
+ if (cat) {
264
+ const value = unquote(cat.value);
265
+ if (cat.multiline) {
266
+ findings.push({
267
+ level: 'error', code: 'E-YAML01', file: rel, line: cat.line,
268
+ msg: `\`category\` absorbs the line below it and parses as "${value.slice(0, 60)}${value.length > 60 ? '…' : ''}" ` +
269
+ '— quote the description above it so the value ends where you think it does',
270
+ });
271
+ } else if (!CATEGORIES.has(value)) {
272
+ findings.push({
273
+ level: 'error', code: 'E-FM03', file: rel, line: cat.line,
274
+ msg: `\`category: ${value}\` is not one of: ${[...CATEGORIES].join(', ')}`,
275
+ });
276
+ }
277
+ }
278
+
279
+ checkLeakedPaths(text, rel, findings);
280
+ checkLocalRefs(text, dir, rel, findings);
281
+ checkSkillRefs(text, rel, known, dirName, findings);
282
+
283
+ // A skill ships more than its SKILL.md, and a leaked path in a reference
284
+ // file is just as published as one in the entry point.
285
+ for (const aux of walk(dir)) {
286
+ if (aux === file || !/\.(md|py|mjs|cjs|js|ts|sh|json|ya?ml)$/.test(aux)) continue;
287
+ checkLeakedPaths(readFileSync(aux, 'utf8'), relative(REPO, aux), findings);
288
+ }
289
+ }
290
+
291
+ for (const file of strays) {
292
+ const rel = relative(REPO, file);
293
+ const fm = scanFrontmatter(readFileSync(file, 'utf8'));
294
+ if (!fm.ok || !fm.keys.some((k) => k.key === 'name')) continue;
295
+ findings.push({
296
+ level: 'error', code: 'E-STRAY01', file: rel,
297
+ msg: 'skill frontmatter in a bare .md file — no harness will discover this. ' +
298
+ `Move it to \`${relative(REPO, join(dirname(file), basename(file, '.md'), 'SKILL.md'))}\``,
299
+ });
300
+ }
301
+
302
+ return { findings, counts: { skills: skills.length, strays: strays.length } };
303
+ }
304
+
305
+ // ---------------------------------------------------------------------- report
306
+
307
+ function report(findings, counts, { json, quiet, strict }) {
308
+ const errors = findings.filter((f) => f.level === 'error');
309
+ const warns = findings.filter((f) => f.level === 'warn');
310
+
311
+ if (json) {
312
+ console.log(JSON.stringify({ ok: errors.length === 0 && (!strict || warns.length === 0), counts, findings }, null, 2));
313
+ return errors.length || (strict && warns.length) ? 1 : 0;
314
+ }
315
+
316
+ const tty = process.stdout.isTTY && !process.env.NO_COLOR;
317
+ const c = (code, s) => (tty ? `\x1b[${code}m${s}\x1b[0m` : s);
318
+ const red = (s) => c(31, s), yellow = (s) => c(33, s), green = (s) => c(32, s), dim = (s) => c(2, s);
319
+
320
+ const show = strict ? findings : (quiet ? errors : findings);
321
+ const byFile = new Map();
322
+ for (const f of show) {
323
+ if (!byFile.has(f.file)) byFile.set(f.file, []);
324
+ byFile.get(f.file).push(f);
325
+ }
326
+
327
+ for (const [file, list] of byFile) {
328
+ console.log(`\n${file}`);
329
+ for (const f of list) {
330
+ const tag = f.level === 'error' ? red('error') : yellow(' warn');
331
+ const at = f.line ? dim(`:${f.line}`) : '';
332
+ console.log(` ${tag} ${dim(f.code)}${at} ${f.msg}`);
333
+ }
334
+ }
335
+
336
+ const summary = `${counts.skills} skills checked · ${errors.length} error(s) · ${warns.length} warning(s)`;
337
+ console.log('');
338
+ if (errors.length === 0 && warns.length === 0) console.log(green(`✓ ${summary}`));
339
+ else if (errors.length === 0) console.log(yellow(`! ${summary}`));
340
+ else console.log(red(`✗ ${summary}`));
341
+
342
+ return errors.length || (strict && warns.length) ? 1 : 0;
343
+ }
344
+
345
+ // -------------------------------------------------------------------- selftest
346
+
347
+ function selftest() {
348
+ // The bug that shipped: an indented line folds into the value above it, so
349
+ // `category` parses as "library used by 60% ..." while grep still sees the key.
350
+ const folded = scanFrontmatter([
351
+ '---', 'name: crewai', 'description: Expert in CrewAI - the leading framework',
352
+ 'category: library', ' used by 60% of Fortune 500 companies.', '---',
353
+ ].join('\n'));
354
+ const cat = folded.keys.find((k) => k.key === 'category');
355
+ assert.ok(cat.multiline, 'folded category must be detected as multiline');
356
+ assert.equal(cat.value, 'library used by 60% of Fortune 500 companies.');
357
+
358
+ // The other shape: an unclosed quote eats the keys below it entirely.
359
+ const eaten = scanFrontmatter([
360
+ '---', "description: 'Debugging specialist for errors", 'category: library',
361
+ '', ' behavior. Use proactively.', '', " '", 'risk: safe', '---',
362
+ ].join('\n'));
363
+ assert.ok(!eaten.keys.some((k) => k.key === 'category'), 'swallowed key must not count as present');
364
+ assert.ok(eaten.issues.some((i) => i.code === 'E-YAML03'), 'swallowing must be reported');
365
+ assert.ok(eaten.keys.some((k) => k.key === 'risk'), 'parsing must resume after the closing quote');
366
+
367
+ // Legitimate YAML must not trip any of it.
368
+ const clean = scanFrontmatter([
369
+ '---', 'name: ask-tim', 'description: >-', ' A folded block scalar',
370
+ ' spanning several lines.', 'category: bdb-core',
371
+ 'metadata:', ' author: firecrawl', ' version: "0.1.0"', '---',
372
+ ].join('\n'));
373
+ const cleanCat = clean.keys.find((k) => k.key === 'category');
374
+ assert.equal(cleanCat.value, 'bdb-core');
375
+ assert.ok(!cleanCat.multiline, 'a clean category is single-line');
376
+ assert.ok(clean.keys.find((k) => k.key === 'description').multiline, 'block scalar spans lines');
377
+ assert.ok(clean.keys.some((k) => k.key === 'metadata'), 'nested mapping is a key');
378
+ assert.ok(!clean.keys.some((k) => k.key === 'author'), 'nested keys are not top-level');
379
+ assert.equal(clean.issues.length, 0);
380
+
381
+ // A quoted value that closes on its own line is fine.
382
+ const quoted = scanFrontmatter(['---', 'name: x', 'description: "it\'s fine: really"', 'category: library', '---'].join('\n'));
383
+ assert.equal(quoted.issues.length, 0);
384
+ assert.equal(quoted.keys.find((k) => k.key === 'category').value, 'library');
385
+
386
+ assert.equal(scanFrontmatter('# no frontmatter').ok, false);
387
+ assert.equal(scanFrontmatter('---\nname: x\n').reason, 'unterminated');
388
+
389
+ console.log('✓ selftest passed');
390
+ }
391
+
392
+ // ------------------------------------------------------------------------ main
393
+
394
+ const argv = process.argv.slice(2);
395
+ if (argv.includes('--selftest')) { selftest(); process.exit(0); }
396
+
397
+ const { findings, counts } = validate();
398
+ process.exit(report(findings, counts, {
399
+ json: argv.includes('--json'),
400
+ quiet: argv.includes('--quiet'),
401
+ strict: argv.includes('--strict'),
402
+ }));
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: godmode-engineering
3
3
  description: BDB Engineering Godmode, enforcing strict Domain-Driven Design, TypeScript strictness, and Clean Architecture. Use when implementing backend/fullstack features or running the systematic 5-step debugging triage.
4
- category: bdb-core
4
+ category: engineering-method
5
5
  ---
6
6
 
7
7
  # ⚙️ BDB Engineering Godmode
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: godmode-shipping
3
3
  description: BDB Shipping Godmode, the final gatekeeper for production releases. Use when running pre-launch checks, feature-flag rollouts, or rollback planning under Spec-Driven Development before a release ships.
4
- category: bdb-core
4
+ category: engineering-method
5
5
  disable-model-invocation: true
6
6
  ---
7
7
 
@@ -37,6 +37,7 @@ Whenever the `github-repo` skill is invoked, the agent MUST perform an automated
37
37
  Before pushing any commit to GitHub, execute this 5-point sanitization audit:
38
38
 
39
39
  ### Rule 1: No Absolute Local Paths or Usernames
40
+ <!-- validate-skills-ignore -->
40
41
  - **Forbidden:** Paths like `/Users/john/projects/...`, `C:\Users\dev\...`, `/home/ubuntu/...`.
41
42
  - **Allowed:** Relative paths (`./src/index.ts`, `config/settings.json`) or environment placeholders (`~/.config/`, `$HOME/`).
42
43
 
@@ -1,10 +1,11 @@
1
1
  ---
2
2
  name: agent-tool-builder
3
- description: Tools are how AI agents interact with the world. A well-designed
3
+ description: >-
4
+ Tools are how AI agents interact with the world. A well-designed tool is the
5
+ difference between an agent that works and one that hallucinates, fails
6
+ silently, or costs 10x more tokens than necessary. This skill covers tool
7
+ design from schema to error handling.
4
8
  category: engineering-method
5
- tool is the difference between an agent that works and one that hallucinates,
6
- fails silently, or costs 10x more tokens than necessary. This skill covers
7
- tool design from schema to error handling.
8
9
  risk: unknown
9
10
  source: vibeship-spawner-skills (Apache 2.0)
10
11
  date_added: 2026-02-27
@@ -1,8 +1,9 @@
1
1
  ---
2
2
  name: ai-product
3
- description: Every product will be AI-powered. The question is whether you'll
3
+ description: >-
4
+ Every product will be AI-powered. The question is whether you'll build it
5
+ right or ship a demo that falls apart in production.
4
6
  category: library
5
- build it right or ship a demo that falls apart in production.
6
7
  risk: safe
7
8
  source: vibeship-spawner-skills (Apache 2.0)
8
9
  date_added: 2026-02-27
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: ask-tim
3
- description: Ask which skill or flow fits your situation. A route through AOS's skills for work that travels idea to ship, plus a catalogue of the ~169 available options for lookup. Use when unsure where to start, or when picking between overlapping choices.
3
+ description: Ask which skill or flow fits your situation. A route through AOS's skills for work that travels idea to ship, plus a catalogue of the 187 available options for lookup. Use when unsure where to start, or when picking between overlapping choices.
4
4
  category: bdb-core
5
5
  disable-model-invocation: true
6
6
  ---
@@ -290,6 +290,8 @@ Use these for 3D, motion, video and live show control.
290
290
  * **Godmodes**: Determine the overarching flow (3D, Media, EventTech).
291
291
  * **Implementations**: `MCP_Manage` drives the creative applications over MCP, `spline-3d-integration` (web 3D), `threejs-skills` (WebGL), `remotion` (React → MP4, deterministic frame counts).
292
292
 
293
+ * **Per-application MCP guides**: once `MCP_Manage` has told you *which* server to use, these document the tool surface of one application each — `bdb-touchdesigner-mcp`, `bdb-resolume-mcp`, `bdb-grandma3-mcp`, `bdb-davinci-mcp`, `bdb-adobe-suite-mcp`, `bdb-after-effects-mcp`, `bdb-blender-mcp`, `bdb-unreal-mcp`, `bdb-rhino-mcp`, `bdb-vectorworks-mcp`. Reach for one only when you already know the application; `MCP_Manage` is the way in.
294
+
293
295
  ### Which video route?
294
296
 
295
297
  The choice is driven by where the pixels come from, not by the output format — all four end in a video file.
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: bdb-adobe-suite-mcp
3
3
  description: Utilizes the Adobe Suite MCP servers (adobe_mcp.py and adobe_uxp_mcp) to automate Photoshop, Illustrator, Premiere Pro, and After Effects using ExtendScript and UXP WebSocket bridges.
4
+ category: media-eventtech
4
5
  ---
5
6
 
6
7
  # Adobe Creative Suite MCP — Integration and AI Guide
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: bdb-after-effects-mcp
3
3
  description: Utilizes the After Effects MCP servers (after-effects-mcp and ae-mcp) to create compositions, layers, masks, keyframe animations, and run ExtendScript.
4
+ category: media-eventtech
4
5
  ---
5
6
 
6
7
  # After Effects MCP — Integration and AI Agent Guide
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: bdb-blender-mcp
3
3
  description: Utilizes the Blender MCP server and addon to build 3D assets, apply materials, inspect scenes, and script bpy.
4
+ category: media-eventtech
4
5
  ---
5
6
 
6
7
  # Blender MCP — Integration and AI Agent Guide
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: bdb-computer-use-mcp
3
3
  description: Utilizes native Rust/Node and Python-based computer-use-mcp servers to control macOS, Windows, and Linux desktops.
4
+ category: engineering-method
4
5
  ---
5
6
 
6
7
  # Computer Use & OS Control MCP — Integration and AI Agent Guide
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: bdb-davinci-mcp
3
3
  description: Utilizes the DaVinci Resolve MCP servers to control timeline editing, media analysis, color grading, and Fusion/Fairlight scripting.
4
+ category: media-eventtech
4
5
  ---
5
6
 
6
7
  # DaVinci Resolve MCP — Integration and AI Agent Guide
@@ -36,7 +36,7 @@ Autonomous verification and remediation skill for maintaining 100% operational i
36
36
 
37
37
  ## Verification
38
38
  - [ ] Health check script `ecosystem-health-audit.js` run completed with exit code `0`.
39
- - [ ] HTML report generated and verifiable at `~/bdb-dev/marketing-intern/reports/ecosystem_health_latest.html`.
39
+ - [ ] HTML report generated and verifiable at `production_artifacts/ecosystem_health_latest.html`.
40
40
  - [ ] Git working trees for all 8 repositories are clean.
41
41
  - [ ] NPM versions are fully synchronized with remote packages.
42
42
 
@@ -53,11 +53,11 @@ Autonomous verification and remediation skill for maintaining 100% operational i
53
53
  ## Automated Health Check Script
54
54
  Run the automated audit at any time:
55
55
  ```bash
56
- ~/bdb-dev/scripts/ecosystem-health-audit.js
56
+ scripts/ecosystem-health-audit.js
57
57
  ```
58
58
 
59
59
  ### Script Output:
60
- * **HTML Dashboard**: `~/bdb-dev/marketing-intern/reports/ecosystem_health_latest.html`
60
+ * **HTML Dashboard**: `production_artifacts/ecosystem_health_latest.html`
61
61
  * **Browser Launch**: Automatically opens the report in Chrome / Default Browser.
62
62
  * **Exit Code**: Returns `0` if all healthy, `1` if attention/remediation is required.
63
63
 
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: bdb-grandma3-mcp
3
3
  description: Utilizes the grandMA3 MCP server to patch fixtures, execute console commands, and trigger macros via OSC.
4
+ category: media-eventtech
4
5
  ---
5
6
 
6
7
  # grandMA3 MCP — Integration and AI Agent Guide
@@ -1,3 +1,13 @@
1
+ ---
2
+ name: bdb-memb-mcp
3
+ description: >-
4
+ Model Context Protocol interface to the memB persistent agent memory layer.
5
+ Use when an agent needs to add, search, list or delete persistent memories
6
+ locally and offline. Exposes add_memory, search_memory, list_memories and
7
+ delete_memory.
8
+ category: bdb-core
9
+ ---
10
+
1
11
  # BDB memB Persistent Memory MCP Server
2
12
 
3
13
  The `memb-mcp` server provides a standard Model Context Protocol (MCP) interface to the **memB** persistent agent memory layer. It allows any compatible developer agent (such as Cursor, Google Antigravity, Claude Code, or VS Code Cline) to read, write, and query persistent memories locally and offline.
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: bdb-resolume-mcp
3
3
  description: Utilizes the Resolume Arena MCP server to trigger clips, clear layers, adjust speeds, and query composition status via the Resolume REST API.
4
+ category: media-eventtech
4
5
  ---
5
6
 
6
7
  # Resolume Arena MCP — Integration and AI Agent Guide
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: bdb-rhino-mcp
3
3
  description: Utilizes the Rhino MCP servers (RhinoMCP and golem-rhino-mcp) to create and manipulate 3D models and run Grasshopper graphs.
4
+ category: media-eventtech
4
5
  ---
5
6
 
6
7
  # Rhino 3D MCP — Integration and AI Agent Guide
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: bdb-touchdesigner-mcp
3
3
  description: Utilizes the TouchDesigner MCP servers (tdmcp and touchdesigner-mcp) to create TOP/CHOP chains, script operators, inspect parameters, and debug node networks.
4
+ category: media-eventtech
4
5
  ---
5
6
 
6
7
  # TouchDesigner MCP — Integration and AI Agent Guide
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: bdb-unreal-mcp
3
3
  description: Utilizes the Unreal Engine MCP server to control UE5 via a native C++ Automation Bridge plugin.
4
+ category: media-eventtech
4
5
  ---
5
6
 
6
7
  # Unreal Engine MCP — Integration and AI Agent Guide
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: bdb-vectorworks-mcp
3
3
  description: Utilizes the Vectorworks RAG + MCP server to search and retrieve Python and VectorScript API documentation.
4
+ category: media-eventtech
4
5
  ---
5
6
 
6
7
  # Vectorworks RAG MCP — Integration and AI Agent Guide