opencode-swarm-plugin 0.61.0 → 0.62.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.
@@ -17256,6 +17256,7 @@ __export(exports_skills, {
17256
17256
  validateCSOCompliance: () => validateCSOCompliance,
17257
17257
  skills_use: () => skills_use,
17258
17258
  skills_update: () => skills_update,
17259
+ skills_reload: () => skills_reload,
17259
17260
  skills_read: () => skills_read,
17260
17261
  skills_list: () => skills_list,
17261
17262
  skills_init: () => skills_init,
@@ -17740,7 +17741,7 @@ var import_gray_matter, ALWAYS_ON_GUIDANCE_HEADER = "## Always-On Guidance Skill
17740
17741
  - Read before Edit; no speculative changes or output`, OPUS_4_5_GUIDANCE = `#### Opus 4.5 (Concise)
17741
17742
  - Be concise and deliberate while obeying mandates
17742
17743
  - Follow tool priorities without shortcuts
17743
- - Prefer direct answers over speculation`, skillsProjectDirectory, skillsCache = null, PROJECT_SKILL_DIRECTORIES, skills_list, skills_use, skills_execute, skills_read, DEFAULT_SKILLS_DIR = ".opencode/skill", skills_create, skills_update, skills_delete, skills_add_script, skills_init, skillsTools;
17744
+ - Prefer direct answers over speculation`, skillsProjectDirectory, skillsCache = null, PROJECT_SKILL_DIRECTORIES, skills_list, skills_use, skills_execute, skills_read, DEFAULT_SKILLS_DIR = ".opencode/skill", skills_create, skills_update, skills_delete, skills_add_script, skills_reload, skills_init, skillsTools;
17744
17745
  var init_skills = __esm(() => {
17745
17746
  init_dist();
17746
17747
  import_gray_matter = __toESM(require_gray_matter(), 1);
@@ -18170,6 +18171,38 @@ executed with skills_execute. Use for:
18170
18171
  }
18171
18172
  }
18172
18173
  });
