@osovv/vv-opencode 1.3.4 → 1.3.6-rc.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @osovv/vv-opencode
2
2
 
3
- **Curated, opinionated OpenCode plugin set** for spec-first, review-driven, safer agentic development — with managed agents, skills, safety plugins, and the `vvoc` CLI.
3
+ **An opinionated agentic development layer for OpenCode** — spec-first when it matters, review-driven execution, portable model roles, safer tools, and long-run safety. Under the hood it ships as a set of OpenCode plugins, managed agents, skills, and the `vvoc` CLI.
4
4
 
5
5
  <p>
6
6
  <a href="https://www.npmjs.com/package/@osovv/vv-opencode"><img src="https://img.shields.io/npm/v/%40osovv%2Fvv-opencode?style=flat&label=npm&color=blue" alt="npm"></a>
@@ -11,49 +11,87 @@
11
11
  <a href="LICENSE"><img src="https://img.shields.io/github/license/osovv/vv-opencode?style=flat&color=green" alt="MIT"></a>
12
12
  </p>
13
13
 
14
+ OpenCode owns the mechanics: streaming, model invocation, sandboxing, permissions. The development *process* — when to clarify, when to plan, when to review, how to survive long runs — it leaves up to you.
15
+
16
+ vv-opencode adds that process layer. It is a hand-picked workflow crystallized from a year and a half of daily agentic development: you run `vvoc install`, learn three skills (`vv-spec`, `vv-plan`, `vv-execute`), and get a disciplined spec-to-code pipeline with review gates, portable model roles, and long-run safety — without needing to know how any of it works inside.
17
+
18
+ The spec pipeline is the most visible part, but it is only one layer. Everything underneath runs on every session whether or not you ever write a spec: each model edits files through the tool it knows best, routine permissions are approved without interrupting your run, secrets never reach the model, and multi-agent work is held together by an explicit state machine instead of prompt luck. If you already have your own spec tooling, keep it — the runtime layers below apply anyway.
19
+
14
20
  ---
15
21
 
