opencode-hive 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,18 +1,22 @@
1
1
  import { createRequire } from "node:module";
2
2
  var __defProp = Object.defineProperty;
3
+ var __returnValue = (v) => v;
4
+ function __exportSetter(name, newValue) {
5
+ this[name] = __returnValue.bind(null, newValue);
6
+ }
3
7
  var __export = (target, all) => {
4
8
  for (var name in all)
5
9
  __defProp(target, name, {
6
10
  get: all[name],
7
11
  enumerable: true,
8
12
  configurable: true,
9
- set: (newValue) => all[name] = () => newValue
13
+ set: __exportSetter.bind(all, name)
10
14
  });
11
15
  };
12
16
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
13
17
 
14
18
  // src/index.ts
15
- import * as path7 from "path";
19
+ import * as path8 from "path";
16
20
  import * as os from "os";
17
21
 
18
22
  // ../../node_modules/zod/v4/classic/external.js
@@ -12336,8 +12340,260 @@ function tool(input) {
12336
12340
  }
12337
12341
  tool.schema = exports_external;
12338
12342
  // src/skills/registry.generated.ts
12339
- 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"];
12343
+ var BUILTIN_SKILL_NAMES = ["agents-md-mastery", "brainstorming", "code-reviewer", "dispatching-parallel-agents", "docker-mastery", "executing-plans", "parallel-exploration", "systematic-debugging", "test-driven-development", "verification-before-completion", "writing-plans"];
12340
12344
  var BUILTIN_SKILLS = [
12345
+ {
12346
+ name: "agents-md-mastery",
12347
+ description: "Use when bootstrapping, updating, or reviewing AGENTS.md — teaches what makes effective agent memory, how to structure sections, signal vs noise filtering, and when to prune stale entries",
12348
+ template: `# AGENTS.md Mastery
12349
+
12350
+ ## Overview
12351
+
12352
+ **AGENTS.md is pseudo-memory loaded at session start.** Every line shapes agent behavior for the entire session. Quality beats quantity. Write for agents, not humans.
12353
+
12354
+ Unlike code comments or READMEs, AGENTS.md entries persist across all agent sessions. A bad entry misleads agents hundreds of times. A missing entry causes the same mistake repeatedly.
12355
+
12356
+ **Core principle:** Optimize for agent comprehension and behavioral change, not human readability.
12357
+
12358
+ ## The Iron Law
12359
+
12360
+ \`\`\`
12361
+ EVERY ENTRY MUST CHANGE AGENT BEHAVIOR
12362
+ \`\`\`
12363
+
12364
+ If an entry doesn't:
12365
+ - Prevent a specific mistake
12366
+ - Enable a capability the agent would otherwise miss
12367
+ - Override a default assumption that breaks in this codebase
12368
+
12369
+ ...then it doesn't belong in AGENTS.md.
12370
+
12371
+ **Test:** Would a fresh agent session make a mistake without this entry? If no → noise.
12372
+
12373
+ ## When to Use
12374
+
12375
+ | Trigger | Action |
12376
+ |---------|--------|
12377
+ | New project bootstrap | Write initial AGENTS.md with build/test/style basics |
12378
+ | Feature completion | Sync new learnings via \`hive_agents_md\` tool |
12379
+ | Periodic review | Audit for stale/redundant entries (quarterly) |
12380
+ | Quality issues | Agent repeating mistakes? Check if AGENTS.md has the fix |
12381
+
12382
+ ## What Makes Good Agent Memory
12383
+
12384
+ ### Signal Entries (Keep)
12385
+
12386
+ ✅ **Project-specific conventions:**
12387
+ - "We use Zustand, not Redux — never add Redux"
12388
+ - "Auth lives in \`/lib/auth\` — never create auth elsewhere"
12389
+ - "Run \`bun test\` not \`npm test\` (we don't use npm)"
12390
+
12391
+ ✅ **Non-obvious patterns:**
12392
+ - "Use \`.js\` extension for local imports (ESM requirement)"
12393
+ - "Worktrees don't share \`node_modules\` — run \`bun install\` in each"
12394
+ - "SandboxConfig is in \`dockerSandboxService.ts\`, NOT \`types.ts\`"
12395
+
12396
+ ✅ **Gotchas that break builds:**
12397
+ - "Never use \`ensureDirSync\` — doesn't exist. Use \`ensureDir\` (sync despite name)"
12398
+ - "Import from \`../utils/paths.js\` not \`./paths\` (ESM strict)"
12399
+
12400
+ ### Noise Entries (Remove)
12401
+
12402
+ ❌ **Agent already knows:**
12403
+ - "This project uses TypeScript" (agent detects from files)
12404
+ - "We follow semantic versioning" (universal convention)
12405
+ - "Use descriptive variable names" (generic advice)
12406
+
12407
+ ❌ **Irrelevant metadata:**
12408
+ - "Created on January 2024"
12409
+ - "Originally written by X"
12410
+ - "License: MIT" (in LICENSE file already)
12411
+
12412
+ ❌ **Describes what code does:**
12413
+ - "FeatureService manages features" (agent can read code)
12414
+ - "The system uses git worktrees" (observable from commands)
12415
+
12416
+ ### Rule of Thumb
12417
+
12418
+ **Signal:** Changes how agent acts
12419
+ **Noise:** Documents what agent observes
12420
+
12421
+ ## Section Structure for Fast Comprehension
12422
+
12423
+ Agents read AGENTS.md top-to-bottom once at session start. Put high-value info first:
12424
+
12425
+ \`\`\`markdown
12426
+ # Project Name
12427
+
12428
+ ## Build & Test Commands
12429
+ # ← Agents need this IMMEDIATELY
12430
+ bun run build
12431
+ bun run test
12432
+ bun run release:check
12433
+
12434
+ ## Code Style
12435
+ # ← Prevents syntax/import errors
12436
+ - Semicolons: Yes
12437
+ - Quotes: Single
12438
+ - Imports: Use \`.js\` extension
12439
+
12440
+ ## Architecture
12441
+ # ← Key directories, where things live
12442
+ packages/
12443
+ ├── hive-core/ # Shared logic
12444
+ ├── opencode-hive/ # Plugin
12445
+ └── vscode-hive/ # Extension
12446
+
12447
+ ## Important Patterns
12448
+ # ← How to do common tasks correctly
12449
+ Use \`readText\` from paths.ts, not fs.readFileSync
12450
+
12451
+ ## Gotchas & Anti-Patterns
12452
+ # ← Things that break or mislead
12453
+ NEVER use \`ensureDirSync\` — doesn't exist
12454
+ \`\`\`
12455
+
12456
+ **Keep total under 500 lines.** Beyond that, agents lose focus and miss critical entries.
12457
+
12458
+ ## The Sync Workflow
12459
+
12460
+ After completing a feature, sync learnings to AGENTS.md:
12461
+
12462
+ 1. **Trigger sync:**
12463
+ \`\`\`typescript
12464
+ hive_agents_md({ action: 'sync', feature: 'feature-name' })
12465
+ \`\`\`
12466
+
12467
+ 2. **Review each proposal:**
12468
+ - Read the proposed change
12469
+ - Ask: "Does this change agent behavior?"
12470
+ - Check: Is this already obvious from code/files?
12471
+
12472
+ 3. **Accept signal, reject noise:**
12473
+ - ❌ "TypeScript is used" → Agent detects this
12474
+ - ✅ "Use \`.js\` extension for imports" → Prevents build failures
12475
+
12476
+ 4. **Apply approved changes:**
12477
+ \`\`\`typescript
12478
+ hive_agents_md({ action: 'apply' })
12479
+ \`\`\`
12480
+
12481
+ **Warning:** Don't auto-approve all proposals. One bad entry pollutes all future sessions.
12482
+
12483
+ ## When to Prune
12484
+
12485
+ Remove entries when they become:
12486
+
12487
+ **Outdated:**
12488
+ - "We use Redux" → Project migrated to Zustand
12489
+ - "Node 16 compatibility required" → Now on Node 22
12490
+
12491
+ **Redundant:**
12492
+ - "Use single quotes" + "Strings use single quotes" → Keep one
12493
+ - Near-duplicates in different sections
12494
+
12495
+ **Too generic:**
12496
+ - "Write clear code" → Applies to any project
12497
+ - "Test your changes" → Universal advice
12498
+
12499
+ **Describing code:**
12500
+ - "TaskService manages tasks" → Agent can read \`TaskService\` class
12501
+ - "Worktrees are in \`.hive/.worktrees/\`" → Observable from filesystem
12502
+
12503
+ **Proven unnecessary:**
12504
+ - Entry added 6 months ago, but agents haven't hit that issue since
12505
+
12506
+ ## Red Flags
12507
+
12508
+ | Warning Sign | Why It's Bad | Fix |
12509
+ |-------------|-------------|-----|
12510
+ | AGENTS.md > 800 lines | Agents lose focus, miss critical info | Prune aggressively |
12511
+ | Describes what code does | Agent can read code | Remove descriptions |
12512
+ | Missing build/test commands | First thing agents need | Add at top |
12513
+ | No gotchas section | Agents repeat past mistakes | Document failure modes |
12514
+ | Generic best practices | Doesn't change behavior | Remove or make specific |
12515
+ | Outdated patterns | Misleads agents | Prune during sync |
12516
+
12517
+ ## Anti-Patterns
12518
+
12519
+ | Anti-Pattern | Better Approach |
12520
+ |-------------|----------------|
12521
+ | "Document everything" | Document only what changes behavior |
12522
+ | "Keep for historical record" | Version control is history |
12523
+ | "Might be useful someday" | Add when proven necessary |
12524
+ | "Explains the system" | Agents read code for that |
12525
+ | "Comprehensive reference" | AGENTS.md is a filter, not docs |
12526
+
12527
+ ## Good Examples
12528
+
12529
+ **Build Commands (High value, agents need immediately):**
12530
+ \`\`\`markdown
12531
+ ## Build & Test Commands
12532
+ bun run build # Build all packages
12533
+ bun run test # Run all tests
12534
+ bun run release:check # Full CI check
12535
+ \`\`\`
12536
+
12537
+ **Project-Specific Convention (Prevents mistakes):**
12538
+ \`\`\`markdown
12539
+ ## Code Style
12540
+ - Imports: Use \`.js\` extension for local imports (ESM requirement)
12541
+ - Paths: Import from \`../utils/paths.js\` never \`./paths\`
12542
+ \`\`\`
12543
+
12544
+ **Non-Obvious Gotcha (Prevents build failure):**
12545
+ \`\`\`markdown
12546
+ ## Important Patterns
12547
+ Use \`ensureDir\` from paths.ts — sync despite name
12548
+ NEVER use \`ensureDirSync\` (doesn't exist)
12549
+ \`\`\`
12550
+
12551
+ ## Bad Examples
12552
+
12553
+ **Generic advice (agent already knows):**
12554
+ \`\`\`markdown
12555
+ ## Best Practices
12556
+ - Use meaningful variable names
12557
+ - Write unit tests
12558
+ - Follow DRY principle
12559
+ \`\`\`
12560
+
12561
+ **Describes code (agent can read it):**
12562
+ \`\`\`markdown
12563
+ ## Architecture
12564
+ The FeatureService class manages features. It has methods
12565
+ for create, read, update, and delete operations.
12566
+ \`\`\`
12567
+
12568
+ **Irrelevant metadata:**
12569
+ \`\`\`markdown
12570
+ ## Project History
12571
+ Created in January 2024 by the platform team.
12572
+ Originally built for internal use.
12573
+ \`\`\`
12574
+
12575
+ ## Verification
12576
+
12577
+ Before finalizing AGENTS.md updates:
12578
+
12579
+ - [ ] Every entry answers: "What mistake does this prevent?"
12580
+ - [ ] No generic advice that applies to all projects
12581
+ - [ ] Build/test commands are first
12582
+ - [ ] Gotchas section exists and is populated
12583
+ - [ ] Total length under 500 lines (800 absolute max)
12584
+ - [ ] No entries describing what code does
12585
+ - [ ] Fresh agent session would benefit from each entry
12586
+
12587
+ ## Summary
12588
+
12589
+ AGENTS.md is **behavioral memory**, not documentation:
12590
+ - Write for agents, optimize for behavior change
12591
+ - Signal = prevents mistakes, Noise = describes observables
12592
+ - Sync after features, prune quarterly
12593
+ - Test: Would agent make a mistake without this entry?
12594
+
12595
+ **Quality > quantity. Every line counts.**`
12596
+ },
12341
12597
  {
12342
12598
  name: "brainstorming",
12343
12599
  description: "Use before any creative work - creating features, building components, adding functionality, or modifying behavior. Explores user intent, requirements and design before implementation.",
@@ -12795,6 +13051,351 @@ From debugging session (2025-10-03):
12795
13051
  - All investigations completed concurrently
12796
13052
  - All fixes integrated successfully
12797
13053
  - Zero conflicts between agent changes`
13054
+ },
13055
+ {
13056
+ name: "docker-mastery",
13057
+ description: "Use when working with Docker containers — debugging container failures, writing Dockerfiles, docker-compose for integration tests, image optimization, or deploying containerized applications",
13058
+ template: `# Docker Mastery
13059
+
13060
+ ## Overview
13061
+
13062
+ Docker is a **platform for building, shipping, and running applications**, not just isolation.
13063
+
13064
+ Agents should think in containers: reproducible environments, declarative dependencies, isolated execution.
13065
+
13066
+ **Core principle:** Containers are not virtual machines. They share the kernel but isolate processes, filesystems, and networks.
13067
+
13068
+ **Violating the letter of these guidelines is violating the spirit of containerization.**
13069
+
13070
+ ## The Iron Law
13071
+
13072
+ \`\`\`
13073
+ UNDERSTAND THE CONTAINER BEFORE DEBUGGING INSIDE IT
13074
+ \`\`\`
13075
+
13076
+ Before exec'ing into a container or adding debug commands:
13077
+ 1. Check the image (what's installed?)
13078
+ 2. Check mounts (what host files are visible?)
13079
+ 3. Check environment variables (what config is passed?)
13080
+ 4. Check the Dockerfile (how was it built?)
13081
+
13082
+ Random debugging inside containers wastes time. Context first, then debug.
13083
+
13084
+ ## When to Use
13085
+
13086
+ Use this skill when working with:
13087
+ - **Container build failures** - Dockerfile errors, missing dependencies
13088
+ - **Test environment setup** - Reproducible test environments across machines
13089
+ - **Integration test orchestration** - Multi-service setups (DB + API + tests)
13090
+ - **Dockerfile authoring** - Writing efficient, maintainable Dockerfiles
13091
+ - **Image size optimization** - Reducing image size, layer caching
13092
+ - **Deployment** - Containerized application deployment
13093
+ - **Sandbox debugging** - Issues with Hive's Docker sandbox mode
13094
+
13095
+ **Use this ESPECIALLY when:**
13096
+ - Tests pass locally but fail in CI (environment mismatch)
13097
+ - "Works on my machine" problems
13098
+ - Need to test against specific dependency versions
13099
+ - Multiple services must coordinate (database + API)
13100
+ - Building for production deployment
13101
+
13102
+ ## Core Concepts
13103
+
13104
+ ### Images vs Containers
13105
+
13106
+ - **Image**: Read-only template (built from Dockerfile)
13107
+ - **Container**: Running instance of an image (ephemeral by default)
13108
+
13109
+ \`\`\`bash
13110
+ # Build once
13111
+ docker build -t myapp:latest .
13112
+
13113
+ # Run many times
13114
+ docker run --rm myapp:latest
13115
+ docker run --rm -e DEBUG=true myapp:latest
13116
+ \`\`\`
13117
+
13118
+ **Key insight:** Changes inside containers are lost unless committed or volumes are used.
13119
+
13120
+ ### Volumes & Mounts
13121
+
13122
+ Mount host directories into containers for persistence and code sharing:
13123
+
13124
+ \`\`\`bash
13125
+ # Mount current directory to /app in container
13126
+ docker run -v $(pwd):/app myapp:latest
13127
+
13128
+ # Hive worktrees are mounted automatically
13129
+ # Your code edits (via Read/Write/Edit tools) affect the host
13130
+ # Container sees the same files at runtime
13131
+ \`\`\`
13132
+
13133
+ **How Hive uses this:** Worktree is mounted into container, so file tools work on host, bash commands run in container.
13134
+
13135
+ ### Multi-Stage Builds
13136
+
13137
+ Minimize image size by using multiple FROM statements:
13138
+
13139
+ \`\`\`dockerfile
13140
+ # Build stage (large, has compilers)
13141
+ FROM node:22 AS builder
13142
+ WORKDIR /app
13143
+ COPY package.json bun.lockb ./
13144
+ RUN bun install
13145
+ COPY . .
13146
+ RUN bun run build
13147
+
13148
+ # Runtime stage (small, production only)
13149
+ FROM node:22-slim
13150
+ WORKDIR /app
13151
+ COPY --from=builder /app/dist ./dist
13152
+ COPY --from=builder /app/node_modules ./node_modules
13153
+ CMD ["node", "dist/index.js"]
13154
+ \`\`\`
13155
+
13156
+ **Result:** Builder tools (TypeScript, bundlers) not included in final image.
13157
+
13158
+ ### Docker Compose for Multi-Service Setups
13159
+
13160
+ Define multiple services in \`docker-compose.yml\`:
13161
+
13162
+ \`\`\`yaml
13163
+ version: '3.8'
13164
+ services:
13165
+ db:
13166
+ image: postgres:15
13167
+ environment:
13168
+ POSTGRES_PASSWORD: testpass
13169
+ ports:
13170
+ - "5432:5432"
13171
+
13172
+ api:
13173
+ build: .
13174
+ environment:
13175
+ DATABASE_URL: postgres://db:5432/testdb
13176
+ depends_on:
13177
+ - db
13178
+ ports:
13179
+ - "3000:3000"
13180
+ \`\`\`
13181
+
13182
+ Run with: \`docker-compose up -d\`
13183
+ Teardown with: \`docker-compose down\`
13184
+
13185
+ ### Network Modes
13186
+
13187
+ - **bridge** (default): Isolated network, containers can talk to each other by name
13188
+ - **host**: Container uses host's network directly (no isolation)
13189
+ - **none**: No network access
13190
+
13191
+ **When to use host mode:** Debugging network issues, accessing host services directly.
13192
+
13193
+ ## Common Patterns
13194
+
13195
+ ### Debug a Failing Container
13196
+
13197
+ **Problem:** Container exits immediately, logs unclear.
13198
+
13199
+ **Pattern:**
13200
+ 1. Run interactively with shell:
13201
+ \`\`\`bash
13202
+ docker run -it --entrypoint sh myapp:latest
13203
+ \`\`\`
13204
+ 2. Inspect filesystem, check if dependencies exist:
13205
+ \`\`\`bash
13206
+ ls /app
13207
+ which node
13208
+ cat /etc/os-release
13209
+ \`\`\`
13210
+ 3. Run command manually to see full error:
13211
+ \`\`\`bash
13212
+ node dist/index.js
13213
+ \`\`\`
13214
+
13215
+ ### Integration Tests with Docker Compose
13216
+
13217
+ **Pattern:**
13218
+ 1. Define services in \`docker-compose.test.yml\`
13219
+ 2. Add wait logic (wait for DB to be ready)
13220
+ 3. Run tests
13221
+ 4. Teardown
13222
+
13223
+ \`\`\`yaml
13224
+ # docker-compose.test.yml
13225
+ services:
13226
+ db:
13227
+ image: postgres:15
13228
+ environment:
13229
+ POSTGRES_PASSWORD: test
13230
+ test:
13231
+ build: .
13232
+ command: bun run test:integration
13233
+ depends_on:
13234
+ - db
13235
+ environment:
13236
+ DATABASE_URL: postgres://postgres:test@db:5432/testdb
13237
+ \`\`\`
13238
+
13239
+ \`\`\`bash
13240
+ docker-compose -f docker-compose.test.yml up --abort-on-container-exit
13241
+ docker-compose -f docker-compose.test.yml down
13242
+ \`\`\`
13243
+
13244
+ ### Optimize Dockerfile
13245
+
13246
+ **Anti-pattern:**
13247
+ \`\`\`dockerfile
13248
+ FROM node:22
13249
+ WORKDIR /app
13250
+ COPY . . # Copies everything (including node_modules, .git)
13251
+ RUN bun install # Invalidates cache on any file change
13252
+ CMD ["bun", "run", "start"]
13253
+ \`\`\`
13254
+
13255
+ **Optimized:**
13256
+ \`\`\`dockerfile
13257
+ FROM node:22-slim # Use slim variant
13258
+ WORKDIR /app
13259
+
13260
+ # Copy dependency files first (cache layer)
13261
+ COPY package.json bun.lockb ./
13262
+ RUN bun install --production
13263
+
13264
+ # Copy source code (changes frequently)
13265
+ COPY src ./src
13266
+ COPY tsconfig.json ./
13267
+
13268
+ CMD ["bun", "run", "start"]
13269
+ \`\`\`
13270
+
13271
+ **Add \`.dockerignore\`:**
13272
+ \`\`\`
13273
+ node_modules
13274
+ .git
13275
+ .env
13276
+ *.log
13277
+ dist
13278
+ .DS_Store
13279
+ \`\`\`
13280
+
13281
+ ### Handle Missing Dependencies
13282
+
13283
+ **Problem:** Command fails with "not found" in container.
13284
+
13285
+ **Pattern:**
13286
+ 1. Check if dependency is in image:
13287
+ \`\`\`bash
13288
+ docker run -it myapp:latest which git
13289
+ \`\`\`
13290
+ 2. If missing, add to Dockerfile:
13291
+ \`\`\`dockerfile
13292
+ RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*
13293
+ \`\`\`
13294
+ 3. Or use a richer base image (e.g., \`node:22\` instead of \`node:22-slim\`).
13295
+
13296
+ ## Hive Sandbox Integration
13297
+
13298
+ ### How Hive Wraps Commands
13299
+
13300
+ When sandbox mode is active (\`sandbox: 'docker'\` in config):
13301
+ 1. Hive hook intercepts bash commands before execution
13302
+ 2. Wraps with \`docker run --rm -v <worktree>:/workspace -w /workspace <image> sh -c "<command>"\`
13303
+ 3. Command runs in container, but file edits (Read/Write/Edit) still affect host
13304
+
13305
+ **Workers are unaware** — they issue normal bash commands, Hive handles containerization.
13306
+
13307
+ ### When Host Access is Needed
13308
+
13309
+ Some operations MUST run on host:
13310
+ - **Git operations** (commit, push, branch) — repo state is on host
13311
+ - **Host-level tools** (Docker itself, system config)
13312
+ - **Cross-worktree operations** (accessing main repo from worktree)
13313
+
13314
+ **Pattern:** Use \`HOST:\` prefix to escape sandbox:
13315
+ \`\`\`bash
13316
+ HOST: git status
13317
+ HOST: docker ps
13318
+ \`\`\`
13319
+
13320
+ **If you need host access frequently:** Report as blocked and ask user if sandbox should be disabled for this task.
13321
+
13322
+ ### Persistent vs Ephemeral Containers
13323
+
13324
+ **Current (v1.2.0):** Each command runs \`docker run --rm\` (ephemeral). State does NOT persist.
13325
+
13326
+ Example: \`npm install lodash\` in one command → not available in next command.
13327
+
13328
+ **Workaround:** Install dependencies in Dockerfile, not at runtime.
13329
+
13330
+ **Future:** \`docker exec\` will reuse containers, persisting state across commands.
13331
+
13332
+ ### Auto-Detected Images
13333
+
13334
+ Hive detects runtime from project files:
13335
+ - \`package.json\` → \`node:22-slim\`
13336
+ - \`requirements.txt\` / \`pyproject.toml\` → \`python:3.12-slim\`
13337
+ - \`go.mod\` → \`golang:1.22-slim\`
13338
+ - \`Cargo.toml\` → \`rust:1.77-slim\`
13339
+ - \`Dockerfile\` → Builds from project Dockerfile
13340
+ - Fallback → \`ubuntu:24.04\`
13341
+
13342
+ **Override:** Set \`dockerImage\` in config (\`~/.config/opencode/agent_hive.json\`).
13343
+
13344
+ ## Red Flags - STOP
13345
+
13346
+ If you catch yourself:
13347
+ - Installing packages on host instead of in Dockerfile
13348
+ - Running \`docker build\` without \`.dockerignore\` (cache invalidation)
13349
+ - Using \`latest\` tag in production (non-reproducible)
13350
+ - Ignoring container exit codes (hides failures)
13351
+ - Assuming state persists between \`docker run --rm\` commands
13352
+ - Using absolute host paths in Dockerfile (not portable)
13353
+ - Copying secrets into image layers (leaks credentials)
13354
+
13355
+ **ALL of these mean: STOP. Review pattern.**
13356
+
13357
+ ## Anti-Patterns
13358
+
13359
+ | Excuse | Reality |
13360
+ |--------|---------|
13361
+ | "I'll just run it on host" | Container mismatch bugs are worse to debug later. Build happens in container anyway. |
13362
+ | "Works in my container, don't need CI" | CI uses different cache state. Always test in CI-like environment. |
13363
+ | "I'll optimize the Dockerfile later" | Later never comes. Large images slow down deployments now. |
13364
+ | "latest tag is fine for dev" | Dev should match prod. Pin versions or face surprises. |
13365
+ | "Don't need .dockerignore, COPY is fast" | Invalidates cache on every file change. Wastes minutes per build. |
13366
+ | "Install at runtime, not in image" | Ephemeral containers lose state. Slows down every command. |
13367
+ | "Skip depends_on, services start fast" | Race conditions in integration tests. Use wait-for-it or health checks. |
13368
+
13369
+ ## Verification Before Completion
13370
+
13371
+ Before marking Docker work complete:
13372
+
13373
+ - [ ] Container runs successfully: \`docker run --rm <image> <command>\` exits 0
13374
+ - [ ] Tests pass inside container (not just on host)
13375
+ - [ ] No host pollution (dependencies installed in container, not host)
13376
+ - [ ] \`.dockerignore\` exists if using \`COPY . .\`
13377
+ - [ ] Image tags are pinned (not \`latest\`) for production
13378
+ - [ ] Multi-stage build used if applicable (separate build/runtime)
13379
+ - [ ] Integration tests teardown properly (\`docker-compose down\`)
13380
+
13381
+ **If any fail:** Don't claim success. Fix or report blocker.
13382
+
13383
+ ## Quick Reference
13384
+
13385
+ | Task | Command Pattern |
13386
+ |------|----------------|
13387
+ | **Debug container** | \`docker run -it --entrypoint sh <image>\` |
13388
+ | **Run with mounts** | \`docker run -v $(pwd):/app <image>\` |
13389
+ | **Multi-service tests** | \`docker-compose up --abort-on-container-exit\` |
13390
+ | **Check image contents** | \`docker run --rm <image> ls /app\` |
13391
+ | **Optimize build** | Add \`.dockerignore\`, use multi-stage, pin versions |
13392
+ | **Escape Hive sandbox** | Prefix with \`HOST:\` (e.g., \`HOST: git status\`) |
13393
+
13394
+ ## Related Skills
13395
+
13396
+ - **hive_skill:systematic-debugging** - When container behavior is unexpected
13397
+ - **hive_skill:test-driven-development** - Write tests that run in containers
13398
+ - **hive_skill:verification-before-completion** - Verify tests pass in container before claiming done`
12798
13399
  },
12799
13400
  {
12800
13401
  name: "executing-plans",
@@ -12857,8 +13458,8 @@ Based on feedback:
12857
13458
  ### Step 6: Complete Development
12858
13459
 
12859
13460
  After all tasks complete and verified:
12860
- - Announce: "I'm using the finishing-a-development-branch skill to complete this work."
12861
- - **REQUIRED SUB-SKILL:** Use hive_skill:finishing-a-development-branch
13461
+ - Announce: "I'm using the verification-before-completion skill to complete this work."
13462
+ - **REQUIRED SUB-SKILL:** Use hive_skill:verification-before-completion
12862
13463
  - Follow that skill to verify tests, present options, execute choice
12863
13464
 
12864
13465
  ## When to Stop and Ask for Help
@@ -12886,66 +13487,6 @@ After all tasks complete and verified:
12886
13487
  - Reference skills when plan says to
12887
13488
  - Between batches: just report and wait
12888
13489
  - Stop when blocked, don't guess`
12889
- },
12890
- {
12891
- name: "onboarding",
12892
- description: "Ask about workflow preferences and store them in .hive/contexts/preferences.md before proceeding.",
12893
- template: `# Onboarding Preferences
12894
-
12895
- ## Overview
12896
-
12897
- Gather workflow preferences so the assistant can match the user's desired working style.
12898
-
12899
- ## When to Ask
12900
-
12901
- - **Immediately when the skill is loaded**, before any other work.
12902
- - If \`.hive/contexts/preferences.md\` does not exist, start onboarding.
12903
- - If later a decision is ambiguous and preferences are missing, ask again.
12904
-
12905
- ## Preference Storage
12906
-
12907
- Use \`hive_context_write\` to write \`.hive/contexts/preferences.md\` with this exact template:
12908
-
12909
- \`\`\`
12910
- # Preferences
12911
-
12912
- ## Exploration Style
12913
- sync
12914
-
12915
- ## Research Depth
12916
- medium
12917
-
12918
- ## Confirmation Level
12919
- standard
12920
-
12921
- ## Commit Behavior
12922
- ask-before-commit
12923
- \`\`\`
12924
-
12925
- ## If Preferences Already Exist
12926
-
12927
- Follow the same pattern used in \`packages/vscode-hive/src/tools/plan.ts\`:
12928
-
12929
- 1. Use \`contextService.list(feature)\` to detect existing contexts.
12930
- 2. Ask **"Preferences already exist. Keep or overwrite?"** using the \`question()\` tool.
12931
- 3. If keep → continue using existing preferences.
12932
- 4. If overwrite → collect new answers and write them with \`hive_context_write\`.
12933
-
12934
- ## Questions to Ask (Always use \`question()\`)
12935
-
12936
- Ask one at a time, with the provided options. Store the answers in \`.hive/contexts/preferences.md\`.
12937
-
12938
- 1. **Exploration Style:** sync | async
12939
- 2. **Research Depth:** shallow | medium | deep
12940
- 3. **Confirmation Level:** minimal | standard | high
12941
- 4. **Commit Behavior:** ask-before-commit | auto-commit | never-commit
12942
-
12943
- ## Requirements
12944
-
12945
- - Use the \`question()\` tool (no plain text questions).
12946
- - Ask immediately when the skill loads if preferences are missing.
12947
- - If later a decision is ambiguous and preferences are missing, ask again.
12948
- - Always store answers using \`hive_context_write\` with the template above.`
12949
13490
  },
12950
13491
  {
12951
13492
  name: "parallel-exploration",
@@ -13837,7 +14378,7 @@ Never fix bugs without a test.
13837
14378
 
13838
14379
  ## Testing Anti-Patterns
13839
14380
 
13840
- When adding mocks or test utilities, read @testing-anti-patterns.md to avoid common pitfalls:
14381
+ When adding mocks or test utilities, avoid common pitfalls:
13841
14382
  - Testing mock behavior instead of real behavior
13842
14383
  - Adding test-only methods to production classes
13843
14384
  - Mocking without understanding dependencies
@@ -14100,6 +14641,12 @@ Always include **Depends on** for each task. Use \`none\` to enable parallel sta
14100
14641
  **Verify**:
14101
14642
  - [ ] Run: \`{command}\` → {expected}
14102
14643
  - [ ] {Additional acceptance criteria}
14644
+
14645
+ All verification MUST be agent-executable (no human intervention):
14646
+ ✅ \`bun test\` → all pass
14647
+ ✅ \`curl -X POST /api/x\` → 201
14648
+ ❌ "User manually tests..."
14649
+ ❌ "Visually confirm..."
14103
14650
  \`\`\`\`
14104
14651
 
14105
14652
  ## Remember
@@ -14108,6 +14655,7 @@ Always include **Depends on** for each task. Use \`none\` to enable parallel sta
14108
14655
  - Exact commands with expected output
14109
14656
  - Reference relevant skills with @ syntax
14110
14657
  - DRY, YAGNI, TDD, frequent commits
14658
+ - All acceptance criteria must be agent-executable (zero human intervention)
14111
14659
 
14112
14660
  ## Execution Handoff
14113
14661
 
@@ -14279,7 +14827,6 @@ Run \`hive_status()\` to detect phase:
14279
14827
  ## Universal (Always Active)
14280
14828
 
14281
14829
  ### Intent Classification
14282
-
14283
14830
  | Intent | Signals | Action |
14284
14831
  |--------|---------|--------|
14285
14832
  | Trivial | Single file, <10 lines | Do directly |
@@ -14287,22 +14834,34 @@ Run \`hive_status()\` to detect phase:
14287
14834
  | Complex | 3+ files, multi-step | Full discovery → plan/delegate |
14288
14835
  | Research | Internal codebase exploration OR external data | Delegate to Scout (Explorer/Researcher/Retrieval) |
14289
14836
 
14290
- ### Canonical Delegation Threshold
14837
+ Intent Verbalization verbalize before acting:
14838
+ > "I detect [type] intent — [reason]. Approach: [route]."
14291
14839
 
14840
+ | Surface Form | True Intent | Routing |
14841
+ |--------------|-------------|---------|
14842
+ | "Quick change" | Trivial | Act directly |
14843
+ | "Add new flow" | Complex | Plan/delegate |
14844
+ | "Where is X?" | Research | Scout exploration |
14845
+ | "Should we…?" | Ambiguous | Ask a question |
14846
+
14847
+ ### Canonical Delegation Threshold
14292
14848
  - Delegate to Scout when you cannot name the file path upfront, expect to inspect 2+ files, or the question is open-ended ("how/where does X work?").
14293
14849
  - Prefer \`task({ subagent_type: "scout-researcher", prompt: "..." })\` for single investigations.
14294
14850
  - Local \`read/grep/glob\` is acceptable only for a single known file and a bounded question.
14295
14851
 
14296
14852
  ### Delegation
14297
-
14298
14853
  - Single-scout research → \`task({ subagent_type: "scout-researcher", prompt: "..." })\`
14299
14854
  - Parallel exploration → Load \`hive_skill("parallel-exploration")\` and follow the task mode delegation guidance.
14300
14855
  - Implementation → \`hive_worktree_create({ task: "01-task-name" })\` (creates worktree + Forager)
14301
14856
 
14302
14857
  During Planning, use \`task({ subagent_type: "scout-researcher", ... })\` for exploration (BLOCKING — returns when done). For parallel exploration, issue multiple \`task()\` calls in the same message.
14303
14858
 
14304
- ### Context Persistence
14859
+ **When NOT to delegate:**
14860
+ - Single-file, <10-line changes — do directly
14861
+ - Sequential operations where you need the result of step N for step N+1
14862
+ - Questions answerable with one grep + one file read
14305
14863
 
14864
+ ### Context Persistence
14306
14865
  Save discoveries with \`hive_context_write\`:
14307
14866
  - Requirements and decisions
14308
14867
  - User preferences
@@ -14311,60 +14870,64 @@ Save discoveries with \`hive_context_write\`:
14311
14870
  When Scout returns substantial findings (3+ files discovered, architecture patterns, or key decisions), persist them to a feature context file via \`hive_context_write\`.
14312
14871
 
14313
14872
  ### Checkpoints
14314
-
14315
14873
  Before major transitions, verify:
14316
14874
  - [ ] Objective clear?
14317
14875
  - [ ] Scope defined?
14318
14876
  - [ ] No critical ambiguities?
14319
14877
 
14320
- ### Loading Skills (On-Demand)
14321
-
14322
- Load when detailed guidance needed:
14323
- - \`hive_skill("brainstorming")\` - exploring ideas and requirements
14324
- - \`hive_skill("writing-plans")\` - structuring implementation plans
14325
- - \`hive_skill("dispatching-parallel-agents")\` - parallel task delegation
14326
- - \`hive_skill("parallel-exploration")\` - parallel read-only research via task() (Scout fan-out)
14327
- - \`hive_skill("executing-plans")\` - step-by-step plan execution
14878
+ ### Turn Termination
14879
+ Valid endings:
14880
+ - Ask a concrete question
14881
+ - Update draft + ask a concrete question
14882
+ - Explicitly state you are waiting on background work (tool/task)
14883
+ - Auto-transition to the next required action
14328
14884
 
14329
- Load ONE skill at a time. Only when you need guidance beyond this prompt.
14885
+ NEVER end with:
14886
+ - "Let me know if you have questions"
14887
+ - Summary without a follow-up action
14888
+ - "When you're ready..."
14330
14889
 
14890
+ ### Loading Skills (On-Demand)
14891
+ Load when detailed guidance needed:
14892
+ | Skill | Use when |
14893
+ |-------|----------|
14894
+ | \`hive_skill("brainstorming")\` | Exploring ideas and requirements |
14895
+ | \`hive_skill("writing-plans")\` | Structuring implementation plans |
14896
+ | \`hive_skill("dispatching-parallel-agents")\` | Parallel task delegation |
14897
+ | \`hive_skill("parallel-exploration")\` | Parallel read-only research via task() |
14898
+ | \`hive_skill("executing-plans")\` | Step-by-step plan execution |
14899
+ | \`hive_skill("systematic-debugging")\` | Bugs, test failures, unexpected behavior |
14900
+ | \`hive_skill("test-driven-development")\` | TDD approach |
14901
+ | \`hive_skill("verification-before-completion")\` | Before claiming work is complete or creating PRs |
14902
+ | \`hive_skill("docker-mastery")\` | Docker containers, debugging, compose |
14903
+ | \`hive_skill("agents-md-mastery")\` | AGENTS.md updates, quality review |
14904
+
14905
+ Load one skill at a time, only when guidance is needed.
14331
14906
  ---
14332
14907
 
14333
14908
  ## Planning Phase
14334
-
14335
14909
  *Active when: no approved plan exists*
14336
14910
 
14337
14911
  ### When to Load Skills
14338
-
14339
14912
  - Exploring vague requirements → \`hive_skill("brainstorming")\`
14340
14913
  - Writing detailed plan → \`hive_skill("writing-plans")\`
14341
14914
 
14342
- ### AI-Slop Flags
14343
-
14344
- | Pattern | Ask |
14345
- |---------|-----|
14915
+ ### Planning Checks
14916
+ | Signal | Prompt |
14917
+ |--------|--------|
14346
14918
  | Scope inflation | "Should I include X?" |
14347
14919
  | Premature abstraction | "Abstract or inline?" |
14348
14920
  | Over-validation | "Minimal or comprehensive checks?" |
14349
-
14350
- ### Challenge User Assumptions
14351
-
14352
- When a proposal relies on fragile assumptions, challenge them explicitly:
14353
-
14354
- - Identify the assumption and state it plainly.
14355
- - Ask what changes if the assumption is wrong.
14356
- - Offer a lean fallback that still meets core goals.
14921
+ | Fragile assumption | "If this assumption is wrong, what changes?" |
14357
14922
 
14358
14923
  ### Gap Classification
14359
-
14360
14924
  | Gap | Action |
14361
14925
  |-----|--------|
14362
- | Critical | ASK immediately |
14926
+ | Critical | Ask immediately |
14363
14927
  | Minor | Fix silently, note in summary |
14364
14928
  | Ambiguous | Apply default, disclose |
14365
14929
 
14366
14930
  ### Plan Output
14367
-
14368
14931
  \`\`\`
14369
14932
  hive_feature_create({ name: "feature-name" })
14370
14933
  hive_plan_write({ content: "..." })
@@ -14375,12 +14938,11 @@ Plan includes: Discovery (Original Request, Interview Summary, Research Findings
14375
14938
  - References must use file:line format
14376
14939
  - Verify must include exact command + expected output
14377
14940
 
14378
- Each task MUST declare dependencies with **Depends on**:
14941
+ Each task declares dependencies with **Depends on**:
14379
14942
  - **Depends on**: none for no dependencies / parallel starts
14380
14943
  - **Depends on**: 1, 3 for explicit task-number dependencies
14381
14944
 
14382
14945
  ### After Plan Written
14383
-
14384
14946
  Ask user via \`question()\`: "Plan complete. Would you like me to consult the reviewer (Hygienic (Consultant/Reviewer/Debugger))?"
14385
14947
 
14386
14948
  If yes → \`task({ subagent_type: "hygienic", prompt: "Review plan..." })\`
@@ -14388,86 +14950,108 @@ If yes → \`task({ subagent_type: "hygienic", prompt: "Review plan..." })\`
14388
14950
  After review decision, offer execution choice (subagent-driven vs parallel session) consistent with writing-plans.
14389
14951
 
14390
14952
  ### Planning Iron Laws
14391
-
14392
- - Research BEFORE asking (use \`hive_skill("parallel-exploration")\` for multi-domain research)
14953
+ - Research before asking (use \`hive_skill("parallel-exploration")\` for multi-domain research)
14393
14954
  - Save draft as working memory
14394
- - Don't implement (no edits/worktrees). Read-only exploration is allowed (local tools + Scout via task()).
14955
+ - Keep planning read-only (local tools + Scout via task())
14956
+ Read-only exploration is allowed.
14957
+ Search Stop conditions: enough context, repeated info, 2 rounds with no new data, or direct answer found.
14395
14958
 
14396
14959
  ---
14397
14960
 
14398
14961
  ## Orchestration Phase
14399
-
14400
14962
  *Active when: plan approved, tasks exist*
14401
14963
 
14402
14964
  ### Task Dependencies (Always Check)
14403
-
14404
14965
  Use \`hive_status()\` to see **runnable** tasks (dependencies satisfied) and **blockedBy** info.
14405
14966
  - Only start tasks from the runnable list
14406
14967
  - When 2+ tasks are runnable: ask operator via \`question()\` before parallelizing
14407
14968
  - Record execution decisions with \`hive_context_write({ name: "execution-decisions", ... })\`
14408
14969
 
14409
14970
  ### When to Load Skills
14410
-
14411
14971
  - Multiple independent tasks → \`hive_skill("dispatching-parallel-agents")\`
14412
14972
  - Executing step-by-step → \`hive_skill("executing-plans")\`
14413
14973
 
14414
14974
  ### Delegation Check
14415
-
14416
14975
  1. Is there a specialized agent?
14417
14976
  2. Does this need external data? → Scout
14418
- 3. Default: DELEGATE (don't do yourself)
14977
+ 3. Default: delegate (don't do yourself)
14419
14978
 
14420
14979
  ### Worker Spawning
14421
-
14422
14980
  \`\`\`
14423
14981
  hive_worktree_create({ task: "01-task-name" }) // Creates worktree + Forager
14424
14982
  \`\`\`
14425
14983
 
14426
14984
  ### After Delegation
14427
-
14428
- 1. \`task()\` is BLOCKING — when it returns, the worker is DONE
14985
+ 1. \`task()\` is blocking — when it returns, the worker is done
14429
14986
  2. Immediately call \`hive_status()\` to check the new task state and find next runnable tasks
14430
- 3. If task status is blocked: read blocker info \`question()\` user decision resume with \`continueFrom: "blocked"\`
14431
- 4. Do NOT wait for notifications or poll the result is already available when \`task()\` returns
14432
-
14433
- ### Failure Recovery
14434
-
14435
- 3 failures on same task revert ask user
14987
+ 3. The delegated task MUST transition out of \`in_progress\`; if still \`in_progress\`, resume worker with explicit instruction to resolve commit response and retry
14988
+ 4. If task status is blocked: read blocker info \`question()\` user decision resume with \`continueFrom: "blocked"\`
14989
+ 5. Skip polling — the result is available when \`task()\` returns
14990
+
14991
+ ### Batch Merge + Verify Workflow
14992
+ When multiple tasks are in flight, prefer **batch completion** over per-task verification:
14993
+ 1. Dispatch a batch of runnable tasks (ask user before parallelizing).
14994
+ 2. Wait for all workers to finish.
14995
+ 3. Merge each completed task branch into the current branch.
14996
+ 4. Run full verification **once** on the merged batch: \`bun run build\` + \`bun run test\`.
14997
+ 5. If verification fails, diagnose with full context. Fix directly or re-dispatch targeted tasks as needed.
14998
+
14999
+ ### Failure Recovery (After 3 Consecutive Failures)
15000
+ 1. Stop all further edits
15001
+ 2. Revert to last known working state
15002
+ 3. Document what was attempted
15003
+ 4. Ask user via question() — present options and context
14436
15004
 
14437
15005
  ### Merge Strategy
14438
-
14439
- \`hive_merge({ task: "01-task-name" })\` after verification
15006
+ \`hive_merge({ task: "01-task-name" })\` for each task after the batch completes, then verify the batch
14440
15007
 
14441
15008
  ### Post-Batch Review (Hygienic)
14442
-
14443
15009
  After completing and merging a batch:
14444
15010
  1. Ask the user via \`question()\` if they want a Hygienic code review for the batch.
14445
15011
  2. If yes, run \`task({ subagent_type: "hygienic", prompt: "Review implementation changes from the latest batch." })\`.
14446
15012
  3. Apply feedback before starting the next batch.
14447
15013
 
14448
- ### Orchestration Iron Laws
15014
+ ### AGENTS.md Maintenance
15015
+ After feature completion (all tasks merged):
15016
+ 1. Sync context findings to AGENTS.md: \`hive_agents_md({ action: "sync", feature: "feature-name" })\`
15017
+ 2. Review the proposed diff with the user
15018
+ 3. Apply approved changes to keep AGENTS.md current
15019
+
15020
+ For projects without AGENTS.md:
15021
+ - Bootstrap with \`hive_agents_md({ action: "init" })\`
15022
+ - Generates initial documentation from codebase analysis
14449
15023
 
15024
+ ### Orchestration Iron Laws
14450
15025
  - Delegate by default
14451
15026
  - Verify all work completes
14452
- - Use \`question()\` for user input (NEVER plain text)
15027
+ - Use \`question()\` for user input (never plain text)
14453
15028
 
14454
15029
  ---
14455
15030
 
14456
15031
  ## Iron Laws (Both Phases)
14457
-
14458
15032
  **Always:**
14459
- - Detect phase FIRST via hive_status
14460
- - Follow ONLY the active phase section
15033
+ - Detect phase first via hive_status
15034
+ - Follow the active phase section
14461
15035
  - Delegate research to Scout, implementation to Forager
14462
15036
  - Ask user before consulting Hygienic (Consultant/Reviewer/Debugger)
14463
15037
  - Load skills on-demand, one at a time
14464
15038
 
14465
- **Never:**
15039
+ Investigate before acting: read referenced files before making claims about them.
15040
+
15041
+ ### Hard Blocks
15042
+
15043
+ Do not violate:
14466
15044
  - Skip phase detection
14467
15045
  - Mix planning and orchestration in same action
14468
15046
  - Auto-load all skills at start
14469
15047
 
14470
- **User Input:** ALWAYS use \`question()\` tool for any user input - NEVER ask questions via plain text. This ensures structured responses.
15048
+ ### Anti-Patterns
15049
+
15050
+ Blocking violations:
15051
+ - Ending a turn without a next action
15052
+ - Asking for user input in plain text instead of question()
15053
+
15054
+ **User Input:** Use \`question()\` tool for any user input — structured prompts get structured responses. Plain text questions are easily missed or misinterpreted.
14471
15055
  `;
14472
15056
 
14473
15057
  // src/agents/architect.ts
@@ -14477,25 +15061,38 @@ PLANNER, NOT IMPLEMENTER. "Do X" means "create plan for X".
14477
15061
 
14478
15062
  ## Intent Classification (First)
14479
15063
 
14480
- | Intent | Signals | Action |
14481
- |--------|---------|--------|
14482
- | Trivial | Single file, <10 lines | Do directly. No plan needed. |
14483
- | Simple | 1-2 files, <30 min | Light interview → quick plan |
14484
- | Complex | 3+ files, review needed | Full discovery → detailed plan |
14485
- | Refactor | Existing code changes | Safety: tests, rollback, blast radius |
14486
- | Greenfield | New feature | Research patterns BEFORE asking. Delegate to Scout via \`task({ subagent_type: "scout-researcher", prompt: "..." })\` for single investigations. |
15064
+ | Intent | Signals | Strategy | Action |
15065
+ |--------|---------|----------|--------|
15066
+ | Trivial | Single file, <10 lines | N/A | Do directly. No plan needed. |
15067
+ | Simple | 1-2 files, <30 min | Quick assessment | Light interview → quick plan |
15068
+ | Complex | 3+ files, review needed | Full discovery | Full discovery → detailed plan |
15069
+ | Refactor | Existing code changes | Safety-first: behavior preservation | Tests → blast radius → plan |
15070
+ | Greenfield | New feature | Discovery-first: explore before asking | Research interview plan |
15071
+ | Architecture | Cross-cutting, multi-system | Strategic: consult Scout | Deep research → plan |
14487
15072
 
14488
15073
  During Planning, use \`task({ subagent_type: "scout-researcher", ... })\` for exploration (BLOCKING — returns when done). For parallel exploration, issue multiple \`task()\` calls in the same message.
14489
15074
 
14490
15075
  ## Self-Clearance Check (After Every Exchange)
14491
15076
 
14492
- □ Core objective clear?
14493
- □ Scope defined (IN/OUT)?
14494
- □ No critical ambiguities?
14495
- Approach decided?
15077
+ □ Core objective clearly defined?
15078
+ □ Scope boundaries established (IN/OUT)?
15079
+ □ No critical ambiguities remaining?
15080
+ Technical approach decided?
15081
+ □ Test strategy confirmed (TDD/tests-after/none)?
15082
+ □ No blocking questions outstanding?
15083
+
15084
+ ALL YES → Announce "Requirements clear. Generating plan." → Write plan
15085
+ ANY NO → Ask the specific unclear thing
15086
+
15087
+ ## Test Strategy (Ask Before Planning)
15088
+
15089
+ For Build and Refactor intents, ASK:
15090
+ "Should this include automated tests?"
15091
+ - TDD: Red-Green-Refactor per task
15092
+ - Tests after: Add test tasks after implementation
15093
+ - None: No unit/integration tests
14496
15094
 
14497
- ALL YES Write plan
14498
- ANY NO → Ask the unclear thing
15095
+ Record decision in draft. Embed in plan tasks.
14499
15096
 
14500
15097
  ## AI-Slop Flags
14501
15098
 
@@ -14515,6 +15112,18 @@ ANY NO → Ask the unclear thing
14515
15112
  | MINOR | FIX silently, note in summary |
14516
15113
  | AMBIGUOUS | Apply default, DISCLOSE in summary |
14517
15114
 
15115
+ ## Turn Termination
15116
+
15117
+ Valid endings:
15118
+ - Question to user (via question() tool)
15119
+ - Draft update + next question
15120
+ - Auto-transition to plan generation
15121
+
15122
+ NEVER end with:
15123
+ - "Let me know if you have questions"
15124
+ - Summary without follow-up action
15125
+ - "When you're ready..."
15126
+
14518
15127
  ## Draft as Working Memory
14519
15128
 
14520
15129
  Create draft on first exchange. Update after EVERY user response:
@@ -14583,28 +15192,18 @@ Delegate by default. Work yourself only when trivial.
14583
15192
  | Open-ended | "Improve", "Refactor" | Assess first, then delegate |
14584
15193
  | Ambiguous | Unclear scope | Ask ONE clarifying question |
14585
15194
 
14586
- ## Delegation Check (Before Acting)
15195
+ Intent Verbalization: "I detect [type] intent — [reason]. Routing to [action]."
14587
15196
 
14588
- ### Task Dependencies (Always Check)
14589
-
14590
- Use \`hive_status()\` to see **runnable** tasks (dependencies satisfied) and **blockedBy** info.
14591
- - Only start tasks from the runnable list
14592
- - When 2+ tasks are runnable: ask operator via \`question()\` before parallelizing
14593
- - Record execution decisions with \`hive_context_write({ name: "execution-decisions", ... })\`
14594
-
14595
- When Scout returns substantial findings (3+ files discovered, architecture patterns, or key decisions), persist them to a feature context file via \`hive_context_write\`.
15197
+ ## Delegation Check (Before Acting)
14596
15198
 
14597
- If tasks are missing **Depends on** metadata, ask the planner to revise the plan before executing.
15199
+ Use \`hive_status()\` to see runnable tasks and blockedBy info. Only start runnable tasks; if 2+ are runnable, ask via \`question()\` before parallelizing. Record execution decisions with \`hive_context_write({ name: "execution-decisions", ... })\`. If tasks lack **Depends on** metadata, ask the planner to revise. If Scout returns substantial findings (3+ files, architecture patterns, or key decisions), persist them via \`hive_context_write\`.
14598
15200
 
14599
- ### Standard Checks
15201
+ Standard checks: specialized agent? can I do it myself for sure? external system data (DBs/APIs/3rd-party tools)? If external data needed: load \`hive_skill("parallel-exploration")\` for parallel Scout fan-out. In task mode, use task() for research fan-out. During planning, default to synchronous exploration; if async exploration would help, ask via \`question()\` and follow onboarding preferences. Default: delegate. Research tools (grep_app, context7, websearch, ast_grep) — delegate to Scout, not direct use.
14600
15202
 
14601
- 1. Is there a specialized agent that matches?
14602
- 2. Can I do it myself FOR SURE? REALLY?
14603
- 3. Does this require external system data (DBs/APIs/3rd-party tools)?
14604
- If external data needed: Load \`hive_skill("parallel-exploration")\` for parallel Scout fan-out
14605
- In task mode, use task() for research fan-out.
14606
- During Planning, default to synchronous exploration. If async exploration would help, ask the user via \`question()\` and follow the onboarding preferences.
14607
- → Default: DELEGATE
15203
+ **When NOT to delegate:**
15204
+ - Single-file, <10-line changes do directly
15205
+ - Sequential operations where you need the result of step N for step N+1
15206
+ - Questions answerable with one grep + one file read
14608
15207
 
14609
15208
  ## Delegation Prompt Structure (All 6 Sections)
14610
15209
 
@@ -14612,8 +15211,8 @@ During Planning, default to synchronous exploration. If async exploration would
14612
15211
  1. TASK: Atomic, specific goal
14613
15212
  2. EXPECTED OUTCOME: Concrete deliverables
14614
15213
  3. REQUIRED TOOLS: Explicit tool whitelist
14615
- 4. MUST DO: Exhaustive requirements
14616
- 5. MUST NOT DO: Forbidden actions
15214
+ 4. REQUIRED: Exhaustive requirements
15215
+ 5. FORBIDDEN: Forbidden actions
14617
15216
  6. CONTEXT: File paths, patterns, constraints
14618
15217
  \`\`\`
14619
15218
 
@@ -14626,31 +15225,45 @@ hive_worktree_create({ task: "01-task-name" })
14626
15225
  // In task mode, use task() for research fan-out.
14627
15226
  \`\`\`
14628
15227
 
14629
- **Delegation Guidance:**
15228
+ Delegation guidance:
14630
15229
  - \`task()\` is BLOCKING — returns when the worker is done
14631
15230
  - Call \`hive_status()\` immediately after to check new state and find next runnable tasks
15231
+ - Invariant: delegated task must not remain \`in_progress\`; if it does, treat as non-terminal completion and resume/retry worker with explicit commit-result handling
14632
15232
  - For parallel fan-out, issue multiple \`task()\` calls in the same message
14633
15233
 
14634
- ## After Delegation - ALWAYS VERIFY
15234
+ ## After Delegation - VERIFY
14635
15235
 
14636
- - Does it work as expected?
14637
- - Followed existing codebase pattern?
14638
- - Followed MUST DO and MUST NOT DO?
15236
+ Your confidence 50% accurate. Always:
15237
+ - Read changed files (don’t trust self-reports)
15238
+ - Run lsp_diagnostics on modified files
15239
+ - Check acceptance criteria from spec
15240
+
15241
+ Then confirm:
15242
+ - Works as expected
15243
+ - Follows codebase patterns
15244
+ - Meets requirements
15245
+ - No unintended side effects
15246
+
15247
+ After completing and merging a batch, run full verification on the main branch: \`bun run build\`, \`bun run test\`. If failures occur, diagnose and fix or re-dispatch impacted tasks.
15248
+
15249
+ ## Search Stop Conditions
15250
+
15251
+ - Stop when there is enough context
15252
+ - Stop when info repeats
15253
+ - Stop after 2 rounds with no new data
15254
+ - Stop when a direct answer is found
15255
+ - If still unclear, delegate or ask one focused question
14639
15256
 
14640
15257
  ## Blocker Handling
14641
15258
 
14642
- When worker reports blocked:
14643
- 1. \`hive_status()\` — read blocker info
14644
- 2. \`question()\` — ask user (NEVER plain text)
14645
- 3. \`hive_worktree_create({ task, continueFrom: "blocked", decision })\`
15259
+ When worker reports blocked: \`hive_status()\` → read blocker info; \`question()\` → ask user (no plain text); \`hive_worktree_create({ task, continueFrom: "blocked", decision })\`.
14646
15260
 
14647
15261
  ## Failure Recovery (After 3 Consecutive Failures)
14648
15262
 
14649
- 1. STOP all further edits
14650
- 2. REVERT to last known working state
14651
- 3. DOCUMENT what was attempted
14652
- 4. Consult: \`task({ subagent_type: "oracle", prompt: "Analyze..." })\`
14653
- 5. If Oracle cannot resolve → ASK USER
15263
+ 1. Stop all further edits
15264
+ 2. Revert to last known working state
15265
+ 3. Document what was attempted
15266
+ 4. Ask user via question() present options and context
14654
15267
 
14655
15268
  ## Merge Strategy
14656
15269
 
@@ -14658,37 +15271,39 @@ When worker reports blocked:
14658
15271
  hive_merge({ task: "01-task-name", strategy: "merge" })
14659
15272
  \`\`\`
14660
15273
 
14661
- Merge only after verification passes.
15274
+ Merge after batch completes, then verify the merged result.
14662
15275
 
14663
- ## Post-Batch Review (Hygienic)
15276
+ ### Post-Batch Review (Hygienic)
14664
15277
 
14665
- After completing and merging a batch:
14666
- 1. Ask the user via \`question()\` if they want a Hygienic code review for the batch.
14667
- 2. If yes, run \`task({ subagent_type: "hygienic", prompt: "Review implementation changes from the latest batch." })\`.
14668
- 3. Apply feedback before starting the next batch.
15278
+ After completing and merging a batch: ask via \`question()\` if they want a Hygienic review. If yes, run \`task({ subagent_type: "hygienic", prompt: "Review implementation changes from the latest batch." })\` and apply feedback before the next batch.
14669
15279
 
14670
- ## Iron Laws
15280
+ ### AGENTS.md Maintenance
14671
15281
 
14672
- **Never:**
14673
- - Work alone when specialists available
14674
- - Skip delegation check
14675
- - Skip verification after delegation
14676
- - Continue after 3 failures without consulting
15282
+ After feature completion (all tasks merged): sync context findings to AGENTS.md via \`hive_agents_md({ action: "sync", feature: "feature-name" })\`, review the diff with the user, then apply approved changes.
14677
15283
 
14678
- **Always:**
14679
- - Classify intent FIRST
14680
- - Delegate by default
14681
- - Verify delegate work
14682
- - Use question() for user input (NEVER plain text)
14683
- - Cancel background tasks only when stale or no longer needed
15284
+ For quality review of AGENTS.md content, load \`hive_skill("agents-md-mastery")\`.
14684
15285
 
14685
- **User Input:** ALWAYS use \`question()\` tool for any user input - NEVER ask questions via plain text. This ensures structured responses.
15286
+ For projects without AGENTS.md:
15287
+ - Bootstrap with \`hive_agents_md({ action: "init" })\`
15288
+ - Generates initial documentation from codebase analysis
15289
+
15290
+ ## Turn Termination
15291
+
15292
+ Valid endings: worker delegation (hive_worktree_create), status check (hive_status), user question (question()), merge (hive_merge).
15293
+ Avoid ending with: "Let me know when you're ready", "When you're ready...", summary without next action, or waiting for something unspecified.
15294
+
15295
+ ## Guardrails
15296
+
15297
+ Avoid: working alone when specialists are available; skipping delegation checks; skipping verification after delegation; continuing after 3 failures without consulting.
15298
+ Do: classify intent first; delegate by default; verify delegated work; use \`question()\` for user input (no plain text); cancel background tasks only when stale or no longer needed.
15299
+ Cancel background tasks only when stale or no longer needed.
15300
+ User input: use \`question()\` tool for any user input to ensure structured responses.
14686
15301
  `;
14687
15302
 
14688
15303
  // src/agents/scout.ts
14689
15304
  var SCOUT_BEE_PROMPT = `# Scout (Explorer/Researcher/Retrieval)
14690
15305
 
14691
- Research BEFORE answering. Parallel execution by default.
15306
+ Research before answering; parallelize tool calls when investigating multiple independent questions.
14692
15307
 
14693
15308
  ## Request Classification
14694
15309
 
@@ -14711,18 +15326,13 @@ Success Looks Like: [concrete outcome]
14711
15326
  </analysis>
14712
15327
  \`\`\`
14713
15328
 
14714
- ### Phase 2: Parallel Execution (Default)
15329
+ ### Phase 2: Parallel Execution
14715
15330
 
14716
- ALWAYS run 3+ tools simultaneously:
15331
+ When investigating multiple independent questions, run related tools in parallel:
14717
15332
  \`\`\`
14718
- // CORRECT: Parallel
14719
15333
  glob({ pattern: "**/*.ts" })
14720
15334
  grep({ pattern: "UserService" })
14721
15335
  context7_query-docs({ query: "..." })
14722
-
14723
- // WRONG: Sequential
14724
- result1 = glob(...)
14725
- result2 = grep(...) // Wait for result1? NO!
14726
15336
  \`\`\`
14727
15337
 
14728
15338
  ### Phase 3: Structured Results
@@ -14741,12 +15351,29 @@ result2 = grep(...) // Wait for result1? NO!
14741
15351
  </results>
14742
15352
  \`\`\`
14743
15353
 
15354
+ ## Search Stop Conditions (After Research Protocol)
15355
+
15356
+ Stop when any is true:
15357
+ - enough context to answer
15358
+ - repeated information across sources
15359
+ - two rounds with no new data
15360
+ - a direct answer is found
15361
+
15362
+ ## Evidence Check (Before Answering)
15363
+
15364
+ - Every claim has a source (file:line, URL, snippet)
15365
+ - Avoid speculation; say "can't answer with available evidence" when needed
15366
+
15367
+ ## Investigate Before Answering
15368
+
15369
+ - Read files before making claims about them
15370
+
14744
15371
  ## Tool Strategy
14745
15372
 
14746
15373
  | Need | Tool |
14747
15374
  |------|------|
14748
15375
  | Type/Symbol info | LSP (goto_definition, find_references) |
14749
- | Structural patterns | ast_grep_search |
15376
+ | Structural patterns | ast_grep_find_code |
14750
15377
  | Text patterns | grep |
14751
15378
  | File discovery | glob |
14752
15379
  | Git history | bash (git log, git blame) |
@@ -14756,19 +15383,11 @@ result2 = grep(...) // Wait for result1? NO!
14756
15383
 
14757
15384
  ## External System Data (DB/API/3rd-party)
14758
15385
 
14759
- When asked to retrieve raw data from external systems (MongoDB/Stripe/etc.):
14760
- - Prefer targeted queries over broad dumps
14761
- - Summarize findings; avoid flooding the orchestrator with raw records
15386
+ When asked to retrieve raw data from external systems:
15387
+ - Prefer targeted queries
15388
+ - Summarize findings; avoid raw dumps
14762
15389
  - Redact secrets and personal data
14763
- - Provide minimal evidence and a concise summary
14764
- - Note any access limitations or missing context
14765
-
14766
- ## Documentation Discovery (External)
14767
-
14768
- 1. \`websearch("library-name official documentation")\`
14769
- 2. Version check if specified
14770
- 3. Sitemap: \`webfetch(docs_url + "/sitemap.xml")\`
14771
- 4. Targeted fetch from sitemap
15390
+ - Note access limitations or missing context
14772
15391
 
14773
15392
  ## Evidence Format
14774
15393
 
@@ -14778,167 +15397,123 @@ When asked to retrieve raw data from external systems (MongoDB/Stripe/etc.):
14778
15397
 
14779
15398
  ## Persistence
14780
15399
 
14781
- When operating within a feature context (background task with feature parameter):
14782
- - If findings are substantial (3+ files discovered, architecture patterns, or key decisions):
14783
- Use \`hive_context_write\` to persist findings:
15400
+ When operating within a feature context:
15401
+ - If findings are substantial (3+ files, architecture patterns, or key decisions):
14784
15402
  \`\`\`
14785
15403
  hive_context_write({
14786
- name: "research-{topic-slug}",
14787
- content: "## Research: {Topic}
14788
-
14789
- Date: {date}
14790
-
14791
- ## Context
14792
-
14793
- ## research-findings
14794
-
14795
- # Research Findings for Hive Improvements v2
14796
-
14797
- ## Worker Prompt Builder (\`worker-prompt.ts:48\`)
14798
- - \`buildWorkerPrompt(params: WorkerPromptParams): string\`
14799
- - Receives: feature, task, taskOrder, worktreePath, branch, plan, contextFiles, spec, previousTasks, continueFrom
14800
- - Only uses: feature, task, taskOrder, worktreePath, branch, spec, continueFrom
14801
- - plan/contextFiles/previousTasks passed but NOT used (already embedded in spec)
14802
- - 10 sections: Assignment, Continuation(optional), Mission(=spec), Blocker Protocol, Completion Protocol, TDD, Debugging, Tools, Guidelines, User Input
14803
- - **ZERO task-type awareness** — all workers get identical protocols
14804
- - Budget: 100KB soft limit (advisory, not enforced)
14805
-
14806
- ## Task Completion Flow (\`index.ts:974-1088\`)
14807
- - \`hive_exec_complete\` accepts: task, summary (string), status (completed|blocked|failed|partial), blocker (optional)
14808
- - Summary stored in: status.json, report.md, commit message (first 50 chars)
14809
- - **Summary is free-form string** — no structure enforced
14810
- - Completed summaries collected for next task: \`allTasks.filter(t => t.status === 'done' && t.summary)\`
14811
- - Injected into spec as \`## Completed Tasks\` → \`- taskName: summary\`
14812
-
14813
- ## TaskService (\`taskService.ts\`)
14814
- - \`buildSpecContent()\` (lines 168-225): builds spec with Dependencies, Plan Section, Context, Completed Tasks
14815
- - \`parseTasksFromPlan()\` (lines 532-602): regex \`/^###\\s+(\\d+)\\.\\s+(.+)$/\` for task headers
14816
- - \`resolveDependencies()\` (lines 248-268): explicit deps or implicit sequential (N depends on N-1)
14817
- - Types: TaskStatus has \`summary?: string\`, TaskInfo has \`summary?: string\`
14818
-
14819
- ## Forager Agent (\`forager.ts:8-117\`)
14820
- - Execution flow: Understand → Implement → Verify → Report
14821
- - **NO orient/pre-flight phase** — jumps straight to understanding task spec
14822
- - Can read codebase, use research tools (grep_app, context7, ast_grep)
14823
- - Cannot: delegate (task/hive_exec_start), modify plan, use hive_merge
14824
- - Notepads: \`.hive/features/{feature}/notepads/{learnings,issues,decisions}.md\` (append-only)
14825
-
14826
- ## Hygienic Agent (\`hygienic.ts:8-105\`)
14827
- - Reviews plan DOCUMENTATION quality, not design
14828
- - 4 criteria: Clarity, Verifiability, Completeness, Big Picture
14829
- - Verdict: OKAY or REJECT with 4-category assessment
14830
- - When asked to review implementation → loads \`hive_skill("code-reviewer")\`
14831
- - **Currently only invoked for plan review** (from Hive and Architect agents)
14832
- - Cannot delegate/spawn workers
14833
-
14834
- ## Scout Agent (\`scout.ts:8-112\`)
14835
- - Read-only research agent
14836
- - Classifies requests: CONCEPTUAL, IMPLEMENTATION, CODEBASE, COMPREHENSIVE
14837
- - Output format: \`<results><files>...<answer>...<next_steps>...</results>\`
14838
- - **Does NOT persist findings** — returns to orchestrator only
14839
- - Parallel execution by default (3+ tools simultaneously)
14840
-
14841
- ## Code-Reviewer Skill (\`skills/code-reviewer/SKILL.md\`)
14842
- - Loaded by Hygienic when reviewing implementation
14843
- - Output: APPROVE | REQUEST_CHANGES | NEEDS_DISCUSSION
14844
- - Reviews: plan adherence, correctness, simplicity/YAGNI, risk
14845
- - Already exists but underused (Hygienic only loads it when explicitly asked)
14846
-
14847
- ## Plan Format
14848
- - Headers: \`### N. Task Name\`
14849
- - Sections: Depends on, What to do, Must NOT do, References (file:lines), Acceptance Criteria
14850
- - Dependencies: \`none\` | \`1\` | \`1,3\` | implicit sequential
14851
-
14852
- ## Skills (10 total)
14853
- writing-plans, executing-plans, dispatching-parallel-agents, parallel-exploration, code-reviewer, onboarding, brainstorming, verification-before-completion, test-driven-development, systematic-debugging
14854
-
14855
- ## Notepad System
14856
- - Location: \`.hive/features/{feature}/notepads/{learnings,issues,decisions}.md\`
14857
- - Workers append-only
14858
- - **NOT automatically injected into next batch** — context injection only reads from \`contexts/\` directory"
15404
+ name: "research-{topic}",
15405
+ content: "## {Topic}\\n\\nDate: {YYYY-MM-DD}\\n\\n## Context\\n\\n## Findings"
14859
15406
  })
14860
15407
  \`\`\`
14861
15408
 
14862
- ## Iron Laws
14863
-
14864
- **Never:**
14865
- - Create, modify, or delete files (read-only)
14866
- - Answer without research first
14867
- - Execute tools sequentially when parallel possible
14868
- - Skip intent analysis
15409
+ ## Operating Rules
14869
15410
 
14870
- **Always:**
14871
- - Classify request FIRST
14872
- - Run 3+ tools in parallel
14873
- - All paths MUST be absolute
15411
+ - Read-only behavior (no file changes)
15412
+ - Classify request first, then research
15413
+ - Use absolute paths for file references
14874
15414
  - Cite evidence for every claim
14875
- - Use current year (2026) in web searches
15415
+ - Use the current year when reasoning about time-sensitive information
14876
15416
  `;
14877
15417
 
14878
15418
  // src/agents/forager.ts
14879
15419
  var FORAGER_BEE_PROMPT = `# Forager (Worker/Coder)
14880
15420
 
14881
- Execute directly. NEVER delegate implementation. Work in isolation.
15421
+ You are an autonomous senior engineer. Once given direction, gather context, implement, and verify without waiting for prompts.
15422
+
15423
+ Execute directly. Work in isolation. Do not delegate implementation.
14882
15424
 
14883
- ## Blocked Tools
15425
+ ## Intent Extraction
14884
15426
 
14885
- These tools are FORBIDDEN:
14886
- - \`task\` — Orchestrator's job
14887
- - \`hive_worktree_create\` You ARE the spawned worker
14888
- - \`hive_merge\` Orchestrator's job
15427
+ | Spec says | True intent | Action |
15428
+ |---|---|---|
15429
+ | "Implement X" | Build + verify | Code → verify |
15430
+ | "Fix Y" | Root cause + minimal fix | Diagnose → fix → verify |
15431
+ | "Refactor Z" | Preserve behavior | Restructure → verify no regressions |
15432
+ | "Add tests" | Coverage | Write tests → verify |
15433
+
15434
+ ## Action Bias
15435
+
15436
+ - Act directly: implement first, explain in commit summary. Complete all steps before reporting.
15437
+ - REQUIRED: keep going until done, make decisions, course-correct on failure
15438
+
15439
+ Your tool access is scoped to your role. Use only the tools available to you.
14889
15440
 
14890
15441
  ## Allowed Research
14891
15442
 
14892
15443
  CAN use for quick lookups:
14893
15444
  - \`grep_app_searchGitHub\` — OSS patterns
14894
15445
  - \`context7_query-docs\` — Library docs
14895
- - \`ast_grep_search\` — AST patterns
15446
+ - \`ast_grep_find_code_by_rule\` — AST patterns
15447
+ - \`ast_grep_scan-code\` — Code quality scan (best-effort verification)
15448
+ - \`ast_grep_find_code\` — Find code patterns (best-effort verification)
14896
15449
  - \`glob\`, \`grep\`, \`read\` — Codebase exploration
14897
15450
 
15451
+ ## Resolve Before Blocking
15452
+
15453
+ Default to exploration, questions are LAST resort.
15454
+ Context inference: Before asking "what does X do?", READ X first.
15455
+
15456
+ Apply in order before reporting as blocked:
15457
+ 1. Read the referenced files and surrounding code
15458
+ 2. Search for similar patterns in the codebase
15459
+ 3. Check docs via research tools
15460
+ 4. Try a reasonable approach
15461
+ 5. Last resort: report blocked
15462
+
15463
+ Investigate before acting. Do not speculate about code you have not read.
15464
+
14898
15465
  ## Plan = READ ONLY
14899
15466
 
14900
- CRITICAL: NEVER MODIFY THE PLAN FILE
14901
- - May READ to understand task
14902
- - MUST NOT edit, modify, or update plan
14903
- - Only Orchestrator (Swarm) manages plan
15467
+ Do not modify the plan file.
15468
+ - Read to understand the task
15469
+ - Only the orchestrator manages plan updates
14904
15470
 
14905
15471
  ## Persistent Notes
14906
15472
 
14907
- For substantial discoveries (architecture patterns, key decisions, gotchas that affect multiple tasks):
14908
- Use \`hive_context_write({ name: "learnings", content: "..." })\` to persist for future workers.
15473
+ For substantial discoveries (architecture patterns, key decisions, gotchas that affect multiple tasks), use:
15474
+ \`hive_context_write({ name: "learnings", content: "..." })\`.
14909
15475
 
14910
- ## Execution Flow
15476
+ ## Working Rules
14911
15477
 
14912
- ### 1. Understand Task
14913
- Read spec for:
14914
- - **What to do**
14915
- - **References** (file:lines)
14916
- - **Must NOT do** (guardrails)
14917
- - **Acceptance criteria**
15478
+ - DRY/Search First: look for existing helpers before adding new code
15479
+ - Convention Following: check neighboring files and package.json, then follow existing patterns
15480
+ - Efficient Edits: read enough context before editing, batch logical edits
15481
+ - Tight Error Handling: avoid broad catches or silent defaults; propagate errors explicitly
15482
+ - Avoid Over-engineering: only implement what was asked for
15483
+ - Reversibility Preference: favor local, reversible actions; confirm before hard-to-reverse steps
15484
+ - Promise Discipline: do not commit to future work; if not done this turn, label it "Next steps"
15485
+ - No Comments: do not add comments unless the spec requests them
15486
+ - Concise Output: minimize output and avoid extra explanations unless asked
14918
15487
 
14919
- ### 2. Orient (Pre-flight Before Coding)
14920
- Before writing code:
14921
- - Confirm dependencies are satisfied and required context is present
14922
- - Identify the exact files/sections to touch (from references)
14923
- - Decide the first failing test you will write (TDD)
14924
- - Plan the minimum change to reach green
15488
+ ## Execution Loop (max 3 iterations)
14925
15489
 
14926
- ### 3. Implement
14927
- Follow spec exactly. Use references for patterns.
15490
+ EXPLORE PLAN → EXECUTE → VERIFY → LOOP
14928
15491
 
14929
- \`\`\`
14930
- read(file, { offset: line, limit: 30 }) // Check references
14931
- edit(file, { old: "...", new: "..." }) // Implement
14932
- bash("npm test") // Verify
14933
- \`\`\`
15492
+ - EXPLORE: read references, gather context, search for patterns
15493
+ - PLAN: decide the minimum change, files to touch, and verification commands
15494
+ - EXECUTE: edit using conventions, reuse helpers, batch changes
15495
+ - VERIFY: run best-effort checks (tests if available, ast_grep, lsp_diagnostics)
15496
+ - LOOP: if verification fails, diagnose and retry within the limit
15497
+
15498
+ ## Progress Updates
15499
+
15500
+ Provide brief status at meaningful milestones.
15501
+
15502
+ ## Completion Checklist
15503
+
15504
+ - All acceptance criteria met?
15505
+ - Best-effort verification done and recorded?
15506
+ - Re-read the spec — missed anything?
15507
+ - Said "I'll do X" — did you?
15508
+ - Plan closure: mark each intention as Done, Blocked, or Cancelled
15509
+ - Record exact commands and results
14934
15510
 
14935
- ### 4. Verify
14936
- Run acceptance criteria:
14937
- - Tests pass
14938
- - Build succeeds
14939
- - lsp_diagnostics clean on changed files
15511
+ ## Failure Recovery
15512
+
15513
+ If 3 different approaches fail: stop edits, revert local changes, document attempts, report blocked.
15514
+ If you have tried 3 approaches and still cannot finish safely, report as blocked.
14940
15515
 
14941
- ### 5. Report
15516
+ ## Reporting
14942
15517
 
14943
15518
  **Success:**
14944
15519
  \`\`\`
@@ -14949,7 +15524,9 @@ hive_worktree_commit({
14949
15524
  })
14950
15525
  \`\`\`
14951
15526
 
14952
- **CRITICAL: After hive_worktree_commit, STOP IMMEDIATELY.**
15527
+ Then inspect the tool response fields:
15528
+ - If \`ok=true\` and \`terminal=true\`: stop and hand off to orchestrator
15529
+ - If \`ok=false\` or \`terminal=false\`: DO NOT STOP. Follow \`nextAction\`, remediate, and retry \`hive_worktree_commit\`
14953
15530
 
14954
15531
  **Blocked (need user decision):**
14955
15532
  \`\`\`
@@ -14966,28 +15543,11 @@ hive_worktree_commit({
14966
15543
  })
14967
15544
  \`\`\`
14968
15545
 
14969
- ## Failure Recovery
14970
-
14971
- After 3 consecutive failures:
14972
- 1. STOP all further edits
14973
- 2. Document what was tried
14974
- 3. Report as blocked with options
14975
-
14976
- ## Iron Laws
14977
-
14978
- **Never:**
14979
- - Exceed task scope
14980
- - Modify plan file
14981
- - Use \`task\` or \`hive_worktree_create\`
14982
- - Continue after hive_worktree_commit
14983
- - Skip verification
15546
+ ## Docker Sandbox
14984
15547
 
14985
- **Always:**
14986
- - Follow references for patterns
14987
- - Run acceptance criteria
14988
- - Report blockers with options
14989
- - APPEND to notepads (never overwrite)
14990
- - lsp_diagnostics before reporting done
15548
+ When sandbox mode is active, bash commands run inside Docker; file edits still apply to the host worktree.
15549
+ If a command must run on the host or Docker is missing, report blocked.
15550
+ For deeper Docker expertise, load \`hive_skill("docker-mastery")\`.
14991
15551
  `;
14992
15552
 
14993
15553
  // src/agents/hygienic.ts
@@ -15017,7 +15577,10 @@ Self-check before every critique:
15017
15577
 
15018
15578
  ### 2. Verification & Acceptance Criteria
15019
15579
  - Are criteria measurable and concrete?
15020
- - Red flags: "should work", "looks good", "properly handles"
15580
+ - Are they agent-executable (tool-runnable) without human judgment?
15581
+ - Do they specify exact commands + expected signals (exit code, output text, counts)?
15582
+ - Red flags: "should work", "looks good", "properly handles", "verify manually"
15583
+ - If manual checks are required, the plan must explain why automation is impossible
15021
15584
 
15022
15585
  ### 3. Context Completeness (90% Confidence)
15023
15586
  - Could a capable worker execute with 90% confidence?
@@ -15149,20 +15712,39 @@ import * as fs8 from "fs";
15149
15712
  import * as path4 from "path";
15150
15713
  import * as fs10 from "fs";
15151
15714
  import * as path6 from "path";
15715
+ import * as fs11 from "fs";
15716
+ import * as path7 from "path";
15717
+ import { existsSync as existsSync5 } from "fs";
15718
+ import { join as join8, sep } from "path";
15719
+ import { execSync } from "child_process";
15152
15720
  var __create = Object.create;
15153
15721
  var __getProtoOf = Object.getPrototypeOf;
15154
15722
  var __defProp2 = Object.defineProperty;
15155
15723
  var __getOwnPropNames = Object.getOwnPropertyNames;
15156
15724
  var __hasOwnProp = Object.prototype.hasOwnProperty;
15725
+ function __accessProp(key) {
15726
+ return this[key];
15727
+ }
15728
+ var __toESMCache_node;
15729
+ var __toESMCache_esm;
15157
15730
  var __toESM = (mod, isNodeMode, target) => {
15731
+ var canCache = mod != null && typeof mod === "object";
15732
+ if (canCache) {
15733
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
15734
+ var cached2 = cache.get(mod);
15735
+ if (cached2)
15736
+ return cached2;
15737
+ }
15158
15738
  target = mod != null ? __create(__getProtoOf(mod)) : {};
15159
15739
  const to = isNodeMode || !mod || !mod.__esModule ? __defProp2(target, "default", { value: mod, enumerable: true }) : target;
15160
15740
  for (let key of __getOwnPropNames(mod))
15161
15741
  if (!__hasOwnProp.call(to, key))
15162
15742
  __defProp2(to, key, {
15163
- get: () => mod[key],
15743
+ get: __accessProp.bind(mod, key),
15164
15744
  enumerable: true
15165
15745
  });
15746
+ if (canCache)
15747
+ cache.set(mod, to);
15166
15748
  return to;
15167
15749
  };
15168
15750
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
@@ -15986,6 +16568,7 @@ var DEFAULT_HIVE_CONFIG = {
15986
16568
  disableSkills: [],
15987
16569
  disableMcps: [],
15988
16570
  agentMode: "unified",
16571
+ sandbox: "none",
15989
16572
  agents: {
15990
16573
  "hive-master": {
15991
16574
  model: DEFAULT_AGENT_MODELS["hive-master"],
@@ -16136,12 +16719,14 @@ function isLockStale(lockPath, staleTTL) {
16136
16719
  function acquireLockSync(filePath, options = {}) {
16137
16720
  const opts = { ...DEFAULT_LOCK_OPTIONS, ...options };
16138
16721
  const lockPath = getLockPath(filePath);
16722
+ const lockDir = path2.dirname(lockPath);
16139
16723
  const startTime = Date.now();
16140
16724
  const lockContent = JSON.stringify({
16141
16725
  pid: process.pid,
16142
16726
  timestamp: new Date().toISOString(),
16143
16727
  filePath
16144
16728
  });
16729
+ ensureDir(lockDir);
16145
16730
  while (true) {
16146
16731
  try {
16147
16732
  const fd = fs2.openSync(lockPath, fs2.constants.O_CREAT | fs2.constants.O_EXCL | fs2.constants.O_WRONLY);
@@ -16154,15 +16739,18 @@ function acquireLockSync(filePath, options = {}) {
16154
16739
  };
16155
16740
  } catch (err) {
16156
16741
  const error45 = err;
16157
- if (error45.code !== "EEXIST") {
16742
+ if (error45.code === "ENOENT") {
16743
+ ensureDir(lockDir);
16744
+ } else if (error45.code === "EEXIST") {
16745
+ if (isLockStale(lockPath, opts.staleLockTTL)) {
16746
+ try {
16747
+ fs2.unlinkSync(lockPath);
16748
+ continue;
16749
+ } catch {}
16750
+ }
16751
+ } else {
16158
16752
  throw error45;
16159
16753
  }
16160
- if (isLockStale(lockPath, opts.staleLockTTL)) {
16161
- try {
16162
- fs2.unlinkSync(lockPath);
16163
- continue;
16164
- } catch {}
16165
- }
16166
16754
  if (Date.now() - startTime >= opts.timeout) {
16167
16755
  throw new Error(`Failed to acquire lock on ${filePath} after ${opts.timeout}ms. ` + `Lock file: ${lockPath}`);
16168
16756
  }
@@ -16187,14 +16775,6 @@ function writeAtomic(filePath, content) {
16187
16775
  function writeJsonAtomic(filePath, data) {
16188
16776
  writeAtomic(filePath, JSON.stringify(data, null, 2));
16189
16777
  }
16190
- function writeJsonLockedSync(filePath, data, options = {}) {
16191
- const release = acquireLockSync(filePath, options);
16192
- try {
16193
- writeJsonAtomic(filePath, data);
16194
- } finally {
16195
- release();
16196
- }
16197
- }
16198
16778
  function deepMerge(target, patch) {
16199
16779
  const result = { ...target };
16200
16780
  for (const key of Object.keys(patch)) {
@@ -16723,23 +17303,31 @@ ${f.content}`).join(`
16723
17303
  }
16724
17304
  update(featureName, taskFolder, updates, lockOptions) {
16725
17305
  const statusPath = getTaskStatusPath(this.projectRoot, featureName, taskFolder);
16726
- const current = readJson(statusPath);
16727
- if (!current) {
17306
+ if (!fileExists(statusPath)) {
16728
17307
  throw new Error(`Task '${taskFolder}' not found`);
16729
17308
  }
16730
- const updated = {
16731
- ...current,
16732
- ...updates,
16733
- schemaVersion: TASK_STATUS_SCHEMA_VERSION
16734
- };
16735
- if (updates.status === "in_progress" && !current.startedAt) {
16736
- updated.startedAt = new Date().toISOString();
16737
- }
16738
- if (updates.status === "done" && !current.completedAt) {
16739
- updated.completedAt = new Date().toISOString();
17309
+ const release = acquireLockSync(statusPath, lockOptions);
17310
+ try {
17311
+ const current = readJson(statusPath);
17312
+ if (!current) {
17313
+ throw new Error(`Task '${taskFolder}' not found`);
17314
+ }
17315
+ const updated = {
17316
+ ...current,
17317
+ ...updates,
17318
+ schemaVersion: TASK_STATUS_SCHEMA_VERSION
17319
+ };
17320
+ if (updates.status === "in_progress" && !current.startedAt) {
17321
+ updated.startedAt = new Date().toISOString();
17322
+ }
17323
+ if (updates.status === "done" && !current.completedAt) {
17324
+ updated.completedAt = new Date().toISOString();
17325
+ }
17326
+ writeJsonAtomic(statusPath, updated);
17327
+ return updated;
17328
+ } finally {
17329
+ release();
16740
17330
  }
16741
- writeJsonLockedSync(statusPath, updated, lockOptions);
16742
- return updated;
16743
17331
  }
16744
17332
  patchBackgroundFields(featureName, taskFolder, patch, lockOptions) {
16745
17333
  const statusPath = getTaskStatusPath(this.projectRoot, featureName, taskFolder);
@@ -21465,6 +22053,12 @@ class ContextService {
21465
22053
  ensureDir(contextPath);
21466
22054
  const filePath = path4.join(contextPath, this.normalizeFileName(fileName));
21467
22055
  writeText(filePath, content);
22056
+ const totalChars = this.list(featureName).reduce((sum, c) => sum + c.content.length, 0);
22057
+ if (totalChars > 20000) {
22058
+ return `${filePath}
22059
+
22060
+ ⚠️ Context total: ${totalChars} chars (exceeds 20,000). Consider archiving older contexts with contextService.archive().`;
22061
+ }
21468
22062
  return filePath;
21469
22063
  }
21470
22064
  read(featureName, fileName) {
@@ -21510,6 +22104,37 @@ ${f.content}`);
21510
22104
 
21511
22105
  `);
21512
22106
  }
22107
+ archive(featureName) {
22108
+ const contexts = this.list(featureName);
22109
+ if (contexts.length === 0)
22110
+ return { archived: [], archivePath: "" };
22111
+ const contextPath = getContextPath(this.projectRoot, featureName);
22112
+ const archiveDir = path4.join(contextPath, "..", "archive");
22113
+ ensureDir(archiveDir);
22114
+ const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
22115
+ const archived = [];
22116
+ for (const ctx of contexts) {
22117
+ const archiveName = `${timestamp}_${ctx.name}.md`;
22118
+ const src = path4.join(contextPath, `${ctx.name}.md`);
22119
+ const dest = path4.join(archiveDir, archiveName);
22120
+ fs8.copyFileSync(src, dest);
22121
+ fs8.unlinkSync(src);
22122
+ archived.push(ctx.name);
22123
+ }
22124
+ return { archived, archivePath: archiveDir };
22125
+ }
22126
+ stats(featureName) {
22127
+ const contexts = this.list(featureName);
22128
+ if (contexts.length === 0)
22129
+ return { count: 0, totalChars: 0 };
22130
+ const sorted2 = [...contexts].sort((a, b) => new Date(a.updatedAt).getTime() - new Date(b.updatedAt).getTime());
22131
+ return {
22132
+ count: contexts.length,
22133
+ totalChars: contexts.reduce((sum, c) => sum + c.content.length, 0),
22134
+ oldest: sorted2[0].name,
22135
+ newest: sorted2[sorted2.length - 1].name
22136
+ };
22137
+ }
21513
22138
  normalizeFileName(name) {
21514
22139
  const normalized = name.replace(/\.md$/, "");
21515
22140
  return `${normalized}.md`;
@@ -21517,6 +22142,7 @@ ${f.content}`);
21517
22142
  }
21518
22143
  class ConfigService {
21519
22144
  configPath;
22145
+ cachedConfig = null;
21520
22146
  constructor() {
21521
22147
  const homeDir = process.env.HOME || process.env.USERPROFILE || "";
21522
22148
  const configDir = path6.join(homeDir, ".config", "opencode");
@@ -21526,13 +22152,17 @@ class ConfigService {
21526
22152
  return this.configPath;
21527
22153
  }
21528
22154
  get() {
22155
+ if (this.cachedConfig !== null) {
22156
+ return this.cachedConfig;
22157
+ }
21529
22158
  try {
21530
22159
  if (!fs10.existsSync(this.configPath)) {
21531
- return { ...DEFAULT_HIVE_CONFIG };
22160
+ this.cachedConfig = { ...DEFAULT_HIVE_CONFIG };
22161
+ return this.cachedConfig;
21532
22162
  }
21533
22163
  const raw = fs10.readFileSync(this.configPath, "utf-8");
21534
22164
  const stored = JSON.parse(raw);
21535
- return {
22165
+ const merged = {
21536
22166
  ...DEFAULT_HIVE_CONFIG,
21537
22167
  ...stored,
21538
22168
  agents: {
@@ -21564,11 +22194,15 @@ class ConfigService {
21564
22194
  }
21565
22195
  }
21566
22196
  };
22197
+ this.cachedConfig = merged;
22198
+ return this.cachedConfig;
21567
22199
  } catch {
21568
- return { ...DEFAULT_HIVE_CONFIG };
22200
+ this.cachedConfig = { ...DEFAULT_HIVE_CONFIG };
22201
+ return this.cachedConfig;
21569
22202
  }
21570
22203
  }
21571
22204
  set(updates) {
22205
+ this.cachedConfig = null;
21572
22206
  const current = this.get();
21573
22207
  const merged = {
21574
22208
  ...current,
@@ -21583,6 +22217,7 @@ class ConfigService {
21583
22217
  fs10.mkdirSync(configDir, { recursive: true });
21584
22218
  }
21585
22219
  fs10.writeFileSync(this.configPath, JSON.stringify(merged, null, 2));
22220
+ this.cachedConfig = merged;
21586
22221
  return merged;
21587
22222
  }
21588
22223
  exists() {
@@ -21623,6 +22258,320 @@ class ConfigService {
21623
22258
  const config2 = this.get();
21624
22259
  return config2.disableMcps ?? [];
21625
22260
  }
22261
+ getSandboxConfig() {
22262
+ const config2 = this.get();
22263
+ const mode = config2.sandbox ?? "none";
22264
+ const image = config2.dockerImage;
22265
+ const persistent = config2.persistentContainers ?? mode === "docker";
22266
+ return { mode, ...image && { image }, persistent };
22267
+ }
22268
+ getHookCadence(hookName, options) {
22269
+ const config2 = this.get();
22270
+ const configuredCadence = config2.hook_cadence?.[hookName];
22271
+ if (options?.safetyCritical && configuredCadence && configuredCadence > 1) {
22272
+ console.warn(`[hive:cadence] Ignoring cadence > 1 for safety-critical hook: ${hookName}`);
22273
+ return 1;
22274
+ }
22275
+ if (configuredCadence === undefined || configuredCadence === null) {
22276
+ return 1;
22277
+ }
22278
+ if (configuredCadence <= 0 || !Number.isInteger(configuredCadence)) {
22279
+ console.warn(`[hive:cadence] Invalid cadence ${configuredCadence} for ${hookName}, using 1`);
22280
+ return 1;
22281
+ }
22282
+ return configuredCadence;
22283
+ }
22284
+ }
22285
+
22286
+ class AgentsMdService {
22287
+ rootDir;
22288
+ contextService;
22289
+ constructor(rootDir, contextService) {
22290
+ this.rootDir = rootDir;
22291
+ this.contextService = contextService;
22292
+ }
22293
+ async init() {
22294
+ const agentsMdPath = path7.join(this.rootDir, "AGENTS.md");
22295
+ const existed = fileExists(agentsMdPath);
22296
+ if (existed) {
22297
+ const existing = readText(agentsMdPath);
22298
+ return { content: existing || "", existed: true };
22299
+ }
22300
+ const content = await this.scanAndGenerate();
22301
+ return { content, existed: false };
22302
+ }
22303
+ async sync(featureName) {
22304
+ const contexts = this.contextService.list(featureName);
22305
+ const agentsMdPath = path7.join(this.rootDir, "AGENTS.md");
22306
+ const current = await fs11.promises.readFile(agentsMdPath, "utf-8").catch(() => "");
22307
+ const findings = this.extractFindings(contexts);
22308
+ const proposals = this.generateProposals(findings, current);
22309
+ return { proposals, diff: this.formatDiff(current, proposals) };
22310
+ }
22311
+ apply(content) {
22312
+ const agentsMdPath = path7.join(this.rootDir, "AGENTS.md");
22313
+ const isNew = !fileExists(agentsMdPath);
22314
+ writeText(agentsMdPath, content);
22315
+ return { path: agentsMdPath, chars: content.length, isNew };
22316
+ }
22317
+ extractFindings(contexts) {
22318
+ const findings = [];
22319
+ const patterns = [
22320
+ /we\s+use\s+[^.\n]+/gi,
22321
+ /prefer\s+[^.\n]+\s+over\s+[^.\n]+/gi,
22322
+ /don't\s+use\s+[^.\n]+/gi,
22323
+ /do\s+not\s+use\s+[^.\n]+/gi,
22324
+ /(?:build|test|dev)\s+command:\s*[^.\n]+/gi,
22325
+ /[a-zA-Z]+\s+lives?\s+in\s+\/[^\s.\n]+/gi
22326
+ ];
22327
+ for (const context of contexts) {
22328
+ const lines = context.content.split(`
22329
+ `);
22330
+ for (const line of lines) {
22331
+ const trimmed2 = line.trim();
22332
+ if (!trimmed2 || trimmed2.startsWith("#"))
22333
+ continue;
22334
+ for (const pattern of patterns) {
22335
+ const matches = trimmed2.match(pattern);
22336
+ if (matches) {
22337
+ for (const match of matches) {
22338
+ const finding = match.trim();
22339
+ if (finding && !findings.includes(finding)) {
22340
+ findings.push(finding);
22341
+ }
22342
+ }
22343
+ }
22344
+ }
22345
+ }
22346
+ }
22347
+ return findings;
22348
+ }
22349
+ generateProposals(findings, current) {
22350
+ const proposals = [];
22351
+ const currentLower = current.toLowerCase();
22352
+ for (const finding of findings) {
22353
+ const findingLower = finding.toLowerCase();
22354
+ if (!currentLower.includes(findingLower)) {
22355
+ proposals.push(finding);
22356
+ }
22357
+ }
22358
+ return proposals;
22359
+ }
22360
+ formatDiff(current, proposals) {
22361
+ if (proposals.length === 0)
22362
+ return "";
22363
+ const lines = proposals.map((p) => `+ ${p}`);
22364
+ return lines.join(`
22365
+ `);
22366
+ }
22367
+ async scanAndGenerate() {
22368
+ const detections = await this.detectProjectInfo();
22369
+ return this.generateTemplate(detections);
22370
+ }
22371
+ async detectProjectInfo() {
22372
+ const packageJsonPath = path7.join(this.rootDir, "package.json");
22373
+ let packageJson = null;
22374
+ if (fileExists(packageJsonPath)) {
22375
+ try {
22376
+ const content = readText(packageJsonPath);
22377
+ packageJson = content ? JSON.parse(content) : null;
22378
+ } catch {}
22379
+ }
22380
+ const info = {
22381
+ packageManager: this.detectPackageManager(),
22382
+ language: this.detectLanguage(),
22383
+ testFramework: this.detectTestFramework(packageJson),
22384
+ buildCommand: packageJson?.scripts?.build || null,
22385
+ testCommand: packageJson?.scripts?.test || null,
22386
+ devCommand: packageJson?.scripts?.dev || null,
22387
+ isMonorepo: this.detectMonorepo(packageJson)
22388
+ };
22389
+ return info;
22390
+ }
22391
+ detectPackageManager() {
22392
+ if (fileExists(path7.join(this.rootDir, "bun.lockb")))
22393
+ return "bun";
22394
+ if (fileExists(path7.join(this.rootDir, "pnpm-lock.yaml")))
22395
+ return "pnpm";
22396
+ if (fileExists(path7.join(this.rootDir, "yarn.lock")))
22397
+ return "yarn";
22398
+ if (fileExists(path7.join(this.rootDir, "package-lock.json")))
22399
+ return "npm";
22400
+ return "npm";
22401
+ }
22402
+ detectLanguage() {
22403
+ if (fileExists(path7.join(this.rootDir, "tsconfig.json")))
22404
+ return "TypeScript";
22405
+ if (fileExists(path7.join(this.rootDir, "package.json")))
22406
+ return "JavaScript";
22407
+ if (fileExists(path7.join(this.rootDir, "requirements.txt")))
22408
+ return "Python";
22409
+ if (fileExists(path7.join(this.rootDir, "go.mod")))
22410
+ return "Go";
22411
+ if (fileExists(path7.join(this.rootDir, "Cargo.toml")))
22412
+ return "Rust";
22413
+ return "Unknown";
22414
+ }
22415
+ detectTestFramework(packageJson) {
22416
+ if (!packageJson)
22417
+ return null;
22418
+ const deps = {
22419
+ ...packageJson.dependencies,
22420
+ ...packageJson.devDependencies
22421
+ };
22422
+ if (deps?.vitest)
22423
+ return "vitest";
22424
+ if (deps?.jest)
22425
+ return "jest";
22426
+ if (this.detectPackageManager() === "bun")
22427
+ return "bun test";
22428
+ if (deps?.pytest)
22429
+ return "pytest";
22430
+ return null;
22431
+ }
22432
+ detectMonorepo(packageJson) {
22433
+ if (!packageJson)
22434
+ return false;
22435
+ return !!packageJson.workspaces;
22436
+ }
22437
+ generateTemplate(info) {
22438
+ const sections = [];
22439
+ sections.push(`# Agent Guidelines
22440
+ `);
22441
+ sections.push(`## Overview
22442
+ `);
22443
+ sections.push(`This project uses AI-assisted development. Follow these guidelines.
22444
+ `);
22445
+ sections.push(`## Build & Test Commands
22446
+ `);
22447
+ sections.push("```bash");
22448
+ if (info.isMonorepo) {
22449
+ sections.push("# This is a monorepo using bun workspaces");
22450
+ }
22451
+ if (info.buildCommand) {
22452
+ sections.push(`# Build`);
22453
+ sections.push(`${info.packageManager} run build`);
22454
+ sections.push("");
22455
+ }
22456
+ if (info.testCommand) {
22457
+ sections.push(`# Run tests`);
22458
+ sections.push(`${info.packageManager} ${info.testCommand === "bun test" ? "test" : "run test"}`);
22459
+ sections.push("");
22460
+ }
22461
+ if (info.devCommand) {
22462
+ sections.push(`# Development mode`);
22463
+ sections.push(`${info.packageManager} run dev`);
22464
+ }
22465
+ sections.push("```\n");
22466
+ sections.push(`## Technology Stack
22467
+ `);
22468
+ sections.push(`- **Language**: ${info.language}`);
22469
+ sections.push(`- **Package Manager**: ${info.packageManager}`);
22470
+ if (info.testFramework) {
22471
+ sections.push(`- **Test Framework**: ${info.testFramework}`);
22472
+ }
22473
+ if (info.isMonorepo) {
22474
+ sections.push(`- **Structure**: Monorepo with workspaces`);
22475
+ }
22476
+ sections.push("");
22477
+ sections.push(`## Code Style
22478
+ `);
22479
+ sections.push(`Follow existing patterns in the codebase.
22480
+ `);
22481
+ sections.push(`## Architecture Principles
22482
+ `);
22483
+ sections.push(`Document key architectural decisions here.
22484
+ `);
22485
+ return sections.join(`
22486
+ `);
22487
+ }
22488
+ }
22489
+
22490
+ class DockerSandboxService {
22491
+ static detectImage(worktreePath) {
22492
+ if (existsSync5(join8(worktreePath, "Dockerfile"))) {
22493
+ return null;
22494
+ }
22495
+ if (existsSync5(join8(worktreePath, "package.json"))) {
22496
+ return "node:22-slim";
22497
+ }
22498
+ if (existsSync5(join8(worktreePath, "requirements.txt")) || existsSync5(join8(worktreePath, "pyproject.toml"))) {
22499
+ return "python:3.12-slim";
22500
+ }
22501
+ if (existsSync5(join8(worktreePath, "go.mod"))) {
22502
+ return "golang:1.22-slim";
22503
+ }
22504
+ if (existsSync5(join8(worktreePath, "Cargo.toml"))) {
22505
+ return "rust:1.77-slim";
22506
+ }
22507
+ return "ubuntu:24.04";
22508
+ }
22509
+ static buildRunCommand(worktreePath, command, image) {
22510
+ const escapedCommand = command.replace(/'/g, "'\\''");
22511
+ return `docker run --rm -v ${worktreePath}:/app -w /app ${image} sh -c '${escapedCommand}'`;
22512
+ }
22513
+ static containerName(worktreePath) {
22514
+ const parts = worktreePath.split(sep);
22515
+ const worktreeIdx = parts.indexOf(".worktrees");
22516
+ if (worktreeIdx === -1 || worktreeIdx + 2 >= parts.length) {
22517
+ return `hive-sandbox-${Date.now()}`;
22518
+ }
22519
+ const feature = parts[worktreeIdx + 1];
22520
+ const task = parts[worktreeIdx + 2];
22521
+ const name = `hive-${feature}-${task}`.replace(/[^a-z0-9-]/gi, "-").toLowerCase();
22522
+ return name.slice(0, 63);
22523
+ }
22524
+ static ensureContainer(worktreePath, image) {
22525
+ const name = this.containerName(worktreePath);
22526
+ try {
22527
+ execSync(`docker inspect --format='{{.State.Running}}' ${name}`, { stdio: "pipe" });
22528
+ return name;
22529
+ } catch {
22530
+ execSync(`docker run -d --name ${name} -v ${worktreePath}:/app -w /app ${image} tail -f /dev/null`, { stdio: "pipe" });
22531
+ return name;
22532
+ }
22533
+ }
22534
+ static buildExecCommand(containerName, command) {
22535
+ const escapedCommand = command.replace(/'/g, "'\\''");
22536
+ return `docker exec ${containerName} sh -c '${escapedCommand}'`;
22537
+ }
22538
+ static stopContainer(worktreePath) {
22539
+ const name = this.containerName(worktreePath);
22540
+ try {
22541
+ execSync(`docker rm -f ${name}`, { stdio: "ignore" });
22542
+ } catch {}
22543
+ }
22544
+ static isDockerAvailable() {
22545
+ try {
22546
+ execSync("docker info", { stdio: "ignore" });
22547
+ return true;
22548
+ } catch {
22549
+ return false;
22550
+ }
22551
+ }
22552
+ static wrapCommand(worktreePath, command, config2) {
22553
+ if (command.startsWith("HOST: ")) {
22554
+ return command.substring(6);
22555
+ }
22556
+ if (config2.mode === "none") {
22557
+ return command;
22558
+ }
22559
+ let image;
22560
+ if (config2.image) {
22561
+ image = config2.image;
22562
+ } else {
22563
+ image = this.detectImage(worktreePath);
22564
+ if (image === null) {
22565
+ return command;
22566
+ }
22567
+ }
22568
+ if (config2.persistent) {
22569
+ const containerName = this.ensureContainer(worktreePath, image);
22570
+ return this.buildExecCommand(containerName, command);
22571
+ } else {
22572
+ return this.buildRunCommand(worktreePath, command, image);
22573
+ }
22574
+ }
21626
22575
  }
21627
22576
  function computeRunnableAndBlocked(tasks) {
21628
22577
  const statusByFolder = new Map;
@@ -21788,8 +22737,16 @@ hive_worktree_commit({
21788
22737
  })
21789
22738
  \`\`\`
21790
22739
 
21791
- **CRITICAL: After calling hive_worktree_commit, you MUST STOP IMMEDIATELY.**
21792
- Do NOT continue working. Do NOT respond further. Your session is DONE.
22740
+ Then inspect the tool response fields:
22741
+ - If \`ok=true\` and \`terminal=true\`: stop the session
22742
+ - Otherwise: **DO NOT STOP**. Follow \`nextAction\`, remediate, and retry \`hive_worktree_commit\`
22743
+
22744
+ **CRITICAL: Stop only on terminal commit result (ok=true and terminal=true).**
22745
+ If commit returns non-terminal (for example verification_required), DO NOT STOP.
22746
+ Follow result.nextAction, fix the issue, and call hive_worktree_commit again.
22747
+
22748
+ Only when commit result is terminal should you stop.
22749
+ Do NOT continue working after a terminal result. Do NOT respond further. Your session is DONE.
21793
22750
  The Hive Master will take over from here.
21794
22751
 
21795
22752
  **Summary Guidance** (used verbatim for downstream task context):
@@ -22136,6 +23093,31 @@ function normalizeVariant(variant) {
22136
23093
  return trimmed2.length > 0 ? trimmed2 : undefined;
22137
23094
  }
22138
23095
 
23096
+ // src/hooks/system-hook.ts
23097
+ var fallbackTurnCounters = {};
23098
+ function shouldExecuteHook(hookName, configService, turnCounters, options) {
23099
+ const cadence = configService?.getHookCadence(hookName, options) ?? 1;
23100
+ const counters = turnCounters ?? fallbackTurnCounters;
23101
+ counters[hookName] = (counters[hookName] || 0) + 1;
23102
+ const currentTurn = counters[hookName];
23103
+ if (cadence === 1) {
23104
+ return true;
23105
+ }
23106
+ return (currentTurn - 1) % cadence === 0;
23107
+ }
23108
+ var HIVE_SYSTEM_PROMPT = `
23109
+ ## Hive — Active Session
23110
+
23111
+ **Important:** hive_worktree_commit commits to the task branch but does NOT merge.
23112
+ Use hive_merge to integrate changes into the current branch.
23113
+ `;
23114
+
23115
+ // src/utils/compaction-prompt.ts
23116
+ var COMPACTION_RESUME_PROMPT = "You were compacted mid-task. " + "Resume by reading your worker-prompt.md (in the task worktree root) to recall your assignment. " + "Do not call status tools or re-read the full codebase. " + "Locate your last commit message or notes, then continue from where you left off.";
23117
+ function buildCompactionPrompt() {
23118
+ return COMPACTION_RESUME_PROMPT;
23119
+ }
23120
+
22139
23121
  // src/index.ts
22140
23122
  function formatSkillsXml(skills) {
22141
23123
  if (skills.length === 0)
@@ -22221,91 +23203,13 @@ No Hive skills available.` : base + formatSkillsXml(filteredSkills);
22221
23203
  }
22222
23204
  });
22223
23205
  }
22224
- var HIVE_SYSTEM_PROMPT = `
22225
- ## Hive - Feature Development System
22226
-
22227
- Plan-first development: Write plan → User reviews → Approve → Execute tasks
22228
-
22229
- ### Tools (14 total)
22230
-
22231
- | Domain | Tools |
22232
- |--------|-------|
22233
- | Feature | hive_feature_create, hive_feature_complete |
22234
- | Plan | hive_plan_write, hive_plan_read, hive_plan_approve |
22235
- | Task | hive_tasks_sync, hive_task_create, hive_task_update |
22236
- | Worktree | hive_worktree_create, hive_worktree_commit, hive_worktree_discard |
22237
- | Merge | hive_merge |
22238
- | Context | hive_context_write |
22239
- | Status | hive_status |
22240
- | Skill | hive_skill |
22241
-
22242
- ### Workflow
22243
-
22244
- 1. \`hive_feature_create(name)\` - Create feature
22245
- 2. \`hive_plan_write(content)\` - Write plan.md
22246
- 3. User adds comments in VSCode → \`hive_plan_read\` to see them
22247
- 4. Revise plan → User approves
22248
- 5. \`hive_tasks_sync()\` - Generate tasks from plan
22249
- 6. \`hive_worktree_create(task)\` → work in worktree → \`hive_worktree_commit(task, summary)\`
22250
- 7. \`hive_merge(task)\` - Merge task branch into main (when ready)
22251
-
22252
- **Important:** \`hive_worktree_commit\` commits changes to task branch but does NOT merge.
22253
- Use \`hive_merge\` to explicitly integrate changes. Worktrees persist until manually removed.
22254
-
22255
- ### Delegated Execution
22256
-
22257
- \`hive_worktree_create\` creates worktree and spawns worker automatically:
22258
-
22259
- 1. \`hive_worktree_create(task)\` → Creates worktree + spawns Forager (Worker/Coder) worker
22260
- 2. Worker executes → calls \`hive_worktree_commit(status: "completed")\`
22261
- 3. Worker blocked → calls \`hive_worktree_commit(status: "blocked", blocker: {...})\`
22262
-
22263
- **Handling blocked workers:**
22264
- 1. Check blockers with \`hive_status()\`
22265
- 2. Read the blocker info (reason, options, recommendation, context)
22266
- 3. Ask user via \`question()\` tool - NEVER plain text
22267
- 4. Resume with \`hive_worktree_create(task, continueFrom: "blocked", decision: answer)\`
22268
-
22269
- **CRITICAL**: When resuming, a NEW worker spawns in the SAME worktree.
22270
- The previous worker's progress is preserved. Include the user's decision in the \`decision\` parameter.
22271
-
22272
- **After task() Returns:**
22273
- - task() is BLOCKING — when it returns, the worker is DONE
22274
- - Call \`hive_status()\` immediately to check the new task state and find next runnable tasks
22275
- - No notifications or polling needed — the result is already available
22276
-
22277
- **For research**, use MCP tools or parallel exploration:
22278
- - \`grep_app_searchGitHub\` - Find code in OSS
22279
- - \`context7_query-docs\` - Library documentation
22280
- - \`websearch_web_search_exa\` - Web search via Exa
22281
- - \`ast_grep_search\` - AST-based search
22282
- - For exploratory fan-out, load \`hive_skill("parallel-exploration")\` and use multiple \`task()\` calls in the same message
22283
-
22284
- ### Planning Phase - Context Management REQUIRED
22285
-
22286
- As you research and plan, CONTINUOUSLY save findings using \`hive_context_write\`:
22287
- - Research findings (API patterns, library docs, codebase structure)
22288
- - User preferences ("we use Zustand, not Redux")
22289
- - Rejected alternatives ("tried X, too complex")
22290
- - Architecture decisions ("auth lives in /lib/auth")
22291
-
22292
- **Update existing context files** when new info emerges - dont create duplicates.
22293
-
22294
- \`hive_tasks_sync\` parses \`### N. Task Name\` headers.
22295
-
22296
- ### Execution Phase - Stay Aligned
22297
-
22298
- During execution, call \`hive_status\` periodically to:
22299
- - Check current progress and pending work
22300
- - See context files to read
22301
- - Get reminded of next actions
22302
- `;
22303
23206
  var plugin = async (ctx) => {
22304
23207
  const { directory, client } = ctx;
22305
23208
  const featureService = new FeatureService(directory);
22306
23209
  const planService = new PlanService(directory);
22307
23210
  const taskService = new TaskService(directory);
22308
23211
  const contextService = new ContextService(directory);
23212
+ const agentsMdService = new AgentsMdService(directory, contextService);
22309
23213
  const configService = new ConfigService;
22310
23214
  const disabledMcps = configService.getDisabledMcps();
22311
23215
  const disabledSkills = configService.getDisabledSkills();
@@ -22314,7 +23218,7 @@ var plugin = async (ctx) => {
22314
23218
  const effectiveAutoLoadSkills = configService.getAgentConfig("hive-master").autoLoadSkills ?? [];
22315
23219
  const worktreeService = new WorktreeService({
22316
23220
  baseDir: directory,
22317
- hiveDir: path7.join(directory, ".hive")
23221
+ hiveDir: path8.join(directory, ".hive")
22318
23222
  });
22319
23223
  const isOmoSlimEnabled = () => {
22320
23224
  return configService.isOmoSlimEnabled();
@@ -22341,7 +23245,7 @@ var plugin = async (ctx) => {
22341
23245
  };
22342
23246
  const checkBlocked = (feature) => {
22343
23247
  const fs9 = __require("fs");
22344
- const blockedPath = path7.join(directory, ".hive", "features", feature, "BLOCKED");
23248
+ const blockedPath = path8.join(directory, ".hive", "features", feature, "BLOCKED");
22345
23249
  if (fs9.existsSync(blockedPath)) {
22346
23250
  const reason = fs9.readFileSync(blockedPath, "utf-8").trim();
22347
23251
  return `⛔ BLOCKED by Beekeeper
@@ -22353,6 +23257,7 @@ To unblock: Remove .hive/features/${feature}/BLOCKED`;
22353
23257
  }
22354
23258
  return null;
22355
23259
  };
23260
+ const turnCounters = {};
22356
23261
  const checkDependencies = (feature, taskFolder) => {
22357
23262
  const taskStatus = taskService.getRawStatus(feature, taskFolder);
22358
23263
  if (!taskStatus) {
@@ -22392,6 +23297,9 @@ To unblock: Remove .hive/features/${feature}/BLOCKED`;
22392
23297
  };
22393
23298
  return {
22394
23299
  "experimental.chat.system.transform": async (input, output) => {
23300
+ if (!shouldExecuteHook("experimental.chat.system.transform", configService, turnCounters)) {
23301
+ return;
23302
+ }
22395
23303
  output.system.push(HIVE_SYSTEM_PROMPT);
22396
23304
  const activeFeature = resolveFeature();
22397
23305
  if (activeFeature) {
@@ -22412,6 +23320,9 @@ To unblock: Remove .hive/features/${feature}/BLOCKED`;
22412
23320
  }
22413
23321
  }
22414
23322
  },
23323
+ "experimental.session.compacting": async (_input, output) => {
23324
+ output.context.push(buildCompactionPrompt());
23325
+ },
22415
23326
  "chat.message": async (input, output) => {
22416
23327
  const { agent } = input;
22417
23328
  if (!agent)
@@ -22426,6 +23337,34 @@ To unblock: Remove .hive/features/${feature}/BLOCKED`;
22426
23337
  output.message.variant = configuredVariant;
22427
23338
  }
22428
23339
  },
23340
+ "tool.execute.before": async (input, output) => {
23341
+ if (!shouldExecuteHook("tool.execute.before", configService, turnCounters, { safetyCritical: true })) {
23342
+ return;
23343
+ }
23344
+ if (input.tool !== "bash")
23345
+ return;
23346
+ const sandboxConfig = configService.getSandboxConfig();
23347
+ if (sandboxConfig.mode === "none")
23348
+ return;
23349
+ const command = output.args?.command?.trim();
23350
+ if (!command)
23351
+ return;
23352
+ if (/^HOST:\s*/i.test(command)) {
23353
+ const strippedCommand = command.replace(/^HOST:\s*/i, "");
23354
+ console.warn(`[hive:sandbox] HOST bypass: ${strippedCommand.slice(0, 80)}${strippedCommand.length > 80 ? "..." : ""}`);
23355
+ output.args.command = strippedCommand;
23356
+ return;
23357
+ }
23358
+ const workdir = output.args?.workdir;
23359
+ if (!workdir)
23360
+ return;
23361
+ const hiveWorktreeBase = path8.join(directory, ".hive", ".worktrees");
23362
+ if (!workdir.startsWith(hiveWorktreeBase))
23363
+ return;
23364
+ const wrapped = DockerSandboxService.wrapCommand(workdir, command, sandboxConfig);
23365
+ output.args.command = wrapped;
23366
+ output.args.workdir = undefined;
23367
+ },
22429
23368
  mcp: builtinMcps,
22430
23369
  tool: {
22431
23370
  hive_skill: createHiveSkillTool(filteredSkills),
@@ -22494,8 +23433,8 @@ NEXT: Ask your first clarifying question about this feature.`;
22494
23433
  const feature = resolveFeature(explicitFeature);
22495
23434
  if (!feature)
22496
23435
  return "Error: No feature specified. Create a feature or provide feature param.";
22497
- const hasDiscovery = content.toLowerCase().includes("## discovery");
22498
- if (!hasDiscovery) {
23436
+ const discoveryMatch = content.match(/^##\s+Discovery\s*$/im);
23437
+ if (!discoveryMatch) {
22499
23438
  return `BLOCKED: Discovery section required before planning.
22500
23439
 
22501
23440
  Your plan must include a \`## Discovery\` section documenting:
@@ -22504,6 +23443,19 @@ Your plan must include a \`## Discovery\` section documenting:
22504
23443
  - Key decisions made
22505
23444
 
22506
23445
  Add this section to your plan content and try again.`;
23446
+ }
23447
+ const afterDiscovery = content.slice(discoveryMatch.index + discoveryMatch[0].length);
23448
+ const nextHeading = afterDiscovery.search(/^##\s+/m);
23449
+ const discoveryContent = nextHeading > -1 ? afterDiscovery.slice(0, nextHeading).trim() : afterDiscovery.trim();
23450
+ if (discoveryContent.length < 100) {
23451
+ return `BLOCKED: Discovery section is too thin (${discoveryContent.length} chars, minimum 100).
23452
+
23453
+ A substantive Discovery section should include:
23454
+ - Original request quoted
23455
+ - Interview summary (key decisions)
23456
+ - Research findings with file:line references
23457
+
23458
+ Expand your Discovery section and try again.`;
22507
23459
  }
22508
23460
  captureSession(feature, toolContext);
22509
23461
  const planPath = planService.write(feature, content);
@@ -22724,9 +23676,9 @@ Reminder: start work with hive_worktree_create to use its worktree, and ensure a
22724
23676
  spec: specContent,
22725
23677
  workerPrompt
22726
23678
  });
22727
- const hiveDir = path7.join(directory, ".hive");
23679
+ const hiveDir = path8.join(directory, ".hive");
22728
23680
  const workerPromptPath = writeWorkerPromptFile(feature, task, workerPrompt, hiveDir);
22729
- const relativePromptPath = normalizePath(path7.relative(directory, workerPromptPath));
23681
+ const relativePromptPath = normalizePath(path8.relative(directory, workerPromptPath));
22730
23682
  const PREVIEW_MAX_LENGTH = 200;
22731
23683
  const workerPromptPreview = workerPrompt.length > PREVIEW_MAX_LENGTH ? workerPrompt.slice(0, PREVIEW_MAX_LENGTH) + "..." : workerPrompt;
22732
23684
  const taskToolPrompt = `Follow instructions in @${relativePromptPath}`;
@@ -22794,7 +23746,7 @@ Use the \`@path\` attachment syntax in the prompt to reference the file. Do not
22794
23746
  }
22795
23747
  }),
22796
23748
  hive_worktree_commit: tool({
22797
- description: "Complete task: commit changes to branch, write report. Supports blocked/failed/partial status for worker communication.",
23749
+ description: "Complete task: commit changes to branch, write report. Supports blocked/failed/partial status for worker communication. Returns JSON with ok/terminal semantics for worker control flow.",
22798
23750
  args: {
22799
23751
  task: tool.schema.string().describe("Task folder name"),
22800
23752
  summary: tool.schema.string().describe("Summary of what was done"),
@@ -22808,29 +23760,54 @@ Use the \`@path\` attachment syntax in the prompt to reference the file. Do not
22808
23760
  feature: tool.schema.string().optional().describe("Feature name (defaults to detection or single feature)")
22809
23761
  },
22810
23762
  async execute({ task, summary, status = "completed", blocker, feature: explicitFeature }) {
23763
+ const respond = (payload) => JSON.stringify(payload, null, 2);
22811
23764
  const feature = resolveFeature(explicitFeature);
22812
- if (!feature)
22813
- return "Error: No feature specified. Create a feature or provide feature param.";
23765
+ if (!feature) {
23766
+ return respond({
23767
+ ok: false,
23768
+ terminal: false,
23769
+ status: "error",
23770
+ reason: "feature_required",
23771
+ task,
23772
+ taskState: "unknown",
23773
+ message: "No feature specified. Create a feature or provide feature param.",
23774
+ nextAction: "Provide feature explicitly or create/select an active feature, then retry hive_worktree_commit."
23775
+ });
23776
+ }
22814
23777
  const taskInfo = taskService.get(feature, task);
22815
- if (!taskInfo)
22816
- return `Error: Task "${task}" not found`;
22817
- if (taskInfo.status !== "in_progress" && taskInfo.status !== "blocked")
22818
- return "Error: Task not in progress";
23778
+ if (!taskInfo) {
23779
+ return respond({
23780
+ ok: false,
23781
+ terminal: false,
23782
+ status: "error",
23783
+ reason: "task_not_found",
23784
+ feature,
23785
+ task,
23786
+ taskState: "unknown",
23787
+ message: `Task "${task}" not found`,
23788
+ nextAction: "Check the task folder name in your worker-prompt.md and retry hive_worktree_commit with the correct task id."
23789
+ });
23790
+ }
23791
+ if (taskInfo.status !== "in_progress" && taskInfo.status !== "blocked") {
23792
+ return respond({
23793
+ ok: false,
23794
+ terminal: false,
23795
+ status: "error",
23796
+ reason: "invalid_task_state",
23797
+ feature,
23798
+ task,
23799
+ taskState: taskInfo.status,
23800
+ message: "Task not in progress",
23801
+ nextAction: "Only in_progress or blocked tasks can be committed. Start/resume the task first."
23802
+ });
23803
+ }
23804
+ let verificationNote;
22819
23805
  if (status === "completed") {
22820
- const verificationKeywords = ["test", "build", "lint", "vitest", "jest", "npm run", "pnpm", "cargo", "pytest", "verified", "passes", "succeeds"];
23806
+ const verificationKeywords = ["test", "build", "lint", "vitest", "jest", "npm run", "pnpm", "cargo", "pytest", "verified", "passes", "succeeds", "ast-grep", "scan"];
22821
23807
  const summaryLower = summary.toLowerCase();
22822
23808
  const hasVerificationMention = verificationKeywords.some((kw) => summaryLower.includes(kw));
22823
23809
  if (!hasVerificationMention) {
22824
- return `BLOCKED: No verification detected in summary.
22825
-
22826
- Before claiming completion, you must:
22827
- 1. Run tests (vitest, jest, pytest, etc.)
22828
- 2. Run build (npm run build, cargo build, etc.)
22829
- 3. Include verification results in summary
22830
-
22831
- Example summary: "Implemented auth flow. Tests pass (vitest). Build succeeds."
22832
-
22833
- Re-run with updated summary showing verification results.`;
23810
+ verificationNote = "No verification evidence in summary. Orchestrator should run build+test after merge.";
22834
23811
  }
22835
23812
  }
22836
23813
  if (status === "blocked") {
@@ -22840,16 +23817,42 @@ Re-run with updated summary showing verification results.`;
22840
23817
  blocker
22841
23818
  });
22842
23819
  const worktree2 = await worktreeService.get(feature, task);
22843
- return JSON.stringify({
23820
+ return respond({
23821
+ ok: true,
23822
+ terminal: true,
22844
23823
  status: "blocked",
23824
+ reason: "user_decision_required",
23825
+ feature,
22845
23826
  task,
23827
+ taskState: "blocked",
22846
23828
  summary,
22847
23829
  blocker,
22848
23830
  worktreePath: worktree2?.path,
22849
- message: 'Task blocked. Hive Master will ask user and resume with hive_worktree_create(continueFrom: "blocked", decision: answer)'
22850
- }, null, 2);
23831
+ branch: worktree2?.branch,
23832
+ message: 'Task blocked. Hive Master will ask user and resume with hive_worktree_create(continueFrom: "blocked", decision: answer)',
23833
+ nextAction: 'Wait for orchestrator to collect user decision and resume with continueFrom: "blocked".'
23834
+ });
22851
23835
  }
22852
23836
  const commitResult = await worktreeService.commitChanges(feature, task, `hive(${task}): ${summary.slice(0, 50)}`);
23837
+ if (status === "completed" && !commitResult.committed && commitResult.message !== "No changes to commit") {
23838
+ return respond({
23839
+ ok: false,
23840
+ terminal: false,
23841
+ status: "rejected",
23842
+ reason: "commit_failed",
23843
+ feature,
23844
+ task,
23845
+ taskState: taskInfo.status,
23846
+ summary,
23847
+ commit: {
23848
+ committed: commitResult.committed,
23849
+ sha: commitResult.sha,
23850
+ message: commitResult.message
23851
+ },
23852
+ message: `Commit failed: ${commitResult.message || "unknown error"}`,
23853
+ nextAction: "Resolve git/worktree issue, then call hive_worktree_commit again."
23854
+ });
23855
+ }
22853
23856
  const diff = await worktreeService.getDiff(feature, task);
22854
23857
  const statusLabel = status === "completed" ? "success" : status;
22855
23858
  const reportLines = [
@@ -22879,13 +23882,31 @@ Re-run with updated summary showing verification results.`;
22879
23882
  } else {
22880
23883
  reportLines.push("---", "", "## Changes", "", "_No file changes detected_", "");
22881
23884
  }
22882
- taskService.writeReport(feature, task, reportLines.join(`
23885
+ const reportPath = taskService.writeReport(feature, task, reportLines.join(`
22883
23886
  `));
22884
23887
  const finalStatus = status === "completed" ? "done" : status;
22885
23888
  taskService.update(feature, task, { status: finalStatus, summary });
22886
23889
  const worktree = await worktreeService.get(feature, task);
22887
- return `Task "${task}" ${status}. Changes committed to branch ${worktree?.branch || "unknown"}.
22888
- Use hive_merge to integrate changes. Worktree preserved at ${worktree?.path || "unknown"}.`;
23890
+ return respond({
23891
+ ok: true,
23892
+ terminal: true,
23893
+ status,
23894
+ feature,
23895
+ task,
23896
+ taskState: finalStatus,
23897
+ summary,
23898
+ ...verificationNote && { verificationNote },
23899
+ commit: {
23900
+ committed: commitResult.committed,
23901
+ sha: commitResult.sha,
23902
+ message: commitResult.message
23903
+ },
23904
+ worktreePath: worktree?.path,
23905
+ branch: worktree?.branch,
23906
+ reportPath,
23907
+ message: `Task "${task}" ${status}.`,
23908
+ nextAction: "Use hive_merge to integrate changes. Worktree is preserved for review."
23909
+ });
22889
23910
  }
22890
23911
  }),
22891
23912
  hive_worktree_discard: tool({
@@ -23066,6 +24087,47 @@ Files changed: ${result.filesChanged?.length || 0}`;
23066
24087
  nextAction: getNextAction(planStatus, tasksSummary, runnable)
23067
24088
  });
23068
24089
  }
24090
+ }),
24091
+ hive_agents_md: tool({
24092
+ description: "Initialize or sync AGENTS.md. init: scan codebase and generate (preview only). sync: propose updates from feature contexts. apply: write approved content to disk.",
24093
+ args: {
24094
+ action: tool.schema.enum(["init", "sync", "apply"]).describe("Action to perform"),
24095
+ feature: tool.schema.string().optional().describe("Feature name for sync action"),
24096
+ content: tool.schema.string().optional().describe("Content to write (required for apply action)")
24097
+ },
24098
+ async execute({ action, feature, content }) {
24099
+ if (action === "init") {
24100
+ const result = await agentsMdService.init();
24101
+ if (result.existed) {
24102
+ return `AGENTS.md already exists (${result.content.length} chars). Use 'sync' to propose updates.`;
24103
+ }
24104
+ return `Generated AGENTS.md from codebase scan (${result.content.length} chars):
24105
+
24106
+ ${result.content}
24107
+
24108
+ ⚠️ This has NOT been written to disk. Ask the user via question() whether to write it to AGENTS.md.`;
24109
+ }
24110
+ if (action === "sync") {
24111
+ if (!feature)
24112
+ return "Error: feature name required for sync action";
24113
+ const result = await agentsMdService.sync(feature);
24114
+ if (result.proposals.length === 0) {
24115
+ return "No new findings to sync to AGENTS.md.";
24116
+ }
24117
+ return `Proposed AGENTS.md updates from feature "${feature}":
24118
+
24119
+ ${result.diff}
24120
+
24121
+ ⚠️ These changes have NOT been applied. Ask the user via question() whether to apply them.`;
24122
+ }
24123
+ if (action === "apply") {
24124
+ if (!content)
24125
+ return "Error: content required for apply action. Use init or sync first to get content, then apply with the approved content.";
24126
+ const result = agentsMdService.apply(content);
24127
+ return `AGENTS.md ${result.isNew ? "created" : "updated"} (${result.chars} chars) at ${result.path}`;
24128
+ }
24129
+ return "Error: unknown action";
24130
+ }
23069
24131
  })
23070
24132
  },
23071
24133
  command: {
@@ -23080,6 +24142,33 @@ Files changed: ${result.filesChanged?.length || 0}`;
23080
24142
  }
23081
24143
  },
23082
24144
  config: async (opencodeConfig) => {
24145
+ function agentTools(allowed) {
24146
+ const allHiveTools = [
24147
+ "hive_feature_create",
24148
+ "hive_feature_complete",
24149
+ "hive_plan_write",
24150
+ "hive_plan_read",
24151
+ "hive_plan_approve",
24152
+ "hive_tasks_sync",
24153
+ "hive_task_create",
24154
+ "hive_task_update",
24155
+ "hive_worktree_create",
24156
+ "hive_worktree_commit",
24157
+ "hive_worktree_discard",
24158
+ "hive_merge",
24159
+ "hive_context_write",
24160
+ "hive_status",
24161
+ "hive_skill",
24162
+ "hive_agents_md"
24163
+ ];
24164
+ const result = {};
24165
+ for (const tool3 of allHiveTools) {
24166
+ if (!allowed.includes(tool3)) {
24167
+ result[tool3] = false;
24168
+ }
24169
+ }
24170
+ return result;
24171
+ }
23083
24172
  configService.init();
23084
24173
  const hiveUserConfig = configService.getAgentConfig("hive-master");
23085
24174
  const hiveAutoLoadedSkills = await buildAutoLoadedSkillsContent("hive-master", configService, directory);
@@ -23104,6 +24193,7 @@ Files changed: ${result.filesChanged?.length || 0}`;
23104
24193
  temperature: architectUserConfig.temperature ?? 0.7,
23105
24194
  description: "Architect (Planner) - Plans features, interviews, writes plans. NEVER executes.",
23106
24195
  prompt: ARCHITECT_BEE_PROMPT + architectAutoLoadedSkills,
24196
+ tools: agentTools(["hive_feature_create", "hive_plan_write", "hive_plan_read", "hive_context_write", "hive_status", "hive_skill"]),
23107
24197
  permission: {
23108
24198
  edit: "deny",
23109
24199
  task: "allow",
@@ -23122,6 +24212,22 @@ Files changed: ${result.filesChanged?.length || 0}`;
23122
24212
  temperature: swarmUserConfig.temperature ?? 0.5,
23123
24213
  description: "Swarm (Orchestrator) - Orchestrates execution. Delegates, spawns workers, verifies, merges.",
23124
24214
  prompt: SWARM_BEE_PROMPT + swarmAutoLoadedSkills,
24215
+ tools: agentTools([
24216
+ "hive_feature_create",
24217
+ "hive_feature_complete",
24218
+ "hive_plan_read",
24219
+ "hive_plan_approve",
24220
+ "hive_tasks_sync",
24221
+ "hive_task_create",
24222
+ "hive_task_update",
24223
+ "hive_worktree_create",
24224
+ "hive_worktree_discard",
24225
+ "hive_merge",
24226
+ "hive_context_write",
24227
+ "hive_status",
24228
+ "hive_skill",
24229
+ "hive_agents_md"
24230
+ ]),
23125
24231
  permission: {
23126
24232
  question: "allow",
23127
24233
  skill: "allow",
@@ -23138,6 +24244,7 @@ Files changed: ${result.filesChanged?.length || 0}`;
23138
24244
  mode: "subagent",
23139
24245
  description: "Scout (Explorer/Researcher/Retrieval) - Researches codebase + external docs/data.",
23140
24246
  prompt: SCOUT_BEE_PROMPT + scoutAutoLoadedSkills,
24247
+ tools: agentTools(["hive_plan_read", "hive_context_write", "hive_status", "hive_skill"]),
23141
24248
  permission: {
23142
24249
  edit: "deny",
23143
24250
  task: "deny",
@@ -23155,6 +24262,7 @@ Files changed: ${result.filesChanged?.length || 0}`;
23155
24262
  mode: "subagent",
23156
24263
  description: "Forager (Worker/Coder) - Executes tasks directly in isolated worktrees. Never delegates.",
23157
24264
  prompt: FORAGER_BEE_PROMPT + foragerAutoLoadedSkills,
24265
+ tools: agentTools(["hive_plan_read", "hive_worktree_commit", "hive_context_write", "hive_skill"]),
23158
24266
  permission: {
23159
24267
  task: "deny",
23160
24268
  delegate: "deny",
@@ -23170,6 +24278,7 @@ Files changed: ${result.filesChanged?.length || 0}`;
23170
24278
  mode: "subagent",
23171
24279
  description: "Hygienic (Consultant/Reviewer/Debugger) - Reviews plan documentation quality. OKAY/REJECT verdict.",
23172
24280
  prompt: HYGIENIC_BEE_PROMPT + hygienicAutoLoadedSkills,
24281
+ tools: agentTools(["hive_plan_read", "hive_context_write", "hive_status", "hive_skill"]),
23173
24282
  permission: {
23174
24283
  edit: "deny",
23175
24284
  task: "deny",