@herjarsa/omo-meta-governor 0.30.0 → 0.31.1
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 +692 -611
- package/dist/graph-retrieval.d.ts +29 -0
- package/dist/index.js +65 -65
- package/dist/index.js.map +6 -6
- package/dist/lib.js +65 -65
- package/dist/lib.js.map +6 -6
- package/dist/mcp-server.d.ts +29 -0
- package/dist/mcp-server.js +209 -0
- package/dist/mcp-server.js.map +242 -0
- package/dist/mcp-tools.d.ts +35 -0
- package/package.json +27 -23
package/README.md
CHANGED
|
@@ -1,612 +1,693 @@
|
|
|
1
|
-
# @herjarsa/omo-meta-governor
|
|
2
|
-
|
|
3
|
-
> Self-judging agent orchestration layer for [OpenCode](https://opencode.ai).
|
|
4
|
-
> Observes tool executions, scores progress, dispatches decisions, and exposes
|
|
5
|
-
> **12 custom tools** the agent can invoke across CodeGraph, Graphify,
|
|
6
|
-
> AgentMemory, and SQLite — for cheaper, more accurate code understanding.
|
|
7
|
-
|
|
8
|
-
**Current version:** `0.26.0` · **License:** MIT · **Status:** stable
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## Table of Contents
|
|
13
|
-
|
|
14
|
-
- [Install](#install)
|
|
15
|
-
- [What it does](#what-it-does)
|
|
16
|
-
- [12 Custom Tools](#12-custom-tools)
|
|
17
|
-
- [Code search & navigation](#code-search--navigation)
|
|
18
|
-
- [Lesson & memory](#lesson--memory)
|
|
19
|
-
- [File & symbol lookup](#file--symbol-lookup)
|
|
20
|
-
- [Safety & status](#safety--status)
|
|
21
|
-
- [Governance pipeline](#governance-pipeline)
|
|
22
|
-
- [Scoring engine](#scoring-engine)
|
|
23
|
-
- [Intervention modes](#intervention-modes)
|
|
24
|
-
- [Protocol enforcement](#protocol-enforcement)
|
|
25
|
-
- [Skill priming](#skill-priming)
|
|
26
|
-
- [Multi-phase plans](#multi-phase-plans)
|
|
27
|
-
- [Graph sync (codegraph + graphify)](#graph-sync-codegraph--graphify)
|
|
28
|
-
- [Auto-init](#auto-init)
|
|
29
|
-
- [Auto-upgrade (v0.26.0)](#auto-upgrade-v0260)
|
|
30
|
-
- [Git hooks](#git-hooks)
|
|
31
|
-
- [Process safeguards](#process-safeguards)
|
|
32
|
-
- [Persistence & observability](#persistence--observability)
|
|
33
|
-
- [CI monitor (v0.25.0)](#ci-monitor-v0250)
|
|
34
|
-
- [Configuration reference](#configuration-reference)
|
|
35
|
-
- [Architecture overview](#architecture-overview)
|
|
36
|
-
- [Testing](#testing)
|
|
37
|
-
- [Migration from earlier versions](#migration-from-earlier-versions)
|
|
38
|
-
- [License](#license)
|
|
39
|
-
|
|
40
|
-
---
|
|
41
|
-
|
|
42
|
-
## Install
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
npm install @herjarsa/omo-meta-governor
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
Add as a plugin in your OpenCode config (`~/.config/opencode/opencode.jsonc`):
|
|
49
|
-
|
|
50
|
-
```jsonc
|
|
51
|
-
{
|
|
52
|
-
"plugins": ["@herjarsa/omo-meta-governor"]
|
|
53
|
-
}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
The 12 custom tools register automatically on every load. To also enable
|
|
57
|
-
the governance pipeline (scoring, intervention, protocol enforcement):
|
|
58
|
-
|
|
59
|
-
```jsonc
|
|
60
|
-
{
|
|
61
|
-
"meta_governor": {
|
|
62
|
-
"enabled": true,
|
|
63
|
-
"intervention": { "mode": "message", "minActionForMessage": "warn" }
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
---
|
|
69
|
-
|
|
70
|
-
## What it does
|
|
71
|
-
|
|
72
|
-
`omo-meta-governor` is a single OpenCode plugin that ships **five
|
|
73
|
-
interconnected subsystems**:
|
|
74
|
-
|
|
75
|
-
| Subsystem | Purpose | Surface |
|
|
76
|
-
|---|---|---|
|
|
77
|
-
| **Graph sync** | Auto-install codegraph + graphify, build initial index, wire git hooks, auto-upgrade binaries on every load | `graphSync.*` config |
|
|
78
|
-
| **12 custom tools** | Semantic code search, impact analysis, symbol lookup, lesson recall, file/caller/node queries, health | `omo_*` tools |
|
|
79
|
-
| **Governance pipeline** | Score session progress → dispatch decision (`continue` / `warn` / `escalate` / `stop`) → optionally inject it into the agent's context | `meta_governor.enabled` |
|
|
80
|
-
| **Memory + lessons** | Persist decisions and lessons in SQLite (FTS5) + bridge to AgentMemory for cross-session recall | `omo_recall`, `omo_remember`, `omo_recall_mcp` |
|
|
81
|
-
| **Observability** | Health JSON, rotating JSONL logs, metrics, audit state, CI monitor | `omo_health`, `~/.config/opencode/meta-governor-health.json` |
|
|
82
|
-
|
|
83
|
-
All five run **inside the plugin** — no daemon, no sidecar. They share
|
|
84
|
-
process boundaries, lifecycle, and the opencode event hooks
|
|
85
|
-
(`tool.execute.before` / `tool.execute.after` / `chat.messages.transform`).
|
|
86
|
-
|
|
87
|
-
---
|
|
88
|
-
|
|
89
|
-
## 12 Custom Tools
|
|
90
|
-
|
|
91
|
-
The plugin registers 12 tools the LLM can invoke. All are available
|
|
92
|
-
immediately on install (no `enabled: true` required for tools — only the
|
|
93
|
-
governance pipeline needs `meta_governor.enabled: true`).
|
|
94
|
-
|
|
95
|
-
### Code search & navigation
|
|
96
|
-
|
|
97
|
-
| Tool | What it does | Use case |
|
|
98
|
-
|------|--------------|----------|
|
|
99
|
-
| `omo_search` | Semantic code search via codegraph or graphify | "Where is authentication handled?" — USE THIS FIRST for any architecture question |
|
|
100
|
-
| `omo_find` | Exact symbol lookup (definition + direct callers) via `codegraph node` | "Find the function `validateToken`" |
|
|
101
|
-
| `omo_impact` | Impact analysis: direct + transitive callers, test files, doc files | Run BEFORE modifying a function |
|
|
102
|
-
| `omo_path` | Shortest conceptual path between two concepts via graphify | "How does auth connect to database?" |
|
|
103
|
-
| `omo_explain` | Plain-language explanation of a concept via graphify | "What is the SwinTransformer?" |
|
|
104
|
-
|
|
105
|
-
### Lesson & memory
|
|
106
|
-
|
|
107
|
-
| Tool | What it does | Use case |
|
|
108
|
-
|------|--------------|----------|
|
|
109
|
-
| `omo_recall` | Search past lessons via local SQLite FTS5 (fast, always available) | "How did we set up auth before?" |
|
|
110
|
-
| `omo_recall_mcp` | Search cross-session memory via AgentMemory | "What did we learn about X in previous sessions?" |
|
|
111
|
-
| `omo_remember` | Save a fact / observation / pattern to cross-session AgentMemory | "Remember this bug pattern for next time" |
|
|
112
|
-
|
|
113
|
-
### File & symbol lookup
|
|
114
|
-
|
|
115
|
-
| Tool | What it does | Use case |
|
|
116
|
-
|------|--------------|----------|
|
|
117
|
-
| `omo_files` | List files indexed by codegraph or graphify | "What files are in the graph?" |
|
|
118
|
-
| `omo_callers` | List all call sites of a symbol via `codegraph callers` | "Who calls `UserService.create`?" |
|
|
119
|
-
| `omo_node` | Get source + direct callers of a symbol via `codegraph node` | "Show me the source of `validateToken` and its callers" |
|
|
120
|
-
|
|
121
|
-
### Safety & status
|
|
122
|
-
|
|
123
|
-
| Tool | What it does | Use case |
|
|
124
|
-
|------|--------------|----------|
|
|
125
|
-
| `omo_health` | Show plugin runtime status: metrics, decisions, errors | "Is the plugin working?" |
|
|
126
|
-
|
|
127
|
-
All tools return a typed `ToolResult` with `title`, `output`, and
|
|
128
|
-
`metadata` (`{tool, kind, durationMs, sessionID}`). They degrade
|
|
129
|
-
gracefully — when codegraph or graphify is missing, they return a
|
|
130
|
-
**friendly hint** (e.g. `npx codegraph init` to recover) instead of
|
|
131
|
-
crashing.
|
|
132
|
-
|
|
133
|
-
---
|
|
134
|
-
|
|
135
|
-
## Governance pipeline
|
|
136
|
-
|
|
137
|
-
When `meta_governor.enabled: true`, the plugin attaches to opencode's
|
|
138
|
-
tool-execution stream and runs an **observe → score → decide → (optionally)
|
|
139
|
-
intervene** loop on every turn.
|
|
140
|
-
|
|
141
|
-
### Scoring engine
|
|
142
|
-
|
|
143
|
-
`src/scoring-engine.ts` computes a single composite score in `[-1, 1]`
|
|
144
|
-
from weighted signals:
|
|
145
|
-
|
|
146
|
-
| Signal | Weight | Source |
|
|
147
|
-
|--------|--------|--------|
|
|
148
|
-
| `progress-detector` | 0.30 | did the last 5 tool calls make forward progress? |
|
|
149
|
-
| `deviation-detector` | 0.20 | accumulated protocol violations (capped at 5/session) |
|
|
150
|
-
| `no-progress-detector` | 0.20 | is the agent reading without writing? |
|
|
151
|
-
| `iteration-budget` | 0.15 | are we approaching `maxIterations`? |
|
|
152
|
-
| `oracle-burn` | 0.10 | did recent oracle calls detect issues? |
|
|
153
|
-
| `stop-advice` | 0.05 | did prior lessons recommend stop? |
|
|
154
|
-
|
|
155
|
-
The score maps to an action via configurable thresholds (see
|
|
156
|
-
[Configuration reference](#configuration-reference)):
|
|
157
|
-
|
|
158
|
-
- `score ≥ continueThreshold` → **continue** (silent)
|
|
159
|
-
- `score ≤ -warnThreshold` → **warn** (log + nudge)
|
|
160
|
-
- `score ≤ -escalateThreshold` → **escalate** (block + inject)
|
|
161
|
-
- `score ≤ -stopThreshold` → **stop** (latch intervention)
|
|
162
|
-
|
|
163
|
-
Default thresholds: `continue: 0.05`, `warn: 0.3`, `escalate: 0.45`,
|
|
164
|
-
`stop: 0.55` (worst-case math gives `stop ≈ -0.55`, so it actually
|
|
165
|
-
fires — verified via Gap C audit).
|
|
166
|
-
|
|
167
|
-
### Intervention modes
|
|
168
|
-
|
|
169
|
-
When the decision is `warn` / `escalate` / `stop`, the plugin can inject
|
|
170
|
-
the rationale into the agent's context via `experimental.chat.messages.transform`:
|
|
171
|
-
|
|
172
|
-
| Mode | Mechanism | Effect |
|
|
173
|
-
|------|-----------|--------|
|
|
174
|
-
| `silent` | (none) | Decision is logged only |
|
|
175
|
-
| `message` | `chat.messages.transform` | Injects a synthetic user message visible to the LLM |
|
|
176
|
-
| `system` | `chat.system.transform` | Appends guidance to the system prompt |
|
|
177
|
-
|
|
178
|
-
`maxInterventionsPerSession: 3` (default) hard-stops injection after 3
|
|
179
|
-
interventions per session to prevent infinite instruction loops
|
|
180
|
-
(v0.10.0). When `respectDoneSignal: true` (default), injection stops
|
|
181
|
-
once the agent emits the terminal signal AND Oracle has verified.
|
|
182
|
-
|
|
183
|
-
### Protocol enforcement
|
|
184
|
-
|
|
185
|
-
`src/protocol-enforcer.ts` audits tool calls against a configurable
|
|
186
|
-
protocol markdown file. Use it to enforce rules like "do not save
|
|
187
|
-
routine operations to memory" or "always invoke Oracle before declaring
|
|
188
|
-
done".
|
|
189
|
-
|
|
190
|
-
```jsonc
|
|
191
|
-
{
|
|
192
|
-
"meta_governor": {
|
|
193
|
-
"enabled": true,
|
|
194
|
-
"protocolEnforcement": {
|
|
195
|
-
"enabled": true,
|
|
196
|
-
"path": "./PROTOCOL.md",
|
|
197
|
-
"injectIntoSystem": true,
|
|
198
|
-
"auditToolCalls": true
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
Violations accumulate in `state.accumulatedDeviations` (capped at 5 per
|
|
205
|
-
session) and feed the `deviation-detector` scoring signal.
|
|
206
|
-
|
|
207
|
-
### Skill priming
|
|
208
|
-
|
|
209
|
-
`src/skill-priming.ts` (v0.20.0) injects **one** synthetic user message
|
|
210
|
-
at session start (or once implementation work begins) prompting the
|
|
211
|
-
agent to select precise skills for the task via the AAS skill catalog
|
|
212
|
-
(`aas search_skills` / `get_skill` / `compose_stack`) and/or the
|
|
213
|
-
task-appropriate superpowers skill — before writing code. Minimal context
|
|
214
|
-
cost: the directive forbids enumerating the full catalog.
|
|
215
|
-
|
|
216
|
-
```jsonc
|
|
217
|
-
{
|
|
218
|
-
"meta_governor": {
|
|
219
|
-
"enabled": true,
|
|
220
|
-
"skillPriming": {
|
|
221
|
-
"enabled": true,
|
|
222
|
-
"trigger": "firstImplement",
|
|
223
|
-
"router": "both"
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
### Multi-phase plans
|
|
230
|
-
|
|
231
|
-
For work plans with multiple phases (e.g. Sisyphus/Prometheus work
|
|
232
|
-
plans), set `phaseAwareDoneSignal: true` and emit
|
|
233
|
-
`<promise>PLAN-COMPLETE</promise>` only when the **entire** plan is
|
|
234
|
-
verified done by Oracle.
|
|
235
|
-
|
|
236
|
-
| Marker | Effect |
|
|
237
|
-
|--------|--------|
|
|
238
|
-
| `<promise>DONE</promise>` | Per-phase hint. Logged but does NOT latch intervention (when `phaseAwareDoneSignal: true`). |
|
|
239
|
-
| `<promise>PHASE-N-COMPLETE</promise>` | Per-phase hint (e.g. `<promise>PHASE-1-COMPLETE</promise>`). Same as `DONE`. |
|
|
240
|
-
| `<promise>PLAN-COMPLETE</promise>` | Terminal. Latches intervention when Oracle has verified. |
|
|
241
|
-
|
|
242
|
-
---
|
|
243
|
-
|
|
244
|
-
## Graph sync (codegraph + graphify)
|
|
245
|
-
|
|
246
|
-
The plugin wires the native git hooks of **codegraph** and **graphify**
|
|
247
|
-
so each commit automatically reindexes both graphs.
|
|
248
|
-
|
|
249
|
-
### Auto-init
|
|
250
|
-
|
|
251
|
-
On first load in a project (when `graphSync.enabled: true`, default):
|
|
252
|
-
|
|
253
|
-
1. **Auto-install** codegraph via `npm i -D @colbymchenry/codegraph` and
|
|
254
|
-
graphify via `pip install graphifyy` (falls back to
|
|
255
|
-
`uv tool install graphifyy`) if not already on PATH.
|
|
256
|
-
2. **Run `codegraph init`** + **`graphify . --no-viz`** to build the
|
|
257
|
-
initial indexes for the project.
|
|
258
|
-
3. **Run `graphify hook install`** to wire up the native `post-commit`
|
|
259
|
-
and `post-checkout` git hooks.
|
|
260
|
-
|
|
261
|
-
### Auto-upgrade (v0.26.0)
|
|
262
|
-
|
|
263
|
-
Before v0.26.0, `autoUpgrade: true` (default) silently failed. Six
|
|
264
|
-
bugs in `src/graph-sync.ts:503-628` forced users to manually run
|
|
265
|
-
`npm install -g @colbymchenry/codegraph@latest` and
|
|
266
|
-
`pip install --upgrade graphifyy`.
|
|
267
|
-
|
|
268
|
-
**Root cause bugs fixed in v0.26.0:**
|
|
269
|
-
|
|
270
|
-
1. `getInstalledCodegraphVersion` only probed `npx` — failed when the
|
|
271
|
-
binary was at `node_modules/.bin/codegraph` (Windows users).
|
|
272
|
-
2. `getInstalledGraphifyVersion` had no DI runner — Windows dual-python
|
|
273
|
-
fallback was untestable.
|
|
274
|
-
3. `shouldUpgrade` ignored the cache value (`latest=null`).
|
|
275
|
-
4. Cache cold + undetectable binary → silent noop (no diagnostic code).
|
|
276
|
-
5. **`pip install` without `--upgrade` returned 0** with
|
|
277
|
-
"Requirement already satisfied" but **did NOT upgrade** — most
|
|
278
|
-
visible bug.
|
|
279
|
-
6. `graphify check-update` was ignored — semantic re-extraction flag
|
|
280
|
-
never triggered.
|
|
281
|
-
|
|
282
|
-
**Fixes:**
|
|
283
|
-
|
|
284
|
-
- Tiered probe matching `checkToolAvailability`: `npx` +
|
|
285
|
-
`node node_modules/.bin/codegraph` for codegraph; `graphify` →
|
|
286
|
-
`python -m pip show` → `python3 -m pip show` for graphify.
|
|
287
|
-
- Runner DI seam on `getInstalledCodegraphVersion`,
|
|
288
|
-
`getInstalledGraphifyVersion`, `installCodegraph`, `installGraphify`
|
|
289
|
-
— hermetic tests, no real network in CI.
|
|
290
|
-
- `resolveLatest()` inlines cache into `shouldUpgrade` — avoids
|
|
291
|
-
double-fetch from the registry.
|
|
292
|
-
- Cache written **ONCE** at the end of the upgrade block (was being
|
|
293
|
-
fetched 3× per run).
|
|
294
|
-
- `pip install --upgrade graphifyy` / `uv tool install --upgrade graphifyy`
|
|
295
|
-
flags.
|
|
296
|
-
- `graphify check-update` integration emits
|
|
297
|
-
`graphify-reextract-triggered` when semantic re-extraction is pending.
|
|
298
|
-
- New codes: `codegraph-upgrade-broken`, `graphify-reextract-triggered`,
|
|
299
|
-
`upgrade-cache-written`.
|
|
300
|
-
- New config fields: `autoUpgrade`, `upgradeCachePath`,
|
|
301
|
-
`checkGraphifyNeedsUpdate`.
|
|
302
|
-
|
|
303
|
-
**Verified surface run:** `codegraph 0.6.8 → 1.5.0` and
|
|
304
|
-
`graphify 0.8.30 → 0.9.46` upgraded silently without manual
|
|
305
|
-
intervention.
|
|
306
|
-
|
|
307
|
-
**Configuration:**
|
|
308
|
-
|
|
309
|
-
```jsonc
|
|
310
|
-
{
|
|
311
|
-
"meta_governor": {
|
|
312
|
-
"graphSync": {
|
|
313
|
-
"enabled": true, // default true
|
|
314
|
-
"autoUpgrade": true, // v0.26.0: default true
|
|
315
|
-
"upgradeCachePath": "~/.omo-meta-governor/upgrade-cache.json",
|
|
316
|
-
"checkGraphifyNeedsUpdate": true // emit graphify-reextract-triggered when schema changed
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
### Git hooks
|
|
323
|
-
|
|
324
|
-
On every `git commit`:
|
|
325
|
-
|
|
326
|
-
- **Primary path** (native git hook): `graphify update` runs in background.
|
|
327
|
-
- **Backup path** (plugin's `tool.execute.after`): detects `git commit`
|
|
328
|
-
in bash commands and runs `codegraph sync -q [path]`.
|
|
329
|
-
|
|
330
|
-
### Process safeguards
|
|
331
|
-
|
|
332
|
-
Every subprocess the plugin spawns (graphify, codegraph, npx, python,
|
|
333
|
-
npm/pip) is guaranteed to die after use — on success, error, AND
|
|
334
|
-
timeout — including its descendant tree. On Windows this uses
|
|
335
|
-
`taskkill /pid <pid> /T /F` (plain `child.kill()` only kills the direct
|
|
336
|
-
shell, orphaning grandchildren — the confirmed cause of the
|
|
337
|
-
Bun/OpenChamber crashes).
|
|
338
|
-
|
|
339
|
-
Config: `graphSync.killOrphanedOnInit` (default `true`) — on graph-sync
|
|
340
|
-
init the plugin sweeps orphaned `graphify`/`codegraph` processes left
|
|
341
|
-
by previous crashed runs. Set to `false` to disable the sweep.
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
```
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
`
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
|
395
|
-
|
|
396
|
-
| `
|
|
397
|
-
| `
|
|
398
|
-
| `
|
|
399
|
-
| `
|
|
400
|
-
| `
|
|
401
|
-
| `
|
|
402
|
-
| `
|
|
403
|
-
| `
|
|
404
|
-
| `
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
|
477
|
-
|
|
478
|
-
| `
|
|
479
|
-
| `
|
|
480
|
-
| `
|
|
481
|
-
| `
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
|
497
|
-
|
|
498
|
-
| `
|
|
499
|
-
| `
|
|
500
|
-
| `
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
1
|
+
# @herjarsa/omo-meta-governor
|
|
2
|
+
|
|
3
|
+
> Self-judging agent orchestration layer for [OpenCode](https://opencode.ai).
|
|
4
|
+
> Observes tool executions, scores progress, dispatches decisions, and exposes
|
|
5
|
+
> **12 custom tools** the agent can invoke across CodeGraph, Graphify,
|
|
6
|
+
> AgentMemory, and SQLite — for cheaper, more accurate code understanding.
|
|
7
|
+
|
|
8
|
+
**Current version:** `0.26.0` · **License:** MIT · **Status:** stable
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Table of Contents
|
|
13
|
+
|
|
14
|
+
- [Install](#install)
|
|
15
|
+
- [What it does](#what-it-does)
|
|
16
|
+
- [12 Custom Tools](#12-custom-tools)
|
|
17
|
+
- [Code search & navigation](#code-search--navigation)
|
|
18
|
+
- [Lesson & memory](#lesson--memory)
|
|
19
|
+
- [File & symbol lookup](#file--symbol-lookup)
|
|
20
|
+
- [Safety & status](#safety--status)
|
|
21
|
+
- [Governance pipeline](#governance-pipeline)
|
|
22
|
+
- [Scoring engine](#scoring-engine)
|
|
23
|
+
- [Intervention modes](#intervention-modes)
|
|
24
|
+
- [Protocol enforcement](#protocol-enforcement)
|
|
25
|
+
- [Skill priming](#skill-priming)
|
|
26
|
+
- [Multi-phase plans](#multi-phase-plans)
|
|
27
|
+
- [Graph sync (codegraph + graphify)](#graph-sync-codegraph--graphify)
|
|
28
|
+
- [Auto-init](#auto-init)
|
|
29
|
+
- [Auto-upgrade (v0.26.0)](#auto-upgrade-v0260)
|
|
30
|
+
- [Git hooks](#git-hooks)
|
|
31
|
+
- [Process safeguards](#process-safeguards)
|
|
32
|
+
- [Persistence & observability](#persistence--observability)
|
|
33
|
+
- [CI monitor (v0.25.0)](#ci-monitor-v0250)
|
|
34
|
+
- [Configuration reference](#configuration-reference)
|
|
35
|
+
- [Architecture overview](#architecture-overview)
|
|
36
|
+
- [Testing](#testing)
|
|
37
|
+
- [Migration from earlier versions](#migration-from-earlier-versions)
|
|
38
|
+
- [License](#license)
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Install
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm install @herjarsa/omo-meta-governor
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Add as a plugin in your OpenCode config (`~/.config/opencode/opencode.jsonc`):
|
|
49
|
+
|
|
50
|
+
```jsonc
|
|
51
|
+
{
|
|
52
|
+
"plugins": ["@herjarsa/omo-meta-governor"]
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The 12 custom tools register automatically on every load. To also enable
|
|
57
|
+
the governance pipeline (scoring, intervention, protocol enforcement):
|
|
58
|
+
|
|
59
|
+
```jsonc
|
|
60
|
+
{
|
|
61
|
+
"meta_governor": {
|
|
62
|
+
"enabled": true,
|
|
63
|
+
"intervention": { "mode": "message", "minActionForMessage": "warn" }
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## What it does
|
|
71
|
+
|
|
72
|
+
`omo-meta-governor` is a single OpenCode plugin that ships **five
|
|
73
|
+
interconnected subsystems**:
|
|
74
|
+
|
|
75
|
+
| Subsystem | Purpose | Surface |
|
|
76
|
+
|---|---|---|
|
|
77
|
+
| **Graph sync** | Auto-install codegraph + graphify, build initial index, wire git hooks, auto-upgrade binaries on every load | `graphSync.*` config |
|
|
78
|
+
| **12 custom tools** | Semantic code search, impact analysis, symbol lookup, lesson recall, file/caller/node queries, health | `omo_*` tools |
|
|
79
|
+
| **Governance pipeline** | Score session progress → dispatch decision (`continue` / `warn` / `escalate` / `stop`) → optionally inject it into the agent's context | `meta_governor.enabled` |
|
|
80
|
+
| **Memory + lessons** | Persist decisions and lessons in SQLite (FTS5) + bridge to AgentMemory for cross-session recall | `omo_recall`, `omo_remember`, `omo_recall_mcp` |
|
|
81
|
+
| **Observability** | Health JSON, rotating JSONL logs, metrics, audit state, CI monitor | `omo_health`, `~/.config/opencode/meta-governor-health.json` |
|
|
82
|
+
|
|
83
|
+
All five run **inside the plugin** — no daemon, no sidecar. They share
|
|
84
|
+
process boundaries, lifecycle, and the opencode event hooks
|
|
85
|
+
(`tool.execute.before` / `tool.execute.after` / `chat.messages.transform`).
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## 12 Custom Tools
|
|
90
|
+
|
|
91
|
+
The plugin registers 12 tools the LLM can invoke. All are available
|
|
92
|
+
immediately on install (no `enabled: true` required for tools — only the
|
|
93
|
+
governance pipeline needs `meta_governor.enabled: true`).
|
|
94
|
+
|
|
95
|
+
### Code search & navigation
|
|
96
|
+
|
|
97
|
+
| Tool | What it does | Use case |
|
|
98
|
+
|------|--------------|----------|
|
|
99
|
+
| `omo_search` | Semantic code search via codegraph or graphify | "Where is authentication handled?" — USE THIS FIRST for any architecture question |
|
|
100
|
+
| `omo_find` | Exact symbol lookup (definition + direct callers) via `codegraph node` | "Find the function `validateToken`" |
|
|
101
|
+
| `omo_impact` | Impact analysis: direct + transitive callers, test files, doc files | Run BEFORE modifying a function |
|
|
102
|
+
| `omo_path` | Shortest conceptual path between two concepts via graphify | "How does auth connect to database?" |
|
|
103
|
+
| `omo_explain` | Plain-language explanation of a concept via graphify | "What is the SwinTransformer?" |
|
|
104
|
+
|
|
105
|
+
### Lesson & memory
|
|
106
|
+
|
|
107
|
+
| Tool | What it does | Use case |
|
|
108
|
+
|------|--------------|----------|
|
|
109
|
+
| `omo_recall` | Search past lessons via local SQLite FTS5 (fast, always available) | "How did we set up auth before?" |
|
|
110
|
+
| `omo_recall_mcp` | Search cross-session memory via AgentMemory | "What did we learn about X in previous sessions?" |
|
|
111
|
+
| `omo_remember` | Save a fact / observation / pattern to cross-session AgentMemory | "Remember this bug pattern for next time" |
|
|
112
|
+
|
|
113
|
+
### File & symbol lookup
|
|
114
|
+
|
|
115
|
+
| Tool | What it does | Use case |
|
|
116
|
+
|------|--------------|----------|
|
|
117
|
+
| `omo_files` | List files indexed by codegraph or graphify | "What files are in the graph?" |
|
|
118
|
+
| `omo_callers` | List all call sites of a symbol via `codegraph callers` | "Who calls `UserService.create`?" |
|
|
119
|
+
| `omo_node` | Get source + direct callers of a symbol via `codegraph node` | "Show me the source of `validateToken` and its callers" |
|
|
120
|
+
|
|
121
|
+
### Safety & status
|
|
122
|
+
|
|
123
|
+
| Tool | What it does | Use case |
|
|
124
|
+
|------|--------------|----------|
|
|
125
|
+
| `omo_health` | Show plugin runtime status: metrics, decisions, errors | "Is the plugin working?" |
|
|
126
|
+
|
|
127
|
+
All tools return a typed `ToolResult` with `title`, `output`, and
|
|
128
|
+
`metadata` (`{tool, kind, durationMs, sessionID}`). They degrade
|
|
129
|
+
gracefully — when codegraph or graphify is missing, they return a
|
|
130
|
+
**friendly hint** (e.g. `npx codegraph init` to recover) instead of
|
|
131
|
+
crashing.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Governance pipeline
|
|
136
|
+
|
|
137
|
+
When `meta_governor.enabled: true`, the plugin attaches to opencode's
|
|
138
|
+
tool-execution stream and runs an **observe → score → decide → (optionally)
|
|
139
|
+
intervene** loop on every turn.
|
|
140
|
+
|
|
141
|
+
### Scoring engine
|
|
142
|
+
|
|
143
|
+
`src/scoring-engine.ts` computes a single composite score in `[-1, 1]`
|
|
144
|
+
from weighted signals:
|
|
145
|
+
|
|
146
|
+
| Signal | Weight | Source |
|
|
147
|
+
|--------|--------|--------|
|
|
148
|
+
| `progress-detector` | 0.30 | did the last 5 tool calls make forward progress? |
|
|
149
|
+
| `deviation-detector` | 0.20 | accumulated protocol violations (capped at 5/session) |
|
|
150
|
+
| `no-progress-detector` | 0.20 | is the agent reading without writing? |
|
|
151
|
+
| `iteration-budget` | 0.15 | are we approaching `maxIterations`? |
|
|
152
|
+
| `oracle-burn` | 0.10 | did recent oracle calls detect issues? |
|
|
153
|
+
| `stop-advice` | 0.05 | did prior lessons recommend stop? |
|
|
154
|
+
|
|
155
|
+
The score maps to an action via configurable thresholds (see
|
|
156
|
+
[Configuration reference](#configuration-reference)):
|
|
157
|
+
|
|
158
|
+
- `score ≥ continueThreshold` → **continue** (silent)
|
|
159
|
+
- `score ≤ -warnThreshold` → **warn** (log + nudge)
|
|
160
|
+
- `score ≤ -escalateThreshold` → **escalate** (block + inject)
|
|
161
|
+
- `score ≤ -stopThreshold` → **stop** (latch intervention)
|
|
162
|
+
|
|
163
|
+
Default thresholds: `continue: 0.05`, `warn: 0.3`, `escalate: 0.45`,
|
|
164
|
+
`stop: 0.55` (worst-case math gives `stop ≈ -0.55`, so it actually
|
|
165
|
+
fires — verified via Gap C audit).
|
|
166
|
+
|
|
167
|
+
### Intervention modes
|
|
168
|
+
|
|
169
|
+
When the decision is `warn` / `escalate` / `stop`, the plugin can inject
|
|
170
|
+
the rationale into the agent's context via `experimental.chat.messages.transform`:
|
|
171
|
+
|
|
172
|
+
| Mode | Mechanism | Effect |
|
|
173
|
+
|------|-----------|--------|
|
|
174
|
+
| `silent` | (none) | Decision is logged only |
|
|
175
|
+
| `message` | `chat.messages.transform` | Injects a synthetic user message visible to the LLM |
|
|
176
|
+
| `system` | `chat.system.transform` | Appends guidance to the system prompt |
|
|
177
|
+
|
|
178
|
+
`maxInterventionsPerSession: 3` (default) hard-stops injection after 3
|
|
179
|
+
interventions per session to prevent infinite instruction loops
|
|
180
|
+
(v0.10.0). When `respectDoneSignal: true` (default), injection stops
|
|
181
|
+
once the agent emits the terminal signal AND Oracle has verified.
|
|
182
|
+
|
|
183
|
+
### Protocol enforcement
|
|
184
|
+
|
|
185
|
+
`src/protocol-enforcer.ts` audits tool calls against a configurable
|
|
186
|
+
protocol markdown file. Use it to enforce rules like "do not save
|
|
187
|
+
routine operations to memory" or "always invoke Oracle before declaring
|
|
188
|
+
done".
|
|
189
|
+
|
|
190
|
+
```jsonc
|
|
191
|
+
{
|
|
192
|
+
"meta_governor": {
|
|
193
|
+
"enabled": true,
|
|
194
|
+
"protocolEnforcement": {
|
|
195
|
+
"enabled": true,
|
|
196
|
+
"path": "./PROTOCOL.md",
|
|
197
|
+
"injectIntoSystem": true,
|
|
198
|
+
"auditToolCalls": true
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Violations accumulate in `state.accumulatedDeviations` (capped at 5 per
|
|
205
|
+
session) and feed the `deviation-detector` scoring signal.
|
|
206
|
+
|
|
207
|
+
### Skill priming
|
|
208
|
+
|
|
209
|
+
`src/skill-priming.ts` (v0.20.0) injects **one** synthetic user message
|
|
210
|
+
at session start (or once implementation work begins) prompting the
|
|
211
|
+
agent to select precise skills for the task via the AAS skill catalog
|
|
212
|
+
(`aas search_skills` / `get_skill` / `compose_stack`) and/or the
|
|
213
|
+
task-appropriate superpowers skill — before writing code. Minimal context
|
|
214
|
+
cost: the directive forbids enumerating the full catalog.
|
|
215
|
+
|
|
216
|
+
```jsonc
|
|
217
|
+
{
|
|
218
|
+
"meta_governor": {
|
|
219
|
+
"enabled": true,
|
|
220
|
+
"skillPriming": {
|
|
221
|
+
"enabled": true,
|
|
222
|
+
"trigger": "firstImplement",
|
|
223
|
+
"router": "both"
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Multi-phase plans
|
|
230
|
+
|
|
231
|
+
For work plans with multiple phases (e.g. Sisyphus/Prometheus work
|
|
232
|
+
plans), set `phaseAwareDoneSignal: true` and emit
|
|
233
|
+
`<promise>PLAN-COMPLETE</promise>` only when the **entire** plan is
|
|
234
|
+
verified done by Oracle.
|
|
235
|
+
|
|
236
|
+
| Marker | Effect |
|
|
237
|
+
|--------|--------|
|
|
238
|
+
| `<promise>DONE</promise>` | Per-phase hint. Logged but does NOT latch intervention (when `phaseAwareDoneSignal: true`). |
|
|
239
|
+
| `<promise>PHASE-N-COMPLETE</promise>` | Per-phase hint (e.g. `<promise>PHASE-1-COMPLETE</promise>`). Same as `DONE`. |
|
|
240
|
+
| `<promise>PLAN-COMPLETE</promise>` | Terminal. Latches intervention when Oracle has verified. |
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Graph sync (codegraph + graphify)
|
|
245
|
+
|
|
246
|
+
The plugin wires the native git hooks of **codegraph** and **graphify**
|
|
247
|
+
so each commit automatically reindexes both graphs.
|
|
248
|
+
|
|
249
|
+
### Auto-init
|
|
250
|
+
|
|
251
|
+
On first load in a project (when `graphSync.enabled: true`, default):
|
|
252
|
+
|
|
253
|
+
1. **Auto-install** codegraph via `npm i -D @colbymchenry/codegraph` and
|
|
254
|
+
graphify via `pip install graphifyy` (falls back to
|
|
255
|
+
`uv tool install graphifyy`) if not already on PATH.
|
|
256
|
+
2. **Run `codegraph init`** + **`graphify . --no-viz`** to build the
|
|
257
|
+
initial indexes for the project.
|
|
258
|
+
3. **Run `graphify hook install`** to wire up the native `post-commit`
|
|
259
|
+
and `post-checkout` git hooks.
|
|
260
|
+
|
|
261
|
+
### Auto-upgrade (v0.26.0)
|
|
262
|
+
|
|
263
|
+
Before v0.26.0, `autoUpgrade: true` (default) silently failed. Six
|
|
264
|
+
bugs in `src/graph-sync.ts:503-628` forced users to manually run
|
|
265
|
+
`npm install -g @colbymchenry/codegraph@latest` and
|
|
266
|
+
`pip install --upgrade graphifyy`.
|
|
267
|
+
|
|
268
|
+
**Root cause bugs fixed in v0.26.0:**
|
|
269
|
+
|
|
270
|
+
1. `getInstalledCodegraphVersion` only probed `npx` — failed when the
|
|
271
|
+
binary was at `node_modules/.bin/codegraph` (Windows users).
|
|
272
|
+
2. `getInstalledGraphifyVersion` had no DI runner — Windows dual-python
|
|
273
|
+
fallback was untestable.
|
|
274
|
+
3. `shouldUpgrade` ignored the cache value (`latest=null`).
|
|
275
|
+
4. Cache cold + undetectable binary → silent noop (no diagnostic code).
|
|
276
|
+
5. **`pip install` without `--upgrade` returned 0** with
|
|
277
|
+
"Requirement already satisfied" but **did NOT upgrade** — most
|
|
278
|
+
visible bug.
|
|
279
|
+
6. `graphify check-update` was ignored — semantic re-extraction flag
|
|
280
|
+
never triggered.
|
|
281
|
+
|
|
282
|
+
**Fixes:**
|
|
283
|
+
|
|
284
|
+
- Tiered probe matching `checkToolAvailability`: `npx` +
|
|
285
|
+
`node node_modules/.bin/codegraph` for codegraph; `graphify` →
|
|
286
|
+
`python -m pip show` → `python3 -m pip show` for graphify.
|
|
287
|
+
- Runner DI seam on `getInstalledCodegraphVersion`,
|
|
288
|
+
`getInstalledGraphifyVersion`, `installCodegraph`, `installGraphify`
|
|
289
|
+
— hermetic tests, no real network in CI.
|
|
290
|
+
- `resolveLatest()` inlines cache into `shouldUpgrade` — avoids
|
|
291
|
+
double-fetch from the registry.
|
|
292
|
+
- Cache written **ONCE** at the end of the upgrade block (was being
|
|
293
|
+
fetched 3× per run).
|
|
294
|
+
- `pip install --upgrade graphifyy` / `uv tool install --upgrade graphifyy`
|
|
295
|
+
flags.
|
|
296
|
+
- `graphify check-update` integration emits
|
|
297
|
+
`graphify-reextract-triggered` when semantic re-extraction is pending.
|
|
298
|
+
- New codes: `codegraph-upgrade-broken`, `graphify-reextract-triggered`,
|
|
299
|
+
`upgrade-cache-written`.
|
|
300
|
+
- New config fields: `autoUpgrade`, `upgradeCachePath`,
|
|
301
|
+
`checkGraphifyNeedsUpdate`.
|
|
302
|
+
|
|
303
|
+
**Verified surface run:** `codegraph 0.6.8 → 1.5.0` and
|
|
304
|
+
`graphify 0.8.30 → 0.9.46` upgraded silently without manual
|
|
305
|
+
intervention.
|
|
306
|
+
|
|
307
|
+
**Configuration:**
|
|
308
|
+
|
|
309
|
+
```jsonc
|
|
310
|
+
{
|
|
311
|
+
"meta_governor": {
|
|
312
|
+
"graphSync": {
|
|
313
|
+
"enabled": true, // default true
|
|
314
|
+
"autoUpgrade": true, // v0.26.0: default true
|
|
315
|
+
"upgradeCachePath": "~/.omo-meta-governor/upgrade-cache.json",
|
|
316
|
+
"checkGraphifyNeedsUpdate": true // emit graphify-reextract-triggered when schema changed
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Git hooks
|
|
323
|
+
|
|
324
|
+
On every `git commit`:
|
|
325
|
+
|
|
326
|
+
- **Primary path** (native git hook): `graphify update` runs in background.
|
|
327
|
+
- **Backup path** (plugin's `tool.execute.after`): detects `git commit`
|
|
328
|
+
in bash commands and runs `codegraph sync -q [path]`.
|
|
329
|
+
|
|
330
|
+
### Process safeguards
|
|
331
|
+
|
|
332
|
+
Every subprocess the plugin spawns (graphify, codegraph, npx, python,
|
|
333
|
+
npm/pip) is guaranteed to die after use — on success, error, AND
|
|
334
|
+
timeout — including its descendant tree. On Windows this uses
|
|
335
|
+
`taskkill /pid <pid> /T /F` (plain `child.kill()` only kills the direct
|
|
336
|
+
shell, orphaning grandchildren — the confirmed cause of the
|
|
337
|
+
Bun/OpenChamber crashes).
|
|
338
|
+
|
|
339
|
+
Config: `graphSync.killOrphanedOnInit` (default `true`) — on graph-sync
|
|
340
|
+
init the plugin sweeps orphaned `graphify`/`codegraph` processes left
|
|
341
|
+
by previous crashed runs. Set to `false` to disable the sweep.
|
|
342
|
+
|
|
343
|
+
## MCP server mode (v0.31.0)
|
|
344
|
+
|
|
345
|
+
OpenCode Desktop and OpenChamber spawn `opencode serve` in HTTP/sidecar mode
|
|
346
|
+
where plugin `hooks.tool` registrations don't reach the UI (the factory
|
|
347
|
+
is never invoked). The MCP server mode exposes the same `omo_*` tools via
|
|
348
|
+
an independent MCP server process — the same delivery mechanism that powers
|
|
349
|
+
`codegraph`, `graphify`, `agentmemory`, etc.
|
|
350
|
+
|
|
351
|
+
Both modes can be active simultaneously without conflict.
|
|
352
|
+
|
|
353
|
+
### Setup
|
|
354
|
+
|
|
355
|
+
Add to your `~/.config/opencode/opencode.jsonc`:
|
|
356
|
+
|
|
357
|
+
```json
|
|
358
|
+
{
|
|
359
|
+
"mcp": {
|
|
360
|
+
"omo-meta-governor": {
|
|
361
|
+
"type": "local",
|
|
362
|
+
"command": ["npx", "-y", "@herjarsa/omo-meta-governor", "omo-meta-governor-mcp"]
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
To target a specific project directory, set the `OMO_CWD` environment
|
|
369
|
+
variable in the MCP config:
|
|
370
|
+
|
|
371
|
+
```json
|
|
372
|
+
{
|
|
373
|
+
"mcp": {
|
|
374
|
+
"omo-meta-governor": {
|
|
375
|
+
"type": "local",
|
|
376
|
+
"command": ["npx", "-y", "@herjarsa/omo-meta-governor", "omo-meta-governor-mcp"],
|
|
377
|
+
"environment": { "OMO_CWD": "/absolute/path/to/project" }
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### Tools exposed
|
|
384
|
+
|
|
385
|
+
The MCP server exposes a curated subset of the full tool surface:
|
|
386
|
+
|
|
387
|
+
| Tool | Description |
|
|
388
|
+
|------|-------------|
|
|
389
|
+
| `omo_search` | Semantic code search via codegraph/graphify |
|
|
390
|
+
| `omo_recall` | Search past lessons in the project memory |
|
|
391
|
+
| `omo_health` | Show plugin runtime status |
|
|
392
|
+
| `omo_find` | Find a symbol by name in the codegraph index |
|
|
393
|
+
| `omo_impact` | Show what a symbol affects |
|
|
394
|
+
| `omo_path` | Find shortest path between two graph nodes |
|
|
395
|
+
| `omo_explain` | Explain a graph node |
|
|
396
|
+
| `omo_status` | Show graphify status |
|
|
397
|
+
| `omo_index` | Run graphify indexing |
|
|
398
|
+
| `omo_visualize` | Open the graphify visualisation server |
|
|
399
|
+
| `omo_serve` | Start the graphify HTTP API server |
|
|
400
|
+
| `omo_diagnose` | Diagnose graph inconsistencies |
|
|
401
|
+
| `omo_uninit` | Remove the codegraph index from disk |
|
|
402
|
+
| `omo_sync_if_dirty` | Trigger codegraph reindex if stale |
|
|
403
|
+
| `omo_mark_dirty` | Mark the codegraph index as stale |
|
|
404
|
+
| `omo_hook_status` | Check whether the graphify post-commit hook is installed |
|
|
405
|
+
|
|
406
|
+
Some tools from the plugin mode (`omo_remember`, `omo_recall_mcp`,
|
|
407
|
+
`omo_unlock`, `omo_clone`, etc.) are intentionally NOT exposed via the MCP
|
|
408
|
+
server — they either require the session client or lack browser-side
|
|
409
|
+
visibility. Use the CLI or plugin hooks for those.
|
|
410
|
+
|
|
411
|
+
### Technical notes
|
|
412
|
+
|
|
413
|
+
- Tool implementations are reused from `custom-tools.ts` via the adapter
|
|
414
|
+
pattern — fixes in the plugin surface are automatically available in MCP
|
|
415
|
+
mode.
|
|
416
|
+
- The MCP server process is independent of the opencode sidecar. It has
|
|
417
|
+
its own `GraphRetrieval`, `SqliteBackend`, and `MetricsCollector`
|
|
418
|
+
singletons.
|
|
419
|
+
- Backward-compatible: existing users who only use the `plugin` key in
|
|
420
|
+
`opencode.jsonc` see no behavior change.
|
|
421
|
+
|
|
422
|
+
---
|
|
423
|
+
|
|
424
|
+
## Persistence & observability
|
|
425
|
+
|
|
426
|
+
**Lesson storage.** Decisions and lessons persist in **SQLite** at
|
|
427
|
+
`~/.omo-meta-governor/meta-governor.db` with full-text search (FTS5) for
|
|
428
|
+
fast recall. Zero dependencies — uses Bun's built-in `bun:sqlite`.
|
|
429
|
+
|
|
430
|
+
**Cross-session memory.** The `omo_remember` / `omo_recall_mcp` tools
|
|
431
|
+
bridge to AgentMemory via `session.prompt()` — the LLM receives a
|
|
432
|
+
structured instruction to call the appropriate MCP tool.
|
|
433
|
+
|
|
434
|
+
**Health JSON** at `~/.config/opencode/meta-governor-health.json`:
|
|
435
|
+
|
|
436
|
+
```bash
|
|
437
|
+
cat ~/.config/opencode/meta-governor-health.json
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
Or invoke `omo_health` directly for a formatted report.
|
|
441
|
+
|
|
442
|
+
**Structured JSONL logs** at `~/.config/opencode/meta-governor.log` with
|
|
443
|
+
size-based rotation (10MB max, 5 rotated files). Secret redaction layer
|
|
444
|
+
strips JWT, OpenAI keys, Bearer tokens, GitHub PATs, and generic
|
|
445
|
+
`key:value` patterns before writing.
|
|
446
|
+
|
|
447
|
+
---
|
|
448
|
+
|
|
449
|
+
## CI monitor (v0.25.0)
|
|
450
|
+
|
|
451
|
+
`src/ci-monitor.ts` auto-triggers GitHub Actions on `git push` and
|
|
452
|
+
surfaces failures to the agent:
|
|
453
|
+
|
|
454
|
+
- Detects `git push` in bash commands via the `tool.execute.after` hook.
|
|
455
|
+
- Polls the GH Actions API for the resulting run (5s initial delay,
|
|
456
|
+
exponential backoff).
|
|
457
|
+
- On failure, injects a synthetic message with the failed logs into the
|
|
458
|
+
agent's context so it can fix and retry.
|
|
459
|
+
|
|
460
|
+
Configurable via `meta_governor.ciMonitor` (disabled by default — opt-in
|
|
461
|
+
feature).
|
|
462
|
+
|
|
463
|
+
---
|
|
464
|
+
|
|
465
|
+
## Configuration reference
|
|
466
|
+
|
|
467
|
+
All configuration lives under the `meta_governor` key in
|
|
468
|
+
`opencode.jsonc`. Full schema:
|
|
469
|
+
[assets/omo-meta-governor.schema.json](assets/omo-meta-governor.schema.json).
|
|
470
|
+
|
|
471
|
+
### Top-level
|
|
472
|
+
|
|
473
|
+
| Field | Type | Default | Description |
|
|
474
|
+
|-------|------|---------|-------------|
|
|
475
|
+
| `enabled` | boolean | `false` | Master feature flag — must be true to run the orchestrator. |
|
|
476
|
+
| `decision` | object | — | Decision handler tuning. |
|
|
477
|
+
| `memory` | object | — | Memory aggregator config. |
|
|
478
|
+
| `tokenPredictor` | object | — | Token predictor (compact-now / switch-model / delegate recommendations). |
|
|
479
|
+
| `scoring` | object | — | Scoring engine thresholds. |
|
|
480
|
+
| `closedLoop` | object | — | Closed-loop learning (save decisions + lessons). |
|
|
481
|
+
| `modelOverride` | object | — | Model override for MetaGovernor's internal LLM usage. |
|
|
482
|
+
| `intervention` | object | — | Visible decision injection config. |
|
|
483
|
+
| `protocolEnforcement` | object | — | Sisyphus protocol enforcement. |
|
|
484
|
+
| `skillPriming` | object | — | Proactive skill-selection nudge (v0.20.0). |
|
|
485
|
+
| `graphSync` | object | — | Graph synchronization (auto-init codegraph/graphify). |
|
|
486
|
+
|
|
487
|
+
### `decision`
|
|
488
|
+
|
|
489
|
+
| Field | Type | Default | Description |
|
|
490
|
+
|-------|------|---------|-------------|
|
|
491
|
+
| `maxHistoryPerSession` | integer | — | Maximum history entries per session before oldest are trimmed. |
|
|
492
|
+
| `forceContinueAfterStops` | integer | — | How many consecutive stops before forcing continue. |
|
|
493
|
+
|
|
494
|
+
### `memory`
|
|
495
|
+
|
|
496
|
+
| Field | Type | Default | Description |
|
|
497
|
+
|-------|------|---------|-------------|
|
|
498
|
+
| `agentmemoryTimeoutMs` | integer | — | Timeout for agentmemory queries in milliseconds. |
|
|
499
|
+
| `boulderStateTimeoutMs` | integer | — | Timeout for boulder-state queries in milliseconds. |
|
|
500
|
+
| `query` | string | — | Natural-language query for memory recall. |
|
|
501
|
+
|
|
502
|
+
### `tokenPredictor`
|
|
503
|
+
|
|
504
|
+
| Field | Type | Default | Description |
|
|
505
|
+
|-------|------|---------|-------------|
|
|
506
|
+
| `compactBurnRateThreshold` | integer | — | Burn rate (tokens/turn) above which to recommend compact-now. |
|
|
507
|
+
| `compactUsageThreshold` | number | — | Context usage ratio (0..1) above which to recommend compact-now. |
|
|
508
|
+
| `switchModelUsageThreshold` | number | — | Context usage ratio above which to recommend switch-model. |
|
|
509
|
+
| `delegateConsecutiveHighBurn` | integer | — | Max consecutive high-burn turns before recommending delegate. |
|
|
510
|
+
|
|
511
|
+
### `scoring`
|
|
512
|
+
|
|
513
|
+
| Field | Type | Default | Description |
|
|
514
|
+
|-------|------|---------|-------------|
|
|
515
|
+
| `continueThreshold` | number | `0.05` | Score ≥ this → continue silently. |
|
|
516
|
+
| `warnThreshold` | number | `0.3` | Score ≤ -this → warn. |
|
|
517
|
+
| `escalateThreshold` | number | `0.45` | Score ≤ -this → escalate. |
|
|
518
|
+
| `stopThreshold` | number | `0.55` | Score ≤ -this → stop. |
|
|
519
|
+
|
|
520
|
+
### `closedLoop`
|
|
521
|
+
|
|
522
|
+
| Field | Type | Default | Description |
|
|
523
|
+
|-------|------|---------|-------------|
|
|
524
|
+
| `saveDecisions` | boolean | `true` | Whether to save decision records. |
|
|
525
|
+
| `saveLessons` | boolean | `true` | Whether to save lessons. |
|
|
526
|
+
|
|
527
|
+
### `modelOverride`
|
|
528
|
+
|
|
529
|
+
| Field | Type | Default | Description |
|
|
530
|
+
|-------|------|---------|-------------|
|
|
531
|
+
| `providerID` | string | — | Provider ID (e.g. `'openai'`, `'anthropic'`). |
|
|
532
|
+
| `modelID` | string | — | Model ID (e.g. `'gpt-4o-mini'`, `'claude-sonnet-4-20250514'`). |
|
|
533
|
+
| `modelLimit` | integer | — | Context window size for token predictor (min 1000). |
|
|
534
|
+
| `temperature` | number | `0.2` | Sampling temperature (0..2). |
|
|
535
|
+
| `topP` | number | `1` | Top-p nucleus sampling (0..1). |
|
|
536
|
+
| `maxTokens` | integer | — | Max output tokens for internal reasoning. |
|
|
537
|
+
| `reasoning` | boolean | — | Enable extended reasoning / thinking mode. |
|
|
538
|
+
| `verbosity` | enum | — | `'silent'` \| `'minimal'` \| `'verbose'`. |
|
|
539
|
+
|
|
540
|
+
### `intervention`
|
|
541
|
+
|
|
542
|
+
| Field | Type | Default | Description |
|
|
543
|
+
|-------|------|---------|-------------|
|
|
544
|
+
| `mode` | enum | — | `'silent'` \| `'message'` \| `'system'`. |
|
|
545
|
+
| `includeDecisionHistory` | boolean | — | Whether to include recent decision history in injection. |
|
|
546
|
+
| `maxHistoryMessages` | integer | `5` | Max history entries when `includeDecisionHistory: true`. |
|
|
547
|
+
| `minActionForMessage` | enum | — | Minimum action: `'warn'` (all non-continue), `'escalate'`, `'stop'`. |
|
|
548
|
+
| `persistToSession` | boolean | `true` | v0.19.0: when true, intervention messages ALSO persist to the session. |
|
|
549
|
+
| `maxInterventionsPerSession` | integer | `3` | v0.10.0: hard cap before auto-disable. |
|
|
550
|
+
| `respectDoneSignal` | boolean | `true` | Stop injecting once terminal signal + Oracle verified. |
|
|
551
|
+
| `phaseAwareDoneSignal` | boolean | `false` | v0.15.0: split per-phase hint from terminal signal. |
|
|
552
|
+
| `compactionLoopGuard.enabled` | boolean | `false` | v0.31.1: opt-in defense against opencode [#27924](https://github.com/anomalyco/opencode/issues/27924) (infinite overflow-compaction loop). |
|
|
553
|
+
| `compactionLoopGuard.maxOverflowRecoveries` | integer | `2` | v0.31.1: consecutive overflow compactions tolerated before the guard trips. |
|
|
554
|
+
|
|
555
|
+
### `protocolEnforcement`
|
|
556
|
+
|
|
557
|
+
| Field | Type | Default | Description |
|
|
558
|
+
|-------|------|---------|-------------|
|
|
559
|
+
| `enabled` | boolean | — | Master switch. |
|
|
560
|
+
| `path` | string | — | Path to protocol markdown file. |
|
|
561
|
+
| `injectIntoSystem` | boolean | — | Whether to inject protocol rules into the system prompt. |
|
|
562
|
+
| `auditToolCalls` | boolean | — | Whether to audit tool calls for violations. |
|
|
563
|
+
|
|
564
|
+
### `skillPriming`
|
|
565
|
+
|
|
566
|
+
| Field | Type | Default | Description |
|
|
567
|
+
|-------|------|---------|-------------|
|
|
568
|
+
| `enabled` | boolean | `false` | Master switch. |
|
|
569
|
+
| `trigger` | enum | `'firstImplement'` | `'sessionStart'` (first transform) or `'firstImplement'` (once write-like tool observed). |
|
|
570
|
+
| `router` | enum | `'both'` | `'aas'` \| `'superpowers'` \| `'both'`. |
|
|
571
|
+
|
|
572
|
+
### `graphSync`
|
|
573
|
+
|
|
574
|
+
| Field | Type | Default | Description |
|
|
575
|
+
|-------|------|---------|-------------|
|
|
576
|
+
| `enabled` | boolean | `true` | Enable auto-initialization. |
|
|
577
|
+
| `watch` | boolean | `false` | Enable watch mode (re-index on file changes). |
|
|
578
|
+
| `killOrphanedOnInit` | boolean | `true` | Sweep orphaned processes on init. |
|
|
579
|
+
| `autoUpgrade` | boolean | `true` | **v0.26.0** — auto-upgrade installed codegraph + graphify binaries. |
|
|
580
|
+
| `upgradeCachePath` | string | — | **v0.26.0** — path for the upgrade cache file. |
|
|
581
|
+
| `checkGraphifyNeedsUpdate` | boolean | `true` | **v0.26.0** — run `graphify check-update` after upgrade. |
|
|
582
|
+
|
|
583
|
+
---
|
|
584
|
+
|
|
585
|
+
## Architecture overview
|
|
586
|
+
|
|
587
|
+
The plugin is a single ESM module with five layers wired through opencode
|
|
588
|
+
event hooks:
|
|
589
|
+
|
|
590
|
+
```
|
|
591
|
+
┌─────────────────────────────────────────────────────┐
|
|
592
|
+
│ opencode event hooks │
|
|
593
|
+
│ tool.execute.before tool.execute.after │
|
|
594
|
+
│ chat.messages.transform chat.system.transform │
|
|
595
|
+
└───────────────┬─────────────────────┬────────────────┘
|
|
596
|
+
│ │
|
|
597
|
+
┌───────────────────▼────────┐ ┌──────────▼─────────────┐
|
|
598
|
+
│ AuditStateCache (TTL) │ │ Decision + Scoring │
|
|
599
|
+
│ recentWriteFilePaths │ │ Engine (-1..+1 score) │
|
|
600
|
+
│ accumulatedDeviations │ └──────────┬─────────────┘
|
|
601
|
+
│ recentInterventionTexts │ │
|
|
602
|
+
└───────────────────────────┘ │
|
|
603
|
+
│ │
|
|
604
|
+
┌─────────────────────────▼─────────────────────▼──────────────┐
|
|
605
|
+
│ Governance pipeline │
|
|
606
|
+
│ Protocol Enforcer → Scoring → Decision Handler → │
|
|
607
|
+
│ Intervention │
|
|
608
|
+
└──────────────────────────────────────────────────────────────┘
|
|
609
|
+
│
|
|
610
|
+
│
|
|
611
|
+
┌─────────────────────────▼──────────────────────────────────────┐
|
|
612
|
+
│ Graph sync + tool layer │
|
|
613
|
+
│ codegraph + graphify (auto-init, git hooks, auto-upgrade) │
|
|
614
|
+
│ 12 omo_* tools (search, find, impact, recall, files, etc.) │
|
|
615
|
+
└───────────────────────────────────────────────────────────────┘
|
|
616
|
+
│
|
|
617
|
+
▼
|
|
618
|
+
┌──────────────────────────────────┐
|
|
619
|
+
│ SQLite (bun:sqlite) + AgentMem │
|
|
620
|
+
│ meta-governor.db / decisions │
|
|
621
|
+
│ / lessons / audit state │
|
|
622
|
+
└──────────────────────────────────┘
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
See [ARCHITECTURE.md](ARCHITECTURE.md) for module-level relationships and
|
|
626
|
+
[STRUCTURE.md](STRUCTURE.md) for the file layout.
|
|
627
|
+
|
|
628
|
+
---
|
|
629
|
+
|
|
630
|
+
## Testing
|
|
631
|
+
|
|
632
|
+
```bash
|
|
633
|
+
bun test # full suite (672+ tests)
|
|
634
|
+
bun test src/upgrade-autofix.test.ts # Wave 1: auto-upgrade regression
|
|
635
|
+
bun test src/custom-tools.test.ts # Wave 2: 12 tools
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
**Coverage highlights (v0.26.0):**
|
|
639
|
+
|
|
640
|
+
- 10 tests in `src/upgrade-autofix.test.ts` (AUT-1..AUT-7) — tiered probe,
|
|
641
|
+
pip `--upgrade` flag, `graphify check-update` integration, cache
|
|
642
|
+
write-once semantics.
|
|
643
|
+
- 7 tests in `src/custom-tools.test.ts` for the new tools
|
|
644
|
+
(FIL-1..3, CAL-1..2, NOD-1..2) plus full coverage of the existing 9.
|
|
645
|
+
- 686+ tests across `decision-store`, `token-predictor`,
|
|
646
|
+
`protocol-enforcer`, `graph-sync`, `skill-priming`, `ci-monitor`,
|
|
647
|
+
`audit-state-cache`, `closed-loop-learning`, `closed-loop`,
|
|
648
|
+
`config-file`, `session-bridge`, `sqlite-backend`, `memory-aggregator`,
|
|
649
|
+
`proc-guard`, `ttl-queue`, `mcp-client`, `scoring-engine`, `v018-fixes`,
|
|
650
|
+
`v172`, `v173-f51`, `v173-gap-d`, `intervention-fix`, `graphsink-fix`,
|
|
651
|
+
`plugin`, `plugin-graphsync`, `plugin-audit-postwave`, `postwave-wire`,
|
|
652
|
+
`postwave-gate`.
|
|
653
|
+
|
|
654
|
+
Known flaky test: `runGuarded > times out` (1 test) — pre-existing,
|
|
655
|
+
unrelated to v0.26.0, confirmed by Oracle audit.
|
|
656
|
+
|
|
657
|
+
---
|
|
658
|
+
|
|
659
|
+
## Migration from earlier versions
|
|
660
|
+
|
|
661
|
+
**From v0.24.x → v0.26.0:**
|
|
662
|
+
|
|
663
|
+
- **Stale-cache detection (v0.24.3):** On plugin load, an async npm
|
|
664
|
+
version check runs in the background. If the loaded version differs
|
|
665
|
+
from the latest published version, a warning is logged with
|
|
666
|
+
cache-clearing instructions. If you see `STALE_CACHE` in
|
|
667
|
+
`meta-governor.log`, run:
|
|
668
|
+
|
|
669
|
+
```bash
|
|
670
|
+
npm cache clean --force && rm -rf ~/.cache/opencode/packages/@herjarsa/omo-meta-governor*
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
Then restart opencode.
|
|
674
|
+
|
|
675
|
+
- **Auto-upgrade (v0.26.0):** No user action required. The plugin now
|
|
676
|
+
upgrades codegraph and graphify silently on every load. If you
|
|
677
|
+
previously disabled `graphSync.enabled` to work around the broken
|
|
678
|
+
upgrade, re-enable it.
|
|
679
|
+
|
|
680
|
+
- **New config fields:** `graphSync.autoUpgrade`,
|
|
681
|
+
`graphSync.upgradeCachePath`, `graphSync.checkGraphifyNeedsUpdate` —
|
|
682
|
+
all default true. Schema is backward-compatible.
|
|
683
|
+
|
|
684
|
+
**From earlier versions:** no user action required. All changes through
|
|
685
|
+
v0.18.0 were transparent — the audit gaps (config drops, circular refs,
|
|
686
|
+
metrics crashes) only affected edge cases where users set obscure
|
|
687
|
+
fields. See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
688
|
+
|
|
689
|
+
---
|
|
690
|
+
|
|
691
|
+
## License
|
|
692
|
+
|
|
612
693
|
MIT
|