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/agents/architect.d.ts +1 -1
- package/dist/agents/forager.d.ts +1 -1
- package/dist/agents/hive.d.ts +1 -1
- package/dist/agents/hygienic.d.ts +1 -1
- package/dist/agents/scout.d.ts +1 -7
- package/dist/agents/swarm.d.ts +1 -1
- package/dist/hooks/system-hook.d.ts +8 -0
- package/dist/index.js +1616 -507
- package/dist/skills/registry.generated.d.ts +1 -1
- package/dist/utils/compaction-prompt.d.ts +1 -0
- package/package.json +1 -1
- package/skills/agents-md-mastery/SKILL.md +253 -0
- package/skills/docker-mastery/SKILL.md +346 -0
- package/skills/executing-plans/SKILL.md +2 -2
- package/skills/test-driven-development/SKILL.md +1 -1
- package/skills/writing-plans/SKILL.md +7 -0
- package/skills/onboarding/SKILL.md +0 -61
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: (
|
|
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
|
|
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", "
|
|
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
|
|
12861
|
-
- **REQUIRED SUB-SKILL:** Use hive_skill:
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
14321
|
-
|
|
14322
|
-
|
|
14323
|
-
-
|
|
14324
|
-
-
|
|
14325
|
-
-
|
|
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
|
-
|
|
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
|
-
###
|
|
14343
|
-
|
|
14344
|
-
|
|
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 |
|
|
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
|
|
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
|
-
-
|
|
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:
|
|
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.
|
|
14431
|
-
4.
|
|
14432
|
-
|
|
14433
|
-
|
|
14434
|
-
|
|
14435
|
-
|
|
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
|
-
###
|
|
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 (
|
|
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
|
|
14460
|
-
- Follow
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
14486
|
-
| Greenfield | New feature |
|
|
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
|
|
14493
|
-
□ Scope
|
|
14494
|
-
□ No critical ambiguities?
|
|
14495
|
-
□
|
|
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
|
-
|
|
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
|
-
|
|
15195
|
+
Intent Verbalization: "I detect [type] intent — [reason]. Routing to [action]."
|
|
14587
15196
|
|
|
14588
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
14602
|
-
|
|
14603
|
-
|
|
14604
|
-
|
|
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.
|
|
14616
|
-
5.
|
|
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
|
-
|
|
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 -
|
|
15234
|
+
## After Delegation - VERIFY
|
|
14635
15235
|
|
|
14636
|
-
|
|
14637
|
-
-
|
|
14638
|
-
-
|
|
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.
|
|
14650
|
-
2.
|
|
14651
|
-
3.
|
|
14652
|
-
4.
|
|
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
|
|
15274
|
+
Merge after batch completes, then verify the merged result.
|
|
14662
15275
|
|
|
14663
|
-
|
|
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
|
-
|
|
15280
|
+
### AGENTS.md Maintenance
|
|
14671
15281
|
|
|
14672
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
15329
|
+
### Phase 2: Parallel Execution
|
|
14715
15330
|
|
|
14716
|
-
|
|
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 |
|
|
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
|
|
14760
|
-
- Prefer targeted queries
|
|
14761
|
-
- Summarize findings; avoid
|
|
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
|
-
-
|
|
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
|
|
14782
|
-
- If findings are substantial (3+ files
|
|
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
|
|
14787
|
-
content: "##
|
|
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
|
-
##
|
|
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
|
-
|
|
14871
|
-
- Classify request
|
|
14872
|
-
-
|
|
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
|
|
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
|
-
|
|
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
|
-
##
|
|
15425
|
+
## Intent Extraction
|
|
14884
15426
|
|
|
14885
|
-
|
|
14886
|
-
|
|
14887
|
-
|
|
14888
|
-
|
|
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
|
-
- \`
|
|
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
|
-
|
|
14901
|
-
-
|
|
14902
|
-
-
|
|
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
|
-
|
|
15473
|
+
For substantial discoveries (architecture patterns, key decisions, gotchas that affect multiple tasks), use:
|
|
15474
|
+
\`hive_context_write({ name: "learnings", content: "..." })\`.
|
|
14909
15475
|
|
|
14910
|
-
##
|
|
15476
|
+
## Working Rules
|
|
14911
15477
|
|
|
14912
|
-
|
|
14913
|
-
|
|
14914
|
-
-
|
|
14915
|
-
-
|
|
14916
|
-
-
|
|
14917
|
-
-
|
|
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
|
-
|
|
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
|
-
|
|
14927
|
-
Follow spec exactly. Use references for patterns.
|
|
15490
|
+
EXPLORE → PLAN → EXECUTE → VERIFY → LOOP
|
|
14928
15491
|
|
|
14929
|
-
|
|
14930
|
-
|
|
14931
|
-
edit
|
|
14932
|
-
|
|
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
|
-
|
|
14936
|
-
|
|
14937
|
-
|
|
14938
|
-
|
|
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
|
-
|
|
15516
|
+
## Reporting
|
|
14942
15517
|
|
|
14943
15518
|
**Success:**
|
|
14944
15519
|
\`\`\`
|
|
@@ -14949,7 +15524,9 @@ hive_worktree_commit({
|
|
|
14949
15524
|
})
|
|
14950
15525
|
\`\`\`
|
|
14951
15526
|
|
|
14952
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
14986
|
-
|
|
14987
|
-
|
|
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
|
-
-
|
|
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: (
|
|
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
|
|
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
|
-
|
|
16727
|
-
if (!current) {
|
|
17306
|
+
if (!fileExists(statusPath)) {
|
|
16728
17307
|
throw new Error(`Task '${taskFolder}' not found`);
|
|
16729
17308
|
}
|
|
16730
|
-
const
|
|
16731
|
-
|
|
16732
|
-
|
|
16733
|
-
|
|
16734
|
-
|
|
16735
|
-
|
|
16736
|
-
updated
|
|
16737
|
-
|
|
16738
|
-
|
|
16739
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
21792
|
-
|
|
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:
|
|
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 =
|
|
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
|
|
22498
|
-
if (!
|
|
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 =
|
|
23679
|
+
const hiveDir = path8.join(directory, ".hive");
|
|
22728
23680
|
const workerPromptPath = writeWorkerPromptFile(feature, task, workerPrompt, hiveDir);
|
|
22729
|
-
const relativePromptPath = normalizePath(
|
|
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
|
|
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
|
|
22817
|
-
|
|
22818
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
22850
|
-
|
|
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
|
|
22888
|
-
|
|
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",
|