18174
+ skills_reload = tool({
18175
+ description: `Hot-reload skills by clearing cache and re-scanning skill directories.
18176
+
18177
+ Use this to:
18178
+ - Test a newly created skill immediately without restarting
18179
+ - Verify skill modifications took effect
18180
+ - Refresh skills after external changes
18181
+
18182
+ The tool clears the cached skills, re-scans all skill directories,
18183
+ and returns a list of loaded skills.`,
18184
+ args: {},
18185
+ async execute() {
18186
+ invalidateSkillsCache();
18187
+ const skills = await discoverSkills();
18188
+ const refs = Array.from(skills.values()).map((skill) => ({
18189
+ name: skill.metadata.name,
18190
+ description: skill.metadata.description,
18191
+ path: skill.path,
18192
+ hasScripts: skill.hasScripts
18193
+ }));
18194
+ return JSON.stringify({
18195
+ success: true,
18196
+ reloaded: refs.length,
18197
+ skills: refs.map((r) => ({
18198
+ name: r.name,
18199
+ description: r.description,
18200
+ hasScripts: r.hasScripts
18201
+ })),
18202
+ message: `Reloaded ${refs.length} skill(s). All skills are now up-to-date.`
18203
+ }, null, 2);
18204
+ }
18205
+ });
18173
18206
  skills_init = tool({
18174
18207
  description: `Initialize a new skill with full directory structure and templates.
18175
18208
 
@@ -18282,6 +18315,7 @@ echo "Project directory: $1"
18282
18315
  skills_update,
18283
18316
  skills_delete,
18284
18317
  skills_add_script,
18318
+ skills_reload,
18285
18319
  skills_init
18286
18320
  };
18287
18321
  });
@@ -39524,6 +39558,7 @@ var EpicCreateArgsSchema = exports_external.object({
39524
39558
  epic_id: exports_external.string().optional(),
39525
39559
  subtasks: exports_external.array(exports_external.object({
39526
39560
  title: exports_external.string().min(1),
39561
+ description: exports_external.string().optional(),
39527
39562
  priority: exports_external.number().int().min(0).max(3).default(2),
39528
39563
  files: exports_external.array(exports_external.string()).optional().default([]),
39529
39564
  id_suffix: exports_external.string().optional()
@@ -40553,7 +40588,8 @@ var hive_create_epic = tool({
40553
40588
  title: subtask.title,
40554
40589
  type: "task",
40555
40590
  priority: subtask.priority ?? 2,
40556
- parent_id: epic.id
40591
+ parent_id: epic.id,
40592
+ description: subtask.description
40557
40593
  });
40558
40594
  await adapter.markDirty(projectKey, subtaskCell.id);
40559
40595
  created.push(subtaskCell);
@@ -43806,6 +43842,152 @@ var swarm_recover = tool({
43806
43842
  }
43807
43843
  }
43808
43844
  });
43845
+ var swarm_branch = tool({
43846
+ description: "Create a session branch for exploration. Saves current context with a label for later return.",
43847
+ args: {
43848
+ project_key: tool.schema.string().describe("Project path"),
43849
+ agent_name: tool.schema.string().describe("Agent name"),
43850
+ bead_id: tool.schema.string().describe("Current subtask bead ID"),
43851
+ epic_id: tool.schema.string().describe("Epic bead ID"),
43852
+ branch_label: tool.schema.string().describe("Label for this branch (e.g., 'debug-cache-issue')"),
43853
+ branch_purpose: tool.schema.string().describe("Why branching? (e.g., 'investigate API timeout')"),
43854
+ files_modified: tool.schema.array(tool.schema.string()).describe("Files modified before branching"),
43855
+ progress_percent: tool.schema.number().min(0).max(100).optional().describe("Current progress percentage")
43856
+ },
43857
+ async execute(args) {
43858
+ try {
43859
+ const branchId = `branch-${Date.now()}-${args.branch_label.replace(/[^a-z0-9-]/gi, "-")}`;
43860
+ const checkpoint = {
43861
+ epic_id: args.epic_id,
43862
+ bead_id: args.bead_id,
43863
+ strategy: "file-based",
43864
+ files: args.files_modified,
43865
+ dependencies: [],
43866
+ directives: {
43867
+ branch_label: args.branch_label,
43868
+ branch_purpose: args.branch_purpose,
43869
+ branch_id: branchId
43870
+ },
43871
+ recovery: {
43872
+ last_checkpoint: Date.now(),
43873
+ files_modified: args.files_modified,
43874
+ progress_percent: args.progress_percent || 0,
43875
+ last_message: `Branched for: ${args.branch_purpose}`
43876
+ }
43877
+ };
43878
+ const { createEvent: createEvent5, appendEvent: appendEvent4 } = await import("swarm-mail");
43879
+ const checkpointData = JSON.stringify(checkpoint);
43880
+ const event = createEvent5("swarm_checkpointed", {
43881
+ project_key: args.project_key,
43882
+ epic_id: args.epic_id,
43883
+ bead_id: args.bead_id,
43884
+ strategy: checkpoint.strategy,
43885
+ files: checkpoint.files,
43886
+ dependencies: checkpoint.dependencies,
43887
+ directives: checkpoint.directives,
43888
+ recovery: checkpoint.recovery,
43889
+ checkpoint_size_bytes: Buffer.byteLength(checkpointData, "utf8"),
43890
+ trigger: "manual"
43891
+ });
43892
+ await appendEvent4(event, args.project_key);
43893
+ return JSON.stringify({
43894
+ success: true,
43895
+ branch_id: branchId,
43896
+ branch_label: args.branch_label,
43897
+ branch_purpose: args.branch_purpose,
43898
+ checkpoint_timestamp: Date.now(),
43899
+ message: `Session branched: ${args.branch_label}. Use swarm_return to restore main context.`,
43900
+ files_snapshot: args.files_modified
43901
+ }, null, 2);
43902
+ } catch (error45) {
43903
+ console.warn(`[swarm_branch] Failed to create branch ${args.branch_label}:`, error45);
43904
+ return JSON.stringify({
43905
+ success: false,
43906
+ error: error45 instanceof Error ? error45.message : String(error45),
43907
+ message: `Failed to branch session: ${args.branch_label}`
43908
+ }, null, 2);
43909
+ }
43910
+ }
43911
+ });
43912
+ var swarm_return = tool({
43913
+ description: "Return from session branch. Restores main context, optionally carrying back learnings.",
43914
+ args: {
43915
+ project_key: tool.schema.string().describe("Project path"),
43916
+ epic_id: tool.schema.string().describe("Epic bead ID"),
43917
+ branch_label: tool.schema.string().optional().describe("Label of branch to return from (defaults to latest)"),
43918
+ carry_back_learnings: tool.schema.string().optional().describe("Learnings or insights to carry back to main context"),
43919
+ carry_back_files: tool.schema.array(tool.schema.string()).optional().describe("Files to preserve from branch (others discarded)")
43920
+ },
43921
+ async execute(args) {
43922
+ try {
43923
+ const { getSwarmMailLibSQL: getSwarmMailLibSQL5 } = await import("swarm-mail");
43924
+ const swarmMail = await getSwarmMailLibSQL5(args.project_key);
43925
+ const db = await swarmMail.getDatabase();
43926
+ const result = await db.query(args.branch_label ? `SELECT * FROM swarm_contexts
43927
+ WHERE epic_id = $1 AND json_extract(directives, '$.branch_label') = $2
43928
+ ORDER BY updated_at DESC
43929
+ LIMIT 1` : `SELECT * FROM swarm_contexts
43930
+ WHERE epic_id = $1 AND json_extract(directives, '$.branch_id') IS NOT NULL
43931
+ ORDER BY updated_at DESC
43932
+ LIMIT 1`, args.branch_label ? [args.epic_id, args.branch_label] : [args.epic_id]);
43933
+ if (!result.rows || result.rows.length === 0) {
43934
+ return JSON.stringify({
43935
+ success: false,
43936
+ found: false,
43937
+ message: args.branch_label ? `No branch found with label: ${args.branch_label}` : "No branch checkpoints found for this epic",
43938
+ epic_id: args.epic_id
43939
+ }, null, 2);
43940
+ }
43941
+ const row = result.rows[0];
43942
+ const parseIfString = (val) => typeof val === "string" ? JSON.parse(val) : val;
43943
+ const context = {
43944
+ id: row.id,
43945
+ epic_id: row.epic_id,
43946
+ bead_id: row.bead_id,
43947
+ strategy: row.strategy,
43948
+ files: parseIfString(row.files),
43949
+ dependencies: parseIfString(row.dependencies),
43950
+ directives: parseIfString(row.directives),
43951
+ recovery: parseIfString(row.recovery),
43952
+ created_at: row.created_at,
43953
+ updated_at: row.updated_at
43954
+ };
43955
+ const { createEvent: createEvent5, appendEvent: appendEvent4 } = await import("swarm-mail");
43956
+ const event = createEvent5("swarm_recovered", {
43957
+ project_key: args.project_key,
43958
+ epic_id: args.epic_id,
43959
+ bead_id: context.bead_id,
43960
+ recovered_from_checkpoint: context.recovery.last_checkpoint
43961
+ });
43962
+ await appendEvent4(event, args.project_key);
43963
+ const branchLabel = context.directives.branch_label || "unnamed-branch";
43964
+ return JSON.stringify({
43965
+ success: true,
43966
+ found: true,
43967
+ branch_label: branchLabel,
43968
+ branch_purpose: context.directives.branch_purpose,
43969
+ context_restored: {
43970
+ bead_id: context.bead_id,
43971
+ files: context.files,
43972
+ progress_percent: context.recovery.progress_percent
43973
+ },
43974
+ learnings_carried_back: args.carry_back_learnings || null,
43975
+ files_carried_back: args.carry_back_files || [],
43976
+ message: `Returned from branch: ${branchLabel}`,
43977
+ age_seconds: Math.round((Date.now() - context.updated_at) / 1000)
43978
+ }, null, 2);
43979
+ } catch (error45) {
43980
+ console.warn(`[swarm_return] Failed to return from branch:`, error45);
43981
+ return JSON.stringify({
43982
+ success: false,
43983
+ found: false,
43984
+ error: error45 instanceof Error ? error45.message : String(error45),
43985
+ message: "Failed to return from branch",
43986
+ epic_id: args.epic_id
43987
+ }, null, 2);
43988
+ }
43989
+ }
43990
+ });
43809
43991
  var swarm_learn = tool({
43810
43992
  description: `Analyze completed work and optionally create a skill from learned patterns.
43811
43993
 
package/dist/swarm.d.ts CHANGED
@@ -340,6 +340,46 @@ export declare const swarmTools: {
340
340
  epic_id: string;
341
341
  }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
342
342
  };
343
+ swarm_branch: {
344
+ description: string;
345
+ args: {
346
+ project_key: import("zod").ZodString;
347
+ agent_name: import("zod").ZodString;
348
+ bead_id: import("zod").ZodString;
349
+ epic_id: import("zod").ZodString;
350
+ branch_label: import("zod").ZodString;
351
+ branch_purpose: import("zod").ZodString;
352
+ files_modified: import("zod").ZodArray<import("zod").ZodString>;
353
+ progress_percent: import("zod").ZodOptional<import("zod").ZodNumber>;
354
+ };
355
+ execute(args: {
356
+ project_key: string;
357
+ agent_name: string;
358
+ bead_id: string;
359
+ epic_id: string;
360
+ branch_label: string;
361
+ branch_purpose: string;
362
+ files_modified: string[];
363
+ progress_percent?: number | undefined;
364
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
365
+ };
366
+ swarm_return: {
367
+ description: string;
368
+ args: {
369
+ project_key: import("zod").ZodString;
370
+ epic_id: import("zod").ZodString;
371
+ branch_label: import("zod").ZodOptional<import("zod").ZodString>;
372
+ carry_back_learnings: import("zod").ZodOptional<import("zod").ZodString>;
373
+ carry_back_files: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
374
+ };
375
+ execute(args: {
376
+ project_key: string;
377
+ epic_id: string;
378
+ branch_label?: string | undefined;
379
+ carry_back_learnings?: string | undefined;
380
+ carry_back_files?: string[] | undefined;
381
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
382
+ };
343
383
  swarm_learn: {
344
384
  description: string;
345
385
  args: {
@@ -1 +1 @@
1
- {"version":3,"file":"swarm.d.ts","sourceRoot":"","sources":["../src/swarm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gBAAgB,CAAC;AAW/B;;;GAGG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAQtB,CAAC"}
1
+ {"version":3,"file":"swarm.d.ts","sourceRoot":"","sources":["../src/swarm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gBAAgB,CAAC;AAW/B;;;GAGG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAQtB,CAAC"}
@@ -40,7 +40,10 @@ import { tool } from "@opencode-ai/plugin";
40
40
  import { spawn } from "child_process";
41
41
  import { appendFileSync, mkdirSync, existsSync } from "node:fs";
42
42
  import { join } from "node:path";
43
- import { homedir } from "node:os";
43
+ import { homedir, platform } from "node:os";
44
+
45
+ // Platform detection for Windows compatibility
46
+ const isWindows = platform() === "win32";
44
47
 
45
48
  // =============================================================================
46
49
  // Swarm Signature Detection (INLINED - do not import from opencode-swarm-plugin)
@@ -304,7 +307,9 @@ function getSwarmSummary(projection: SwarmProjection): string {
304
307
  // Constants
305
308
  // =============================================================================
306
309
 
307
- const SWARM_CLI = "swarm";
310
+ // On Windows, use .cmd extension to avoid shell escaping issues with JSON args
311
+ const SWARM_CLI = isWindows ? "swarm.cmd" : "swarm";
312
+ const OPENCODE_CLI = isWindows ? "opencode.cmd" : "opencode";
308
313
 
309
314
  // =============================================================================
310
315
  // File-based Logging (writes to ~/.config/swarm-tools/logs/)
@@ -2058,7 +2063,7 @@ Keep the prompt concise but actionable. Use actual data from the snapshot, not p
2058
2063
  const llmStart = Date.now();
2059
2064
  const result = await new Promise<{ exitCode: number; stdout: string; stderr: string }>(
2060
2065
  (resolve, reject) => {
2061
- const proc = spawn("opencode", ["run", "-m", liteModel, "--", promptText], {
2066
+ const proc = spawn(OPENCODE_CLI, ["run", "-m", liteModel, "--", promptText], {
2062
2067
  cwd: projectDirectory,
2063
2068
  stdio: ["ignore", "pipe", "pipe"],
2064
2069
  timeout: 30000, // 30 second timeout
@@ -0,0 +1,155 @@
1
+ ---
2
+ name: skill-generator
3
+ description: Meta-skill for generating new skills with proper format and structure. Use when creating new skills for the swarm system or when agents need to generate skill scaffolds. Ensures skills follow conventions (frontmatter format, directory structure, bundled resources).
4
+ ---
5
+
6
+ # Skill Generator
7
+
8
+ Generate new skills with proper format, structure, and conventions. This meta-skill helps agents create skills without hallucinating the format.
9
+
10
+ ## Quick Start
11
+
12
+ To generate a new skill:
13
+
14
+ ```bash
15
+ bash scripts/generate-skill.sh <skill-name> [target-directory]
16
+ ```
17
+
18
+ This creates a complete skill scaffold with:
19
+ - SKILL.md with proper frontmatter
20
+ - scripts/ directory for executable helpers
21
+ - references/ directory for documentation
22
+ - Placeholder content following conventions
23
+
24
+ ## Skill Format Conventions
25
+
26
+ Every skill MUST include:
27
+
28
+ 1. **SKILL.md** (required) - Main skill file with:
29
+ - YAML frontmatter (name, description)
30
+ - Markdown body with instructions
31
+
32
+ 2. **Bundled Resources** (optional):
33
+ - `scripts/` - Executable code (bash/python/etc)
34
+ - `references/` - Documentation loaded on-demand
35
+ - `assets/` - Files used in output (templates, etc)
36
+
37
+ ### Frontmatter Requirements
38
+
39
+ ```yaml
40
+ ---
41
+ name: skill-name
42
+ description: What the skill does AND when to use it. Include triggering scenarios.
43
+ ---
44
+ ```
45
+
46
+ The description field is critical for skill discovery and triggering. Include:
47
+ - What the skill does
48
+ - When to use it (specific triggers)
49
+ - What contexts activate it
50
+
51
+ ### Directory Structure
52
+
53
+ ```
54
+ skill-name/
55
+ ├── SKILL.md (required)
56
+ ├── scripts/ (optional)
57
+ │ └── example-script.sh
58
+ ├── references/ (optional)
59
+ │ └── conventions.md
60
+ └── assets/ (optional)
61
+ └── template-file
62
+ ```
63
+
64
+ ## Writing Effective Skills
65
+
66
+ ### Keep SKILL.md Lean
67
+
68
+ Target <500 lines in SKILL.md. Move detailed content to references/:
69
+
70
+ - Core workflow → SKILL.md
71
+ - Detailed examples → references/
72
+ - API docs → references/
73
+ - Long explanations → references/
74
+
75
+ ### Use Imperative Form
76
+
77
+ Write instructions as commands:
78
+ - "Read the file first" ✓
79
+ - "You should read the file" ✗
80
+ - "Check for patterns" ✓
81
+ - "Consider checking patterns" ✗
82
+
83
+ ### Progressive Disclosure
84
+
85
+ Skills use three-level loading:
86
+
87
+ 1. **Metadata** (~100 words) - Always in context
88
+ 2. **SKILL.md body** (<5k words) - When skill triggers
89
+ 3. **Bundled resources** (unlimited) - Loaded as needed
90
+
91
+ ## Bundled Resources
92
+
93
+ ### scripts/
94
+
95
+ Executable code for deterministic tasks:
96
+ - When the same code is rewritten repeatedly
97
+ - When reliability is critical
98
+ - Run via bash/python without loading to context
99
+
100
+ Make scripts executable:
101
+ ```bash
102
+ chmod +x scripts/my-script.sh
103
+ ```
104
+
105
+ ### references/
106
+
107
+ Documentation loaded on-demand:
108
+ - Database schemas
109
+ - API documentation
110
+ - Detailed workflow guides
111
+ - Domain knowledge
112
+
113
+ Keep reference files focused. For files >100 lines, include a table of contents.
114
+
115
+ Reference from SKILL.md with clear guidance on when to read:
116
+ ```markdown
117
+ See references/api-docs.md for complete API reference.
118
+ ```
119
+
120
+ ### assets/
121
+
122
+ Files used in output (not loaded to context):
123
+ - Templates
124
+ - Images/icons
125
+ - Boilerplate code
126
+ - Fonts/typography
127
+
128
+ ## What NOT to Include
129
+
130
+ Do NOT create these files:
131
+ - README.md
132
+ - INSTALLATION_GUIDE.md
133
+ - QUICK_REFERENCE.md
134
+ - CHANGELOG.md
135
+
136
+ Skills should contain only what an AI agent needs to execute the task. No auxiliary documentation.
137
+
138
+ ## Validation
139
+
140
+ Before finalizing, validate the skill:
141
+
142
+ ```bash
143
+ bun scripts/validate-skill.ts path/to/skill
144
+ ```
145
+
146
+ Checks:
147
+ - YAML frontmatter format
148
+ - Required fields present
149
+ - No TODO placeholders
150
+ - No extraneous files
151
+ - Naming conventions
152
+
153
+ ## Reference
154
+
155
+ See references/conventions.md for complete skill format specification.