@pablozrrrr/jevguard 0.1.0 → 0.2.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 +129 -43
- package/cli/main.js +345 -25
- package/index.js +524 -60
- package/package.json +5 -3
- package/skills/jev-init/SKILL.md +252 -0
- package/skills/jev-init/validate-init.js +1526 -0
- package/skills/jevguard-rules/SKILL.md +17 -1
- package/skills/jevguard-rules/validate-rules.js +254 -0
package/README.md
CHANGED
|
@@ -27,10 +27,13 @@ specific policy, and leaves planning, code generation, and correction with the
|
|
|
27
27
|
coding agent.
|
|
28
28
|
|
|
29
29
|
> [!WARNING]
|
|
30
|
-
> JevGuard is in active development. The current release targets OpenCode `1.18.
|
|
31
|
-
> evaluates every rule block declared in `.jev/rules.md` plus the `SCOPE-CREEP`
|
|
32
|
-
> `COMPLEXITY` built-ins
|
|
33
|
-
>
|
|
30
|
+
> JevGuard is in active development. The current release targets OpenCode `1.18.32`
|
|
31
|
+
> and evaluates every rule block declared in `.jev/rules.md` plus the `SCOPE-CREEP`
|
|
32
|
+
> and `COMPLEXITY` built-ins. Reviews are background and observe-only: they report
|
|
33
|
+
> results but never alter the agent context or block a task. When remediation is
|
|
34
|
+
> enabled and a review has any `FAIL`, the plugin asks a hidden `jevguard-proposer`
|
|
35
|
+
> subagent for a proposal in an isolated child session and shows a generic toast; the
|
|
36
|
+
> proposer never edits code.
|
|
34
37
|
|
|
35
38
|
## Why JevGuard
|
|
36
39
|
|
|
@@ -122,7 +125,7 @@ malformed answer fails only its own check.
|
|
|
122
125
|
`SCOPE-CREEP` asks whether the change contains material functional, behavioral,
|
|
123
126
|
architectural, dependency, configuration, documentation, or refactoring work the task
|
|
124
127
|
did not request and that is not reasonably necessary to complete it. It uses fixed
|
|
125
|
-
`error` thresholds (`
|
|
128
|
+
`error` thresholds (`65%`/`90%`), independent of `.jev/config.yaml`.
|
|
126
129
|
|
|
127
130
|
`COMPLEXITY` asks whether the change introduces material complexity disproportionate
|
|
128
131
|
to, or not reasonably necessary for, completing the task, such as unnecessary
|
|
@@ -140,32 +143,73 @@ Reviews run in the background. The idle event returns as soon as the serialized
|
|
|
140
143
|
attribution step is scheduled; policy reads, Jev calls, and presentation never sit on
|
|
141
144
|
the agent's critical path.
|
|
142
145
|
|
|
146
|
+
## Safe auto-propose remediation
|
|
147
|
+
|
|
148
|
+
Reviews are observe-only by default: a review never injects feedback into the agent
|
|
149
|
+
context, adds a session message, prompts a session, blocks a turn, or changes your
|
|
150
|
+
code. A separate, configurable path can turn a review result into a proposal, and it is
|
|
151
|
+
delivered entirely by the same server plugin.
|
|
152
|
+
|
|
153
|
+
When `.jev/config.yaml` enables remediation (it is enabled by default) and a review
|
|
154
|
+
contains any `FAIL`, the plugin, after presenting the review, sends one aggregate
|
|
155
|
+
proposal request to a hidden `jevguard-proposer` subagent:
|
|
156
|
+
|
|
157
|
+
- The request aggregates every `FAIL` finding in the review — local `error` rules and
|
|
158
|
+
the `SCOPE-CREEP` built-in — together with the turn's task and its **complete, safe,
|
|
159
|
+
full attributed patch**. `COMPLEXITY` is advisory and never fails, and `warning`
|
|
160
|
+
rules never fail.
|
|
161
|
+
- The full attributed patch must pass the same safety policy as the review. If any
|
|
162
|
+
attributed file is blocked or the patch is oversized, the plugin records no proposal
|
|
163
|
+
at all — even when a rule-scoped `FAIL` exists — because there is no complete safe
|
|
164
|
+
evidence to send. It never falls back to a repository or global diff.
|
|
165
|
+
- The request is sent in an isolated child session parented to the source session. The
|
|
166
|
+
`jevguard-proposer` subagent has wildcard-deny permissions and wildcard-disabled
|
|
167
|
+
tools, so it cannot call a tool, edit a file, or produce a patch. It returns a
|
|
168
|
+
strategy and one manual apply instruction only.
|
|
169
|
+
- A generic toast reports that the proposal is ready in the child session. It carries
|
|
170
|
+
no rule, task, diff, finding, or credential.
|
|
171
|
+
|
|
172
|
+
The plugin creates at most one proposal per evaluated turn, and the child session is
|
|
173
|
+
excluded from review for the plugin lifetime, so a proposal can never recurse or
|
|
174
|
+
trigger a second one. A host, model, or toast failure is contained and never changes
|
|
175
|
+
the review.
|
|
176
|
+
|
|
177
|
+
The proposer is a strategy step, not an apply step: it never edits code, and nothing
|
|
178
|
+
is applied automatically. You read the proposal, copy its manual apply instruction
|
|
179
|
+
into your normal coding agent, and apply it there. That apply is an ordinary completed
|
|
180
|
+
assistant turn, so the server plugin reviews it normally on the next idle — exactly
|
|
181
|
+
like any other turn.
|
|
182
|
+
|
|
183
|
+
The proposal prompt treats the task, paths, diff, rules, and findings as untrusted
|
|
184
|
+
data, and requires a separate explicit confirmation before proposing changes to tests,
|
|
185
|
+
configuration, or dependencies. No secret is ever carried, and no payload, task, diff,
|
|
186
|
+
or secret is logged.
|
|
187
|
+
|
|
143
188
|
## Install
|
|
144
189
|
|
|
145
|
-
Once `@pablozrrrr/jevguard` is
|
|
190
|
+
Once `@pablozrrrr/jevguard` is installed, the intended setup is one line in
|
|
146
191
|
`opencode.json`:
|
|
147
192
|
|
|
148
193
|
```json
|
|
149
194
|
{ "plugin": ["@pablozrrrr/jevguard"] }
|
|
150
195
|
```
|
|
151
196
|
|
|
152
|
-
OpenCode
|
|
153
|
-
|
|
154
|
-
`jevguard` CLI on `PATH` (see [Install the CLI](#install-the-cli)). Restart
|
|
155
|
-
|
|
197
|
+
OpenCode resolves the package from the npm registry or its cache and loads it on the
|
|
198
|
+
next start. Adding the entry only loads the plugin; it does **not** put the
|
|
199
|
+
`jevguard` CLI on `PATH` (see [Install the CLI](#install-the-cli)). Restart OpenCode
|
|
200
|
+
after changing the plugin list.
|
|
156
201
|
|
|
157
202
|
> [!IMPORTANT]
|
|
158
|
-
>
|
|
159
|
-
>
|
|
160
|
-
> publication, load the plugin as a local artifact plugin instead.
|
|
203
|
+
> A bare plugin entry resolves only from the npm registry. To run an unreleased
|
|
204
|
+
> local build, load the packed tarball as a local artifact plugin instead.
|
|
161
205
|
|
|
162
206
|
### Build the local artifact
|
|
163
207
|
|
|
164
208
|
The artifact ships the plugin as a **locally packed tarball** that bundles the
|
|
165
209
|
private `@jevguard/core` and `@jevguard/opencode-adapter` workspace code, so a
|
|
166
210
|
clean consumer installs one tarball and never resolves a workspace link or a
|
|
167
|
-
private registry package. It also packages the `jevguard-rules`
|
|
168
|
-
private
|
|
211
|
+
private registry package. It also packages the `jevguard-rules` and `jev-init`
|
|
212
|
+
skills and their private validators under `skills/<name>/`.
|
|
169
213
|
|
|
170
214
|
Build the tarball from this repository:
|
|
171
215
|
|
|
@@ -184,12 +228,19 @@ The packed manifest depends only on public runtime packages
|
|
|
184
228
|
the tarball therefore needs npm registry access for those packages; the artifact
|
|
185
229
|
does not vendor them and does not promise an offline install.
|
|
186
230
|
|
|
187
|
-
### Load the
|
|
231
|
+
### Load the plugin
|
|
232
|
+
|
|
233
|
+
OpenCode `1.18.32` resolves a **bare** `opencode.json` `plugin` entry from the npm
|
|
234
|
+
registry or its cache:
|
|
235
|
+
|
|
236
|
+
```json
|
|
237
|
+
{
|
|
238
|
+
"plugin": ["@pablozrrrr/jevguard"]
|
|
239
|
+
}
|
|
240
|
+
```
|
|
188
241
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
published, install the tarball into the project's `.opencode` directory and load it
|
|
192
|
-
through a local plugin shim:
|
|
242
|
+
To run an unreleased local build instead, install the packed tarball into the
|
|
243
|
+
project's `.opencode` directory and load it through a local plugin shim:
|
|
193
244
|
|
|
194
245
|
```sh
|
|
195
246
|
cd /path/to/consumer/.opencode
|
|
@@ -203,16 +254,28 @@ export { JevGuardPlugin } from "@pablozrrrr/jevguard";
|
|
|
203
254
|
|
|
204
255
|
OpenCode loads `.opencode/plugins/` with its bundled Bun runtime. The shim runs as
|
|
205
256
|
a local plugin module and resolves `@pablozrrrr/jevguard` from
|
|
206
|
-
`.opencode/node_modules`.
|
|
207
|
-
|
|
257
|
+
`.opencode/node_modules`. Use either the bare `plugin` entry or the local shim, not
|
|
258
|
+
both.
|
|
259
|
+
|
|
260
|
+
Remediation is built into the same server plugin: the `config` hook registers the
|
|
261
|
+
hidden `jevguard-proposer` subagent, so no second entrypoint or shim is needed. The
|
|
262
|
+
server plugin reviews and reports turns, and — when remediation is enabled and a review
|
|
263
|
+
fails — creates the proposal child session automatically.
|
|
208
264
|
|
|
209
265
|
### Author rules with the bundled skill
|
|
210
266
|
|
|
211
|
-
The package ships
|
|
212
|
-
|
|
213
|
-
`
|
|
214
|
-
|
|
215
|
-
updating the package so
|
|
267
|
+
The package ships two OpenCode skills beside the plugin: `jevguard-rules` to author
|
|
268
|
+
rules, and `jev-init` to bootstrap a policy where none exists. On startup the plugin's
|
|
269
|
+
`config` hook appends the installed skill directories to the host's `skills.paths`, so
|
|
270
|
+
the skills are discovered without a manual `opencode.json` entry. Skill discovery is
|
|
271
|
+
read at OpenCode startup: restart OpenCode after installing or updating the package so
|
|
272
|
+
the skills appear.
|
|
273
|
+
|
|
274
|
+
`jev-init` runs only when neither `.jev/rules.md` nor `.jev/config.yaml` exists. It
|
|
275
|
+
reads a bounded inventory of the repository, keeps rules only from the user's explicit
|
|
276
|
+
constraints and strongly evidenced local conventions, records provenance in a preamble,
|
|
277
|
+
and previews both candidate files before requiring explicit confirmation naming both
|
|
278
|
+
exact paths. Once a policy exists, every rule change belongs to `jevguard-rules`.
|
|
216
279
|
|
|
217
280
|
Policy content is different. `.jev/rules.md` and `.jev/config.yaml` are read once
|
|
218
281
|
per attributed turn, so editing rule text takes effect on the next reviewed turn
|
|
@@ -223,8 +286,8 @@ Jev.
|
|
|
223
286
|
|
|
224
287
|
### Install the CLI
|
|
225
288
|
|
|
226
|
-
Loading the plugin does not expose the `jevguard` binary on `PATH`.
|
|
227
|
-
|
|
289
|
+
Loading the plugin does not expose the `jevguard` binary on `PATH`. Run the login
|
|
290
|
+
command without a global install:
|
|
228
291
|
|
|
229
292
|
```sh
|
|
230
293
|
bunx --package @pablozrrrr/jevguard jevguard login
|
|
@@ -237,7 +300,7 @@ bun install --global @pablozrrrr/jevguard
|
|
|
237
300
|
jevguard login
|
|
238
301
|
```
|
|
239
302
|
|
|
240
|
-
|
|
303
|
+
To run an unreleased local build, install the packed tarball globally instead:
|
|
241
304
|
|
|
242
305
|
```sh
|
|
243
306
|
bun install --global /path/to/pablozrrrr-jevguard-<version>.tgz
|
|
@@ -246,9 +309,7 @@ jevguard login
|
|
|
246
309
|
|
|
247
310
|
Known limitations:
|
|
248
311
|
|
|
249
|
-
-
|
|
250
|
-
plugin entry does not resolve until the package is published.
|
|
251
|
-
- Target host is OpenCode `1.18.31`. Exact `1.18.31` runtime smoke is still
|
|
312
|
+
- Target host is OpenCode `1.18.32`. Exact `1.18.32` runtime smoke is still
|
|
252
313
|
pending; a local `1.18.28` run worked.
|
|
253
314
|
- The plugin and CLI run on Bun, and the packed `jevguard` bin keeps a Bun
|
|
254
315
|
shebang. Install and run the artifact with the Bun runtime.
|
|
@@ -288,7 +349,7 @@ safely or completely evaluate that rule.
|
|
|
288
349
|
|
|
289
350
|
## Implemented behavior
|
|
290
351
|
|
|
291
|
-
The current release implements the full local
|
|
352
|
+
The current release implements the full local review path:
|
|
292
353
|
|
|
293
354
|
- OpenCode V1 plugin loads.
|
|
294
355
|
- A completed assistant response is detected.
|
|
@@ -330,9 +391,18 @@ The current release implements the full local, observe-only path:
|
|
|
330
391
|
carries every entry's outcome, raw probability, or reason, including the built-in
|
|
331
392
|
results and the synthetic review-level entry when there is one. The fixed result
|
|
332
393
|
order is rules in source order, then `SCOPE-CREEP`, then `COMPLEXITY`.
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
394
|
+
- After presentation, when remediation is enabled and the review contains any `FAIL`,
|
|
395
|
+
at most one aggregate proposal request is sent to the hidden `jevguard-proposer`
|
|
396
|
+
subagent in an isolated child session parented to the source session, and a generic
|
|
397
|
+
toast reports that the proposal is ready. The request carries every `FAIL` finding
|
|
398
|
+
(local `error` rules and the `SCOPE-CREEP` built-in), the task, and the complete,
|
|
399
|
+
safe, full attributed patch; a blocked or oversized patch records no proposal. A
|
|
400
|
+
notifier or host failure never affects the review, presentation, or later turns.
|
|
401
|
+
|
|
402
|
+
The review itself injects no feedback into the agent session, prompts no session, and
|
|
403
|
+
blocks no task. The proposal above is a strategy only; nothing is applied, and
|
|
404
|
+
the user copies its manual apply instruction into their normal coding agent, whose
|
|
405
|
+
ordinary turn is reviewed normally.
|
|
336
406
|
|
|
337
407
|
## Roadmap
|
|
338
408
|
|
|
@@ -357,6 +427,17 @@ V0.9 Local feedback and calibration
|
|
|
357
427
|
V1 Claude Code and Codex adapters
|
|
358
428
|
```
|
|
359
429
|
|
|
430
|
+
The auto-propose slice is implemented: after a review with a `FAIL`, an enabled
|
|
431
|
+
configuration asks the hidden `jevguard-proposer` subagent for a strategy in an
|
|
432
|
+
isolated child session, and never applies a change. The `V0.6` entry remains the
|
|
433
|
+
future, unattended corrective loop; the proposer is a bounded, strategy-only step, not
|
|
434
|
+
that loop.
|
|
435
|
+
|
|
436
|
+
The `V0.4` `jev-init` skill is implemented: when no policy exists it bootstraps
|
|
437
|
+
`.jev/rules.md` and `.jev/config.yaml` from the user's explicit constraints and
|
|
438
|
+
strongly evidenced local conventions, records each rule's provenance, and writes both
|
|
439
|
+
files only after validating the confirmed candidates.
|
|
440
|
+
|
|
360
441
|
CI and pull-request policy review come after V1, using the same versioned rules.
|
|
361
442
|
|
|
362
443
|
## Architecture
|
|
@@ -376,9 +457,10 @@ plugin → opencode-adapter → core
|
|
|
376
457
|
|
|
377
458
|
## Status
|
|
378
459
|
|
|
379
|
-
The multi-rule, multi-built-in, observe-only review is implemented. It
|
|
380
|
-
OpenCode, attributes one completed turn, parses every rule block in
|
|
381
|
-
asks Jev once per applicable rule and once per built-in batch, runs
|
|
460
|
+
The multi-rule, multi-built-in, background and observe-only review is implemented. It
|
|
461
|
+
loads in OpenCode, attributes one completed turn, parses every rule block in
|
|
462
|
+
`.jev/rules.md`, asks Jev once per applicable rule and once per built-in batch, runs
|
|
463
|
+
the `SCOPE-CREEP`
|
|
382
464
|
and `COMPLEXITY` built-ins over the complete attributed patch behind one shared
|
|
383
465
|
concurrency limit, applies the local gate to each, and presents one aggregate result
|
|
384
466
|
as a transient TUI toast and a structured log entry.
|
|
@@ -386,9 +468,13 @@ as a transient TUI toast and a structured log entry.
|
|
|
386
468
|
The local, private tarball (`pnpm artifact:build`, `pnpm artifact:pack`) packages
|
|
387
469
|
that slice so a clean consumer can install it without workspace links.
|
|
388
470
|
|
|
389
|
-
OpenCode sees only transient toasts
|
|
390
|
-
|
|
391
|
-
|
|
471
|
+
OpenCode sees only transient toasts, structured logs, and — when remediation is
|
|
472
|
+
enabled and a review has a `FAIL` — one proposal child session and a generic toast.
|
|
473
|
+
The review does not inject anything into the agent context, prompt the source session,
|
|
474
|
+
add session messages, or block a task. The proposal is a separate, configurable,
|
|
475
|
+
strategy-only workflow delivered by the server plugin; it never edits code and never
|
|
476
|
+
applies a change. Real-host validation against exact OpenCode `1.18.32` is still
|
|
477
|
+
pending.
|
|
392
478
|
|
|
393
479
|
## Development
|
|
394
480
|
|