opencode-hive 1.0.3 → 1.0.5

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.
package/README.md CHANGED
@@ -165,6 +165,7 @@ Hive uses a config file at `~/.config/opencode/agent_hive.json`. You can customi
165
165
  | `dispatching-parallel-agents` | Use when facing 2+ independent tasks. Dispatches multiple agents to work concurrently on unrelated problems. |
166
166
  | `test-driven-development` | Use when implementing any feature or bugfix. Enforces write-test-first, red-green-refactor cycle. |
167
167
  | `systematic-debugging` | Use when encountering any bug or test failure. Requires root cause investigation before proposing fixes. |
168
+ | `code-reviewer` | Use when reviewing implementation changes against an approved plan or task to catch missing requirements, YAGNI, dead code, and risky patterns. |
168
169
  | `verification-before-completion` | Use before claiming work is complete. Requires running verification commands and confirming output before success claims. |
169
170
 
170
171
  #### Available MCPs
@@ -178,7 +179,7 @@ Hive uses a config file at `~/.config/opencode/agent_hive.json`. You can customi
178
179
 
179
180
  ### Per-Agent Skills
180
181
 
181
- Each agent can have specific skills enabled. If configured, only those skills are available:
182
+ Each agent can have specific skills enabled. If configured, only those skills appear in `hive_skill()`:
182
183
 
183
184
  ```json
184
185
  {
@@ -205,7 +206,7 @@ Note: Wildcards like `["*"]` are **not supported** - use explicit skill names or
205
206
 
206
207
  ### Auto-load Skills
207
208
 
208
- Use `autoLoadSkills` to automatically inject skills into an agent's system prompt (in addition to any skills selected by the agent).
209
+ Use `autoLoadSkills` to automatically inject skills into an agent's system prompt at session start.
209
210
 
210
211
  ```json
211
212
  {
@@ -221,6 +222,25 @@ Use `autoLoadSkills` to automatically inject skills into an agent's system promp
221
222
  }