16
- ## Quick Start
22
+ ## Why vv-opencode?
23
+
24
+ OpenCode is a strong, flexible base, but it intentionally leaves the development process up to you. Left to itself, agentic work tends to drift: requirements get skipped, one agent silently implements and "reviews" itself, multi-agent loops churn through "one more final review", long runs stall on permission prompts, and model choices are hardcoded everywhere.
25
+
26
+ vv-opencode addresses each of these:
27
+
28
+ - **Formalized trajectories** — small changes stay direct, unclear bugs start with investigation, large changes go through spec and plan, risky implementation uses review loops.
29
+ - **Spec-first by default** — broad requests become explicit specs, plans, and review gates before implementation, and every artifact is saved as grep-able XML.
30
+ - **Review-driven execution** — implementation, spec review, and code review are separate steps with bounded retries, not one agent silently doing everything.
31
+ - **A state machine for multi-agent work** — explicit work items, required reviewers, round limits, and hard stops instead of free-form subagent loops.
32
+ - **Portable model choices** — agents reference roles like `vv-role:smart` and `vv-role:fast`; you map roles to concrete models per machine or project and switch stacks with one preset command.
33
+ - **Per-model editing** — each model edits through the tool it knows best: DeepSeek gets its `str_replace_editor` contract, GLM/Qwen/Kimi get exact-match replace, and GPT keeps the host editing path. Routing is resolved dynamically per session, and every edit is anchored to a fresh file read — fewer wrong-line and stale-context errors.
34
+ - **Provider-neutral web tools** — agents get one canonical `web_search` and `web_fetch` contract backed by Exa, Brave, Z.AI, native retrieval, or Spider, instead of provider-specific search and reader schemas leaking into your prompts.
35
+ - **Long-run safety** — Guardian auto-approves routine low-risk permissions (risky ones stay in OpenCode's manual approval flow), and secrets are redacted before they reach the model.
36
+ - **Reproducible setup** — `vvoc install` / `vvoc sync` recreate the same workflow on any machine or project.
37
+
38
+ ---
39
+
40
+ ## You just talk to OpenCode normally
41
+
42
+ You don't need to learn a command surface first. Ask for what you want — `vv-controller` picks the lightest appropriate trajectory, and explicit skills take over only when the work needs them:
43
+
44
+ ```text
45
+ > Rename this field and update its tests.
46
+ → handled directly
47
+
48
+ > Why does auth occasionally return 401 after a token refresh?
49
+ → root-cause investigation first → targeted fix → verification
50
+
51
+ > Add organizations with role-based access.
52
+ → vv-spec → approval → vv-plan → approval → vv-execute
53
+ ├─ implement
54
+ ├─ spec review
55
+ └─ code review
56
+ ```
57
+
58
+ Every managed skill can also be invoked explicitly when you want to drive the process yourself.
59
+
60
+ ---
61
+
62
+ ## Quick start
17
63
 
18
64
  ```bash
19
- bun add -g opencode-ai@1.18.2
65
+ bun add -g opencode-ai
20
66
  bun add -g @osovv/vv-opencode
21
67
  vvoc install
22
68
  ```
23
69
 
24
- That's it. `vvoc install` pins the server plugin, registers the same pinned package for OpenCode to load its `/context` TUI export, scaffolds managed agents and skills, writes canonical config, and sets `vv-controller` as your default OpenCode agent with auto-triggered spec, planning, review, reflection, and handoff skills. The TUI integration requires OpenCode `1.18.2` or newer; `vvoc status` and `vvoc doctor` report the installed host version and fail compatibility checks for older releases.
70
+ `vvoc install` does four things:
71
+
72
+ - pins `@osovv/vv-opencode` as an OpenCode runtime plugin and registers the same pinned package as the OpenCode TUI plugin;
73
+ - scaffolds the managed agents and skills;
74
+ - writes the canonical `vvoc.json` config;
75
+ - sets `vv-controller` as your default OpenCode agent, with the spec, planning, review, reflection, and handoff skills auto-triggered by request type.
76
+
77
+ The TUI integration requires OpenCode `1.18.2` or newer; `vvoc status` and `vvoc doctor` report the installed host version and fail compatibility checks for older releases.
25
78
 
26
- To scope everything to the current project instead of the global OpenCode config:
79
+ **Want to try it without touching your global setup?** Scope everything to one project:
27
80
 
28
81
  ```bash
29
82
  vvoc install --scope project
30
83
  vvoc launch --scope project
31
84
  ```
32
85
 
33
- Project scope writes only to `./.opencode/` and `./.vvoc/`. A normal `opencode` launch may still apply OpenCode's native config discovery and merge behavior; `vvoc launch --scope project` is the hard sandbox path and starts OpenCode with `OPENCODE_CONFIG`, `OPENCODE_TUI_CONFIG`, and `VVOC_CONFIG` pinned to the selected local files, so you can smoke-test vv-opencode in one repository without mutating your primary global setup.
86
+ Project scope writes only to `./.opencode/` and `./.vvoc/`. A plain `opencode` launch may still apply OpenCode's native config discovery and merge behavior; `vvoc launch --scope project` is the hard sandbox path — it starts OpenCode with `OPENCODE_CONFIG`, `OPENCODE_TUI_CONFIG`, and `VVOC_CONFIG` pinned to the selected local files, so you can smoke-test vv-opencode in one repository without mutating your primary global setup.
34
87
 
35
88
  > **Already installed?** Run `vvoc sync` anytime to refresh plugins, prompts, skills, and presets.
36
89
 
37
90
  ---
38
91
 
39
- ## 1.0 Stability Posture
40
-
41
- `vv-opencode` 1.0 marks the workflow as a daily-driver baseline: a hand-picked, curated OpenCode setup that packages the agent routing, managed skills, model-role indirection, safer editing, review loops, and release discipline used in real projects.
42
-
43
- The stable user-facing surface is intentionally practical:
44
-
45
- - `vvoc install` / `vvoc sync` / `vvoc launch` remain the primary setup and refresh path.
46
- - `vv-spec`, `vv-plan`, and `vv-execute` remain the canonical spec-to-code path for larger work.
47
- - `vv-review`, `vv-reflect`, and `vv-handoff` remain the auxiliary review, durable-learning, and session-continuity workflows.
48
- - The published package exports, CLI command names, canonical vvoc schema v3, and date-prefixed `.vvoc/specs/YYYY-MM-DD-<slug>/` artifact layout are treated as compatibility surfaces.
49
-
50
- The project still prefers conservative, explicit changes over hidden migration magic: user-owned config is not silently clobbered, invalid current config fails loudly, and breaking workflow or config changes must be documented in release notes.
51
-
52
- ---
53
-
54
- ## Spec-to-Code Pipeline
92
+ ## How it works: spec → plan → execute
55
93
 
56
- vvoc keeps larger agentic work from jumping straight into edits. The process turns a request into explicit artifacts first, then executes the approved plan with bounded implementation and review loops.
94
+ vvoc keeps larger agentic work from jumping straight into edits. A request first becomes explicit artifacts; only the approved plan gets executed, with bounded implementation and review loops. This trajectory is opt-in per request: small changes never go through it, and if you already run your own spec workflow, you can keep it — nothing else in vv-opencode depends on these skills.
57
95
 
58
96
  ```
59
97
  Request / idea
@@ -77,7 +115,7 @@ vv-execute
77
115
  Verified result
78
116
  ```
79
117
 
80
- Inside `vv-execute`:
118
+ Inside `vv-execute`, each plan task goes through a tracked loop:
81
119
 
82
120
  ```text
83
121
  Each plan task
@@ -106,84 +144,267 @@ All artifacts for one feature live together:
106
144
  plan.xml # how to implement and verify it
107
145
  ```
108
146
 
109
- New `vv-spec` packages use a date-prefixed id (`YYYY-MM-DD-<slug>`, for example `2026-06-24-cache-store`) so active packages sort by creation date. The prefix is date-only; it must not include hours, minutes, seconds, timezone, or a full ISO timestamp.
147
+ Package ids are date-prefixed (`YYYY-MM-DD-<slug>`, for example `2026-06-24-cache-store`) so active packages sort by creation date; the prefix is date-only, never a full timestamp. Spec and plan lifecycle runs through a top-level status: `draft` while being written, `approved` after explicit user approval, `applied` after successful execution. `vv-execute` archives applied packages by moving the whole directory to `.vvoc/specs/archive/YYYY-MM-DD-<slug>-<timestamp>/`.
110
148
 
111
- Specs and plans use a top-level lifecycle status: `draft` while being written, `approved` after explicit user approval, and `applied` after successful execution. `vv-execute` archives applied artifact packages by moving the entire spec package directory `.vvoc/specs/YYYY-MM-DD-<slug>/` to `.vvoc/specs/archive/YYYY-MM-DD-<slug>-<timestamp>/`.
149
+ Specs and plans are XML, so requirements, tasks, acceptance criteria, and dependencies stay grep-able. Task and wave identity lives in unique element names (`<TASK-T-001>…</TASK-T-001>`, `<WAVE-1>…</WAVE-1>`), so grep/sed extraction stays exact without a separate query language:
112
150
 
113
- ### XML grep
151
+ ```bash
152
+ grep '<TASK-T-' .vvoc/specs/*/plan.xml # task ids
153
+ grep '<criterion>' .vvoc/specs/*/plan.xml # acceptance criteria
154
+ grep '<task_id>' .vvoc/specs/*/plan.xml # dependency graph
155
+ ```
114
156
 
115
- Plans and specs are XML documents, making every element grep-able:
157
+ `vv-controller` explicitly routes `vv-spec`, `vv-plan`, and `vv-review`; `vv-execute`, `vv-reflect`, and `vv-handoff` are available as managed skills for plan execution, durable repository memory, and end-of-session handoff notes.
116
158
 
117
- ```bash
118
- # Extract tasks from plan
119
- grep '<id>T-' .vvoc/specs/*/plan.xml
159
+ ---
120
160
 
121
- # Extract all acceptance criteria
122
- grep '<criterion>' .vvoc/specs/*/plan.xml
161
+ ## What's inside
123
162
 
124
- # Extract dependency graph
125
- grep '<task_id>' .vvoc/specs/*/plan.xml
163
+ ### The eleven plugins
126
164
 
127
- # Extract method signatures
128
- grep '/\*\*' .vvoc/specs/*/plan.xml
165
+ | Plugin | What it does |
166
+ |---|---|
167
+ | **WorkflowPlugin** | A state machine over multi-agent work: explicit work items, required reviewers, bounded implementation/review rounds, and hard stops when more context is needed. |
168
+ | **ModelRolesPlugin** | Semantic model roles (`vv-role:smart`, `vv-role:fast`, …) instead of hardcoded model IDs in agents, subagents, and commands — resolved per machine or project at startup. |
169
+ | **GuardianPlugin** | Keeps long or AFK runs moving by auto-approving routine low-risk permission requests; anything risky stays in OpenCode's normal manual approval flow. |
170
+ | **HashlineEditPlugin** | Routes each model to the edit tool it knows best (DeepSeek `str_replace_editor`, exact replace for GLM/Qwen/Kimi, host path for GPT) and ties every edit to a fresh `read`, reducing wrong-line and stale-context edits. |
171
+ | **SystemContextInjectionPlugin** | Injects the work policy selected by the orchestration profile into vv-controller at startup, plus skill discovery; subagents stay unpolluted. |
172
+ | **SecretsRedactionPlugin** | Redacts tokens, keys, emails, and other sensitive values before messages reach the model, restoring them only where local execution needs the originals. |
173
+ | **WebToolsPlugin** | Two provider-neutral tools — `web_search` and `web_fetch` — over Exa, Brave, Z.AI, native retrieval, or Spider, with permission checks and normalized output. |
174
+ | **ToolHistoryCompactionPlugin** | Shrinks the context replayed to the model by compacting old tool outputs non-destructively, without touching on-disk history. |
175
+ | **AnalyticsPlugin** | Local-only token and cache telemetry per model step, a live `cache NN%` indicator in the TUI, and `vvoc analytics cache-hit-rate` for retrospective comparison. |
176
+ | **PeakHoursPlugin** | Warns or blocks models whose provider is in peak-priced hours right now, suggests connected off-peak providers, and shows a persistent orange banner in the TUI. |
177
+ | **ContextTuiPlugin** | The `/context` inspector: an honest, scrollable TUI dialog showing context-window usage by category, tool, and MCP server. |
178
+
179
+ ### Managed agents
129
180
 
130
- # Extract all modules from architecture
131
- grep '<name>' .vvoc/specs/*/plan.xml
132
- ```
181
+ All prompt files are scaffolded by `vvoc install` / `vvoc sync`:
182
+
183
+ | Agent | When it helps |
184
+ |---|---|
185
+ | `vv-controller` | Primary agent that follows the concrete work policy selected for the session by the orchestration profile |
186
+ | `enhancer` | Improves rough requests before execution when a clearer prompt would help |
187
+ | `vv-implementer` | Applies a focused approved change and verifies it before reporting completion |
188
+ | `vv-spec-reviewer` | Checks whether implementation matches the requested spec and acceptance criteria |
189
+ | `vv-code-reviewer` | Looks for bugs, regressions, maintainability risks, and missing tests |
190
+ | `investigator` | Finds the root cause first when behavior is unclear or a failure needs diagnosis |
191
+ | `guardian` | Supports GuardianPlugin by reviewing permission requests and auto-approving only routine low-risk ones |
192
+
193
+ ### Managed skills
194
+
195
+ Two families: `vv-*` skills guide the work protocol, while `vvoc-*` skills operate and observe the vvoc/OpenCode tooling itself.
196
+
197
+ | Skill | When to use it | What it gives you |
198
+ |---|---|---|
199
+ | `vv-spec` | You have a feature or creative request and no agreed contract yet | A guided interview, recommended options, and a saved spec in `.vvoc/specs/YYYY-MM-DD-<slug>/spec.xml` |
200
+ | `vv-plan` | A spec is approved and ready to implement | A task-level implementation plan with file targets, contracts, dependencies, and acceptance criteria |
201
+ | `vv-execute` | A plan is approved and you want it applied step by step | Ordered execution with verification, an explicit inline-or-classic mode choice, and applied spec/plan archival |
202
+ | `vv-review` | You want findings, not fixes | A review-only workflow that reports spec/code issues and stops before implementation |
203
+ | `vv-reflect` | A long development, debugging, ops, or investigation session produced reusable knowledge | Durable notes in existing docs or `.vvoc/lessons` / `.vvoc/runbooks` for future agents |
204
+ | `vv-handoff` | You are ending a session and want the visible context preserved | A redacted XML note at `.vvoc/handoff/YYYY-MM-DD-<session-slug>/handoff.xml`, written from already-visible context only |
205
+ | `vvoc-usage-analytics` | You ask about token usage, cache hit rate, costs, or caching regressions | Read-only analysis across `vvoc analytics`, the analytics JSONL, and historical `opencode.db` data |
133
206
 
134
- Managed skills are installed by `vvoc`. `vv-controller` explicitly routes `vv-spec`, `vv-plan`, and `vv-review`; `vv-execute`, `vv-reflect`, and `vv-handoff` are available as managed skills for plan execution, durable repository memory, and end-of-session handoff notes.
207
+ Skills are loaded by OpenCode at session start through `config.skills.paths` (registered by SystemContextInjectionPlugin); the `vv-controller` agent's skill-trigger rules invoke them automatically when a request matches their conditions.
135
208
 
136
209
  ---
137
210
 
138
- ## Why vv-opencode?
211
+ ## CLI at a glance
139
212
 
140
- OpenCode is a strong, flexible base for agentic coding, but it intentionally leaves the development process mostly up to you: when to clarify requirements, when to plan, when to investigate first, when to review, and how to keep longer runs safe. That flexibility is powerful, but it can also make agent work feel loose and inconsistent.
213
+ | Command | Purpose |
214
+ |---|---|
215
+ | `vvoc init` | Interactive bootstrap flow |
216
+ | `vvoc install` | Non-interactive setup and scaffolding |
217
+ | `vvoc sync` | Refresh runtime/TUI plugin entries, agents, prompts, skills, config |
218
+ | `vvoc launch` | Launch OpenCode with deterministic runtime, TUI, and vvoc config sources |
219
+ | `vvoc status` | Show current installation state, including OpenCode version compatibility and TUI registration |
220
+ | `vvoc doctor` | Diagnose OpenCode version/runtime/TUI/vvoc setup problems (exits non-zero on issues) |
221
+ | `vvoc config validate` | Validate canonical `vvoc.json` |
222
+ | `vvoc role list\|set\|unset` | Manage model role assignments |
223
+ | `vvoc preset list\|show\|<name>` | Inspect or apply named presets |
224
+ | `vvoc guardian config` | Print or write the guardian section |
225
+ | `vvoc plugin list` | List OpenCode plugin entries |
226
+ | `vvoc plugin enable\|disable` | Toggle a vvoc-managed plugin on or off |
227
+ | `vvoc orchestration show\|set` | Show or set the vv-controller orchestration profile |
228
+ | `vvoc patch-provider stepfun-ai\|codex\|deepseek\|kimi\|alibaba\|all` | Patch OpenCode providers; `codex` adds subscription-safe OpenAI aliases (also accepts `openai`), `deepseek`/`kimi`/`alibaba` add vv- reasoning-effort aliases, `all` patches every provider at once |
229
+ | `vvoc completion` | Install shell completions |
230
+ | `vvoc upgrade` | Upgrade the global package and run follow-up sync; sync failure is reported as a partial upgrade |
231
+ | `vvoc analytics cache-hit-rate` | Aggregate persisted cache hit rate by day, week, month, session, model, provider, project, vvoc version, or OpenCode version |
232
+ | `vvoc version` | Print installed version |
141
233
 
142
- **vv-opencode adds a curated process layer on top of OpenCode:**
234
+ Guardian duration overrides use positive whole milliseconds. Both `--timeout-ms` and `--review-toast-duration-ms` reject zero, negative, fractional, missing, or malformed values:
143
235
 
144
- - **Formalized trajectories** — small changes stay direct, unclear bugs start with investigation, large changes go through spec and plan, and risky implementation uses review loops
145
- - **Spec-first by default** — turn broad requests into explicit specs, plans, and review gates before implementation
146
- - **Review-driven execution** — keep implementation, spec review, and code review as separate steps instead of one agent silently doing everything
147
- - **Portable model choices** — use roles like `vv-role:smart` and `vv-role:fast` in shared agents, then map those roles per machine or project
148
- - **Long-run safety** — Guardian auto-approves routine low-risk permission requests, leaves risky ones to OpenCode's manual approval flow, and secrets redaction reduces accidental leakage
149
- - **Safer edits** — per-model edit routing gives each model its native editing tool: hashline-anchored edits, exact oldString/newString replace, or the DeepSeek `str_replace_editor`, all tied to fresh `read` output so agents rarely write against stale content
236
+ ```bash
237
+ vvoc guardian config --print --timeout-ms 30000 --review-toast-duration-ms 5000
238
+ ```
150
239
 
151
240
  ---
152
241
 
153
- ## Features
242
+ ## Configuration
154
243
 
155
- | Area | What you get |
156
- |---|---|
157
- | **Plugins** | A curated set of OpenCode plugins that make agentic work more structured, portable, and safer without hand-wiring each piece yourself |
158
- | **Agent System** | A default controller (vv-controller) that follows the concrete work policy selected by the orchestration profile |
159
- | **Skills** | Guided workflows for turning ideas into specs, specs into plans, plans into execution, reviews into findings, and long sessions into reusable memory |
160
- | **Spec-to-Code Pipeline** | A repeatable path from request → spec → plan → implementation → review, so agents do not silently skip requirements or acceptance criteria |
161
- | **One-Click Setup** | Recreate the same opinionated workflow on a new machine or project with `vvoc install` / `vvoc sync` |
162
- | **CLI Tooling** | Operate and diagnose the setup from one CLI: install, sync, launch, status, doctor, roles, presets, orchestration profiles, plugin toggles, completion, and upgrade |
163
- | **Long-Run Safety** | Guardian keeps safe long/AFK runs moving by auto-approving routine low-risk permissions, while risky actions stay in OpenCode's manual approval flow; secrets redaction reduces accidental leakage |
164
- | **Model Roles** | Put roles like `vv-role:smart` or `vv-role:fast` in shared agents and skills instead of hardcoded model IDs, then choose provider/model mappings per environment |
165
- | **Orchestration Profiles** | Select a concrete work policy — single-session, balanced, or orchestrated — to control how vv-controller delegates. Built-in presets pick a sensible default and status reports the effective profile. |
166
- | **Workflow Tracking** | Replace free-form multi-agent chaos with explicit work items, bounded review rounds, reviewer result collection, and hard stops when more context is needed |
167
- | **Unified Web Tools** | Replace provider-specific search and reader schemas with the canonical `web_search` and `web_fetch` tools, configurable for Exa, Brave, native retrieval, or Spider extraction |
168
- | **Context Inspector** | Run `/context` in an active OpenCode TUI session for Overview, Tools, and MCP tabs with provider-reported usage, approximate context-window percentages, active post-compaction tool history, and deterministic source attribution |
169
- | **Cache Analytics** | Watch a live per-session `cache NN%` indicator in the TUI and compare cache hit rates across vvoc releases, OpenCode versions, models, and projects with `vvoc analytics cache-hit-rate` |
244
+ Mutating commands default to global scope for backward compatibility; add `--scope project` to write a project-local layer. Read and diagnostic commands accept `--scope global|project|effective`, where `effective` resolves in this order:
245
+
246
+ 1. explicit env override (`VVOC_CONFIG` / `OPENCODE_CONFIG` / `OPENCODE_TUI_CONFIG`)
247
+ 2. nearest project layer
248
+ 3. global layer
249
+ 4. built-in defaults when the command/runtime permits defaults
250
+
251
+ Canonical project-local paths:
252
+
253
+ ```text
254
+ OpenCode config → ./.opencode/opencode.json(c)
255
+ OpenCode TUI config → ./.opencode/tui.json(c)
256
+ vvoc config → ./.vvoc/vvoc.json
257
+ Managed agent prompts → ./.vvoc/agents/*.md
258
+ Managed skills → ./.vvoc/skills/*/SKILL.md
259
+ Spec package directory → ./.vvoc/specs/YYYY-MM-DD-<slug>/
260
+ Handoff notes → ./.vvoc/handoff/YYYY-MM-DD-<session-slug>/handoff.xml
261
+ Repository memory → ./.vvoc/lessons/*.xml, ./.vvoc/runbooks/*.xml
262
+ ```
263
+
264
+ Legacy root-level `./opencode.json` and `./opencode.jsonc` are intentionally not used as vvoc project layers.
265
+
266
+ Global paths:
267
+
268
+ ```text
269
+ OpenCode config → $XDG_CONFIG_HOME/opencode/opencode.json
270
+ OpenCode TUI config → $XDG_CONFIG_HOME/opencode/tui.json(c)
271
+ vvoc config → $XDG_CONFIG_HOME/vvoc/vvoc.json
272
+ Managed agent prompts → $XDG_CONFIG_HOME/vvoc/agents/*.md
273
+ Managed skills → $XDG_CONFIG_HOME/vvoc/skills/*/SKILL.md
274
+ Persisted data → $XDG_DATA_HOME/vvoc/
275
+ Usage analytics → $XDG_DATA_HOME/vvoc/analytics/usage-YYYY-MM.jsonl
276
+ ```
277
+
278
+ ### Two config surfaces, one pinned package
279
+
280
+ OpenCode keeps server/runtime plugins and native TUI plugins in separate configuration surfaces. `opencode.json(c)` is loaded by the core/server plugin runtime and activates vvoc features such as model roles, Guardian, workflow, hashline edit, redaction, and web tools. `tui.json(c)` is loaded by the terminal UI process and activates the package's `./tui` module (the `/context` inspector). The same pinned package version appears in both files, but OpenCode selects a different public export for each process; headless/server launches therefore never load the UI module.
281
+
282
+ `vvoc install`, `vvoc init`, and `vvoc sync` conservatively add the pinned base package specifier (for example `@osovv/vv-opencode@X.Y.Z`) to `tui.json(c)`; sync also migrates the broken legacy `@osovv/vv-opencode/tui` form and older managed pins. Existing comments, unrelated settings, unrelated plugin entries, and `[specifier, options]` tuples are preserved; malformed plugin entries fail without rewrite.
283
+
284
+ Runtime plugins load the effective `vvoc.json` once during OpenCode startup and share one immutable config snapshot for the lifetime of the process. There is no live reload: restart OpenCode after changing `vvoc.json` or `tui.json(c)`.
285
+
286
+ ### Strict schema, loud failures
287
+
288
+ The config contract is versioned and published with the package — source of truth at `schemas/vvoc/v3.json`. `vvoc.json` must be canonical version 3 and include required sections such as `plugins`. Existing v1/v2/pre-role, incomplete, malformed, or otherwise invalid config files fail instead of being migrated or repaired. `vvoc install` and `vvoc sync` may create a fresh canonical config when no config exists, but they refuse to rewrite an invalid existing `vvoc.json`; fix the file manually and rerun `vvoc sync`.
289
+
290
+ The optional schema-v3 `web` section follows the same layer precedence and is omitted from generated defaults — see [Web tools](#web-tools) for provider selection:
291
+
292
+ ```json
293
+ "web": {
294
+ "search": { "provider": "exa", "apiKey": "optional-exa-key" },
295
+ "fetch": { "provider": "native" }
296
+ }
297
+ ```
298
+
299
+ ### Diagnostics never mutate
300
+
301
+ `vvoc status` and `vvoc doctor` report the installed OpenCode version, the `1.18.2` TUI minimum, selected runtime/TUI/vvoc config paths, and validation problems without normalizing or rewriting files. `vvoc upgrade` can still finish the package installation when the follow-up `vvoc sync` fails; it then reports a partial upgrade, leaves config unchanged, and tells you to fix the invalid config before rerunning `vvoc sync`.
302
+
303
+ Runtime compatibility is current-only: Guardian permission replies use the current OpenCode permission reply path (with the current HTTP reply fallback), hashline edit refs must use current hash/context anchors, and sync writes current managed agents without deleting old pre-rename user or command entries.
304
+
305
+ ### Release channels
306
+
307
+ The package publishes through npm dist-tags with exactly one pre-release channel, `rc`. A default `vvoc upgrade` resolves only the stable `latest` dist-tag and never offers a release candidate; pre-release versions are published with `--tag rc`, so `latest` can never move onto a candidate.
308
+
309
+ Opt in explicitly when you want candidates:
310
+
311
+ ```bash
312
+ vvoc upgrade --rc # upgrade to the version currently on the rc dist-tag
313
+ vvoc upgrade --allow-prerelease # same behavior, kept as an alias
314
+ ```
315
+
316
+ When the `rc` dist-tag has no published candidate yet, the command reports it and installs nothing. If you sit on `1.4.0-rc.1` and the stable `1.4.0` ships, the default `vvoc upgrade` moves you onto the stable release — semver orders `1.4.0` above its candidates. Plugin consumers can install the channel directly with `npm i -g @osovv/vv-opencode@rc`.
317
+
318
+ Maintainers release candidates through the same exact-SHA CI-gated flow, with the channel derived from the bumped version:
319
+
320
+ ```bash
321
+ bun run release:bump -- prerelease --preid rc # 1.4.0-rc.1, published to the rc dist-tag, GitHub Release marked pre-release
322
+ bun run release:bump -- prerelease --preid rc # next candidate: 1.4.0-rc.2
323
+ bun run release:bump -- 1.4.0 # final stable release, published to latest
324
+ ```
325
+
326
+ An explicit `--channel latest|rc` argument may only confirm the derived channel; a contradicting value aborts the bump before any commit or publication.
327
+
328
+ ### Stability and compatibility
329
+
330
+ Since 1.0, vv-opencode treats the daily-driver surface as stable. The compatibility surfaces are: `vvoc install` / `vvoc sync` / `vvoc launch`, the managed skill names (`vv-spec`, `vv-plan`, `vv-execute`, `vv-review`, `vv-reflect`, `vv-handoff`), the published package exports, canonical vvoc schema v3, and the date-prefixed `.vvoc/specs/YYYY-MM-DD-<slug>/` artifact layout. Breaking workflow or config changes are documented in release notes. The project still prefers conservative, explicit changes over hidden migration magic: user-owned config is never silently clobbered, and invalid current config fails loudly.
331
+
332
+ ### Deterministic local launch
333
+
334
+ Use `vvoc launch` when the vvoc-selected config files should be the only files OpenCode sees for this run:
335
+
336
+ ```bash
337
+ vvoc install --scope project
338
+ vvoc launch --scope project -- run "hello"
339
+ ```
340
+
341
+ `vvoc launch --scope project` is strict and non-mutating: if `.opencode/opencode.json` or `.vvoc/vvoc.json` is missing, it fails with a hint to run `vvoc install --scope project`. When the selected `.opencode/tui.json(c)` exists, launch also sets `OPENCODE_TUI_CONFIG`; a missing TUI file is not synthesized. `--scope effective` follows the layered lookup order, and `--scope global` uses the global config paths.
170
342
 
171
343
  ---
172
344
 
173
- ## The Ten Plugins
345
+ ## Deep dives
346
+
347
+ ### Model roles & presets
348
+
349
+ ```bash
350
+ # View current assignments
351
+ vvoc role list
352
+ vvoc role list --scope effective
353
+
354
+ # Assign models to roles
355
+ vvoc role set default deepseek/deepseek-v4-flash
356
+ vvoc role set smart openai/vv-codex-gpt-5.6-sol-xhigh
357
+ vvoc role set fast openai/vv-codex-gpt-5.6-luna-low
358
+ vvoc role set reviewer zai-coding-plan/glm-5.2 --scope project
174
359
 
175
- | Plugin | What it helps you do |
360
+ # Switch provider presets
361
+ vvoc preset vv-codex
362
+ vvoc preset vv-zai
363
+ vvoc preset vv-deepseek
364
+ vvoc preset vv-kimi
365
+ vvoc preset vv-alibaba
366
+ vvoc preset vv-osovv-sol
367
+ vvoc preset vv-osovv-flash
368
+ vvoc preset vv-osovv-kimi
369
+ vvoc preset vv-osovv-qwen
370
+ ```
371
+
372
+ Built-in role IDs: `default`, `smart`, `fast`, `reviewer`, plus any custom lowercase-hyphenated IDs. Presets are partial — applying one only changes the roles it defines. Managed built-in presets (`vv-*`) are refreshed on every `vvoc install`/`vvoc sync`; user-defined presets are preserved as-is.
373
+
374
+ ### Orchestration profiles
375
+
376
+ Three concrete policies control how vv-controller delegates work at runtime:
377
+
378
+ - `single-session` — vv-controller performs exploration, investigation, planning, implementation, and verification directly. Independent reviewer subagents remain available when the user explicitly requests review or when a materially risky completed change benefits from independent cross-model evaluation.
379
+ - `balanced` — vv-controller keeps architecture, critical reading, and final synthesis in the primary session and may selectively delegate bounded search, investigation, mechanical implementation, or review when that is the lightest safe route. Delegation is optional, not mechanically mandatory.
380
+ - `orchestrated` — vv-controller uses the full tracked implementer/reviewer workflow with explicit work items, required reviewers, bounded rounds, and hard stops.
381
+
382
+ Pick a profile explicitly or let a built-in preset select one:
383
+
384
+ ```bash
385
+ vvoc orchestration show --scope effective
386
+ vvoc orchestration set single-session --scope project
387
+ ```
388
+
389
+ Built-in presets declare an orchestration mapping:
390
+
391
+ | Preset | Profile |
176
392
  |---|---|
177
- | **WorkflowPlugin** | Keep multi-agent work structured with explicit work items, bounded implementation/review loops, reviewer result collection, and safe stops when more context is needed. |
178
- | **ModelRolesPlugin** | Use semantic model roles instead of hardcoded model IDs in OpenCode agents, subagents, and command configs — e.g. `vv-role:smart`, `vv-role:fast` — then map those roles per machine or project. |
179
- | **GuardianPlugin** | Keep long or AFK agent runs moving by auto-approving routine low-risk permission requests. If something looks risky, Guardian does not auto-approve it and leaves the decision to OpenCode's normal manual approval flow. |
180
- | **HashlineEditPlugin** | Route each model to its native editing tool (hashline anchors, exact replace, or DeepSeek `str_replace_editor`), tying changes to fresh `read` output to reduce wrong-line and stale-context edits. |
181
- | **SystemContextInjectionPlugin** | Inject universal primary guidance plus one startup-resolved orchestration policy into vv-controller, with skill discovery and subagent-only explore worker prompts. |
182
- | **SecretsRedactionPlugin** | Reduce accidental secret leakage by redacting tokens, keys, emails, and other sensitive values before messages are sent to the model. |
183
- | **WebToolsPlugin** | Register the provider-neutral `web_search` and `web_fetch` tools, return direct image/PDF attachments, and hide OpenCode's built-in web tools at runtime unless the user explicitly configured their permissions. |
184
- | **ContextTuiPlugin** | Add a native scrollable `/context` dialog with measured usage plus detailed observable per-tool and per-MCP schema/history estimates, explicitly marking data that OpenCode does not expose. |
185
- | **ToolHistoryCompactionPlugin** | Shrink the replayed conversation context non-destructively by compacting old tool outputs in the model replay (old reads to `[Read <file>, lines X-Y]`, over-budget ephemeral outputs pruned), while retaining web/search/skill knowledge results. |
186
- | **AnalyticsPlugin** | Persist per-step token and cache telemetry with vvoc/OpenCode version attribution, show a live `cache NN%` indicator next to the session prompt plus a combined OpenCode/vvoc version line in the sidebar footer, and answer "did my cache optimizations help?" via `vvoc analytics cache-hit-rate`. |
393
+ | `vv-codex` | single-session |
394
+ | `vv-kimi` | single-session |
395
+ | `vv-alibaba` | single-session |
396
+ | `vv-osovv-sol` | single-session |
397
+ | `vv-osovv-flash` | single-session |
398
+ | `vv-osovv-kimi` | single-session |
399
+ | `vv-osovv-qwen` | single-session |
400
+ | `vv-zai` | balanced |
401
+ | `vv-deepseek` | balanced |
402
+
403
+ Applying a built-in preset changes both model roles and the root orchestration profile atomically. A custom user-defined preset without an orchestration section preserves the current root profile. `vvoc status` reports the profile resolved from the selected vvoc source; effective status with no config files reports `balanced`.
404
+
405
+ Profiles are enforced through the concrete policy injected into vv-controller at startup — the model only receives its active work instructions and never sees inactive profile alternatives. The first version does not disable tools, change permissions, or block subagent types; the policy is prompt-driven, and asynchronous vv-execute classic mode remains available through that skill's explicit inline/classic selection. Profile changes take effect after an OpenCode restart, like all vvoc config changes.
406
+
407
+ ### Workflow work items
187
408
 
188
409
  Workflow work items are opened with explicit intent. For implementation loops, controllers use:
189
410
 
@@ -202,7 +423,7 @@ Workflow work items are opened with explicit intent. For implementation loops, c
202
423
 
203
424
  For review-only reports, use `"mode": "review_only"`. In review-only mode, reviewer `FAIL` is a completed finding result: required reviewers are collected independently, parallel `spec` and `code` reviewers may both return `FAIL`, and the item does not route to `vv-implementer` unless the user explicitly requests fixes.
204
425
 
205
- ### Edit Format Routing
426
+ ### Edit format routing
206
427
 
207
428
  `HashlineEditPlugin` resolves an edit mode per session model and exposes only the matching edit tool to that model:
208
429
 
@@ -213,9 +434,7 @@ For review-only reports, use `"mode": "review_only"`. In review-only mode, revie
213
434
 
214
435
  The default routing table sends `deepseek` to `str_replace_editor`, `kimi`, `qwen`, and `glm` to `replace`, and `gpt`/`codex` to `passthrough`; everything else stays on `hashline`. Patterns match case-insensitively against the session `providerID` first, then `modelID`; the first matching rule wins.
215
436
 
216
- `vvoc sync` and `vvoc init` write this default table into `vvoc.json` so it is visible and editable. Materialization is conservative: a routing value you have changed is never overwritten; the table is only filled in where it is missing.
217
-
218
- Override routing in `vvoc.json` (schema v3). The `plugins["hashline-edit"]` entry accepts a boolean or an object:
437
+ `vvoc sync` and `vvoc init` write this default table into `vvoc.json` so it is visible and editable. Materialization is conservative: a routing value you have changed is never overwritten; the table is only filled in where it is missing. Override routing in `vvoc.json` (schema v3) — the `plugins["hashline-edit"]` entry accepts a boolean or an object:
219
438
 
220
439
  ```json
221
440
  "plugins": {
@@ -228,21 +447,22 @@ Override routing in `vvoc.json` (schema v3). The `plugins["hashline-edit"]` entr
228
447
  }
229
448
  }
230
449
  ```
450
+
231
451
  Routing changes require an OpenCode restart, like other runtime plugin settings.
232
452
 
233
- ### Tool History Compaction
453
+ ### Tool history compaction
234
454
 
235
455
  `ToolHistoryCompactionPlugin` shrinks the context replayed to the model on every turn without touching on-disk storage. It rewrites only the in-memory message copy through the `experimental.chat.messages.transform` hook, and only the `output` of old completed tool parts — `input` and part structure (callID/type/order) are never changed, so provider tool_use/tool_result stitching stays intact.
236
456
 
237
- The **recent working context is never touched**: the newest message and the last `protectRecentMessages` messages (default 8, measured by message recency time with array-order fallback) are always replayed verbatim, regardless of call count, output size, tool class, or parallel batching. Compaction only applies to messages older than that window.
457
+ The recent working context is never touched: the newest message and the last `protectRecentMessages` messages (default 8, measured by message recency time with array-order fallback) are always replayed verbatim, regardless of call count, output size, tool class, or parallel batching. Compaction only applies to messages older than that window.
238
458
 
239
459
  Compaction is tool-classified, not blanket:
240
460
 
241
461
  - **Retained (never compacted):** results that stay relevant for the whole session — `webfetch`/`web_fetch`/web readers, web/search tools, `skill`, and subagent (`task`/`agent`) outputs. Retained tools also never consume the per-call protection budget.
242
462
  - **Old reads** collapse to `[Read <file>, lines X-Y]` (range recovered from the line-numbered output; missing file or range falls back to head/tail pruning, never a fabricated summary).
243
- - **Other ephemeral outputs** (`bash`, `grep`, `glob`, …) past `outputMaxChars` are pruned to `headChars` + a fixed marker + `tailChars`, DeepSeek-Harness style. With `savePrunedOutput` (default on), the full output is written once to `$XDG_DATA_HOME/vvoc/tool-output/tool-<callID>.txt` and the marker embeds `Full output saved to: <path>`, so the model can re-read the full content instead of reconstructing it from fragments.
463
+ - **Other ephemeral outputs** (`bash`, `grep`, `glob`, …) past `outputMaxChars` are pruned to `headChars` + a fixed marker + `tailChars`. With `savePrunedOutput` (default on), the full output is written once to `$XDG_DATA_HOME/vvoc/tool-output/tool-<callID>.txt` and the marker embeds `Full output saved to: <path>`, so the model can re-read the full content instead of reconstructing it from fragments.
244
464
 
245
- Outside the window, the last `protectLastCalls` completed calls are also protected; error parts and parts already compacted by OpenCode are skipped. Rewrites are deterministic and idempotent (each part is rewritten at most once, and the saved path is deterministic per callID), and a `minSavingsChars` guard skips rewrites that would churn the prompt cache for a tiny gain.
465
+ Outside the recent window, the last `protectLastCalls` completed calls are also protected; error parts and parts already compacted by OpenCode are skipped. Rewrites are deterministic and idempotent (each part is rewritten at most once, and the saved path is deterministic per callID), and a `minSavingsChars` guard skips rewrites that would churn the prompt cache for a tiny gain.
246
466
 
247
467
  Config lives in `vvoc.json` under `plugins["tool-history-compaction"]` (boolean or object) and is conservatively materialized by `vvoc sync`/`init`:
248
468
 
@@ -265,11 +485,11 @@ Config lives in `vvoc.json` under `plugins["tool-history-compaction"]` (boolean
265
485
 
266
486
  Set `outputMaxChars` to `0` to disable pruning, `protectRecentMessages` to `0` to disable the message window (only the newest message stays protected), `savePrunedOutput` to `false` to skip disk persistence, or `"enabled": false` to disable the plugin entirely. Changes require an OpenCode restart.
267
487
 
268
- ### Cache Hit Rate Analytics
488
+ ### Cache hit rate analytics
269
489
 
270
490
  `AnalyticsPlugin` records one line per completed model step — fresh input, cache read, cache write, output, reasoning, recorded cost — to `$XDG_DATA_HOME/vvoc/analytics/usage-YYYY-MM.jsonl`, attributed with the vvoc version, the OpenCode version (from session telemetry), project, provider, model, and agent. Telemetry never leaves the machine; disable collection with `"plugins": { "analytics": false }` and delete old monthly files freely.
271
491
 
272
- In the TUI you get a live `cache NN%` indicator next to the session prompt (green at 80%+, yellow at 50%+, red below, muted `n/a` before the first cache-eligible step) and a combined footer line `• OpenCode <version> · vvoc vX.Y.Z` in the sidebar (the stock version line, extended with the vvoc version). The indicator is per-session and computed in memory.
492
+ In the TUI you get a live `cache NN%` indicator next to the session prompt (green at 80%+, yellow at 50%+, red below, muted `n/a` before the first cache-eligible step) and a combined footer line `• OpenCode <version> · vvoc vX.Y.Z` in the sidebar. The indicator is per-session and computed in memory.
273
493
 
274
494
  Retrospective analysis lives in the CLI:
275
495
 
@@ -281,20 +501,54 @@ vvoc analytics cache-hit-rate --group-by session|model|provider|project|week|mon
281
501
  vvoc analytics cache-hit-rate --project my-repo --order hit-rate --limit 10 --json
282
502
  ```
283
503
 
284
- The hit rate is token-weighted: `cacheRead / (cacheRead + cacheWrite + input)` over cache-eligible steps; `COVERAGE` shows the share of steps whose provider reported cache tokens at all, so providers without prompt caching read as `n/a` instead of a misleading `0%`. `--since`/`--until` accept `Nd`/`Nw`/`Nm` or `YYYY-MM-DD`.
504
+ The hit rate is token-weighted: `cacheRead / (cacheRead + cacheWrite + input)` over cache-eligible steps; `COVERAGE` shows the share of steps whose provider reported cache tokens at all, so providers without prompt caching read as `n/a` instead of a misleading `0%`. `--since`/`--until` accept `Nd`/`Nw`/`Nm` or `YYYY-MM-DD`; `--order` accepts `date`, `steps`, or `hit-rate`.
505
+
506
+ Agents can run this analysis conversationally too: the managed `vvoc-usage-analytics` skill answers usage, cache, and cost questions inside a session — including historical comparisons from `opencode.db` that predate the analytics plugin.
507
+
508
+ ### Peak hours
509
+
510
+ Several providers (DeepSeek, Z.AI, Qwen) bill higher rates during daily or weekday peak windows. `PeakHoursPlugin` matches the provider of each outgoing message against local schedules and either warns or blocks — it never switches the model for you and never fetches pricing from the network.
511
+
512
+ Behavior per mode:
513
+
514
+ - **hard** (default): a message to a peak-priced provider is rejected before any LLM request, with the window end, the wait time, and the connected providers that are currently outside peak (`PEAK_HOURS_BLOCK: provider "deepseek" is in peak hours until 10:00 UTC (about 3 h). … Connected providers outside peak hours right now: z-ai, qwen. …`).
515
+ - **soft**: the message goes through, the model receives a one-line cost notice, and the TUI shows a persistent orange banner in the bottom slot: `⚠ PEAK deepseek until 10:00 UTC · elevated pricing · off-peak now: z-ai, qwen`.
516
+
517
+ Nothing already in flight is ever killed:
518
+
519
+ - a session created before the current window started is grandfathered to soft for its lifetime (`graceActiveSessions`, on by default — decisions come from persisted session data, so they survive restarts);
520
+ - subagent sessions, managed subagents, and `guardian` are always soft — the decision to work was already admitted at the parent level;
521
+ - internal OpenCode agents (`compaction`, `title`, `summary`) are exempt entirely.
522
+
523
+ Schedules match **providers, not models**, with alias normalization (`zai`/`zhipu`/`glm` → `z-ai`, `alibaba`/`dashscope` → `qwen`). Unknown providers are never warned about or blocked, and a malformed schedule logs a warning and disables that provider's schedule instead of blocking anything (fail-open).
285
524
 
286
- Agents can run this analysis conversationally too: the managed `vvoc-usage-analytics` skill answers usage, cache, and cost questions inside a session — including historical comparisons from `opencode.db` that predate the analytics plugin (see Managed Skills).
525
+ Config lives in `vvoc.json` under `plugins["peak-hours"]` and is conservatively materialized by `vvoc sync`/`init` — your edits are never overwritten. The built-in defaults carry a revision date because providers move these clocks (verified 2026-08-21: DeepSeek ×2 surcharge effective 2026-08-16; Z.AI weekday coding-plan clock; Qwen 22:00–08:00 UTC+8 off-peak plan window):
287
526
 
288
- ### Web Tools
527
+ ```json
528
+ "plugins": {
529
+ "peak-hours": {
530
+ "enabled": true,
531
+ "mode": "hard",
532
+ "graceActiveSessions": true,
533
+ "schedules": {
534
+ "deepseek": { "windows": [{ "start": "01:00", "end": "04:00", "tz": "UTC" }, { "start": "06:00", "end": "10:00", "tz": "UTC" }] },
535
+ "z-ai": { "windows": [{ "start": "06:00", "end": "10:00", "tz": "UTC", "days": [1, 2, 3, 4, 5] }] },
536
+ "qwen": { "windows": [{ "start": "00:00", "end": "14:00", "tz": "UTC" }] }
537
+ }
538
+ }
539
+ }
540
+ ```
541
+
542
+ Windows use `HH:MM` in an explicit timezone (default UTC), may cross midnight (`"start": "22:00", "end": "02:00"`), and accept an optional `days` restriction (0=Sunday … 6=Saturday, default all days). A provider entry may override the global mode with `"mode": "soft"`. Set the top-level `"mode": "soft"` to downgrade everywhere, or `"enabled": false` to disable the plugin entirely. Changes require an OpenCode restart, like other runtime plugin settings.
543
+
544
+ ### Web tools
289
545
 
290
546
  `WebToolsPlugin` exposes exactly two canonical model-facing tools:
291
547
 
292
548
  - `web_search` requests the `web_search` permission and returns ranked titles, URLs, snippets, and publication dates. Search uses Exa by default, Brave when configured, or the direct Z.AI/Zhipu Tool API for an explicitly selected region.
293
549
  - `web_fetch` requests the `web_fetch` permission and retrieves a known HTTP or HTTPS URL as Markdown, text, raw HTML, or a direct JPEG, PNG, GIF, WebP, or PDF attachment. Fetch uses local native retrieval by default, Spider for configured textual extraction, or the direct Z.AI/Zhipu Reader Tool API.
294
550
 
295
- The `web-tools` vvoc plugin toggle is enabled by default.
296
-
297
- Provider selection belongs to `vvoc.json`, not to individual model calls. Add this optional property fragment to an otherwise valid canonical schema-v3 config:
551
+ The `web-tools` vvoc plugin toggle is enabled by default. Provider selection belongs to `vvoc.json`, not to individual model calls:
298
552
 
299
553
  ```json
300
554
  "web": {
@@ -305,7 +559,7 @@ Provider selection belongs to `vvoc.json`, not to individual model calls. Add th
305
559
 
306
560
  Supported search providers are `exa` (default), `brave`, and `zai`. Supported fetch providers are `native` (default, no credential required), `spider`, and `zai`. A `zai` section must set `region` to either `international` or `china`; the plugin never guesses or falls back to another region.
307
561
 
308
- Direct Z.AI endpoint routing is:
562
+ Direct Z.AI endpoint routing:
309
563
 
310
564
  | Region | Search | Reader | Search engine |
311
565
  |---|---|---|---|
@@ -319,7 +573,7 @@ Credentials resolve in this order:
319
573
  1. `EXA_API_KEY`, `BRAVE_API_KEY`, `SPIDER_API_KEY`, or `ZAI_API_KEY` for the selected provider
320
574
  2. `web.search.apiKey` or `web.fetch.apiKey` in the effective `vvoc.json`
321
575
 
322
- Environment variables win when both sources exist. Config changes take effect after restarting OpenCode. Configured `apiKey` values become exact-match SecretsRedactionPlugin rules for provider-bound message flows, and WebToolsPlugin diagnostics report only the credential source (`env` or `config`), never the value. If a project-layer `.vvoc/vvoc.json` containing an `apiKey` is tracked by Git, startup logs warn with the file name only. Prefer environment variables or the global vvoc layer; do not commit credentials.
576
+ Environment variables win when both sources exist; config changes take effect after restarting OpenCode. Configured `apiKey` values become exact-match SecretsRedactionPlugin rules for provider-bound message flows, and WebToolsPlugin diagnostics report only the credential source (`env` or `config`), never the value. If a project-layer `.vvoc/vvoc.json` containing an `apiKey` is tracked by Git, startup logs warn with the file name only. Prefer environment variables or the global vvoc layer; do not commit credentials.
323
577
 
324
578
  While `web-tools` is enabled, its runtime config hook denies the built-in `webfetch` and `websearch` permission ids in memory, leaving only `web_fetch` and `web_search` in the normal tool surface. It does not rewrite OpenCode files or remove MCP servers. An explicit user permission entry for `webfetch` or `websearch` is respected and may intentionally keep that built-in visible. Disable the plugin and restart to restore stock behavior:
325
579
 
@@ -329,15 +583,15 @@ vvoc plugin disable web-tools
329
583
 
330
584
  Unrelated MCP search or reader tools are not removed automatically; disable those separately if you want only the two canonical tools visible.
331
585
 
332
- ### `/context` accuracy
586
+ ### `/context` inspector
333
587
 
334
- Run `/context` inside an active session. Its bounded host-owned dialog has three tabs: **Overview**, **Tools**, and **MCP**. Use left/right arrows or `1`, `2`, and `3` to switch tabs and up/down to scroll long detail. The measured header remains visible on every tab. Top-line used/remaining values come from the latest assistant turn's provider-reported input, cache-read, and output token counts when OpenCode exposes them.
588
+ Run `/context` inside an active session. Its bounded host-owned dialog has three tabs: **Overview**, **Tools**, and **MCP**. Use left/right arrows or `1`, `2`, and `3` to switch tabs and up/down to scroll long detail; the measured header remains visible on every tab. Top-line used/remaining values come from the latest assistant turn's provider-reported input, cache-read, and output token counts when OpenCode exposes them.
335
589
 
336
- Overview category rows remain provider-neutral estimates derived from observable TUI/SDK state: system instructions, skill catalog, loaded skills, tool schemas, user and assistant messages, tool calls and results, files, and the latest compaction summary. Percentages are always `estimated tokens / current model contextLimit`; if OpenCode does not expose a positive current limit, the percentage is shown as an em dash rather than using another denominator. Numeric percentages may exceed 100% when estimates drift, while visual bars clamp only their fill at 100%.
590
+ Overview category rows are provider-neutral estimates derived from observable TUI/SDK state: system instructions, skill catalog, loaded skills, tool schemas, user and assistant messages, tool calls and results, files, and the latest compaction summary. Percentages are always `estimated tokens / current model contextLimit`; if OpenCode does not expose a positive current limit, the percentage is shown as an em dash rather than using another denominator. Numeric percentages may exceed 100% when estimates drift, while visual bars clamp only their fill at 100%.
337
591
 
338
- The Tools tab separates each observable current tool's persistent **schema** estimate from its active **history** estimate, call count, combined total, source, and percentages. When a schema catalog is unavailable, the row says `schema unavailable` and labels the history-only subtotal as `known total` rather than presenting a false zero. History includes only tool parts in the active context: the latest compaction summary and subsequent turns. Pending and running calls include observable input; completed calls include output and failed calls include errors. The `skill` tool remains visible in detail, but its history continues to belong to Overview's `Loaded skill results` category so it is not double-counted as `Tool calls and results`.
592
+ The Tools tab separates each observable current tool's persistent **schema** estimate from its active **history** estimate, call count, combined total, source, and percentages. When a schema catalog is unavailable, the row says `schema unavailable` and labels the history-only subtotal as `known total` rather than presenting a false zero. History includes only tool parts in the active context: the latest compaction summary and subsequent turns. The `skill` tool remains visible in detail, but its history belongs to Overview's `Loaded skill results` category so it is not double-counted.
339
593
 
340
- The MCP tab aggregates observable current schema and retained active history by server and nests the attributed tools. OpenCode 1.18.x does not expose connected MCP tool definitions through its public TUI/SDK tool catalog, so connected servers show `current tools unavailable` and `schema unavailable`; their `known total` includes retained history only, while the unexposed schema overhead remains in `Unknown/provider-only`. `disabled`, `failed`, `needs_auth`, and `needs_client_registration` servers have a known zero current schema, while matching call history can remain visible until compaction removes it. Attribution follows OpenCode's sanitized `<server>_<tool>` naming contract with unique longest-prefix matching. Sanitized collisions or other ambiguous ownership fail closed under **Other external/plugin** with a bounded warning instead of being guessed.
594
+ The MCP tab aggregates observable current schema and retained active history by server and nests the attributed tools. OpenCode 1.18.x does not expose connected MCP tool definitions through its public TUI/SDK tool catalog, so connected servers show `current tools unavailable` and `schema unavailable`; their `known total` includes retained history only, while the unexposed schema overhead remains in `Unknown/provider-only`. Attribution follows OpenCode's sanitized `<server>_<tool>` naming contract with unique longest-prefix matching; sanitized collisions or other ambiguous ownership fail closed under **Other external/plugin** with a bounded warning instead of being guessed.
341
595
 
342
596
  The plugin does **not** claim to reconstruct the exact final provider request or provide provider-exact tokenization. Hidden provider transformations, plugin-added data, or otherwise unattributable content appears as `Unknown/provider-only`; when visible estimates exceed provider usage, the dialog reports estimation drift instead of forcing totals to match. Collection reuses OpenCode's existing tool catalog, active parts, model metadata, and MCP status snapshot without issuing extra MCP requests.
343
597
 
@@ -345,206 +599,27 @@ The `context` vvoc plugin toggle defaults to enabled. Disable it with `vvoc plug
345
599
 
346
600
  ---
347
601
 
348
- ## CLI at a Glance
349
-
350
- | Command | Purpose |
351
- |---|---|
352
- | `vvoc init` | Interactive bootstrap flow |
353
- | `vvoc install` | Non-interactive setup and scaffolding |
354
- | `vvoc sync` | Refresh runtime/TUI plugin entries, agents, prompts, skills, config |
355
- | `vvoc launch` | Launch OpenCode with deterministic runtime, TUI, and vvoc config sources |
356
- | `vvoc status` | Show current installation state, including OpenCode version compatibility and TUI registration |
357
- | `vvoc doctor` | Diagnose OpenCode version/runtime/TUI/vvoc setup problems (exits non-zero on issues) |
358
- | `vvoc config validate` | Validate canonical `vvoc.json` |
359
- | `vvoc role list\|set\|unset` | Manage model role assignments |
360
- | `vvoc preset list\|show\|<name>` | Inspect or apply named presets |
361
- | `vvoc guardian config` | Print or write guardian section |
362
- | `vvoc plugin list` | List OpenCode plugin entries |
363
- | `vvoc plugin enable\|disable` | Toggle a vvoc-managed plugin on or off |
364
- | `vvoc orchestration show\|set` | Show or set the vv-controller orchestration profile |
365
- | `vvoc patch-provider stepfun-ai\|codex\|deepseek\|kimi\|alibaba\|all` | Patch OpenCode providers; `codex` adds subscription-safe OpenAI aliases (also accepts `openai`), `deepseek`/`kimi`/`alibaba` add vv- reasoning-effort aliases, `all` patches every provider at once |
366
- | `vvoc completion` | Install shell completions |
367
- | `vvoc upgrade` | Upgrade global package and run follow-up sync; sync failure is reported as a partial upgrade |
368
- | `vvoc analytics cache-hit-rate` | Aggregate persisted cache hit rate by day, week, month, session, model, provider, project, vvoc version, or OpenCode version |
369
- | `vvoc version` | Print installed version |
370
-
371
- Guardian duration overrides use positive whole milliseconds. Both `--timeout-ms` and
372
- `--review-toast-duration-ms` reject zero, negative, fractional, missing, or malformed values:
373
-
374
- ```bash
375
- vvoc guardian config --print --timeout-ms 30000 --review-toast-duration-ms 5000
376
- ```
377
-
378
- ---
379
- ---
380
-
381
- ## Orchestration Profiles
382
-
383
- Three concrete policies control how vv-controller delegates work at runtime:
384
-
385
- - `single-session`: vv-controller performs exploration, investigation, planning, implementation,
386
- and verification directly. Independent reviewer subagents remain available when the user
387
- explicitly requests review or when a materially risky completed change benefits from independent
388
- cross-model evaluation.
389
- - `balanced`: vv-controller keeps architecture, critical reading, and final synthesis in the
390
- primary session and may selectively delegate bounded search, investigation, mechanical
391
- implementation, or review when that is the lightest safe route. Delegation is optional, not
392
- mechanically mandatory.
393
- - `orchestrated`: vv-controller uses the full tracked implementer/reviewer workflow with
394
- explicit work items, required reviewers, bounded rounds, and hard stops.
395
-
396
- Pick a profile explicitly or let a built-in preset select one:
397
-
398
- ```bash
399
- vvoc orchestration show --scope effective
400
- vvoc orchestration set single-session --scope project
401
- ```
402
-
403
- Built-in presets declare an orchestration mapping:
404
-
405
- | Preset | Profile |
406
- |---|---|
407
- | `vv-codex` | single-session |
408
- | `vv-kimi` | single-session |
409
- | `vv-alibaba` | single-session |
410
- | `vv-osovv-sol` | single-session |
411
- | `vv-osovv-flash` | single-session |
412
- | `vv-osovv-kimi` | single-session |
413
- | `vv-osovv-qwen` | single-session |
414
- | `vv-zai` | balanced |
415
- | `vv-deepseek` | balanced |
416
-
417
- Applying a built-in preset changes both model roles and the root orchestration profile
418
- atomically. A custom user-defined preset without an orchestration section preserves the current
419
- root profile. `vvoc status` reports the profile resolved from the selected vvoc source; effective
420
- status with no config files reports `balanced`.
421
-
422
- ### Prompt-only first version
423
-
424
- Profiles are enforced through the concrete policy injected into vv-controller at startup —
425
- the model only receives its active work instructions and does not see inactive profile alternatives.
426
- The first version does not disable tools, change permissions, or block subagent types; the policy
427
- is prompt-driven and asynchronous vv-execute classic mode remains available through that skill's
428
- explicit inline/classic selection.
429
-
430
- ### Restart requirement
431
-
432
- Config changes to the orchestration profile take effect after an OpenCode restart. Runtime plugins
433
- resolve the profile once from the startup vvoc config snapshot and do not live-reload.
434
-
435
- ## Model Roles & Presets
602
+ ## Local development
436
603
 
437
604
  ```bash
438
- # View current assignments
439
- vvoc role list
440
- vvoc role list --scope effective
441
-
442
- # Assign models to roles
443
- vvoc role set default openai/gpt-5.6-terra
444
- vvoc role set team-review anthropic/claude-sonnet-4-5 --scope project
445
- vvoc role set smart openai/vv-codex-gpt-5.6-sol-xhigh
446
- vvoc role set fast openai/gpt-5.6-luna
447
-
448
- # Switch provider presets
449
- vvoc preset vv-codex
450
- vvoc preset vv-zai
451
- vvoc preset vv-deepseek
452
- vvoc preset vv-kimi
453
- vvoc preset vv-alibaba
454
- vvoc preset vv-osovv-sol
455
- vvoc preset vv-osovv-flash
456
- vvoc preset vv-osovv-kimi
457
- vvoc preset vv-osovv-qwen
458
- ```
459
-
460
- Built-in role IDs: `default`, `smart`, `fast`, `reviewer` + any custom lowercase-hyphenated IDs.
461
-
462
- Presets are partial — applying one only changes the roles it defines. Managed built-in presets (`vv-*`) are refreshed on every `vvoc install`/`vvoc sync`; user-defined presets are preserved as-is.
463
-
464
- ---
465
-
466
- ## Config & Data Layout
467
-
468
- Mutating commands default to global for backward compatibility. Add `--scope project` to write a project-local layer. Read/diagnostic commands accept `--scope global|project|effective`, where `effective` resolves in this order:
469
-
470
- 1. explicit env override (`VVOC_CONFIG` / `OPENCODE_CONFIG` / `OPENCODE_TUI_CONFIG`)
471
- 2. nearest project layer
472
- 3. global layer
473
- 4. built-in defaults when the command/runtime permits defaults
474
-
475
- Canonical project-local paths:
476
-
477
- ```text
478
- OpenCode config → ./.opencode/opencode.json(c)
479
- OpenCode TUI config → ./.opencode/tui.json(c)
480
- vvoc config → ./.vvoc/vvoc.json
481
- Managed agent prompts → ./.vvoc/agents/*.md
482
- Managed skills → ./.vvoc/skills/*/SKILL.md
483
- Spec package directory → ./.vvoc/specs/YYYY-MM-DD-<slug>/
484
- spec.xml # normative spec document (required)
485
- design-context.xml # curated design memory (optional)
486
- plan.xml # implementation plan (created by vv-plan)
487
- Handoff notes → ./.vvoc/handoff/YYYY-MM-DD-<session-slug>/handoff.xml
488
-
489
- ```
490
-
491
- Legacy root-level `./opencode.json` and `./opencode.jsonc` are intentionally not used as vvoc project layers.
492
-
493
- ```
494
- Global OpenCode config → $XDG_CONFIG_HOME/opencode/opencode.json
495
- Global OpenCode TUI → $XDG_CONFIG_HOME/opencode/tui.json(c)
496
- Global vvoc config → $XDG_CONFIG_HOME/vvoc/vvoc.json
497
- Managed agent prompts → $XDG_CONFIG_HOME/vvoc/agents/*.md (global)
498
- ./.vvoc/agents/*.md (project)
499
- Managed skills → $XDG_CONFIG_HOME/vvoc/skills/*/SKILL.md (global)
500
- ./.vvoc/skills/*/SKILL.md (project)
501
- Spec documents → ./.vvoc/specs/YYYY-MM-DD-<slug>/spec.xml
502
- Optional design context → ./.vvoc/specs/YYYY-MM-DD-<slug>/design-context.xml
503
- Implementation plans → ./.vvoc/specs/YYYY-MM-DD-<slug>/plan.xml
504
- Persisted data → $XDG_DATA_HOME/vvoc/
505
- Usage analytics → $XDG_DATA_HOME/vvoc/analytics/usage-YYYY-MM.jsonl (local-only cache telemetry)
506
- Repository memory → ./.vvoc/lessons/*.xml (lazy vv-reflect fallback)
507
- ./.vvoc/runbooks/*.xml (lazy vv-reflect fallback)
508
- Session handoff notes → ./.vvoc/handoff/YYYY-MM-DD-<session-slug>/handoff.xml
509
- ```
510
-
511
- Schema is versioned and published with the package — source of truth at `schemas/vvoc/v3.json`. The current config contract is strict: `vvoc.json` must be canonical version 3 and include required sections such as `plugins`. Existing v1/v2/pre-role, incomplete, malformed, or otherwise invalid config files fail instead of being migrated or repaired. `vvoc install` and `vvoc sync` may create a fresh canonical config when no config exists, but they refuse to rewrite an invalid existing `vvoc.json`; fix the file manually and rerun `vvoc sync`.
512
-
513
- The optional schema-v3 `web` section follows the same layer precedence as the rest of `vvoc.json` and is omitted from generated defaults:
514
-
515
- ```json
516
- "web": {
517
- "search": { "provider": "exa", "apiKey": "optional-exa-key" },
518
- "fetch": { "provider": "native" }
519
- }
605
+ bun install # Install dependencies
606
+ bun run check # Typecheck + lint + format check + GRACE markup check + test
607
+ bun run fmt # Auto-format source files
608
+ bun run release:check # Verify package/schema release consistency
520
609
  ```
521
610
 
522
- Use `brave` instead of `exa` for Brave Web Search, or `spider` instead of `native` for Spider textual extraction. The matching environment variable takes precedence over `apiKey` fields.
523
-
524
- OpenCode intentionally keeps server/runtime plugins and native terminal UI plugins in separate configuration surfaces. `opencode.json(c)` is loaded by the core/server plugin runtime and activates vvoc features such as model roles, Guardian, workflow, hashline edit, redaction, and web tools. `tui.json(c)` is loaded by the terminal UI process and activates the package's `./tui` module, currently the `/context` inspector. The same pinned package version appears in both files, but OpenCode selects a different public export for each process; headless/server launches therefore do not need to load the Solid/OpenTUI UI module.
525
-
526
- `vvoc install`, `vvoc init`, and `vvoc sync` conservatively add the pinned base package specifier (for example `@osovv/vv-opencode@X.Y.Z`) to dedicated `tui.json(c)`; OpenCode then selects the package's public `./tui` export. Sync migrates the broken legacy `@osovv/vv-opencode/tui` form and older managed pins. Existing comments, unrelated settings, unrelated plugin entries, and `[specifier, options]` tuples are preserved; malformed plugin entries fail without rewrite.
611
+ Git hooks are managed via `lefthook`.
527
612
 
528
- `vvoc status` and `vvoc doctor` are diagnostic exceptions: they report the installed OpenCode version, the `1.18.2` TUI minimum, selected runtime/TUI/vvoc config paths, and validation problems without normalizing or rewriting the files. `vvoc upgrade` can still finish the package installation when the follow-up `vvoc sync` fails; in that case it reports a partial upgrade, leaves config unchanged, and tells you to fix the invalid config manually before rerunning `vvoc sync`.
529
-
530
- Runtime compatibility is current-only. Guardian permission replies use the current OpenCode permission reply path (with the current HTTP reply fallback), Hashline edit refs must use current hash/context anchors, and sync writes current managed agents without deleting old pre-rename user or command entries.
531
-
532
- Runtime plugins load the effective `vvoc.json` once during OpenCode startup and share the same immutable config snapshot for the lifetime of the process. There is no live reload; restart OpenCode after changing `vvoc.json` or `tui.json(c)`.
533
-
534
- ### Deterministic local launch
535
-
536
- Use `vvoc launch` when you want the vvoc-selected config files to be the only files OpenCode sees for this run:
613
+ Smoke-test the built CLI against an isolated config home:
537
614
 
538
615
  ```bash
539
- vvoc install --scope project
540
- vvoc launch --scope project -- run "hello"
616
+ tmpdir="$(mktemp -d)"
617
+ bun run build
618
+ bun dist/cli.js install --config-dir "$tmpdir"
619
+ bun dist/cli.js status --config-dir "$tmpdir"
541
620
  ```
542
621
 
543
- `vvoc launch --scope project` is strict and non-mutating: if `.opencode/opencode.json` or `.vvoc/vvoc.json` is missing, it fails with a hint to run `vvoc install --scope project`. When the selected `.opencode/tui.json(c)` exists, launch also sets `OPENCODE_TUI_CONFIG`; a missing TUI file is not synthesized during launch. `--scope effective` follows the layered lookup order, and `--scope global` uses the global config paths.
544
-
545
- ### Test the local TUI before release
546
-
547
- From this repository, launch OpenCode against the freshly built local `dist/tui.js` without publishing or rewriting your selected configs:
622
+ Test the local TUI against a freshly built `dist/tui.js` without publishing or rewriting your selected configs:
548
623
 
549
624
  ```bash
550
625
  bun run tui:local
@@ -554,69 +629,7 @@ bun run tui:local -- --scope project
554
629
 
555
630
  The command defaults to `effective` config resolution. It builds the package, copies the selected `tui.json(c)` into a temporary isolated config home, replaces only the managed vv-opencode TUI entry with a local `file://` URL, preserves unrelated TUI settings and tuple options, and forwards remaining arguments to OpenCode. The original OpenCode, TUI, and vvoc config files are not modified, and the temporary config is removed after OpenCode exits. Restart the command after source changes because runtime plugins do not live reload.
556
631
 
557
- ---
558
-
559
- ## Managed Agents
560
-
561
- All prompt files are scaffolded by `vvoc install` / `vvoc sync`:
562
-
563
- | Agent | When it helps |
564
- |---|---|
565
- | `vv-controller` | Primary agent that follows the concrete work policy selected for the session by the orchestration profile |
566
- | `enhancer` | Improves rough requests before execution when a clearer prompt would help |
567
- | `vv-implementer` | Applies a focused approved change and verifies it before reporting completion |
568
- | `vv-spec-reviewer` | Checks whether implementation matches the requested spec and acceptance criteria |
569
- | `vv-code-reviewer` | Looks for bugs, regressions, maintainability risks, and missing tests |
570
- | `investigator` | Finds the root cause first when behavior is unclear or a failure needs diagnosis |
571
- | `guardian` | Supports GuardianPlugin by auto-approving routine low-risk permission requests and leaving risky ones for manual approval |
572
-
573
- ---
574
-
575
- ## Managed Skills
576
-
577
- Managed skills come in two families: `vv-*` skills guide the work protocol (spec, plan, execute, review, reflect, handoff), while `vvoc-*` skills operate and observe the vvoc/OpenCode tooling itself. Seven skills are scaffolded alongside agents:
578
-
579
- | Skill | When to use it | What it gives you |
580
- |---|---|---|
581
- | `vv-spec` | You have a feature or creative request and no agreed contract yet | A guided interview, recommended options, and a saved spec in `.vvoc/specs/YYYY-MM-DD-<slug>/spec.xml` |
582
- | `vv-plan` | A spec is approved and ready to implement | A task-level implementation plan with file targets, contracts, dependencies, and acceptance criteria |
583
- | `vv-execute` | A plan is approved and you want it applied step by step | Ordered execution with verification, explicit inline-or-classic mode choice, and applied spec/plan archival |
584
- | `vv-review` | You want findings, not fixes | A review-only workflow that reports spec/code issues and stops before implementation |
585
- | `vv-reflect` | A long development, debugging, ops, or investigation session produced reusable knowledge | Durable notes in existing docs or `.vvoc/lessons` / `.vvoc/runbooks` for future agents |
586
- | `vv-handoff` | You are ending a session and want the visible context preserved for a future session | A redacted XML note at `.vvoc/handoff/YYYY-MM-DD-<session-slug>/handoff.xml`, without running new checks or collecting fresh context |
587
- | `vvoc-usage-analytics` | You ask about token usage, cache hit rate, costs, or whether a vvoc/OpenCode upgrade changed caching | An agent-run read-only analysis across `vvoc analytics`, the analytics JSONL, and historical `opencode.db` data (validated SQL snippets included) |
588
-
589
- Spec and plan artifacts stay XML so requirements, tasks, acceptance criteria, and dependencies remain easy to grep and review.
590
-
591
- `vv-reflect` creates `.vvoc/lessons` and `.vvoc/runbooks` lazily only after approved fallback writes. It prefers an existing repository documentation convention when there is a high-confidence match.
592
-
593
- `vv-handoff` writes only the project-local XML handoff artifact from context already visible in the session. It records missing git, diff, or verification evidence as not collected in the current session instead of running commands.
594
-
595
- Skills are loaded by OpenCode at session start through `config.skills.paths` (registered by the SystemContextInjectionPlugin). The `vv-controller` agent's `<skill_trigger_rule>` ensures they are invoked automatically when the user's request matches their trigger conditions.
596
-
597
- ---
598
-
599
- ## Local Development
600
-
601
- ```bash
602
- bun install # Install dependencies
603
- bun run check # Typecheck + lint + format check + test
604
- bun run fmt # Auto-format source files
605
- bun run release:check # Verify package/schema release consistency
606
- ```
607
-
608
- Git hooks managed via `lefthook`.
609
-
610
- ### Smoke-test the built CLI
611
-
612
- ```bash
613
- tmpdir="$(mktemp -d)"
614
- bun run build
615
- bun dist/cli.js install --config-dir "$tmpdir"
616
- bun dist/cli.js status --config-dir "$tmpdir"
617
- ```
618
-
619
- ### Full release verification
632
+ Full release verification:
620
633
 
621
634
  ```bash
622
635
  bun run release:check
@@ -625,17 +638,17 @@ bun run pack:check
625
638
  ```
626
639
 
627
640
  ---
641
+
628
642
  ## Publishing
629
643
 
630
644
  The release flow is automated via a local wrapper and an exact-commit, CI-gated GitHub Actions workflow.
631
645
 
632
- ### Local bump
633
-
634
646
  ```bash
635
647
  bun run release:bump patch # or minor, major, prerelease, or explicit semver
636
648
  ```
637
649
 
638
650
  This will:
651
+
639
652
  1. Reject if the worktree is dirty
640
653
  2. Bump `package.json` via `npm version --no-git-tag-version`
641
654
  3. Generate a required AI release summary with `opencode --pure run`
@@ -649,38 +662,19 @@ This will:
649
662
  11. Retry npm metadata propagation, then verify that npm reports the exact release commit as the published `gitHead`
650
663
  12. Create and push the annotated tag locally, then create the GitHub Release through `gh`
651
664
 
652
- Required local release prerequisite:
653
- - `opencode` must be available from `PATH`.
654
- - `gh` must be installed and authenticated with permission to dispatch/watch workflows and create releases in the repository.
655
- - `gh run watch` does not support fine-grained PAT authentication; use a supported `gh` login such as OAuth or a classic token.
656
- - The summary model defaults to `deepseek/deepseek-v4-flash`.
657
- - Override with `VVOC_RELEASE_SUMMARY_MODEL=provider/model`.
658
- - Override the per-attempt timeout with `VVOC_RELEASE_SUMMARY_TIMEOUT_MS=120000`.
659
- Run `release:bump` from a checked-out branch with branch and tag push access to `origin`. A normal branch push never publishes by itself; the wrapper explicitly dispatches the workflow for the exact pushed commit.
660
-
661
- The GitHub Actions workflow checks out the requested commit SHA, verifies that its
662
- `package.json` version matches the dispatch input, and runs full validation
663
- (typecheck, lint, fmt check, tests, build, pack check, and `release:check`). Only
664
- after every gate passes does it publish to npm with provenance. The local wrapper
665
- waits for that CI result, retries registry metadata propagation, verifies npm
666
- `gitHead`, and only then uses the maintainer's authenticated `git` and `gh` clients
667
- to create the annotated `vX.Y.Z` tag and GitHub Release. This avoids GitHub App
668
- token restrictions on tagging commits that contain workflow changes while preserving
669
- verification-before-tagging.
670
-
671
- ### Checking consistency manually
672
-
673
- ```bash
674
- bun run release:check
675
- ```
665
+ Local prerequisites:
676
666
 
677
- This verifies that `package.json` name, version, and `schemas/vvoc/v3.json` `$id` and
678
- config format version are all consistent. Run it independently anytime.
667
+ - `opencode` must be available from `PATH`.
668
+ - `gh` must be installed and authenticated with permission to dispatch/watch workflows and create releases in the repository. `gh run watch` does not support fine-grained PAT authentication; use a supported `gh` login such as OAuth or a classic token.
669
+ - The summary model defaults to `deepseek/deepseek-v4-flash`; override with `VVOC_RELEASE_SUMMARY_MODEL=provider/model` and the per-attempt timeout with `VVOC_RELEASE_SUMMARY_TIMEOUT_MS=120000`.
670
+ - Run `release:bump` from a checked-out branch with branch and tag push access to `origin`. A normal branch push never publishes by itself; the wrapper explicitly dispatches the workflow for the exact pushed commit.
679
671
 
680
- ### CI publish workflow
672
+ The GitHub Actions workflow checks out the requested commit SHA, verifies that its `package.json` version matches the dispatch input, and runs full validation (typecheck, lint, fmt check, tests, build, pack check, and `release:check`). Only after every gate passes does it publish to npm with provenance. The local wrapper waits for that CI result, retries registry metadata propagation, verifies npm `gitHead`, and only then uses the maintainer's authenticated `git` and `gh` clients to create the annotated `vX.Y.Z` tag and GitHub Release. This avoids GitHub App token restrictions on tagging commits that contain workflow changes while preserving verification-before-tagging.
681
673
 
682
674
  The workflow uses npm provenance/trusted publishing (`id-token: write`) and read-only repository contents access. It can only publish through an explicit `workflow_dispatch` request; normal branch and tag pushes do not publish. Tag and GitHub Release creation happen locally only after the workflow succeeds. Configure npm trusted publishing for this GitHub repository/package, or adapt the publish step to use an `NPM_TOKEN` secret if token-based publishing is required.
683
675
 
676
+ `bun run release:check` verifies independently that `package.json` name, version, and `schemas/vvoc/v3.json` `$id` and config format version are all consistent; run it anytime.
677
+
684
678
  ---
685
679
 
686
680
  ## License