@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 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`,
31
- > evaluates every rule block declared in `.jev/rules.md` plus the `SCOPE-CREEP` and
32
- > `COMPLEXITY` built-ins, and runs in observe mode only: it reports results but never
33
- > alters the agent context or blocks a task.
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 (`40%`/`70%`), independent of `.jev/config.yaml`.
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 published to npm, the intended install is one line in
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 then resolves the package from the npm registry or its cache and loads it
153
- on the next start. Adding the entry only loads the plugin; it does **not** put the
154
- `jevguard` CLI on `PATH` (see [Install the CLI](#install-the-cli)). Restart
155
- OpenCode after changing the plugin list.
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
- > `@pablozrrrr/jevguard` is **not published to npm yet**. The one-line entry above is
159
- > future behavior and will not resolve until the package is released. Before
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` skill and its
168
- private rule validator under `skills/jevguard-rules/`.
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 local plugin before publication
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
- OpenCode `1.18.31` resolves a **bare** `opencode.json` `plugin` entry from the npm
190
- registry or its cache, not from the consumer's `node_modules`. Until the package is
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`. Do **not** add `@pablozrrrr/jevguard` to the `opencode.json`
207
- `plugin` list before publication; that bare entry does not resolve locally.
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 a `jevguard-rules` OpenCode skill beside the plugin. On startup
212
- the plugin's `config` hook appends the installed skill directory to the host's
213
- `skills.paths`, so the skill is discovered without a manual `opencode.json` entry.
214
- Skill discovery is read at OpenCode startup: restart OpenCode after installing or
215
- updating the package so the skill appears.
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`. Once the
227
- package is published, run the login command without a global install:
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
- Until the package is published, install the local tarball globally instead:
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
- - `@pablozrrrr/jevguard` has no registry release yet, so the one-line `opencode.json`
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, observe-only path:
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
- No feedback is injected into the agent session. No remediation is attempted. No
335
- task is blocked.
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 loads in
380
- OpenCode, attributes one completed turn, parses every rule block in `.jev/rules.md`,
381
- asks Jev once per applicable rule and once per built-in batch, runs the `SCOPE-CREEP`
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 and structured logs. JevGuard does not inject
390
- anything into the agent context, does not add session messages, and does not block
391
- a task. Real-host validation against exact OpenCode `1.18.31` is still pending.
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