Skip to content
This repository was archived by the owner on Oct 17, 2026. It is now read-only.

Commit b3b03a5

Browse files
committed
chore(release): v0.6.2
Plan freeze, parallel waves, one delivery Critic, run-to-completion loop.
1 parent c89cbe2 commit b3b03a5

63 files changed

Lines changed: 1947 additions & 401 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎AGENTS.md‎

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,37 @@ Removed from default registry (v0.3.0): `mempalace`, `stitch`, `context7`. Conte
6666
| `visual-engineering` | designer |
6767
| `writing` | writer |
6868
| `ultrabrain` | plan |
69-
| review/verification | critic |
69+
| review/verification | critic (once at delivery, after all plan waves) |
7070
| research/discovery | explore |
7171
| browser/visual | vision |
7272

73+
## Orchestration contract (v0.6.2+)
74+
75+
Default path for a user request:
76+
77+
1. Bob classifies. Trivial 1–2 files → `general` (no Plan; Critic only if high-risk).
78+
2. Non-trivial → **Plan once**. Plan may fan out 1–3 `explore` calls, writes `.bob/plans/*.md`, returns `Status: done` → **frozen**.
79+
3. Bob dispatches waves from the frozen graph. `parallel: yes` = several `task()` in **one** assistant turn. Manager only if ≥6 workers; Manager never spawns Plan or Critic.
80+
4. Workers execute the annotated step. They do not re-plan or review.
81+
5. **One Critic** after every implementation wave. UI work → Critic delegates Vision.
82+
6. Re-plan only with `INVALIDATE_PLAN` in the Plan prompt (user changed scope, worker `Status: blocked` because the plan is wrong, or delivery Critic said the plan is unexecutable).
83+
84+
Hard wall: `getTaskPermissions()` in [src/permissions.ts](src/permissions.ts). Runtime freeze: [src/features/plan-lifecycle/](src/features/plan-lifecycle) + [src/hooks/plan-lifecycle-gate.ts](src/hooks/plan-lifecycle-gate.ts). Freeze is **per session** in `.bob/plans/.lifecycle.json` (plus plan-file frontmatter). A new session in the same repo is not blocked by another session's plan.
85+
86+
**Native OpenCode UI (do not reinvent):**
87+
- Tasks: Bob calls `todowrite` after Plan returns — phase rows + indented `N.M` steps. Host `task()` sessions are the parent/child tree.
88+
- Question: direct Plan (picker / Tab) uses the native `question` tool for complex/unclear **user-owned** facts. Plan invoked **through Bob** never interviews (`host-interaction-gate` denies `question` when the session has `parentID`).
89+
- Memory: native `memory` tool first; `hiai_memory_search` only if that misses.
90+
91+
| Agent | May `task()` |
92+
|---|---|
93+
| bob | manager + all workers |
94+
| manager | explore, build, general, designer, writer, vision, **critic (phase close only)** |
95+
| plan | explore |
96+
| critic | vision, explore |
97+
| build | explore (missing path only) |
98+
| explore, designer, writer, vision, general | none |
99+
73100
## Change Map
74101

75102
When you need to change something, edit the right file first.
@@ -82,7 +109,8 @@ When you need to change something, edit the right file first.
82109
| Shared prompt fragments | [src/prompt-library/](src/prompt-library) (browser, caveman, native-memory, postgres-rules, workspace, worktree) |
83110
| Runtime prompt injection | [src/hooks/closure-injector.ts](src/hooks/closure-injector.ts), [src/hooks/caveman-system-injector.ts](src/hooks/caveman-system-injector.ts) |
84111
| Agent registration (visibility, mode, model) | [src/agents/index.ts](src/agents/index.ts) + [src/index.ts](src/index.ts) `hooks.config` |
85-
| Per-agent permissions | [src/permissions.ts](src/permissions.ts) — `applyAgentPermissions()` |
112+
| Per-agent permissions | [src/permissions.ts](src/permissions.ts) — `applyAgentPermissions()` / `getTaskPermissions()` spawn matrix |
113+
| Plan freeze / single Critic | [src/features/plan-lifecycle/](src/features/plan-lifecycle) + [src/hooks/plan-lifecycle-gate.ts](src/hooks/plan-lifecycle-gate.ts) |
86114
| Closure protocol | [src/shared/closure.ts](src/shared/closure.ts) — `CLOSURE_SCHEMA_PROMPT` + `validateClosure()` |
87115
| Prompt override / `prompt_append` | [src/agents/index.ts](src/agents/index.ts) — `applyPromptOverride()` |
88116
| Skill tool | [src/tools/skill.ts](src/tools/skill.ts) |
@@ -112,17 +140,21 @@ Use [bob.env.example](bob.env.example) as the canonical template. Model provider
112140
| `HIAI_OPENCODE_MCP_EXPORT_PATH` | Override `.opencode/.mcp.json` output path |
113141
| `HIAI_OPENCODE_EXPORT_MCP_MODE` | `safe` (default) \| `force` (overwrite policy) |
114142