222
223
  ```
223
224
 
225
+ **Supported skill sources:**
226
+
227
+ `autoLoadSkills` accepts both Hive builtin skill IDs and file-based skill IDs. Resolution order:
228
+
229
+ 1. **Hive builtin** — Skills bundled with opencode-hive (always win if ID matches)
230
+ 2. **Project OpenCode** — `<project>/.opencode/skills/<id>/SKILL.md`
231
+ 3. **Global OpenCode** — `~/.config/opencode/skills/<id>/SKILL.md`
232
+ 4. **Project Claude** — `<project>/.claude/skills/<id>/SKILL.md`
233
+ 5. **Global Claude** — `~/.claude/skills/<id>/SKILL.md`
234
+
235
+ Skill IDs must be safe directory names (no `/`, `\`, `..`, or `.`). Missing or invalid skills emit a warning and are skipped—startup continues without failure.
236
+
237
+ **How `skills` and `autoLoadSkills` interact:**
238
+
239
+ - `skills` controls what appears in `hive_skill()` — the agent can manually load these on demand
240
+ - `autoLoadSkills` injects skills unconditionally at session start — no manual loading needed
241
+ - These are **independent**: a skill can be auto-loaded but not appear in `hive_skill()`, or vice versa
242
+ - User `autoLoadSkills` are **merged** with defaults (use global `disableSkills` to remove defaults)
243
+
224
244
  **Default auto-load skills by agent:**
225
245
 
226
246
  | Agent | autoLoadSkills default |
@@ -4,7 +4,7 @@
4
4
  * Inspired by Momus from OmO (Greek god of satire who found fault in everything).
5
5
  * Reviews plans for documentation gaps, NOT design decisions.
6
6
  */
7
- export declare const HYGIENIC_BEE_PROMPT = "# Hygienic (Consultant/Reviewer/Debugger)\n\nNamed after Momus - finds fault in everything. Reviews DOCUMENTATION, not DESIGN.\n\n## Core Mandate\n\nReview plan WITHIN the stated approach. Question DOCUMENTATION gaps, NOT design decisions.\n\nSelf-check before every critique:\n> \"Am I questioning APPROACH or DOCUMENTATION?\"\n> APPROACH \u2192 Stay silent\n> DOCUMENTATION \u2192 Raise it\n\n## Four Core Criteria\n\n### 1. Clarity of Work Content\n- Are reference sources specified with file:lines?\n- Can the implementer find what they need?\n\n### 2. Verification & Acceptance Criteria\n- Are criteria measurable and concrete?\n- Red flags: \"should work\", \"looks good\", \"properly handles\"\n\n### 3. Context Completeness (90% Confidence)\n- Could a capable worker execute with 90% confidence?\n- What's missing that would drop below 90%?\n\n### 4. Big Picture & Workflow\n- Is the WHY clear (not just WHAT and HOW)?\n- Does the flow make sense?\n\n## Red Flags Table\n\n| Pattern | Problem |\n|---------|---------|\n| Vague verbs | \"Handle appropriately\", \"Process correctly\" |\n| Missing paths | Task mentions file but no path |\n| Subjective criteria | \"Should be clean\", \"Well-structured\" |\n| Assumed context | \"As discussed\", \"Obviously\" |\n| Magic numbers | Timeouts, limits without rationale |\n\n## Active Implementation Simulation\n\nBefore verdict, mentally execute 2-3 tasks:\n1. Pick a representative task\n2. Simulate: \"I'm starting this task now...\"\n3. Where do I get stuck? What's missing?\n4. Document gaps found\n\n## Output Format\n\n```\n[OKAY / REJECT]\n\n**Justification**: [one-line explanation]\n\n**Assessment**:\n- Clarity: [Good/Needs Work]\n- Verifiability: [Good/Needs Work]\n- Completeness: [Good/Needs Work]\n- Big Picture: [Good/Needs Work]\n\n[If REJECT - Top 3-5 Critical Improvements]:\n1. [Specific gap with location]\n2. [Specific gap with location]\n3. [Specific gap with location]\n```\n\n## When to OKAY vs REJECT\n\n| Situation | Verdict |\n|-----------|---------|\n| Minor gaps, easily inferred | OKAY with notes |\n| Design seems suboptimal | OKAY (not your call) |\n| Missing file paths for key tasks | REJECT |\n| Vague acceptance criteria | REJECT |\n| Unclear dependencies | REJECT |\n| Assumed context not documented | REJECT |\n\n## Iron Laws\n\n**Never:**\n- Reject based on design decisions\n- Suggest alternative architectures\n- Block on style preferences\n- Review implementation (plans only)\n\n**Always:**\n- Self-check: approach vs documentation\n- Simulate 2-3 tasks before verdict\n- Cite specific locations for gaps\n- Focus on worker success, not perfection\n";
7
+ export declare const HYGIENIC_BEE_PROMPT = "# Hygienic (Consultant/Reviewer/Debugger)\n\nNamed after Momus - finds fault in everything. Reviews DOCUMENTATION, not DESIGN.\n\n## Core Mandate\n\nReview plan WITHIN the stated approach. Question DOCUMENTATION gaps, NOT design decisions.\n\nIf you are asked to review IMPLEMENTATION (code changes, diffs, PRs) instead of a plan:\n1. Load `hive_skill(\"code-reviewer\")`\n2. Apply it and return its output format\n3. Still do NOT edit code (review only)\n\nSelf-check before every critique:\n> \"Am I questioning APPROACH or DOCUMENTATION?\"\n> APPROACH \u2192 Stay silent\n> DOCUMENTATION \u2192 Raise it\n\n## Four Core Criteria\n\n### 1. Clarity of Work Content\n- Are reference sources specified with file:lines?\n- Can the implementer find what they need?\n\n### 2. Verification & Acceptance Criteria\n- Are criteria measurable and concrete?\n- Red flags: \"should work\", \"looks good\", \"properly handles\"\n\n### 3. Context Completeness (90% Confidence)\n- Could a capable worker execute with 90% confidence?\n- What's missing that would drop below 90%?\n\n### 4. Big Picture & Workflow\n- Is the WHY clear (not just WHAT and HOW)?\n- Does the flow make sense?\n\n## Red Flags Table\n\n| Pattern | Problem |\n|---------|---------|\n| Vague verbs | \"Handle appropriately\", \"Process correctly\" |\n| Missing paths | Task mentions file but no path |\n| Subjective criteria | \"Should be clean\", \"Well-structured\" |\n| Assumed context | \"As discussed\", \"Obviously\" |\n| Magic numbers | Timeouts, limits without rationale |\n\n## Active Implementation Simulation\n\nBefore verdict, mentally execute 2-3 tasks:\n1. Pick a representative task\n2. Simulate: \"I'm starting this task now...\"\n3. Where do I get stuck? What's missing?\n4. Document gaps found\n\n## Output Format\n\n```\n[OKAY / REJECT]\n\n**Justification**: [one-line explanation]\n\n**Assessment**:\n- Clarity: [Good/Needs Work]\n- Verifiability: [Good/Needs Work]\n- Completeness: [Good/Needs Work]\n- Big Picture: [Good/Needs Work]\n\n[If REJECT - Top 3-5 Critical Improvements]:\n1. [Specific gap with location]\n2. [Specific gap with location]\n3. [Specific gap with location]\n```\n\n## When to OKAY vs REJECT\n\n| Situation | Verdict |\n|-----------|---------|\n| Minor gaps, easily inferred | OKAY with notes |\n| Design seems suboptimal | OKAY (not your call) |\n| Missing file paths for key tasks | REJECT |\n| Vague acceptance criteria | REJECT |\n| Unclear dependencies | REJECT |\n| Assumed context not documented | REJECT |\n\n## Iron Laws\n\n**Never:**\n- Reject based on design decisions\n- Suggest alternative architectures\n- Block on style preferences\n- Review implementation unless explicitly asked (default is plans only)\n\n**Always:**\n- Self-check: approach vs documentation\n- Simulate 2-3 tasks before verdict\n- Cite specific locations for gaps\n- Focus on worker success, not perfection\n";
8
8
  export declare const hygienicBeeAgent: {
9
9
  name: string;
10
10
  description: string;
package/dist/index.js CHANGED
@@ -14,6 +14,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
14
14
  // src/index.ts
15
15
  import * as path7 from "path";
16
16
  import * as fs9 from "fs";
17
+ import * as os from "os";
17
18
 
18
19
  // ../../node_modules/zod/v4/classic/external.js
19
20
  var exports_external = {};
@@ -12336,7 +12337,7 @@ function tool(input) {
12336
12337
  }
12337
12338
  tool.schema = exports_external;
12338
12339
  // src/skills/registry.generated.ts
12339
- var BUILTIN_SKILL_NAMES = ["brainstorming", "dispatching-parallel-agents", "executing-plans", "onboarding", "parallel-exploration", "systematic-debugging", "test-driven-development", "verification-before-completion", "writing-plans"];
12340
+ var BUILTIN_SKILL_NAMES = ["brainstorming", "code-reviewer", "dispatching-parallel-agents", "executing-plans", "onboarding", "parallel-exploration", "systematic-debugging", "test-driven-development", "verification-before-completion", "writing-plans"];
12340
12341
  var BUILTIN_SKILLS = [
12341
12342
  {
12342
12343
  name: "brainstorming",
@@ -12388,6 +12389,213 @@ Start by understanding the current project context, then ask questions one at a
12388
12389
  - **Explore alternatives** - Always propose 2-3 approaches before settling
12389
12390
  - **Incremental validation** - Present design in sections, validate each
12390
12391
  - **Be flexible** - Go back and clarify when something doesn't make sense`
12392
+ },
12393
+ {
12394
+ name: "code-reviewer",
12395
+ description: "Use when reviewing implementation changes against an approved plan or task (especially before merging or between Hive tasks) to catch missing requirements, YAGNI, dead code, and risky patterns",
12396
+ template: `# Code Reviewer
12397
+
12398
+ ## Overview
12399
+
12400
+ This skill teaches a reviewer to evaluate implementation changes for:
12401
+ - Adherence to the approved plan/task (did we build what we said?)
12402
+ - Correctness (does it work, including edge cases?)
12403
+ - Simplicity (YAGNI, dead code, over-abstraction)
12404
+ - Risk (security, performance, maintainability)
12405
+
12406
+ **Core principle:** The best change is the smallest correct change that satisfies the plan.
12407
+
12408
+ ## Iron Laws
12409
+
12410
+ - Review against the task/plan first. Code quality comes second.
12411
+ - Bias toward deletion and simplification. Every extra line is a liability.
12412
+ - Prefer changes that leverage existing patterns and dependencies.
12413
+ - Be specific: cite file paths and (when available) line numbers.
12414
+ - Do not invent requirements. If the plan/task is ambiguous, mark it and request clarification.
12415
+
12416
+ ## What Inputs You Need
12417
+
12418
+ Minimum:
12419
+ - The task intent (1-3 sentences)
12420
+ - The plan/task requirements (or a link/path to plan section)
12421
+ - The code changes (diff or list of changed files)
12422
+
12423
+ If available (recommended):
12424
+ - Acceptance criteria / verification steps from the plan
12425
+ - Test output or proof the change was verified
12426
+ - Any relevant context files (design decisions, constraints)
12427
+
12428
+ ## Review Process (In Order)
12429
+
12430
+ ### 1) Identify Scope
12431
+
12432
+ 1. List all files changed.
12433
+ 2. For each file, state why it changed (what requirement it serves).
12434
+ 3. Flag any changes that do not map to the task/plan.
12435
+
12436
+ **Rule:** If you cannot map a change to a requirement, treat it as suspicious until justified.
12437
+
12438
+ ### 2) Plan/Task Adherence (Non-Negotiable)
12439
+
12440
+ Create a simple checklist:
12441
+ - What the task says must happen
12442
+ - Evidence in code/tests that it happens
12443
+
12444
+ Flag as issues:
12445
+ - Missing requirements (implemented behavior does not match intent)
12446
+ - Partial implementation with no follow-up task (TODO-driven shipping)
12447
+ - Behavior changes that are not in the plan/task
12448
+
12449
+ ### 3) Correctness Layer
12450
+
12451
+ Review for:
12452
+ - Edge cases and error paths
12453
+ - Incorrect assumptions about inputs/types
12454
+ - Inconsistent behavior across platforms/environments
12455
+ - Broken invariants (e.g., state can become invalid)
12456
+
12457
+ Prefer "fail fast, fail loud": invalid states should become clear errors, not silent fallbacks.
12458
+
12459
+ ### 4) Simplicity / YAGNI Layer
12460
+
12461
+ Be ruthless and concrete:
12462
+ - Remove dead branches, unused flags/options, unreachable code
12463
+ - Remove speculative TODOs and "reserved for future" scaffolding
12464
+ - Remove comments that restate the code or narrate obvious steps
12465
+ - Inline one-off abstractions (helpers/classes/interfaces used once)
12466
+ - Replace cleverness with obvious code
12467
+ - Reduce nesting with guard clauses / early returns
12468
+
12469
+ Prefer clarity over brevity:
12470
+ - Avoid nested ternary operators; use \`if/else\` or \`switch\` when branches matter
12471
+ - Avoid dense one-liners that hide intent or make debugging harder
12472
+
12473
+ ### 4b) De-Slop Pass (AI Artifacts / Style Drift)
12474
+
12475
+ Scan the diff (not just the final code) for AI-generated slop introduced in this branch:
12476
+ - Extra comments that a human would not add, or that do not match the file's tone
12477
+ - Defensive checks or try/catch blocks that are abnormal for that area of the codebase
12478
+ - Especially swallowed errors ("ignore and continue") and silent fallbacks
12479
+ - Especially redundant validation in trusted internal codepaths
12480
+ - TypeScript escape hatches used to dodge type errors (\`as any\`, \`as unknown as X\`) without necessity
12481
+ - Style drift: naming, error handling patterns, logging style, and structure inconsistent with nearby code
12482
+
12483
+ Default stance:
12484
+ - Prefer deletion over justification.
12485
+ - If validation is needed, do it at boundaries; keep internals trusting parsed inputs.
12486
+ - If a cast is truly unavoidable, localize it and keep the justification to a single short note.
12487
+
12488
+ When recommending simplifications, do not accidentally change behavior. If the current behavior is unclear, request clarification or ask for a test that pins it down.
12489
+
12490
+ **Default stance:** Do not add extensibility points without an explicit current requirement.
12491
+
12492
+ ### 5) Risk Layer (Security / Performance / Maintainability)
12493
+
12494
+ Only report what you are confident about.
12495
+
12496
+ Security checks (examples):
12497
+ - No secrets in code/logs
12498
+ - No injection vectors (shell/SQL/HTML) introduced
12499
+ - Authz/authn checks preserved
12500
+ - Sensitive data not leaked
12501
+
12502
+ Performance checks (examples):
12503
+ - Avoid unnecessary repeated work (N+1 queries, repeated parsing, repeated filesystem hits)
12504
+ - Avoid obvious hot-path allocations or large sync operations
12505
+
12506
+ Maintainability checks:
12507
+ - Clear naming and intent
12508
+ - Consistent error handling
12509
+ - API boundaries not blurred
12510
+ - Consistent with local file patterns (imports, export style, function style)
12511
+
12512
+ ### 6) Make One Primary Recommendation
12513
+
12514
+ Provide one clear path to reach approval.
12515
+ Mention alternatives only when they have materially different trade-offs.
12516
+
12517
+ ### 7) Signal the Investment
12518
+
12519
+ Tag the required follow-up effort using:
12520
+ - Quick (<1h)
12521
+ - Short (1-4h)
12522
+ - Medium (1-2d)
12523
+ - Large (3d+)
12524
+
12525
+ ## Confidence Filter
12526
+
12527
+ Only report findings you believe are >=80% likely to be correct.
12528
+ If you are unsure, explicitly label it as "Uncertain" and explain what evidence would confirm it.
12529
+
12530
+ ## Output Format (Use This Exactly)
12531
+
12532
+ ---
12533
+
12534
+ **Files Reviewed:** [list]
12535
+
12536
+ **Plan/Task Reference:** [task name + link/path to plan section if known]
12537
+
12538
+ **Overall Assessment:** [APPROVE | REQUEST_CHANGES | NEEDS_DISCUSSION]
12539
+
12540
+ **Bottom Line:** 2-3 sentences describing whether it matches the task/plan and what must change.
12541
+
12542
+ ### Critical Issues
12543
+ - None | [file:line] - [issue] (why it blocks approval) + (recommended fix)
12544
+
12545
+ ### Major Issues
12546
+ - None | [file:line] - [issue] + (recommended fix)
12547
+
12548
+ ### Minor Issues
12549
+ - None | [file:line] - [issue] + (suggested fix)
12550
+
12551
+ ### YAGNI / Dead Code
12552
+ - None | [file:line] - [what to remove/simplify] + (why it is unnecessary)
12553
+
12554
+ ### Positive Observations
12555
+ - [at least one concrete good thing]
12556
+
12557
+ ### Action Plan
12558
+ 1. [highest priority change]
12559
+ 2. [next]
12560
+ 3. [next]
12561
+
12562
+ ### Effort Estimate
12563
+ [Quick | Short | Medium | Large]
12564
+
12565
+ ---
12566
+
12567
+ ## Common Review Smells (Fast Scan)
12568
+
12569
+ Task/plan adherence:
12570
+ - Adds features not mentioned in the plan/task
12571
+ - Leaves TODOs as the mechanism for correctness
12572
+ - Introduces new configuration modes/flags "for future"
12573
+
12574
+ YAGNI / dead code:
12575
+ - Options/config that are parsed but not used
12576
+ - Branches that do the same thing on both sides
12577
+ - Comments like "reserved for future" or "we might need this"
12578
+
12579
+ AI slop / inconsistency:
12580
+ - Commentary that restates code, narrates obvious steps, or adds process noise
12581
+ - try/catch that swallows errors or returns defaults without a requirement
12582
+ - \`as any\` used to silence type errors instead of fixing types
12583
+ - New helpers/abstractions with a single call site
12584
+
12585
+ Correctness:
12586
+ - Silent fallbacks to defaults on error when the task expects a hard failure
12587
+ - Unhandled error paths, missing cleanup, missing returns
12588
+
12589
+ Maintainability:
12590
+ - Abstractions used once
12591
+ - Unclear naming, "utility" grab-bags
12592
+
12593
+ ## When to Escalate
12594
+
12595
+ Use NEEDS_DISCUSSION (instead of REQUEST_CHANGES) when:
12596
+ - The plan/task is ambiguous and multiple implementations could be correct
12597
+ - The change implies a product/architecture decision not documented
12598
+ - Fixing issues requires changing scope, dependencies, or public API`
12391
12599
  },
12392
12600
  {
12393
12601
  name: "dispatching-parallel-agents",
@@ -13933,6 +14141,107 @@ function getFilteredSkills(disabledSkills = [], agentSkills) {
13933
14141
  return filtered;
13934
14142
  }
13935
14143
 
14144
+ // src/skills/file-loader.ts
14145
+ import * as fs from "node:fs/promises";
14146
+ import * as path from "node:path";
14147
+ function validateSkillId(skillId) {
14148
+ if (!skillId || skillId.trim() === "") {
14149
+ return "Skill ID cannot be empty";
14150
+ }
14151
+ if (skillId.includes("/")) {
14152
+ return `Invalid skill ID "${skillId}": contains path traversal character "/"`;
14153
+ }
14154
+ if (skillId.includes("\\")) {
14155
+ return `Invalid skill ID "${skillId}": contains path traversal character "\\"`;
14156
+ }
14157
+ if (skillId.includes("..")) {
14158
+ return `Invalid skill ID "${skillId}": contains path traversal sequence ".."`;
14159
+ }
14160
+ if (skillId === "." || skillId.includes(".")) {
14161
+ return `Invalid skill ID "${skillId}": contains path traversal character "."`;
14162
+ }
14163
+ return;
14164
+ }
14165
+ function stripQuotes(value) {
14166
+ const trimmed = value.trim();
14167
+ if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
14168
+ return trimmed.slice(1, -1);
14169
+ }
14170
+ return trimmed;
14171
+ }
14172
+ function parseFrontmatter(content) {
14173
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
14174
+ if (!match)
14175
+ return null;
14176
+ const frontmatter = match[1];
14177
+ const body = match[2];
14178
+ const nameMatch = frontmatter.match(/^name:\s*(.+)$/m);
14179
+ const descMatch = frontmatter.match(/^description:\s*(.+)$/m);
14180
+ if (!nameMatch || !descMatch)
14181
+ return null;
14182
+ return {
14183
+ name: stripQuotes(nameMatch[1]),
14184
+ description: stripQuotes(descMatch[1]),
14185
+ body
14186
+ };
14187
+ }
14188
+ function getSearchPaths(skillId, projectRoot, homeDir) {
14189
+ return [
14190
+ path.join(projectRoot, ".opencode", "skills", skillId, "SKILL.md"),
14191
+ path.join(homeDir, ".config", "opencode", "skills", skillId, "SKILL.md"),
14192
+ path.join(projectRoot, ".claude", "skills", skillId, "SKILL.md"),
14193
+ path.join(homeDir, ".claude", "skills", skillId, "SKILL.md")
14194
+ ];
14195
+ }
14196
+ async function tryReadFile(filePath) {
14197
+ try {
14198
+ const content = await fs.readFile(filePath, "utf-8");
14199
+ return content;
14200
+ } catch {
14201
+ return null;
14202
+ }
14203
+ }
14204
+ async function loadFileSkill(skillId, projectRoot, homeDir) {
14205
+ const validationError = validateSkillId(skillId);
14206
+ if (validationError) {
14207
+ return { found: false, error: validationError };
14208
+ }
14209
+ const searchPaths = getSearchPaths(skillId, projectRoot, homeDir);
14210
+ for (const skillPath of searchPaths) {
14211
+ const content = await tryReadFile(skillPath);
14212
+ if (content === null) {
14213
+ continue;
14214
+ }
14215
+ const parsed = parseFrontmatter(content);
14216
+ if (!parsed) {
14217
+ return {
14218
+ found: false,
14219
+ error: `Invalid frontmatter in skill file: ${skillPath}. Expected YAML frontmatter with "name" and "description" fields.`
14220
+ };
14221
+ }
14222
+ if (parsed.name !== skillId) {
14223
+ return {
14224
+ found: false,
14225
+ error: `Skill name mismatch in ${skillPath}: frontmatter name "${parsed.name}" does not match skill ID "${skillId}"`
14226
+ };
14227
+ }
14228
+ const skill = {
14229
+ name: parsed.name,
14230
+ description: parsed.description,
14231
+ template: parsed.body
14232
+ };
14233
+ return {
14234
+ found: true,
14235
+ skill,
14236
+ source: skillPath
14237
+ };
14238
+ }
14239
+ return {
14240
+ found: false,
14241
+ error: `Skill "${skillId}" not found in any of the search paths`
14242
+ };
14243
+ }
14244
+
13936
14245
  // src/agents/hive.ts
13937
14246
  var QUEEN_BEE_PROMPT = `# Hive (Hybrid)
13938
14247
 
@@ -14535,6 +14844,11 @@ Named after Momus - finds fault in everything. Reviews DOCUMENTATION, not DESIGN
14535
14844
 
14536
14845
  Review plan WITHIN the stated approach. Question DOCUMENTATION gaps, NOT design decisions.
14537
14846
 
14847
+ If you are asked to review IMPLEMENTATION (code changes, diffs, PRs) instead of a plan:
14848
+ 1. Load \`hive_skill("code-reviewer")\`
14849
+ 2. Apply it and return its output format
14850
+ 3. Still do NOT edit code (review only)
14851
+
14538
14852
  Self-check before every critique:
14539
14853
  > "Am I questioning APPROACH or DOCUMENTATION?"
14540
14854
  > APPROACH → Stay silent
@@ -14612,7 +14926,7 @@ Before verdict, mentally execute 2-3 tasks:
14612
14926
  - Reject based on design decisions
14613
14927
  - Suggest alternative architectures
14614
14928
  - Block on style preferences
14615
- - Review implementation (plans only)
14929
+ - Review implementation unless explicitly asked (default is plans only)
14616
14930
 
14617
14931
  **Always:**
14618
14932
  - Self-check: approach vs documentation
@@ -14663,10 +14977,10 @@ var createBuiltinMcps = (disabledMcps = []) => {
14663
14977
 
14664
14978
  // ../hive-core/dist/index.js
14665
14979
  import { createRequire as createRequire2 } from "node:module";
14666
- import * as path from "path";
14667
- import * as fs from "fs";
14668
14980
  import * as path2 from "path";
14669
14981
  import * as fs2 from "fs";
14982
+ import * as path22 from "path";
14983
+ import * as fs22 from "fs";
14670
14984
  import * as fs3 from "fs";
14671
14985
  import * as fs4 from "fs";
14672
14986
  import * as fs5 from "fs";
@@ -15556,7 +15870,7 @@ var DEFAULT_HIVE_CONFIG = {
15556
15870
  "hygienic-reviewer": {
15557
15871
  model: DEFAULT_AGENT_MODELS["hygienic-reviewer"],
15558
15872
  temperature: 0.3,
15559
- skills: ["systematic-debugging"],
15873
+ skills: ["systematic-debugging", "code-reviewer"],
15560
15874
  autoLoadSkills: []
15561
15875
  }
15562
15876
  }
@@ -15572,82 +15886,85 @@ var STATUS_FILE = "status.json";
15572
15886
  var REPORT_FILE = "report.md";
15573
15887
  var APPROVED_FILE = "APPROVED";
15574
15888
  var JOURNAL_FILE = "journal.md";
15889
+ function normalizePath(filePath) {
15890
+ return filePath.replace(/\\/g, "/");
15891
+ }
15575
15892
  function getHivePath(projectRoot) {
15576
- return path.join(projectRoot, HIVE_DIR);
15893
+ return path2.join(projectRoot, HIVE_DIR);
15577
15894
  }
15578
15895
  function getJournalPath(projectRoot) {
15579
- return path.join(getHivePath(projectRoot), JOURNAL_FILE);
15896
+ return path2.join(getHivePath(projectRoot), JOURNAL_FILE);
15580
15897
  }
15581
15898
  function getFeaturesPath(projectRoot) {
15582
- return path.join(getHivePath(projectRoot), FEATURES_DIR);
15899
+ return path2.join(getHivePath(projectRoot), FEATURES_DIR);
15583
15900
  }
15584
15901
  function getFeaturePath(projectRoot, featureName) {
15585
- return path.join(getFeaturesPath(projectRoot), featureName);
15902
+ return path2.join(getFeaturesPath(projectRoot), featureName);
15586
15903
  }
15587
15904
  function getPlanPath(projectRoot, featureName) {
15588
- return path.join(getFeaturePath(projectRoot, featureName), PLAN_FILE);
15905
+ return path2.join(getFeaturePath(projectRoot, featureName), PLAN_FILE);
15589
15906
  }
15590
15907
  function getCommentsPath(projectRoot, featureName) {
15591
- return path.join(getFeaturePath(projectRoot, featureName), COMMENTS_FILE);
15908
+ return path2.join(getFeaturePath(projectRoot, featureName), COMMENTS_FILE);
15592
15909
  }
15593
15910
  function getFeatureJsonPath(projectRoot, featureName) {
15594
- return path.join(getFeaturePath(projectRoot, featureName), FEATURE_FILE);
15911
+ return path2.join(getFeaturePath(projectRoot, featureName), FEATURE_FILE);
15595
15912
  }
15596
15913
  function getContextPath(projectRoot, featureName) {
15597
- return path.join(getFeaturePath(projectRoot, featureName), CONTEXT_DIR);
15914
+ return path2.join(getFeaturePath(projectRoot, featureName), CONTEXT_DIR);
15598
15915
  }
15599
15916
  function getTasksPath(projectRoot, featureName) {
15600
- return path.join(getFeaturePath(projectRoot, featureName), TASKS_DIR);
15917
+ return path2.join(getFeaturePath(projectRoot, featureName), TASKS_DIR);
15601
15918
  }
15602
15919
  function getTaskPath(projectRoot, featureName, taskFolder) {
15603
- return path.join(getTasksPath(projectRoot, featureName), taskFolder);
15920
+ return path2.join(getTasksPath(projectRoot, featureName), taskFolder);
15604
15921
  }
15605
15922
  function getTaskStatusPath(projectRoot, featureName, taskFolder) {
15606
- return path.join(getTaskPath(projectRoot, featureName, taskFolder), STATUS_FILE);
15923
+ return path2.join(getTaskPath(projectRoot, featureName, taskFolder), STATUS_FILE);
15607
15924
  }
15608
15925
  function getTaskReportPath(projectRoot, featureName, taskFolder) {
15609
- return path.join(getTaskPath(projectRoot, featureName, taskFolder), REPORT_FILE);
15926
+ return path2.join(getTaskPath(projectRoot, featureName, taskFolder), REPORT_FILE);
15610
15927
  }
15611
15928
  function getTaskSpecPath(projectRoot, featureName, taskFolder) {
15612
- return path.join(getTaskPath(projectRoot, featureName, taskFolder), "spec.md");
15929
+ return path2.join(getTaskPath(projectRoot, featureName, taskFolder), "spec.md");
15613
15930
  }
15614
15931
  function getApprovedPath(projectRoot, featureName) {
15615
- return path.join(getFeaturePath(projectRoot, featureName), APPROVED_FILE);
15932
+ return path2.join(getFeaturePath(projectRoot, featureName), APPROVED_FILE);
15616
15933
  }
15617
15934
  var SUBTASKS_DIR = "subtasks";
15618
15935
  var SPEC_FILE = "spec.md";
15619
15936
  function getSubtasksPath(projectRoot, featureName, taskFolder) {
15620
- return path.join(getTaskPath(projectRoot, featureName, taskFolder), SUBTASKS_DIR);
15937
+ return path2.join(getTaskPath(projectRoot, featureName, taskFolder), SUBTASKS_DIR);
15621
15938
  }
15622
15939
  function getSubtaskPath(projectRoot, featureName, taskFolder, subtaskFolder) {
15623
- return path.join(getSubtasksPath(projectRoot, featureName, taskFolder), subtaskFolder);
15940
+ return path2.join(getSubtasksPath(projectRoot, featureName, taskFolder), subtaskFolder);
15624
15941
  }
15625
15942
  function getSubtaskStatusPath(projectRoot, featureName, taskFolder, subtaskFolder) {
15626
- return path.join(getSubtaskPath(projectRoot, featureName, taskFolder, subtaskFolder), STATUS_FILE);
15943
+ return path2.join(getSubtaskPath(projectRoot, featureName, taskFolder, subtaskFolder), STATUS_FILE);
15627
15944
  }
15628
15945
  function getSubtaskSpecPath(projectRoot, featureName, taskFolder, subtaskFolder) {
15629
- return path.join(getSubtaskPath(projectRoot, featureName, taskFolder, subtaskFolder), SPEC_FILE);
15946
+ return path2.join(getSubtaskPath(projectRoot, featureName, taskFolder, subtaskFolder), SPEC_FILE);
15630
15947
  }
15631
15948
  function getSubtaskReportPath(projectRoot, featureName, taskFolder, subtaskFolder) {
15632
- return path.join(getSubtaskPath(projectRoot, featureName, taskFolder, subtaskFolder), REPORT_FILE);
15949
+ return path2.join(getSubtaskPath(projectRoot, featureName, taskFolder, subtaskFolder), REPORT_FILE);
15633
15950
  }
15634
15951
  function ensureDir(dirPath) {
15635
- if (!fs.existsSync(dirPath)) {
15636
- fs.mkdirSync(dirPath, { recursive: true });
15952
+ if (!fs2.existsSync(dirPath)) {
15953
+ fs2.mkdirSync(dirPath, { recursive: true });
15637
15954
  }
15638
15955
  }
15639
15956
  function fileExists(filePath) {
15640
- return fs.existsSync(filePath);
15957
+ return fs2.existsSync(filePath);
15641
15958
  }
15642
15959
  function readJson(filePath) {
15643
- if (!fs.existsSync(filePath))
15960
+ if (!fs2.existsSync(filePath))
15644
15961
  return null;
15645
- const content = fs.readFileSync(filePath, "utf-8");
15962
+ const content = fs2.readFileSync(filePath, "utf-8");
15646
15963
  return JSON.parse(content);
15647
15964
  }
15648
15965
  function writeJson(filePath, data) {
15649
- ensureDir(path.dirname(filePath));
15650
- fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
15966
+ ensureDir(path2.dirname(filePath));
15967
+ fs2.writeFileSync(filePath, JSON.stringify(data, null, 2));
15651
15968
  }
15652
15969
  var DEFAULT_LOCK_OPTIONS = {
15653
15970
  timeout: 5000,
@@ -15659,7 +15976,7 @@ function getLockPath(filePath) {
15659
15976
  }
15660
15977
  function isLockStale(lockPath, staleTTL) {
15661
15978
  try {
15662
- const stat2 = fs.statSync(lockPath);
15979
+ const stat2 = fs2.statSync(lockPath);
15663
15980
  const age = Date.now() - stat2.mtimeMs;
15664
15981
  return age > staleTTL;
15665
15982
  } catch {
@@ -15677,12 +15994,12 @@ function acquireLockSync(filePath, options = {}) {
15677
15994
  });
15678
15995
  while (true) {
15679
15996
  try {
15680
- const fd = fs.openSync(lockPath, fs.constants.O_CREAT | fs.constants.O_EXCL | fs.constants.O_WRONLY);
15681
- fs.writeSync(fd, lockContent);
15682
- fs.closeSync(fd);
15997
+ const fd = fs2.openSync(lockPath, fs2.constants.O_CREAT | fs2.constants.O_EXCL | fs2.constants.O_WRONLY);
15998
+ fs2.writeSync(fd, lockContent);
15999
+ fs2.closeSync(fd);
15683
16000
  return () => {
15684
16001
  try {
15685
- fs.unlinkSync(lockPath);
16002
+ fs2.unlinkSync(lockPath);
15686
16003
  } catch {}
15687
16004
  };
15688
16005
  } catch (err) {
@@ -15692,7 +16009,7 @@ function acquireLockSync(filePath, options = {}) {
15692
16009
  }
15693
16010
  if (isLockStale(lockPath, opts.staleLockTTL)) {
15694
16011
  try {
15695
- fs.unlinkSync(lockPath);
16012
+ fs2.unlinkSync(lockPath);
15696
16013
  continue;
15697
16014
  } catch {}
15698
16015
  }
@@ -15705,14 +16022,14 @@ function acquireLockSync(filePath, options = {}) {
15705
16022
  }
15706
16023
  }
15707
16024
  function writeAtomic(filePath, content) {
15708
- ensureDir(path.dirname(filePath));
16025
+ ensureDir(path2.dirname(filePath));
15709
16026
  const tempPath = `${filePath}.tmp.${process.pid}.${Date.now()}`;
15710
16027
  try {
15711
- fs.writeFileSync(tempPath, content);
15712
- fs.renameSync(tempPath, filePath);
16028
+ fs2.writeFileSync(tempPath, content);
16029
+ fs2.renameSync(tempPath, filePath);
15713
16030
  } catch (error45) {
15714
16031
  try {
15715
- fs.unlinkSync(tempPath);
16032
+ fs2.unlinkSync(tempPath);
15716
16033
  } catch {}
15717
16034
  throw error45;
15718
16035
  }
@@ -15755,13 +16072,13 @@ function patchJsonLockedSync(filePath, patch, options = {}) {
15755
16072
  }
15756
16073
  }
15757
16074
  function readText(filePath) {
15758
- if (!fs.existsSync(filePath))
16075
+ if (!fs2.existsSync(filePath))
15759
16076
  return null;
15760
- return fs.readFileSync(filePath, "utf-8");
16077
+ return fs2.readFileSync(filePath, "utf-8");
15761
16078
  }
15762
16079
  function writeText(filePath, content) {
15763
- ensureDir(path.dirname(filePath));
15764
- fs.writeFileSync(filePath, content);
16080
+ ensureDir(path2.dirname(filePath));
16081
+ fs2.writeFileSync(filePath, content);
15765
16082
  }
15766
16083
  function detectContext(cwd) {
15767
16084
  const result = {
@@ -15771,7 +16088,8 @@ function detectContext(cwd) {
15771
16088
  isWorktree: false,
15772
16089
  mainProjectRoot: null
15773
16090
  };
15774
- const worktreeMatch = cwd.match(/(.+)\/\.hive\/\.worktrees\/([^/]+)\/([^/]+)/);
16091
+ const normalizedCwd = normalizePath(cwd);
16092
+ const worktreeMatch = normalizedCwd.match(/(.+)\/\.hive\/\.worktrees\/([^/]+)\/([^/]+)/);
15775
16093
  if (worktreeMatch) {
15776
16094
  result.mainProjectRoot = worktreeMatch[1];
15777
16095
  result.feature = worktreeMatch[2];
@@ -15780,18 +16098,19 @@ function detectContext(cwd) {
15780
16098
  result.projectRoot = worktreeMatch[1];
15781
16099
  return result;
15782
16100
  }
15783
- const gitPath = path2.join(cwd, ".git");
15784
- if (fs2.existsSync(gitPath)) {
15785
- const stat2 = fs2.statSync(gitPath);
16101
+ const gitPath = path22.join(cwd, ".git");
16102
+ if (fs22.existsSync(gitPath)) {
16103
+ const stat2 = fs22.statSync(gitPath);
15786
16104
  if (stat2.isFile()) {
15787
- const gitContent = fs2.readFileSync(gitPath, "utf-8").trim();
16105
+ const gitContent = fs22.readFileSync(gitPath, "utf-8").trim();
15788
16106
  const gitdirMatch = gitContent.match(/gitdir:\s*(.+)/);
15789
16107
  if (gitdirMatch) {
15790
16108
  const gitdir = gitdirMatch[1];
15791
- const worktreePathMatch = gitdir.match(/(.+)\/\.git\/worktrees\/(.+)/);
16109
+ const normalizedGitdir = normalizePath(gitdir);
16110
+ const worktreePathMatch = normalizedGitdir.match(/(.+)\/\.git\/worktrees\/(.+)/);
15792
16111
  if (worktreePathMatch) {
15793
16112
  const mainRepo = worktreePathMatch[1];
15794
- const cwdWorktreeMatch = cwd.match(/\.hive\/\.worktrees\/([^/]+)\/([^/]+)/);
16113
+ const cwdWorktreeMatch = normalizedCwd.match(/\.hive\/\.worktrees\/([^/]+)\/([^/]+)/);
15795
16114
  if (cwdWorktreeMatch) {
15796
16115
  result.mainProjectRoot = mainRepo;
15797
16116
  result.feature = cwdWorktreeMatch[1];
@@ -15808,9 +16127,9 @@ function detectContext(cwd) {
15808
16127
  }
15809
16128
  function listFeatures(projectRoot) {
15810
16129
  const featuresPath = getFeaturesPath(projectRoot);
15811
- if (!fs2.existsSync(featuresPath))
16130
+ if (!fs22.existsSync(featuresPath))
15812
16131
  return [];
15813
- return fs2.readdirSync(featuresPath, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
16132
+ return fs22.readdirSync(featuresPath, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
15814
16133
  }
15815
16134
  var JOURNAL_TEMPLATE = `# Hive Journal
15816
16135
 
@@ -21470,7 +21789,13 @@ function isValidPromptFilePath(filePath, workspaceRoot) {
21470
21789
  try {
21471
21790
  const normalizedFilePath = path5.resolve(filePath);
21472
21791
  const normalizedWorkspace = path5.resolve(workspaceRoot);
21473
- if (!normalizedFilePath.startsWith(normalizedWorkspace + path5.sep) && normalizedFilePath !== normalizedWorkspace) {
21792
+ let normalizedFilePathForCompare = normalizePath(normalizedFilePath);
21793
+ let normalizedWorkspaceForCompare = normalizePath(normalizedWorkspace);
21794
+ if (process.platform === "win32") {
21795
+ normalizedFilePathForCompare = normalizedFilePathForCompare.toLowerCase();
21796
+ normalizedWorkspaceForCompare = normalizedWorkspaceForCompare.toLowerCase();
21797
+ }
21798
+ if (!normalizedFilePathForCompare.startsWith(normalizedWorkspaceForCompare + "/") && normalizedFilePathForCompare !== normalizedWorkspaceForCompare) {
21474
21799
  return false;
21475
21800
  }
21476
21801
  return true;
@@ -22891,6 +23216,36 @@ function formatSkillsXml(skills) {
22891
23216
  ${skillsXml}
22892
23217
  </available_skills>`;
22893
23218
  }
23219
+ async function buildAutoLoadedSkillsContent(agentName, configService, projectRoot) {
23220
+ const agentConfig = configService.getAgentConfig(agentName);
23221
+ const autoLoadSkills = agentConfig.autoLoadSkills ?? [];
23222
+ if (autoLoadSkills.length === 0) {
23223
+ return "";
23224
+ }
23225
+ const homeDir = process.env.HOME || os.homedir();
23226
+ const skillTemplates = [];
23227
+ for (const skillId of autoLoadSkills) {
23228
+ const builtinSkill = BUILTIN_SKILLS.find((entry) => entry.name === skillId);
23229
+ if (builtinSkill) {
23230
+ skillTemplates.push(builtinSkill.template);
23231
+ continue;
23232
+ }
23233
+ const fileResult = await loadFileSkill(skillId, projectRoot, homeDir);
23234
+ if (fileResult.found && fileResult.skill) {
23235
+ skillTemplates.push(fileResult.skill.template);
23236
+ continue;
23237
+ }
23238
+ console.warn(`[hive] Unknown skill id "${skillId}" for agent "${agentName}"`);
23239
+ }
23240
+ if (skillTemplates.length === 0) {
23241
+ return "";
23242
+ }
23243
+ return `
23244
+
23245
+ ` + skillTemplates.join(`
23246
+
23247
+ `);
23248
+ }
22894
23249
  function createHiveSkillTool(filteredSkills) {
22895
23250
  const base = `Load a Hive skill to get detailed instructions for a specific workflow.
22896
23251
 
@@ -23072,22 +23427,6 @@ To unblock: Remove .hive/features/${feature}/BLOCKED`;
23072
23427
  return {
23073
23428
  "experimental.chat.system.transform": async (input, output) => {
23074
23429
  output.system.push(HIVE_SYSTEM_PROMPT);
23075
- const agentInput = input;
23076
- const agentName = agentInput?.agent;
23077
- if (agentName && isHiveAgent(agentName)) {
23078
- const agentConfig = configService.getAgentConfig(agentName);
23079
- const autoLoadSkills = agentConfig.autoLoadSkills ?? [];
23080
- if (autoLoadSkills.length > 0) {
23081
- for (const skillId of autoLoadSkills) {
23082
- const skill = BUILTIN_SKILLS.find((entry) => entry.name === skillId);
23083
- if (!skill) {
23084
- console.warn("Unknown skill id", skillId);
23085
- continue;
23086
- }
23087
- output.system.push(skill.template);
23088
- }
23089
- }
23090
- }
23091
23430
  const activeFeature = resolveFeature();
23092
23431
  if (activeFeature) {
23093
23432
  const info = featureService.getInfo(activeFeature);
@@ -23485,7 +23824,7 @@ ${priorTasksFormatted}
23485
23824
  });
23486
23825
  const hiveDir = path7.join(directory, ".hive");
23487
23826
  const workerPromptPath = writeWorkerPromptFile(feature, task, workerPrompt, hiveDir);
23488
- const relativePromptPath = path7.relative(directory, workerPromptPath);
23827
+ const relativePromptPath = normalizePath(path7.relative(directory, workerPromptPath));
23489
23828
  const PREVIEW_MAX_LENGTH = 200;
23490
23829
  const workerPromptPreview = workerPrompt.length > PREVIEW_MAX_LENGTH ? workerPrompt.slice(0, PREVIEW_MAX_LENGTH) + "..." : workerPrompt;
23491
23830
  const hiveBackgroundInstructions = `## Delegation Required
@@ -24042,11 +24381,12 @@ Make the requested changes, then call hive_request_review again.`;
24042
24381
  config: async (opencodeConfig) => {
24043
24382
  configService.init();
24044
24383
  const hiveUserConfig = configService.getAgentConfig("hive-master");
24384
+ const hiveAutoLoadedSkills = await buildAutoLoadedSkillsContent("hive-master", configService, directory);
24045
24385
  const hiveConfig = {
24046
24386
  model: hiveUserConfig.model,
24047
24387
  temperature: hiveUserConfig.temperature ?? 0.5,
24048
24388
  description: "Hive (Hybrid) - Plans + orchestrates. Detects phase, loads skills on-demand.",
24049
- prompt: QUEEN_BEE_PROMPT,
24389
+ prompt: QUEEN_BEE_PROMPT + hiveAutoLoadedSkills,
24050
24390
  permission: {
24051
24391
  question: "allow",
24052
24392
  skill: "allow",
@@ -24058,11 +24398,12 @@ Make the requested changes, then call hive_request_review again.`;
24058
24398
  }
24059
24399
  };
24060
24400
  const architectUserConfig = configService.getAgentConfig("architect-planner");
24401
+ const architectAutoLoadedSkills = await buildAutoLoadedSkillsContent("architect-planner", configService, directory);
24061
24402
  const architectConfig = {
24062
24403
  model: architectUserConfig.model,
24063
24404
  temperature: architectUserConfig.temperature ?? 0.7,
24064
24405
  description: "Architect (Planner) - Plans features, interviews, writes plans. NEVER executes.",
24065
- prompt: ARCHITECT_BEE_PROMPT,
24406
+ prompt: ARCHITECT_BEE_PROMPT + architectAutoLoadedSkills,
24066
24407
  permission: {
24067
24408
  edit: "deny",
24068
24409
  task: "deny",
@@ -24077,11 +24418,12 @@ Make the requested changes, then call hive_request_review again.`;
24077
24418
  }
24078
24419
  };
24079
24420
  const swarmUserConfig = configService.getAgentConfig("swarm-orchestrator");
24421
+ const swarmAutoLoadedSkills = await buildAutoLoadedSkillsContent("swarm-orchestrator", configService, directory);
24080
24422
  const swarmConfig = {
24081
24423
  model: swarmUserConfig.model,
24082
24424
  temperature: swarmUserConfig.temperature ?? 0.5,
24083
24425
  description: "Swarm (Orchestrator) - Orchestrates execution. Delegates, spawns workers, verifies, merges.",
24084
- prompt: SWARM_BEE_PROMPT,
24426
+ prompt: SWARM_BEE_PROMPT + swarmAutoLoadedSkills,
24085
24427
  permission: {
24086
24428
  question: "allow",
24087
24429
  skill: "allow",
@@ -24093,12 +24435,13 @@ Make the requested changes, then call hive_request_review again.`;
24093
24435
  }
24094
24436
  };
24095
24437
  const scoutUserConfig = configService.getAgentConfig("scout-researcher");
24438
+ const scoutAutoLoadedSkills = await buildAutoLoadedSkillsContent("scout-researcher", configService, directory);
24096
24439
  const scoutConfig = {
24097
24440
  model: scoutUserConfig.model,
24098
24441
  temperature: scoutUserConfig.temperature ?? 0.5,
24099
24442
  mode: "subagent",
24100
24443
  description: "Scout (Explorer/Researcher/Retrieval) - Researches codebase + external docs/data.",
24101
- prompt: SCOUT_BEE_PROMPT,
24444
+ prompt: SCOUT_BEE_PROMPT + scoutAutoLoadedSkills,
24102
24445
  permission: {
24103
24446
  edit: "deny",
24104
24447
  skill: "allow",
@@ -24106,23 +24449,25 @@ Make the requested changes, then call hive_request_review again.`;
24106
24449
  }
24107
24450
  };
24108
24451
  const foragerUserConfig = configService.getAgentConfig("forager-worker");
24452
+ const foragerAutoLoadedSkills = await buildAutoLoadedSkillsContent("forager-worker", configService, directory);
24109
24453
  const foragerConfig = {
24110
24454
  model: foragerUserConfig.model,
24111
24455
  temperature: foragerUserConfig.temperature ?? 0.3,
24112
24456
  mode: "subagent",
24113
24457
  description: "Forager (Worker/Coder) - Executes tasks directly in isolated worktrees. Never delegates.",
24114
- prompt: FORAGER_BEE_PROMPT,
24458
+ prompt: FORAGER_BEE_PROMPT + foragerAutoLoadedSkills,
24115
24459
  permission: {
24116
24460
  skill: "allow"
24117
24461
  }
24118
24462
  };
24119
24463
  const hygienicUserConfig = configService.getAgentConfig("hygienic-reviewer");
24464
+ const hygienicAutoLoadedSkills = await buildAutoLoadedSkillsContent("hygienic-reviewer", configService, directory);
24120
24465
  const hygienicConfig = {
24121
24466
  model: hygienicUserConfig.model,
24122
24467
  temperature: hygienicUserConfig.temperature ?? 0.3,
24123
24468
  mode: "subagent",
24124
24469
  description: "Hygienic (Consultant/Reviewer/Debugger) - Reviews plan documentation quality. OKAY/REJECT verdict.",
24125
- prompt: HYGIENIC_BEE_PROMPT,
24470
+ prompt: HYGIENIC_BEE_PROMPT + hygienicAutoLoadedSkills,
24126
24471
  permission: {
24127
24472
  edit: "deny",
24128
24473
  skill: "allow"
@@ -0,0 +1,22 @@
1
+ /**
2
+ * File-based Skill Loader
3
+ *
4
+ * Resolves and loads skill files from OpenCode and Claude-compatible paths.
5
+ * Implements strict skill ID validation and deterministic search order.
6
+ */
7
+ import type { SkillLoadResult } from './types.js';
8
+ /**
9
+ * Load a skill from file-based locations.
10
+ *
11
+ * Searches for skill files in the following order:
12
+ * 1. Project OpenCode: `<projectRoot>/.opencode/skills/<skillId>/SKILL.md`
13
+ * 2. Global OpenCode: `~/.config/opencode/skills/<skillId>/SKILL.md`
14
+ * 3. Project Claude-compatible: `<projectRoot>/.claude/skills/<skillId>/SKILL.md`
15
+ * 4. Global Claude-compatible: `~/.claude/skills/<skillId>/SKILL.md`
16
+ *
17
+ * @param skillId - The skill ID to load
18
+ * @param projectRoot - The project root directory
19
+ * @param homeDir - The user's home directory
20
+ * @returns The skill load result
21
+ */
22
+ export declare function loadFileSkill(skillId: string, projectRoot: string, homeDir: string): Promise<SkillLoadResult>;
@@ -5,3 +5,4 @@
5
5
  */
6
6
  export type { SkillDefinition, SkillLoadResult } from './types.js';
7
7
  export { BUILTIN_SKILLS, loadBuiltinSkill, getBuiltinSkills, getFilteredSkills, getBuiltinSkillsXml, type BuiltinSkillName } from './builtin.js';
8
+ export { loadFileSkill } from './file-loader.js';
@@ -7,7 +7,7 @@ import type { SkillDefinition } from './types.js';
7
7
  /**
8
8
  * List of builtin skill names.
9
9
  */
10
- export declare const BUILTIN_SKILL_NAMES: readonly ["brainstorming", "dispatching-parallel-agents", "executing-plans", "onboarding", "parallel-exploration", "systematic-debugging", "test-driven-development", "verification-before-completion", "writing-plans"];
10
+ export declare const BUILTIN_SKILL_NAMES: readonly ["brainstorming", "code-reviewer", "dispatching-parallel-agents", "executing-plans", "onboarding", "parallel-exploration", "systematic-debugging", "test-driven-development", "verification-before-completion", "writing-plans"];
11
11
  /**
12
12
  * All builtin skill definitions.
13
13
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-hive",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "type": "module",
5
5
  "description": "OpenCode plugin for Agent Hive - from vibe coding to hive coding",
6
6
  "license": "MIT WITH Commons-Clause",
@@ -0,0 +1,208 @@
1
+ ---
2
+ name: code-reviewer
3
+ description: Use when reviewing implementation changes against an approved plan or task (especially before merging or between Hive tasks) to catch missing requirements, YAGNI, dead code, and risky patterns
4
+ ---
5
+
6
+ # Code Reviewer
7
+
8
+ ## Overview
9
+
10
+ This skill teaches a reviewer to evaluate implementation changes for:
11
+ - Adherence to the approved plan/task (did we build what we said?)
12
+ - Correctness (does it work, including edge cases?)
13
+ - Simplicity (YAGNI, dead code, over-abstraction)
14
+ - Risk (security, performance, maintainability)
15
+
16
+ **Core principle:** The best change is the smallest correct change that satisfies the plan.
17
+
18
+ ## Iron Laws
19
+
20
+ - Review against the task/plan first. Code quality comes second.
21
+ - Bias toward deletion and simplification. Every extra line is a liability.
22
+ - Prefer changes that leverage existing patterns and dependencies.
23
+ - Be specific: cite file paths and (when available) line numbers.
24
+ - Do not invent requirements. If the plan/task is ambiguous, mark it and request clarification.
25
+
26
+ ## What Inputs You Need
27
+
28
+ Minimum:
29
+ - The task intent (1-3 sentences)
30
+ - The plan/task requirements (or a link/path to plan section)
31
+ - The code changes (diff or list of changed files)
32
+
33
+ If available (recommended):
34
+ - Acceptance criteria / verification steps from the plan
35
+ - Test output or proof the change was verified
36
+ - Any relevant context files (design decisions, constraints)
37
+
38
+ ## Review Process (In Order)
39
+
40
+ ### 1) Identify Scope
41
+
42
+ 1. List all files changed.
43
+ 2. For each file, state why it changed (what requirement it serves).
44
+ 3. Flag any changes that do not map to the task/plan.
45
+
46
+ **Rule:** If you cannot map a change to a requirement, treat it as suspicious until justified.
47
+
48
+ ### 2) Plan/Task Adherence (Non-Negotiable)
49
+
50
+ Create a simple checklist:
51
+ - What the task says must happen
52
+ - Evidence in code/tests that it happens
53
+
54
+ Flag as issues:
55
+ - Missing requirements (implemented behavior does not match intent)
56
+ - Partial implementation with no follow-up task (TODO-driven shipping)
57
+ - Behavior changes that are not in the plan/task
58
+
59
+ ### 3) Correctness Layer
60
+
61
+ Review for:
62
+ - Edge cases and error paths
63
+ - Incorrect assumptions about inputs/types
64
+ - Inconsistent behavior across platforms/environments
65
+ - Broken invariants (e.g., state can become invalid)
66
+
67
+ Prefer "fail fast, fail loud": invalid states should become clear errors, not silent fallbacks.
68
+
69
+ ### 4) Simplicity / YAGNI Layer
70
+
71
+ Be ruthless and concrete:
72
+ - Remove dead branches, unused flags/options, unreachable code
73
+ - Remove speculative TODOs and "reserved for future" scaffolding
74
+ - Remove comments that restate the code or narrate obvious steps
75
+ - Inline one-off abstractions (helpers/classes/interfaces used once)
76
+ - Replace cleverness with obvious code
77
+ - Reduce nesting with guard clauses / early returns
78
+
79
+ Prefer clarity over brevity:
80
+ - Avoid nested ternary operators; use `if/else` or `switch` when branches matter
81
+ - Avoid dense one-liners that hide intent or make debugging harder
82
+
83
+ ### 4b) De-Slop Pass (AI Artifacts / Style Drift)
84
+
85
+ Scan the diff (not just the final code) for AI-generated slop introduced in this branch:
86
+ - Extra comments that a human would not add, or that do not match the file's tone
87
+ - Defensive checks or try/catch blocks that are abnormal for that area of the codebase
88
+ - Especially swallowed errors ("ignore and continue") and silent fallbacks
89
+ - Especially redundant validation in trusted internal codepaths
90
+ - TypeScript escape hatches used to dodge type errors (`as any`, `as unknown as X`) without necessity
91
+ - Style drift: naming, error handling patterns, logging style, and structure inconsistent with nearby code
92
+
93
+ Default stance:
94
+ - Prefer deletion over justification.
95
+ - If validation is needed, do it at boundaries; keep internals trusting parsed inputs.
96
+ - If a cast is truly unavoidable, localize it and keep the justification to a single short note.
97
+
98
+ When recommending simplifications, do not accidentally change behavior. If the current behavior is unclear, request clarification or ask for a test that pins it down.
99
+
100
+ **Default stance:** Do not add extensibility points without an explicit current requirement.
101
+
102
+ ### 5) Risk Layer (Security / Performance / Maintainability)
103
+
104
+ Only report what you are confident about.
105
+
106
+ Security checks (examples):
107
+ - No secrets in code/logs
108
+ - No injection vectors (shell/SQL/HTML) introduced
109
+ - Authz/authn checks preserved
110
+ - Sensitive data not leaked
111
+
112
+ Performance checks (examples):
113
+ - Avoid unnecessary repeated work (N+1 queries, repeated parsing, repeated filesystem hits)
114
+ - Avoid obvious hot-path allocations or large sync operations
115
+
116
+ Maintainability checks:
117
+ - Clear naming and intent
118
+ - Consistent error handling
119
+ - API boundaries not blurred
120
+ - Consistent with local file patterns (imports, export style, function style)
121
+
122
+ ### 6) Make One Primary Recommendation
123
+
124
+ Provide one clear path to reach approval.
125
+ Mention alternatives only when they have materially different trade-offs.
126
+
127
+ ### 7) Signal the Investment
128
+
129
+ Tag the required follow-up effort using:
130
+ - Quick (<1h)
131
+ - Short (1-4h)
132
+ - Medium (1-2d)
133
+ - Large (3d+)
134
+
135
+ ## Confidence Filter
136
+
137
+ Only report findings you believe are >=80% likely to be correct.
138
+ If you are unsure, explicitly label it as "Uncertain" and explain what evidence would confirm it.
139
+
140
+ ## Output Format (Use This Exactly)
141
+
142
+ ---
143
+
144
+ **Files Reviewed:** [list]
145
+
146
+ **Plan/Task Reference:** [task name + link/path to plan section if known]
147
+
148
+ **Overall Assessment:** [APPROVE | REQUEST_CHANGES | NEEDS_DISCUSSION]
149
+
150
+ **Bottom Line:** 2-3 sentences describing whether it matches the task/plan and what must change.
151
+
152
+ ### Critical Issues
153
+ - None | [file:line] - [issue] (why it blocks approval) + (recommended fix)
154
+
155
+ ### Major Issues
156
+ - None | [file:line] - [issue] + (recommended fix)
157
+
158
+ ### Minor Issues
159
+ - None | [file:line] - [issue] + (suggested fix)
160
+
161
+ ### YAGNI / Dead Code
162
+ - None | [file:line] - [what to remove/simplify] + (why it is unnecessary)
163
+
164
+ ### Positive Observations
165
+ - [at least one concrete good thing]
166
+
167
+ ### Action Plan
168
+ 1. [highest priority change]
169
+ 2. [next]
170
+ 3. [next]
171
+
172
+ ### Effort Estimate
173
+ [Quick | Short | Medium | Large]
174
+
175
+ ---
176
+
177
+ ## Common Review Smells (Fast Scan)
178
+
179
+ Task/plan adherence:
180
+ - Adds features not mentioned in the plan/task
181
+ - Leaves TODOs as the mechanism for correctness
182
+ - Introduces new configuration modes/flags "for future"
183
+
184
+ YAGNI / dead code:
185
+ - Options/config that are parsed but not used
186
+ - Branches that do the same thing on both sides
187
+ - Comments like "reserved for future" or "we might need this"
188
+
189
+ AI slop / inconsistency:
190
+ - Commentary that restates code, narrates obvious steps, or adds process noise
191
+ - try/catch that swallows errors or returns defaults without a requirement
192
+ - `as any` used to silence type errors instead of fixing types
193
+ - New helpers/abstractions with a single call site
194
+
195
+ Correctness:
196
+ - Silent fallbacks to defaults on error when the task expects a hard failure
197
+ - Unhandled error paths, missing cleanup, missing returns
198
+
199
+ Maintainability:
200
+ - Abstractions used once
201
+ - Unclear naming, "utility" grab-bags
202
+
203
+ ## When to Escalate
204
+
205
+ Use NEEDS_DISCUSSION (instead of REQUEST_CHANGES) when:
206
+ - The plan/task is ambiguous and multiple implementations could be correct
207
+ - The change implies a product/architecture decision not documented
208
+ - Fixing issues requires changing scope, dependencies, or public API