opencode-hive 0.8.3 → 0.9.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.
package/dist/index.js CHANGED
@@ -14,7 +14,6 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
14
14
  // src/index.ts
15
15
  import * as path5 from "path";
16
16
  import * as fs6 from "fs";
17
- import { fileURLToPath } from "url";
18
17
 
19
18
  // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/classic/external.js
20
19
  var exports_external = {};
@@ -12336,6 +12335,337 @@ function tool(input) {
12336
12335
  return input;
12337
12336
  }
12338
12337
  tool.schema = exports_external;
12338
+ // src/skills/registry.generated.ts
12339
+ var BUILTIN_SKILL_NAMES = ["hive", "hive-execution"];
12340
+ var BUILTIN_SKILLS = [
12341
+ {
12342
+ name: "hive",
12343
+ description: "Plan-first AI development with isolated git worktrees and human review. Use for any feature development.",
12344
+ template: `# Hive Workflow
12345
+
12346
+ You are working in a Hive-enabled repository. Follow this plan-first workflow.
12347
+
12348
+ ## Lifecycle
12349
+
12350
+ \`\`\`
12351
+ Feature -> Plan -> Review -> Approve -> Execute -> Merge -> Complete
12352
+ \`\`\`
12353
+
12354
+ ---
12355
+
12356
+ ## Phase 1: Planning
12357
+
12358
+ ### Start Feature
12359
+
12360
+ \`\`\`
12361
+ hive_feature_create({ name: "feature-name" })
12362
+ \`\`\`
12363
+
12364
+ ### Discovery Phase (Required)
12365
+
12366
+ BEFORE writing a plan, you MUST:
12367
+ 1. Ask clarifying questions about the feature
12368
+ 2. Document Q&A in plan.md with a \`## Discovery\` section
12369
+ 3. Research the codebase (grep, read existing code)
12370
+ 4. Save findings with hive_context_write
12371
+
12372
+ Your plan MUST include a \`## Discovery\` section or hive_plan_write will be BLOCKED.
12373
+
12374
+ Example discovery section:
12375
+ \`\`\`markdown
12376
+ ## Discovery
12377
+
12378
+ **Q: What authentication system do we use?**
12379
+ A: JWT with refresh tokens, see src/auth/
12380
+
12381
+ **Q: Should this work offline?**
12382
+ A: No, online-only is fine
12383
+
12384
+ **Research:**
12385
+ - Found existing theme system in src/theme/
12386
+ - Uses CSS variables pattern
12387
+ \`\`\`
12388
+
12389
+ ### Research First
12390
+
12391
+ Before writing anything:
12392
+ 1. Search for relevant files (grep, explore)
12393
+ 2. Read existing implementations
12394
+ 3. Identify patterns and conventions
12395
+
12396
+ Save all findings:
12397
+ \`\`\`
12398
+ hive_context_write({
12399
+ name: "research",
12400
+ content: \`# Research Findings
12401
+
12402
+ ## Existing Patterns
12403
+ - Theme system uses CSS variables in src/theme/
12404
+ - Components follow atomic design
12405
+
12406
+ ## Files to Modify
12407
+ - src/theme/colors.ts
12408
+ - src/components/ThemeProvider.tsx
12409
+ \`
12410
+ })
12411
+ \`\`\`
12412
+
12413
+ ### Write the Plan
12414
+
12415
+ Your plan should include these sections:
12416
+
12417
+ | Section | Required | Purpose |
12418
+ |---------|----------|---------|
12419
+ | \`## Discovery\` | Yes (gate enforced) | Q&A and research before planning |
12420
+ | \`## Problem\` | Yes | What we're solving |
12421
+ | \`## Non-Goals\` | Recommended | What we're NOT building (scope boundaries) |
12422
+ | \`## Tasks\` | Yes | Implementation steps with \`### N. Task Name\` format |
12423
+ | \`## Ghost Diffs\` | Recommended | Rejected alternatives (prevents re-proposing) |
12424
+ | \`## Success Criteria\` | Optional | How we know we're done |
12425
+
12426
+ Format for task parsing:
12427
+
12428
+ \`\`\`markdown
12429
+ # Feature Name
12430
+
12431
+ ## Overview
12432
+ One paragraph explaining what and why.
12433
+
12434
+ ## Tasks
12435
+
12436
+ ### 1. Task Name
12437
+ Description of what this task accomplishes.
12438
+ - Specific files to modify
12439
+ - Expected outcome
12440
+
12441
+ ### 2. Another Task
12442
+ Description...
12443
+
12444
+ ### 3. Final Task
12445
+ Description...
12446
+ \`\`\`
12447
+
12448
+ Write with:
12449
+ \`\`\`
12450
+ hive_plan_write({ content: \`...\` })
12451
+ \`\`\`
12452
+
12453
+ **STOP** and tell user: "Plan written. Please review."
12454
+
12455
+ ---
12456
+
12457
+ ## Phase 2: Review (Human)
12458
+
12459
+ - User reviews plan.md in VS Code sidebar
12460
+ - User can add comments
12461
+ - Use \`hive_plan_read()\` to see user comments
12462
+ - Revise plan based on feedback
12463
+ - User clicks "Approve" or runs \`hive_plan_approve()\`
12464
+
12465
+ ---
12466
+
12467
+ ## Phase 3: Execution
12468
+
12469
+ ### Generate Tasks
12470
+
12471
+ \`\`\`
12472
+ hive_tasks_sync()
12473
+ \`\`\`
12474
+
12475
+ Parses \`### N. Task Name\` headers into task folders.
12476
+
12477
+ ### Execute Each Task
12478
+
12479
+ For each task in order:
12480
+
12481
+ #### 1. Start (creates worktree)
12482
+ \`\`\`
12483
+ hive_exec_start({ task: "01-task-name" })
12484
+ \`\`\`
12485
+
12486
+ #### 2. Implement
12487
+ Work in the isolated worktree path. Read \`spec.md\` for context.
12488
+
12489
+ #### 3. Complete (commits to branch)
12490
+ \`\`\`
12491
+ hive_exec_complete({ task: "01-task-name", summary: "What was done. Tests pass." })
12492
+ \`\`\`
12493
+
12494
+ **Note**: Summary must mention verification (tests/build) or completion will be BLOCKED.
12495
+
12496
+ #### 4. Merge (integrates to main)
12497
+ \`\`\`
12498
+ hive_merge({ task: "01-task-name", strategy: "squash" })
12499
+ \`\`\`
12500
+
12501
+ ---
12502
+
12503
+ ## Phase 4: Completion
12504
+
12505
+ After all tasks merged:
12506
+ \`\`\`
12507
+ hive_feature_complete({ name: "feature-name" })
12508
+ \`\`\`
12509
+
12510
+ ---
12511
+
12512
+ ## Tool Quick Reference
12513
+
12514
+ | Phase | Tool | Purpose |
12515
+ |-------|------|---------|
12516
+ | Plan | \`hive_feature_create\` | Start new feature |
12517
+ | Plan | \`hive_context_write\` | Save research findings |
12518
+ | Plan | \`hive_plan_write\` | Write the plan |
12519
+ | Plan | \`hive_plan_read\` | Check for user comments |
12520
+ | Plan | \`hive_plan_approve\` | Approve plan |
12521
+ | Execute | \`hive_tasks_sync\` | Generate tasks from plan |
12522
+ | Execute | \`hive_exec_start\` | Start task (creates worktree) |
12523
+ | Execute | \`hive_exec_complete\` | Finish task (commits changes) |
12524
+ | Execute | \`hive_merge\` | Integrate task to main |
12525
+ | Complete | \`hive_feature_complete\` | Mark feature done |
12526
+
12527
+ ---
12528
+
12529
+ ## Task Design Guidelines
12530
+
12531
+ ### Good Tasks
12532
+
12533
+ | Characteristic | Example |
12534
+ |---------------|---------|
12535
+ | **Atomic** | "Add ThemeContext provider" not "Add theming" |
12536
+ | **Testable** | "Toggle switches between light/dark" |
12537
+ | **Independent** | Can be completed without other tasks (where possible) |
12538
+ | **Ordered** | Dependencies come first |
12539
+
12540
+ ### Task Sizing
12541
+
12542
+ - **Too small**: "Add import statement" - combine with related work
12543
+ - **Too large**: "Implement entire feature" - break into logical units
12544
+ - **Just right**: "Create theme context with light/dark values"
12545
+
12546
+ ---
12547
+
12548
+ ## Rules
12549
+
12550
+ 1. **Never skip planning** - Always write plan first
12551
+ 2. **Context is critical** - Save all research with \`hive_context_write\`
12552
+ 3. **Wait for approval** - Don't execute until user approves
12553
+ 4. **One task at a time** - Complete and merge before starting next
12554
+ 5. **Squash merges** - Keep history clean with single commit per task
12555
+
12556
+ ---
12557
+
12558
+ ## Error Recovery
12559
+
12560
+ ### Task Failed
12561
+ \`\`\`
12562
+ hive_exec_abort(task="<task>") # Discards changes
12563
+ hive_exec_start(task="<task>") # Fresh start
12564
+ \`\`\`
12565
+
12566
+ ### Merge Conflicts
12567
+ 1. Resolve conflicts in the worktree
12568
+ 2. Commit the resolution
12569
+ 3. Run \`hive_merge\` again
12570
+
12571
+ ---
12572
+
12573
+ ## Example
12574
+
12575
+ User: "Add dark mode support"
12576
+
12577
+ \`\`\`
12578
+ 1. hive_feature_create({ name: "dark-mode" })
12579
+ 2. Research: grep for theme, colors, CSS variables
12580
+ 3. hive_context_write({ name: "research", content: "Found theme in src/theme/..." })
12581
+ 4. hive_plan_write({ content: "# Dark Mode\\n\\n## Tasks\\n\\n### 1. Add theme context..." })
12582
+ 5. Tell user: "Plan ready for review"
12583
+ 6. [User reviews and approves]
12584
+ 7. hive_tasks_sync()
12585
+ 8. For each task: exec_start -> implement -> exec_complete -> merge
12586
+ 9. hive_feature_complete({ name: "dark-mode" })
12587
+ \`\`\``
12588
+ },
12589
+ {
12590
+ name: "hive-execution",
12591
+ description: "Execute Hive feature tasks with worktree isolation, parallel orchestration, and clean git history. Use when running synced Hive tasks.",
12592
+ template: `# Hive Execution
12593
+
12594
+ Quick reference for executing Hive tasks.
12595
+
12596
+ ## Workflow Summary
12597
+
12598
+ 1. **Feature create** → Discovery guide injected
12599
+ 2. **Discovery** → Q&A documented in plan.md
12600
+ 3. **Plan write** → GATE: requires ## Discovery section
12601
+ 4. **Approval** → User reviews in VS Code
12602
+ 5. **Exec start** → Delegation guide (Master), TDD+debugging (Worker)
12603
+ 6. **Complete** → GATE: requires verification mention
12604
+ 7. **Merge** → Squash into feature branch
12605
+
12606
+ ## Gates
12607
+
12608
+ | Tool | Gate | Error |
12609
+ |------|------|-------|
12610
+ | hive_plan_write | ## Discovery section | "BLOCKED: Discovery required" |
12611
+ | hive_exec_complete | Verification in summary | "BLOCKED: No verification" |
12612
+
12613
+ ## Task Lifecycle
12614
+
12615
+ \`\`\`
12616
+ hive_exec_start(task) # Creates worktree
12617
+
12618
+ [implement in worktree]
12619
+
12620
+ hive_exec_complete(task, summary) # Commits to branch
12621
+
12622
+ hive_merge(task, strategy: "squash") # Integrates to main
12623
+ \`\`\`
12624
+
12625
+ ## Quick Reference
12626
+
12627
+ | Tool | Purpose |
12628
+ |------|---------|
12629
+ | hive_status | Check overall progress |
12630
+ | hive_worker_status | Check delegated workers |
12631
+ | hive_exec_abort | Discard changes, restart |
12632
+ | hive_merge | Integrate completed task |
12633
+ | hive_worktree_list | See active worktrees |
12634
+
12635
+ ## Error Recovery
12636
+
12637
+ ### Task Failed
12638
+ \`\`\`
12639
+ hive_exec_abort(task) # Discards changes
12640
+ hive_exec_start(task) # Fresh start
12641
+ \`\`\`
12642
+
12643
+ ### Merge Conflicts
12644
+ 1. Resolve conflicts in worktree
12645
+ 2. Commit resolution
12646
+ 3. Run hive_merge again`
12647
+ }
12648
+ ];
12649
+
12650
+ // src/skills/builtin.ts
12651
+ function loadBuiltinSkill(name) {
12652
+ const skill = BUILTIN_SKILLS.find((s) => s.name === name);
12653
+ if (!skill) {
12654
+ return {
12655
+ found: false,
12656
+ error: `Unknown builtin skill: ${name}. Available: ${BUILTIN_SKILL_NAMES.join(", ")}`
12657
+ };
12658
+ }
12659
+ return {
12660
+ found: true,
12661
+ skill,
12662
+ source: "builtin"
12663
+ };
12664
+ }
12665
+ function getBuiltinSkills() {
12666
+ return BUILTIN_SKILLS;
12667
+ }
12668
+
12339
12669
  // ../hive-core/dist/index.js