143+
All plugin settings go through **one** `bob.json` (or `bob.jsonc`). Search order (first found wins): current dir → each parent up to filesystem root (`bob.json`, then `.opencode/bob.json`, then jsonc) → `~/.config/hiai-opencode/bob.json`. CLI `doctor` uses the same order. Credentials stay in `bob.env` / Connect, not in JSON.
144+
145+
`loop.enabled` (default true) keeps Bob running on idle until the frozen plan and todos are done. Do not wait for the user to re-prompt.
146+
115147
Use `{env:VAR_NAME}` placeholders in config JSON — never raw keys, never `${VAR}` (blocked for names containing `KEY`/`TOKEN`/`SECRET`). Check with `grep -E '(fc-\|ctx7sk-\|sk-\|key-)' bob.json` — should return 0 matches.
116148

117149
## Mental Map
118150

119151
```
120152
AGENTS: bob (orchestrator) · build (impl) · plan (architecture) · explore (discovery)
121153
critic (review gate) · designer · writer · vision (browser) · manager · general (fallback)
122-
MCP: grep_app -> explore, build · sequential-thinking -> plan, critic
154+
MCP: grep_app -> explore · sequential-thinking optional (Plan uses native thinking)
123155
CLI SKILLS: firecrawl -> explore · context7 -> explore, build · agent-browser -> vision
124156
LSP: typescript, svelte, eslint, bash, pyright → build MUST run lsp_diagnostics after every edit
125-
GATES: critic-review · quality-gate · lsp-pending · legal-gate · circuit-breaker · closure
157+
GATES: plan-freeze · delivery-critic (once) · quality-gate · lsp-pending · legal-gate · circuit-breaker · closure
126158
```
127159

128160
## Closure Protocol
@@ -178,6 +210,9 @@ Headed mode (`AGENT_BROWSER_HEADED=1`) works only with Chrome — Lightpanda is
178210
### Agent prompt correct in source but wrong at runtime
179211
The runtime prompt is assembled in layers: (1) `src/agents/<agent>.ts`, (2) `src/prompt-library/*.ts` imports, (3) runtime hooks (closure-injector, caveman-system-injector), (4) `hooks.config` in [src/index.ts](src/index.ts) applies model/visibility/permissions. Inspect `hooks.config` first when runtime output diverges from source.
180212

213+
### Plan is called again or Critic runs after every step
214+
Expected contract since v0.6.2: one Plan, frozen until done; one Critic at delivery. If you still see mid-plan Plan/Critic calls, check (1) agent prompts import the freeze/delivery wording, (2) `plan-lifecycle-gate` is not in `hooks.disabled`, (3) logs for `[hiai-opencode] plan-lifecycle: denied_replan` / `denied_early_critic`. Invalidate only with `INVALIDATE_PLAN` in the Plan prompt.
215+
181216
### Circuit breaker triggered
182217
Sessions are aborted at 20+ consecutive identical tool calls (default) or 4000+ total tool calls (default). Search logs for `[background-agent] Circuit breaker:`. Adjust via `background_manager.circuit_breaker.consecutive_threshold` / `max_tool_calls` in config. State is in-memory only — lost on restart.
183218

@@ -192,6 +227,9 @@ Windows/OpenCode may fail to spawn local MCP processes (`sequential-thinking`, n
192227
- **`{env:VAR}` not `${VAR}`** in hiai-opencode config files — the latter blocks names containing `KEY`/`TOKEN`/`SECRET`.
193228
- **Never hardcode API keys** in JSON. Use `{env:VARIABLE_NAME}` placeholders.
194229
- **Bob's prompt is the routing source of truth** — there is no separate TypeScript routing map.
230+
- **Do not re-plan a frozen plan.** Execute waves. Invalidate only with `INVALIDATE_PLAN`.
231+
- **Do not call Critic after each todo.** Delivery Critic once. Skills that say otherwise (`subagent-driven-development`) are opt-in paranoid mode.
232+
- **Leaf agents cannot spawn Plan/Critic.** If a prompt still shows `task({subagent_type: "explore"})` on Writer, that call is denied at the permission wall — report the gap to Bob instead.
195233

196234
## Documentation
197235

‎ARCHITECTURE.md‎

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,20 @@ User input
2626
▼
2727
┌──────────────────────────────────────────────────────┐
2828
│ │
29-
│ Simple / small (<5 todos, no parallelism) │
30-
│ └─► build (hidden, deep/bounded implementation) │
29+
│ Simple / small (1–2 files) │
3130
│ └─► general (visible, quick/fallback executor) │
3231
│ │
33-
│ Planning / architecture │
32+
│ Non-trivial: Plan ONCE → freeze → parallel waves │
3433
│ └─► plan (visible, deep planning, read-only) │
34+
│ then build/general/designer/… per annotations │
35+
│ then critic ONCE at delivery │
3536
│ │
36-
│ Specialist tiers (always delegated, not routed): │
37+
│ Specialist tiers (delegated, not re-planned): │
3738
│ explore ◄── discovery (grep, firecrawl, context7) │
3839
│ writer ◄── copy / SEO / messaging │
3940
│ designer ◄── visual direction │
40-
│ critic ◄── review gate (APPROVED/REJECTED) │
41-
│ manager ◄── delegation orchestrator, memory │
41+
│ critic ◄── delivery review gate (APPROVED/REJECTED) │
42+
│ manager ◄── group coordinator (no plan/critic) │
4243
│ vision ◄── browser operator, multimodal │
4344
│ │
4445
└──────────────────────────────────────────────────────┘
@@ -66,7 +67,7 @@ User input
6667
- [src/shared/](src/shared): closure protocol, env-var resolution, event helpers
6768
- [src/permissions.ts](src/permissions.ts): per-agent permission/tool-disable resolution
6869
- [src/hooks/](src/hooks): all runtime hooks (circuit breaker, quality gate, closure injector, legal gate, worktree lifecycle, etc.)
69-
- [src/features/](src/features): background-manager, completion-controller, dream-distill, mcp, shell-env, telemetry, workspace-adapter, worktree
70+
- [src/features/](src/features): background-manager, completion-controller, plan-lifecycle, dream-distill, mcp, shell-env, telemetry, workspace-adapter, worktree
7071
- [src/tools/](src/tools): tool registrations (skill, lsp, session-manager, background-task, worktree, agent-browser, firecrawl, memory-tool)
7172
- [assets/cli/hiai-opencode.mjs](assets/cli/hiai-opencode.mjs): the `hiai-opencode` CLI (doctor, mcp-status, export-mcp, diagnose)
7273
- [assets/runtime/](assets/runtime): npm bootstrap helper for MCP/LSP tools
@@ -85,11 +86,11 @@ User input
8586

8687
- `build` — Senior Staff Engineer, implementation (deep/bounded)
8788
- `explore` — discovery (firecrawl + grep_app + context7)
88-
- `critic` — review gate (binary APPROVED/REJECTED)
89+
- `critic` — delivery review gate (binary APPROVED/REJECTED), once per plan
8990
- `designer` — UI/visual direction
9091
- `writer` — copy/positioning/SEO
9192
- `vision` — browser operator, multimodal
92-
- `manager` — delegation orchestrator, memory steward
93+
- `manager` — large-phase coordinator (workers + one phase-close Critic; no Plan), memory steward
9394
- `dream-consolidator` — memory consolidation (auto-triggered)
9495
- `distill-packager` — workflow packaging (auto-triggered)
9596

@@ -106,6 +107,8 @@ There is **no** separate migration module. Legacy agent keys are mapped only in
106107
- [src/agents/index.ts](src/agents/index.ts) — `createAllAgents()` registers 8 agents with visibility, mode, description, and prompts; `resolveAgentModel` / `applyPromptOverride` helpers
107108
- [src/index.ts](src/index.ts) — `hooks.config` callback native-upgrades `explore`/`plan`/`build`/`general` and merges all agents into OpenCode's `cfg.agent` dict; assembles MCP config
108109
- [src/types.ts](src/types.ts) — `AgentConfig`, `BobConfig`, `CompletionConfig`, `WorktreeConfig`, `ClosureBlock` types
110+
- [src/permissions.ts](src/permissions.ts) — `getTaskPermissions()` spawn matrix (leaf agents cannot spawn Plan/Critic)
111+
- [src/features/plan-lifecycle/](src/features/plan-lifecycle) — freeze / executing / done / invalidated **per session** (`.bob/plans/.lifecycle.json` map + plan frontmatter + todo snapshot)
109112

110113
## Models
111114

@@ -247,7 +250,9 @@ The plugin enforces a layered safety model. From strongest to weakest:
247250

248251
- **Legal gate** — [src/hooks/legal-gate.ts](src/hooks/legal-gate.ts): three-tier deny list (browser automation always blocked, military/malicious always blocked, contextual dual-use with offensive-intent regex). Throws `BlockingHookError`.
249252
- **Per-agent permission maps** — [src/permissions.ts](src/permissions.ts): `applyAgentPermissions()` converts `agent_restrictions` into `permission.deny` / `tools.<key>=false`. Applied in `src/index.ts` `hooks.config`.
250-
- **Completion controller** — [src/features/completion-controller/](src/features/completion-controller): state machine that gates task completion. `decide()` (decide.ts) requires: no blocker, no incomplete todos, quality gate passed, LSP diagnostics run (if edits made), and Critic approval (if `require_critic` and changed files exist).
253+
- **Plan lifecycle gate** — [src/features/plan-lifecycle/](src/features/plan-lifecycle) + [src/hooks/plan-lifecycle-gate.ts](src/hooks/plan-lifecycle-gate.ts): freezes a Plan `Status: done` result; blocks a second Plan spawn and blocks Critic until implementation waves finish.
254+
- **Host interaction gate** — [src/hooks/host-interaction-gate.ts](src/hooks/host-interaction-gate.ts): blocks the native `question` tool on any session with a `parentID` (Plan-via-Bob cannot interview). Direct Plan and Bob keep `question: allow`.
255+
- **Completion controller** — [src/features/completion-controller/](src/features/completion-controller): state machine that gates task completion. `decide()` (decide.ts) requires: no blocker, no incomplete todos, quality gate passed, LSP diagnostics run (if edits made), frozen plan not still executing, and Critic approval (if `require_critic` and changed files exist). Critic is a delivery gate, not a per-step gate.
251256
- **Circuit breaker** — [src/hooks/circuit-breaker.ts](src/hooks/circuit-breaker.ts) + [src/features/background-manager/index.ts](src/features/background-manager/index.ts): feeds every `tool.execute.after` call into `BackgroundManager.recordSessionToolCall()`; trips on N consecutive identical calls (default 20) or total tool calls (default 4000), aborting the session via `client.session.abort`.
252257
- **Agent-browser guard** — [src/tools/agent-browser/index.ts](src/tools/agent-browser/index.ts): `browserGateGuard()` throws for non-`vision`/`general` agents.
253258
- **LSP sandbox** — [src/tools/lsp/index.ts](src/tools/lsp/index.ts): throws on paths resolving outside `ctx.directory`.
@@ -274,7 +279,7 @@ Git worktree-based task isolation for parallel work.
274279

275280
- **WorktreeManager** — [src/features/worktree/index.ts](src/features/worktree/index.ts): create/list/remove/cleanup operations
276281
- **Tools** — [src/tools/worktree.ts](src/tools/worktree.ts): `hiai_worktree_create`, `hiai_worktree_remove`, `hiai_worktree_list`, `hiai_worktree_status`
277-
- **Lifecycle hooks** — [src/hooks/worktree-lifecycle.ts](src/hooks/worktree-lifecycle.ts): auto-create on plan-start signals, auto-remove on `<CLOSURE>`
282+
- **Lifecycle hooks** — [src/hooks/worktree-lifecycle.ts](src/hooks/worktree-lifecycle.ts): track explicit `hiai_worktree_create` calls; clean up on session delete / dispose. No auto-create from user-message regex.
278283
- **Skill** — [skills/general/using-git-worktrees/](skills/general/using-git-worktrees/)
279284
- **Prompt integration** — [src/prompt-library/worktree.ts](src/prompt-library/worktree.ts): `WORKTREE_AWARENESS`
280285

‎CHANGELOG.md‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,33 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.6.2] — 2026-08-23
9+
10+
### ⚡ Orchestration contract: plan once, parallel waves, critic once
11+
12+
Breaking agent-behavior change. Multi-point work is no longer re-planned mid-flight and no longer sends Critic after every specialist.
13+
14+
- **Plan freeze.** Plan is invoked once, then frozen. A second Plan spawn is denied unless the prompt contains `INVALIDATE_PLAN` (scope change, worker proved the plan wrong, or delivery Critic said it is unexecutable). Runtime: `src/features/plan-lifecycle/` + `src/hooks/plan-lifecycle-gate.ts`.
15+
- **Delivery Critic once.** Bob/Manager/Build prompts no longer require Critic after every specialist. Critic is blocked while a frozen plan is still executing and incomplete todos remain. The completion controller will not inject a review prompt mid-plan.
16+
- **Spawn matrix.** `getTaskPermissions()`: Manager cannot spawn Plan/Critic; Plan spawns explore only; Build spawns explore only; Critic spawns vision+explore; other workers are leaves.
17+
- **Parallel waves.** Prompts require concurrent `task()` in the **same** assistant message for `parallel: yes` steps. Manager no longer re-reads the plan after every delegation.
18+
- **Skills.** `subagent-driven-development` is opt-in paranoid mode. `writing-plans` hands off to frozen `.bob/plans/` waves. Code review is at delivery, not after each task.
19+
- **Worktree lifecycle.** No auto-create on user-message regex; no teardown on arbitrary `<CLOSURE>`. Explicit `hiai_worktree_create` only.
20+
- **Quality gate.** Bare `\bfailed\b` no longer trips the gate (false positives). Counts like `1 failed` and `FAIL` still do.
21+
- **Docs.** README / AGENTS.md / ARCHITECTURE.md describe the frozen-plan → waves → delivery-Critic path; spawn matrix; `INVALIDATE_PLAN`.
22+
- **Native OpenCode UI.** Bob/`todowrite` mirrors the frozen plan as phase parents + indented step children so the TUI task list is hierarchical. `task()` remains the parent/child session tree.
23+
- **Question tool.** Plan and Bob have `question: allow`. Direct Plan interviews on complex/unclear user-owned facts (native `question` UI). Plan spawned by Bob cannot interview — `host-interaction-gate` blocks `question` when the session has a `parentID`. Other agents `question: deny`.
24+
- **Memory.** Prompts use OpenCode native `memory` first; `hiai_memory_search` is forensic fallback.
25+
- **Manager.** Only for a **large phase** (not 1–2 file / `general` work). May spawn **one Critic at phase close** (that slice only). Bob still runs one **delivery Critic** after all phases. Phase-close critic does not mark the frozen plan `done`.
26+
- **Freeze persists** in `.bob/plans/.lifecycle.json` plus YAML frontmatter (`status`, `checksum`) so a restart does not unlock re-plan.
27+
- **Progress line.** Bob must lead user-facing messages with Plan / status / phase N/M / what is running.
28+
- **Skills.** `subagent-driven-development` is loadable only as `plan/subagent-driven-development` — not a short-name default hit.
29+
- **Doctor.** Missing/empty `models.bob`, `models.plan`, or `models.build` is a hard fail.
30+
- **Single `bob.json`.** Plugin and CLI walk ancestors the same way (`bob.json` → `.opencode/bob.json` → jsonc → `~/.config/hiai-opencode`). All tunables (loop, completion, models, mcp) live there.
31+
- **Run-to-completion loop.** Default `loop.enabled=true`. Canonical budget is `loop.max_auto_continues` (default 50; aliases `loop.maxIterations` and `completion.max_auto_continues`). Idle `session.prompt` is a fallback only — skipped when native `actor.postStop` continue is already running (no double TUI loop). `question` is blocked while a plan is executing.
32+
- **Per-session freeze.** `.bob/plans/.lifecycle.json` is a map of session → plan. A new chat in the same repo can start a new Plan. Todos snapshot with the freeze; Bob restores via `todowrite` after restart of the same session.
33+
- **Doctor.** First check prints the resolved `bob.json` absolute path (or warn if defaults).
34+
835
## [0.6.1] — 2026-08-13
936

1037
### 🌐 Runtime Lightpanda auto-selection

0 commit comments

Comments
 (0)