12340
12670
  import { createRequire as createRequire2 } from "node:module";
12341
12671
  import * as path from "path";
@@ -12353,6 +12683,8 @@ import { normalize } from "node:path";
12353
12683
  import { EventEmitter } from "node:events";
12354
12684
  import * as fs8 from "fs";
12355
12685
  import * as path4 from "path";
12686
+ import * as fs10 from "fs";
12687
+ import * as path6 from "path";
12356
12688
  var __create = Object.create;
12357
12689
  var __getProtoOf = Object.getPrototypeOf;
12358
12690
  var __defProp2 = Object.defineProperty;
@@ -13176,6 +13508,17 @@ var require_dist2 = __commonJS((exports) => {
13176
13508
  exports.createDeferred = deferred;
13177
13509
  exports.default = deferred;
13178
13510
  });
13511
+ var DEFAULT_HIVE_CONFIG = {
13512
+ enableToolsFor: [],
13513
+ agents: {
13514
+ worker: {
13515
+ visible: true
13516
+ }
13517
+ },
13518
+ omoSlim: {
13519
+ enabled: false
13520
+ }
13521
+ };
13179
13522
  var HIVE_DIR = ".hive";
13180
13523
  var FEATURES_DIR = "features";
13181
13524
  var TASKS_DIR = "tasks";
@@ -13186,9 +13529,13 @@ var FEATURE_FILE = "feature.json";
13186
13529
  var STATUS_FILE = "status.json";
13187
13530
  var REPORT_FILE = "report.md";
13188
13531
  var APPROVED_FILE = "APPROVED";
13532
+ var JOURNAL_FILE = "journal.md";
13189
13533
  function getHivePath(projectRoot) {
13190
13534
  return path.join(projectRoot, HIVE_DIR);
13191
13535
  }
13536
+ function getJournalPath(projectRoot) {
13537
+ return path.join(getHivePath(projectRoot), JOURNAL_FILE);
13538
+ }
13192
13539
  function getFeaturesPath(projectRoot) {
13193
13540
  return path.join(getHivePath(projectRoot), FEATURES_DIR);
13194
13541
  }
@@ -13318,6 +13665,22 @@ function listFeatures(projectRoot) {
13318
13665
  return [];
13319
13666
  return fs2.readdirSync(featuresPath, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
13320
13667
  }
13668
+ var JOURNAL_TEMPLATE = `# Hive Journal
13669
+
13670
+ Audit trail of project learnings. Updated when trouble is resolved.
13671
+
13672
+ ---
13673
+
13674
+ <!-- Entry template:
13675
+ ### YYYY-MM-DD: feature-name
13676
+
13677
+ **Trouble**: What went wrong
13678
+ **Resolution**: How it was fixed
13679
+ **Constraint**: Never/Always rule derived (add to Iron Laws if recurring)
13680
+ **See**: .hive/features/feature-name/plan.md
13681
+ -->
13682
+ `;
13683
+
13321
13684
  class FeatureService {
13322
13685
  projectRoot;
13323
13686
  constructor(projectRoot) {
@@ -13331,6 +13694,10 @@ class FeatureService {
13331
13694
  ensureDir(featurePath);
13332
13695
  ensureDir(getContextPath(this.projectRoot, name));
13333
13696
  ensureDir(getTasksPath(this.projectRoot, name));
13697
+ const journalPath = getJournalPath(this.projectRoot);
13698
+ if (!fileExists(journalPath)) {
13699
+ fs3.writeFileSync(journalPath, JOURNAL_TEMPLATE);
13700
+ }
13334
13701
  const feature = {
13335
13702
  name,
13336
13703
  status: "planning",
@@ -18384,16 +18751,83 @@ ${f.content}`);
18384
18751
  return `${normalized}.md`;
18385
18752
  }
18386
18753
  }
18754
+ class ConfigService {
18755
+ configPath;
18756
+ constructor() {
18757
+ const homeDir = process.env.HOME || process.env.USERPROFILE || "";
18758
+ const configDir = path6.join(homeDir, ".config", "opencode");
18759
+ this.configPath = path6.join(configDir, "agent_hive.json");
18760
+ }
18761
+ getPath() {
18762
+ return this.configPath;
18763
+ }
18764
+ get() {
18765
+ try {
18766
+ if (!fs10.existsSync(this.configPath)) {
18767
+ return { ...DEFAULT_HIVE_CONFIG };
18768
+ }
18769
+ const raw = fs10.readFileSync(this.configPath, "utf-8");
18770
+ const stored = JSON.parse(raw);
18771
+ return {
18772
+ ...DEFAULT_HIVE_CONFIG,
18773
+ ...stored,
18774
+ agents: {
18775
+ ...DEFAULT_HIVE_CONFIG.agents,
18776
+ ...stored.agents
18777
+ },
18778
+ omoSlim: {
18779
+ ...DEFAULT_HIVE_CONFIG.omoSlim,
18780
+ ...stored.omoSlim
18781
+ }
18782
+ };
18783
+ } catch {
18784
+ return { ...DEFAULT_HIVE_CONFIG };
18785
+ }
18786
+ }
18787
+ set(updates) {
18788
+ const current = this.get();
18789
+ const merged = {
18790
+ ...current,
18791
+ ...updates,
18792
+ agents: updates.agents ? {
18793
+ ...current.agents,
18794
+ ...updates.agents
18795
+ } : current.agents,
18796
+ omoSlim: updates.omoSlim ? {
18797
+ ...current.omoSlim,
18798
+ ...updates.omoSlim
18799
+ } : current.omoSlim
18800
+ };
18801
+ const configDir = path6.dirname(this.configPath);
18802
+ if (!fs10.existsSync(configDir)) {
18803
+ fs10.mkdirSync(configDir, { recursive: true });
18804
+ }
18805
+ fs10.writeFileSync(this.configPath, JSON.stringify(merged, null, 2));
18806
+ return merged;
18807
+ }
18808
+ exists() {
18809
+ return fs10.existsSync(this.configPath);
18810
+ }
18811
+ init() {
18812
+ if (!this.exists()) {
18813
+ return this.set(DEFAULT_HIVE_CONFIG);
18814
+ }
18815
+ return this.get();
18816
+ }
18817
+ isOmoSlimEnabled() {
18818
+ return this.get().omoSlim?.enabled ?? false;
18819
+ }
18820
+ setOmoSlim(enabled) {
18821
+ return this.set({ omoSlim: { enabled } });
18822
+ }
18823
+ }
18387
18824
 
18388
18825
  // src/utils/agent-selector.ts
18389
18826
  var AGENT_PATTERNS = [
18390
- { pattern: /\b(find|search|locate|where|grep|explore|scan)\b/i, agent: "explore" },
18391
- { pattern: /\b(research|investigate|learn|understand|docs?|documentation|library|api)\b/i, agent: "librarian" },
18392
- { pattern: /\b(ui|ux|component|frontend|react|vue|svelte|css|style|layout|design|button|form|modal)\b/i, agent: "frontend-ui-ux-engineer" },
18393
- { pattern: /\b(refactor|simplify|clean|reduce|complexity|review|optimize)\b/i, agent: "code-simplicity-reviewer" },
18394
- { pattern: /\b(readme|document|explain|write.*doc|comment|jsdoc|tsdoc)\b/i, agent: "document-writer" },
18395
- { pattern: /\b(image|screenshot|visual|diagram|mockup|pdf|picture|photo)\b/i, agent: "multimodal-looker" },
18396
- { pattern: /\b(architect|design.*decision|tradeoff|approach|strategy|choose|decide|compare)\b/i, agent: "oracle" }
18827
+ { pattern: /\b(find|search|locate|where|grep|explore|scan|codebase)\b/i, agent: "explorer" },
18828
+ { pattern: /\b(research|investigate|learn|docs?|documentation|library|api|external|github)\b/i, agent: "librarian" },
18829
+ { pattern: /\b(ui|ux|component|frontend|react|vue|svelte|css|style|layout|design|button|form|modal|visual|responsive)\b/i, agent: "designer" },
18830
+ { pattern: /\b(architect|decision|tradeoff|approach|strategy|choose|decide|compare|review|debug|complex)\b/i, agent: "oracle" }
18397
18831
  ];
18398
18832
  function selectAgent(taskName, spec) {
18399
18833
  const content = `${taskName} ${spec}`.toLowerCase();
@@ -18402,7 +18836,7 @@ function selectAgent(taskName, spec) {
18402
18836
  return agent;
18403
18837
  }
18404
18838
  }
18405
- return "general";
18839
+ return "fixer";
18406
18840
  }
18407
18841
 
18408
18842
  // src/utils/worker-prompt.ts
@@ -18493,6 +18927,7 @@ Instead, escalate via the blocker protocol:
18493
18927
  \`\`\`
18494
18928
  hive_exec_complete({
18495
18929
  task: "${task}",
18930
+ feature: "${feature}",
18496
18931
  status: "blocked",
18497
18932
  summary: "What you accomplished so far",
18498
18933
  blocker: {
@@ -18504,6 +18939,8 @@ hive_exec_complete({
18504
18939
  })
18505
18940
  \`\`\`
18506
18941
 
18942
+ **After calling hive_exec_complete with blocked status, STOP IMMEDIATELY.**
18943
+
18507
18944
  The Hive Master will:
18508
18945
  1. Receive your blocker info
18509
18946
  2. Ask the user via question()
@@ -18520,16 +18957,22 @@ When your task is **fully complete**:
18520
18957
  \`\`\`
18521
18958
  hive_exec_complete({
18522
18959
  task: "${task}",
18960
+ feature: "${feature}",
18523
18961
  status: "completed",
18524
18962
  summary: "Concise summary of what you accomplished"
18525
18963
  })
18526
18964
  \`\`\`
18527
18965
 
18966
+ **CRITICAL: After calling hive_exec_complete, you MUST STOP IMMEDIATELY.**
18967
+ Do NOT continue working. Do NOT respond further. Your session is DONE.
18968
+ The Hive Master will take over from here.
18969
+
18528
18970
  If you encounter an **unrecoverable error**:
18529
18971
 
18530
18972
  \`\`\`
18531
18973
  hive_exec_complete({
18532
18974
  task: "${task}",
18975
+ feature: "${feature}",
18533
18976
  status: "failed",
18534
18977
  summary: "What went wrong and what was attempted"
18535
18978
  })
@@ -18540,6 +18983,7 @@ If you made **partial progress** but can't continue:
18540
18983
  \`\`\`
18541
18984
  hive_exec_complete({
18542
18985
  task: "${task}",
18986
+ feature: "${feature}",
18543
18987
  status: "partial",
18544
18988
  summary: "What was completed and what remains"
18545
18989
  })
@@ -18547,6 +18991,26 @@ hive_exec_complete({
18547
18991
 
18548
18992
  ---
18549
18993
 
18994
+ ## TDD Protocol (Required)
18995
+
18996
+ 1. **Red**: Write failing test first
18997
+ 2. **Green**: Minimal code to pass
18998
+ 3. **Refactor**: Clean up, keep tests green
18999
+
19000
+ Never write implementation before test exists.
19001
+ Exception: Pure refactoring of existing tested code.
19002
+
19003
+ ## Debugging Protocol (When stuck)
19004
+
19005
+ 1. **Reproduce**: Get consistent failure
19006
+ 2. **Isolate**: Binary search to find cause
19007
+ 3. **Hypothesize**: Form theory, test it
19008
+ 4. **Fix**: Minimal change that resolves
19009
+
19010
+ After 3 failed attempts at same fix: STOP and report blocker.
19011
+
19012
+ ---
19013
+
18550
19014
  ## Tool Access
18551
19015
 
18552
19016
  **You have access to:**
@@ -18656,6 +19120,22 @@ When a worker returns status: 'blocked':
18656
19120
 
18657
19121
  This keeps the user focused on ONE conversation (you) instead of multiple worker panes.
18658
19122
 
19123
+ ## Iron Laws
19124
+
19125
+ ### Never
19126
+ - Plan without asking questions first (discovery required)
19127
+ - Code without failing test first
19128
+ - Complete without running verification
19129
+ - Assume when uncertain - ASK
19130
+ - Put raw data in Master context - DELEGATE
19131
+ - Attempt same fix more than 3 times
19132
+
19133
+ ### Always
19134
+ - One question at a time (discovery)
19135
+ - Test -> Code -> Verify (TDD)
19136
+ - Delegate data queries to subagents
19137
+ - Stop and ask when blocked
19138
+
18659
19139
  ## Communication Style
18660
19140
 
18661
19141
  - Be concise, no preamble
@@ -18683,7 +19163,7 @@ Workers spawn in tmux panes with specialized agents:
18683
19163
  - **librarian** - External docs and library research
18684
19164
  - **oracle** - Architecture decisions and guidance
18685
19165
  - **designer** - UI/UX implementation
18686
- - **general** - Default implementation
19166
+ - **fixer** - Default implementation (code changes)
18687
19167
 
18688
19168
  Agent is auto-selected based on task content.
18689
19169
  Watch workers in tmux panes for real-time progress.
@@ -18700,57 +19180,8 @@ function buildHiveAgentPrompt(featureContext, omoSlimDetected) {
18700
19180
  }
18701
19181
 
18702
19182
  // src/index.ts
18703
- function parseFrontmatter(content) {
18704
- const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
18705
- if (!match) {
18706
- return { meta: {}, body: content.trim() };
18707
- }
18708
- const meta = {};
18709
- const frontmatter = match[1];
18710
- const body = match[2];
18711
- for (const line of frontmatter.split(`
18712
- `)) {
18713
- const colonIdx = line.indexOf(":");
18714
- if (colonIdx > 0) {
18715
- const key = line.slice(0, colonIdx).trim();
18716
- const value = line.slice(colonIdx + 1).trim();
18717
- meta[key] = value;
18718
- }
18719
- }
18720
- return { meta, body: body.trim() };
18721
- }
18722
- function getSkillsDir() {
18723
- const filename = fileURLToPath(import.meta.url);
18724
- const dirname5 = path5.dirname(filename);
18725
- return path5.join(dirname5, "..", "skills");
18726
- }
18727
- function discoverHiveSkills() {
18728
- const skillsDir = getSkillsDir();
18729
- const skills = [];
18730
- if (!fs6.existsSync(skillsDir)) {
18731
- return skills;
18732
- }
18733
- const entries = fs6.readdirSync(skillsDir, { withFileTypes: true });
18734
- for (const entry of entries) {
18735
- if (!entry.isDirectory())
18736
- continue;
18737
- const skillPath = path5.join(skillsDir, entry.name, "SKILL.md");
18738
- if (!fs6.existsSync(skillPath))
18739
- continue;
18740
- try {
18741
- const content = fs6.readFileSync(skillPath, "utf-8");
18742
- const { meta, body } = parseFrontmatter(content);
18743
- skills.push({
18744
- name: meta.name || entry.name,
18745
- description: meta.description || "",
18746
- path: skillPath,
18747
- body
18748
- });
18749
- } catch {}
18750
- }
18751
- return skills;
18752
- }
18753
- function formatSkillsXml(skills) {
19183
+ function formatSkillsXml() {
19184
+ const skills = getBuiltinSkills();
18754
19185
  if (skills.length === 0)
18755
19186
  return "";
18756
19187
  const skillsXml = skills.map((skill) => {
@@ -18770,49 +19201,29 @@ ${skillsXml}
18770
19201
  </available_skills>`;
18771
19202
  }
18772
19203
  function createHiveSkillTool() {
18773
- let cachedSkills = null;
18774
- let cachedDescription = null;
18775
- const getSkills = () => {
18776
- if (cachedSkills)
18777
- return cachedSkills;
18778
- cachedSkills = discoverHiveSkills();
18779
- return cachedSkills;
18780
- };
18781
- const getDescription = () => {
18782
- if (cachedDescription)
18783
- return cachedDescription;
18784
- const skills = getSkills();
18785
- const base = "Load a Hive skill to get detailed instructions for a specific workflow.";
18786
- if (skills.length === 0) {
18787
- cachedDescription = base + `
18788
-
18789
- No Hive skills available.`;
18790
- } else {
18791
- cachedDescription = base + formatSkillsXml(skills);
18792
- }
18793
- return cachedDescription;
18794
- };
18795
- getDescription();
19204
+ const base = "Load a Hive skill to get detailed instructions for a specific workflow.";
19205
+ const skills = getBuiltinSkills();
19206
+ const description = skills.length === 0 ? base + `
19207
+
19208
+ No Hive skills available.` : base + formatSkillsXml();
18796
19209
  return tool({
18797
- get description() {
18798
- return cachedDescription ?? "Load a Hive skill to get detailed instructions for a specific workflow.";
18799
- },
19210
+ description,
18800
19211
  args: {
18801
19212
  name: tool.schema.string().describe("The skill name from available_skills")
18802
19213
  },
18803
19214
  async execute({ name }) {
18804
- const skills = getSkills();
18805
- const skill = skills.find((s) => s.name === name);
18806
- if (!skill) {
19215
+ const result = loadBuiltinSkill(name);
19216
+ if (!result.found || !result.skill) {
18807
19217
  const available = skills.map((s) => s.name).join(", ");
18808
19218
  throw new Error(`Skill "${name}" not found. Available Hive skills: ${available || "none"}`);
18809
19219
  }
19220
+ const skill = result.skill;
18810
19221
  return [
18811
19222
  `## Hive Skill: ${skill.name}`,
18812
19223
  "",
18813
19224
  `**Description**: ${skill.description}`,
18814
19225
  "",
18815
- skill.body
19226
+ skill.template
18816
19227
  ].join(`
18817
19228
  `);
18818
19229
  }
@@ -18897,29 +19308,18 @@ During execution, call \`hive_status\` periodically to:
18897
19308
  - Get reminded of next actions
18898
19309
  `;
18899
19310
  var plugin = async (ctx) => {
18900
- const { directory } = ctx;
19311
+ const { directory, client } = ctx;
18901
19312
  const featureService = new FeatureService(directory);
18902
19313
  const planService = new PlanService(directory);
18903
19314
  const taskService = new TaskService(directory);
18904
19315
  const contextService = new ContextService(directory);
19316
+ const configService = new ConfigService;
18905
19317
  const worktreeService = new WorktreeService({
18906
19318
  baseDir: directory,
18907
19319
  hiveDir: path5.join(directory, ".hive")
18908
19320
  });
18909
- let omoSlimDetected = false;
18910
- let detectionDone = false;
18911
- const detectOmoSlim = (toolContext) => {
18912
- if (detectionDone)
18913
- return omoSlimDetected;
18914
- const ctx2 = toolContext;
18915
- if (ctx2?.tools?.includes?.("background_task") || ctx2?.background_task || typeof ctx2?.callTool === "function") {
18916
- omoSlimDetected = true;
18917
- }
18918
- detectionDone = true;
18919
- if (omoSlimDetected) {
18920
- console.log("[Hive] OMO-Slim detected: delegated execution with tmux panes enabled");
18921
- }
18922
- return omoSlimDetected;
19321
+ const isOmoSlimEnabled = () => {
19322
+ return configService.isOmoSlimEnabled();
18923
19323
  };
18924
19324
  const resolveFeature = (explicit) => {
18925
19325
  if (explicit)
@@ -18987,7 +19387,40 @@ To unblock: Remove .hive/features/${feature}/BLOCKED`;
18987
19387
  },
18988
19388
  async execute({ name, ticket }) {
18989
19389
  const feature = featureService.create(name, ticket);
18990
- return `Feature "${name}" created. Status: ${feature.status}. Write a plan with hive_plan_write.`;
19390
+ return `Feature "${name}" created.
19391
+
19392
+ ## Discovery Phase Required
19393
+
19394
+ Before writing a plan, you MUST:
19395
+ 1. Ask clarifying questions about the feature
19396
+ 2. Document Q&A in plan.md with a \`## Discovery\` section
19397
+ 3. Research the codebase (grep, read existing code)
19398
+ 4. Save findings with hive_context_write
19399
+
19400
+ Example discovery section:
19401
+ \`\`\`markdown
19402
+ ## Discovery
19403
+
19404
+ **Q: What authentication system do we use?**
19405
+ A: JWT with refresh tokens, see src/auth/
19406
+
19407
+ **Q: Should this work offline?**
19408
+ A: No, online-only is fine
19409
+
19410
+ **Research:**
19411
+ - Found existing theme system in src/theme/
19412
+ - Uses CSS variables pattern
19413
+ \`\`\`
19414
+
19415
+ ## Planning Guidelines
19416
+
19417
+ When writing your plan, include:
19418
+ - \`## Non-Goals\` - What we're explicitly NOT building (scope boundaries)
19419
+ - \`## Ghost Diffs\` - Alternatives you considered but rejected
19420
+
19421
+ These prevent scope creep and re-proposing rejected solutions.
19422
+
19423
+ NEXT: Ask your first clarifying question about this feature.`;
18991
19424
  }
18992
19425
  }),
18993
19426
  hive_feature_list: tool({
@@ -19017,6 +19450,34 @@ To unblock: Remove .hive/features/${feature}/BLOCKED`;
19017
19450
  return `Feature "${feature}" marked as completed`;
19018
19451
  }
19019
19452
  }),
19453
+ hive_journal_append: tool({
19454
+ description: "Append entry to .hive/journal.md for audit trail",
19455
+ args: {
19456
+ feature: tool.schema.string().describe("Feature name for context"),
19457
+ trouble: tool.schema.string().describe("What went wrong"),
19458
+ resolution: tool.schema.string().describe("How it was fixed"),
19459
+ constraint: tool.schema.string().optional().describe("Never/Always rule derived")
19460
+ },
19461
+ async execute({ feature, trouble, resolution, constraint }) {
19462
+ const journalPath = path5.join(directory, ".hive", "journal.md");
19463
+ if (!fs6.existsSync(journalPath)) {
19464
+ return `Error: journal.md not found. Create a feature first to initialize the journal.`;
19465
+ }
19466
+ const date5 = new Date().toISOString().split("T")[0];
19467
+ const entry = `
19468
+ ### ${date5}: ${feature}
19469
+
19470
+ **Trouble**: ${trouble}
19471
+ **Resolution**: ${resolution}
19472
+ ${constraint ? `**Constraint**: ${constraint}` : ""}
19473
+ **See**: .hive/features/${feature}/plan.md
19474
+
19475
+ ---
19476
+ `;
19477
+ fs6.appendFileSync(journalPath, entry);
19478
+ return `Journal entry added for ${feature}. ${constraint ? `Constraint: "${constraint}"` : ""}`;
19479
+ }
19480
+ }),
19020
19481
  hive_plan_write: tool({
19021
19482
  description: "Write plan.md (clears existing comments)",
19022
19483
  args: {
@@ -19027,6 +19488,17 @@ To unblock: Remove .hive/features/${feature}/BLOCKED`;
19027
19488
  const feature = resolveFeature(explicitFeature);
19028
19489
  if (!feature)
19029
19490
  return "Error: No feature specified. Create a feature or provide feature param.";
19491
+ const hasDiscovery = content.toLowerCase().includes("## discovery");
19492
+ if (!hasDiscovery) {
19493
+ return `BLOCKED: Discovery section required before planning.
19494
+
19495
+ Your plan must include a \`## Discovery\` section documenting:
19496
+ - Questions you asked and answers received
19497
+ - Research findings from codebase exploration
19498
+ - Key decisions made
19499
+
19500
+ Add this section to your plan content and try again.`;
19501
+ }
19030
19502
  captureSession(feature, toolContext);
19031
19503
  const planPath = planService.write(feature, content);
19032
19504
  return `Plan written to ${planPath}. Comments cleared for fresh review.`;
@@ -19192,8 +19664,7 @@ ${priorTasks.join(`
19192
19664
  `;
19193
19665
  }
19194
19666
  taskService.writeSpec(feature, task, specContent);
19195
- detectOmoSlim(toolContext);
19196
- if (omoSlimDetected) {
19667
+ if (isOmoSlimEnabled()) {
19197
19668
  const contextFiles = [];
19198
19669
  const contextDir = path5.join(directory, ".hive", "features", feature, "context");
19199
19670
  if (fs6.existsSync(contextDir)) {
@@ -19221,33 +19692,39 @@ ${priorTasks.join(`
19221
19692
  } : undefined
19222
19693
  });
19223
19694
  const agent = selectAgent(taskInfo.name, specContent);
19224
- try {
19225
- const ctx2 = toolContext;
19226
- if (ctx2.callTool) {
19227
- const result = await ctx2.callTool("background_task", {
19228
- agent,
19229
- prompt: workerPrompt,
19230
- description: `Hive: ${task}`,
19231
- sync: false
19232
- });
19233
- taskService.update(feature, task, {
19234
- status: "in_progress",
19235
- workerId: result?.task_id,
19236
- agent,
19237
- mode: "omo-slim"
19238
- });
19239
- return JSON.stringify({
19240
- worktreePath: worktree.path,
19241
- branch: worktree.branch,
19242
- mode: "delegated",
19243
- agent,
19244
- taskId: result?.task_id,
19245
- message: `Worker spawned via OMO-Slim (${agent} agent). Watch in tmux pane. Use hive_worker_status to check progress.`
19246
- }, null, 2);
19247
- }
19248
- } catch (e) {
19249
- console.log("[Hive] OMO-Slim delegation failed, falling back to inline:", e.message);
19250
- }
19695
+ return JSON.stringify({
19696
+ worktreePath: worktree.path,
19697
+ branch: worktree.branch,
19698
+ mode: "delegate",
19699
+ agent,
19700
+ delegationRequired: true,
19701
+ backgroundTaskCall: {
19702
+ agent,
19703
+ prompt: workerPrompt,
19704
+ description: `Hive: ${task}`,
19705
+ sync: false
19706
+ },
19707
+ instructions: `## Delegation Required
19708
+
19709
+ You MUST now call background_task to spawn a worker:
19710
+
19711
+ \`\`\`
19712
+ background_task({
19713
+ agent: "${agent}",
19714
+ prompt: <the workerPrompt below>,
19715
+ description: "Hive: ${task}",
19716
+ sync: false
19717
+ })
19718
+ \`\`\`
19719
+
19720
+ After spawning:
19721
+ - Monitor with hive_worker_status
19722
+ - Handle blockers when worker exits
19723
+ - Merge completed work with hive_merge
19724
+
19725
+ DO NOT do the work yourself. Delegate it.`,
19726
+ workerPrompt
19727
+ }, null, 2);
19251
19728
  }
19252
19729
  return `Worktree created at ${worktree.path}
19253
19730
  Branch: ${worktree.branch}
@@ -19279,6 +19756,23 @@ Reminder: do all work inside this worktree and ensure any subagents do the same.
19279
19756
  return `Error: Task "${task}" not found`;
19280
19757
  if (taskInfo.status !== "in_progress" && taskInfo.status !== "blocked")
19281
19758
  return "Error: Task not in progress";
19759
+ if (status === "completed") {
19760
+ const verificationKeywords = ["test", "build", "lint", "vitest", "jest", "npm run", "pnpm", "cargo", "pytest", "verified", "passes", "succeeds"];
19761
+ const summaryLower = summary.toLowerCase();
19762
+ const hasVerificationMention = verificationKeywords.some((kw) => summaryLower.includes(kw));
19763
+ if (!hasVerificationMention) {
19764
+ return `BLOCKED: No verification detected in summary.
19765
+
19766
+ Before claiming completion, you must:
19767
+ 1. Run tests (vitest, jest, pytest, etc.)
19768
+ 2. Run build (npm run build, cargo build, etc.)
19769
+ 3. Include verification results in summary
19770
+
19771
+ Example summary: "Implemented auth flow. Tests pass (vitest). Build succeeds."
19772
+
19773
+ Re-run with updated summary showing verification results.`;
19774
+ }
19775
+ }
19282
19776
  if (status === "blocked") {
19283
19777
  taskService.update(feature, task, {
19284
19778
  status: "blocked",
@@ -19385,9 +19879,10 @@ Use hive_merge to integrate changes. Worktree preserved at ${worktree?.path || "
19385
19879
  summary: t.summary || null
19386
19880
  };
19387
19881
  }));
19882
+ const omoSlimEnabled = isOmoSlimEnabled();
19388
19883
  return JSON.stringify({
19389
19884
  feature,
19390
- omoSlimDetected,
19885
+ omoSlimEnabled,
19391
19886
  workers,
19392
19887
  hint: workers.some((w) => w.status === "blocked") ? 'Use hive_exec_start(task, continueFrom: "blocked", decision: answer) to resume blocked workers' : workers.some((w) => w.maybeStuck) ? "Some workers may be stuck. Check tmux panes or abort with hive_exec_abort." : "Workers in progress. Watch tmux panes for live updates."
19393
19888
  }, null, 2);
@@ -19673,8 +20168,8 @@ Make the requested changes, then call hive_request_review again.`;
19673
20168
  break;
19674
20169
  }
19675
20170
  }
19676
- if (featureContext || omoSlimDetected) {
19677
- return buildHiveAgentPrompt(featureContext, omoSlimDetected);
20171
+ if (featureContext || isOmoSlimEnabled()) {
20172
+ return buildHiveAgentPrompt(featureContext, isOmoSlimEnabled());
19678
20173
  }
19679
20174
  return existingPrompt;
19680
20175
  },