@tryinget/pi-agent-vent 0.1.1 → 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 +10 -3
- package/docs/engineering.local.md +13 -0
- package/docs/project/2026-05-21-agent-vent-design.md +7 -5
- package/docs/project/2026-06-05-self-toolbox-agent-vent-diagnostic-boundary.md +66 -0
- package/docs/project/product-posture.md +3 -1
- package/docs/project/vision.md +4 -0
- package/extensions/agent-vent.ts +93 -14
- package/package.json +16 -7
- package/policy/engineering-lane.json +13 -1
- package/prompts/{implementation-planning.md → pi-agent-vent-implementation-planning.md} +3 -3
- package/prompts/{security-review.md → pi-agent-vent-security-review.md} +3 -3
- package/scripts/release-check.sh +96 -51
- package/scripts/release-smoke-check.mjs +26 -1
- package/scripts/release-smoke.sh +12 -15
- package/scripts/validate-structure.mjs +3 -3
- package/scripts/validate-structure.sh +2 -2
- package/src/vent-store.js +78 -6
- package/tests/agent-vent-extension.test.js +166 -1
- package/tests/release-smoke-check.test.js +19 -0
- package/tests/vent-store.test.js +24 -0
package/README.md
CHANGED
|
@@ -45,11 +45,12 @@ Then in Pi:
|
|
|
45
45
|
|
|
46
46
|
## Tool behavior
|
|
47
47
|
|
|
48
|
-
`agent_vent` supports
|
|
48
|
+
`agent_vent` supports fifteen actions:
|
|
49
49
|
|
|
50
50
|
| Action | Purpose |
|
|
51
51
|
|---|---|
|
|
52
|
-
| `record` | Append a minimized vent record. Requires `summary
|
|
52
|
+
| `record` | Append a minimized vent record. Requires `summary` and must pass the local anti-junk quality check. |
|
|
53
|
+
| `preview` | Build the sanitized would-be record and anti-junk quality result without writing the local store. |
|
|
53
54
|
| `summary` | Show recurrence groups and advisory candidate incidents. |
|
|
54
55
|
| `list` | Show recent local records. |
|
|
55
56
|
| `path` | Show the store path and boundary contract. |
|
|
@@ -99,11 +100,14 @@ The runtime-facing name is intentionally singular: use `agent_vent` for the LLM
|
|
|
99
100
|
|
|
100
101
|
`pi-agent-vent` is a companion to `pi-autonomous-session-control`, not part of it. ASC/`self` remains the execution and operational-mirror owner; this package owns only local vent diagnostics.
|
|
101
102
|
|
|
103
|
+
For the cross-package handoff between ASC `self` diagnostic candidates, toolbox activation, and `agent_vent` preview/record writes, see [Self, toolbox, and agent_vent diagnostic boundary](docs/project/2026-06-05-self-toolbox-agent-vent-diagnostic-boundary.md).
|
|
104
|
+
|
|
102
105
|
When `pi-toolbox-discovery` is installed, it exposes the `agent_vent` bundle so agents can discover or activate the same-named `agent_vent` tool on demand:
|
|
103
106
|
|
|
104
107
|
```ts
|
|
105
108
|
toolbox({ action: "search", query: "vent" })
|
|
106
109
|
toolbox({ action: "activate", bundle: "agent_vent" })
|
|
110
|
+
agent_vent({ action: "preview", summary: "...", category: "workflow", tool: "..." })
|
|
107
111
|
```
|
|
108
112
|
|
|
109
113
|
The owner extension must still be installed/reloaded so the `agent_vent` tool is registered before toolbox can activate it.
|
|
@@ -157,6 +161,7 @@ Product docs:
|
|
|
157
161
|
- [Vision](docs/project/vision.md)
|
|
158
162
|
- [Product posture](docs/project/product-posture.md)
|
|
159
163
|
- [Agent vent design](docs/project/2026-05-21-agent-vent-design.md)
|
|
164
|
+
- [Self/toolbox/agent_vent diagnostic boundary](docs/project/2026-06-05-self-toolbox-agent-vent-diagnostic-boundary.md)
|
|
160
165
|
- [Implementation plan](docs/project/2026-05-21-agent-vent-implementation-plan.md)
|
|
161
166
|
|
|
162
167
|
## Package checks
|
|
@@ -168,7 +173,9 @@ npm install
|
|
|
168
173
|
npm run check
|
|
169
174
|
```
|
|
170
175
|
|
|
171
|
-
For release confidence, `npm run release:check` packs the package, verifies packaged docs/scripts, runs the packaged fallback gate, installs the tarball into an isolated npm prefix for a no-auth shadow registered-tool `agent_vent path` smoke, then installs the tarball with isolated Pi settings and npm prefix/cache, validates that local `npm:<tarball>` is being used only as the install source, and smokes the installed artifact through local-path Pi package discovery with `/agent_vent path`. Use `npm run release:check:quick` for artifact-only checks when live Pi smoke is not available; quick checks still include the no-auth installed shadow registered-tool smoke.
|
|
176
|
+
For release confidence, `npm run release:check` packs the package, verifies packaged docs/scripts, runs the packaged fallback gate, installs the tarball into an isolated npm prefix for a no-auth shadow registered-tool `agent_vent path` smoke, then installs the tarball with isolated Pi settings and npm prefix/cache, validates that local `npm:<tarball>` is being used only as the install source, and smokes the installed artifact through local-path Pi package discovery with `/agent_vent path`. Use `npm run release:check:quick` for artifact-only checks when live Pi smoke is not available; quick checks still include the no-auth installed shadow registered-tool smoke.
|
|
177
|
+
|
|
178
|
+
Release probes pin `pi-ai` and `pi-coding-agent` to one exact version and fail before installation if that contract diverges from the selected/installed Pi host. Only the isolated artifact/probe installs set `min-release-age=0`, allowing a newly selected exact host contract to be tested while ordinary installs continue to obey the workstation supply-chain cutoff. These smokes prove artifact/package-loading behavior only, not npm/GitHub publication or provenance.
|
|
172
179
|
|
|
173
180
|
Run from monorepo root through the canonical package gate:
|
|
174
181
|
|
|
@@ -55,3 +55,16 @@ Not selected by default:
|
|
|
55
55
|
- Authority: candidate incidents are recommendations only; do not create or imply AK/GitHub/incident mutations.
|
|
56
56
|
- Validation: `npm run check` from this package, or root `bash ./scripts/package-quality-gate.sh ci packages/pi-agent-vent`.
|
|
57
57
|
- Optional companions are intentionally not adopted for v0.1: no `fast-check`, Cucumber, Nunjucks, or ts-quality rollout.
|
|
58
|
+
|
|
59
|
+
## Repo loop validation
|
|
60
|
+
|
|
61
|
+
`@tryinget/pi-agent-vent` adopts `repo-loop-validation-v1` for package-local loop prompt dogfooding. The policy declaration is in `policy/engineering-lane.json`.
|
|
62
|
+
|
|
63
|
+
- `loop-doctor`: `npm run loop-doctor` (non-failing Node/npm/package/git diagnostics)
|
|
64
|
+
- `loop-verify-fast`: `npm run loop-verify-fast` (maps to `quality:pre-commit`)
|
|
65
|
+
- `loop-impact-plan`: `npm run loop-impact-plan` (coarse package impact note plus changed-file listing)
|
|
66
|
+
- `loop-impact-run`: `npm run loop-impact-run` (maps to `npm run check`)
|
|
67
|
+
- `loop-impact-wide`: `npm run loop-impact-wide` (explicit full package gate, also `npm run check`)
|
|
68
|
+
- `loop-landing-check`: `npm run loop-landing-check` (maps to `npm run check`)
|
|
69
|
+
|
|
70
|
+
These commands produce package-local evidence for orchestration prompts. They do not replace Pi runtime install/reload proof, release approval, or monorepo owner authority.
|
|
@@ -95,7 +95,8 @@ The tool prompt and runtime validation both bias toward minimal summaries:
|
|
|
95
95
|
|
|
96
96
|
Actions:
|
|
97
97
|
|
|
98
|
-
- `record` — append a vent record.
|
|
98
|
+
- `record` — append a vent record after the local anti-junk quality check accepts it.
|
|
99
|
+
- `preview` — build the sanitized would-be record and anti-junk quality result without writing the local store.
|
|
99
100
|
- `summary` — summarize recurrence groups and candidate incidents.
|
|
100
101
|
- `list` — show recent records.
|
|
101
102
|
- `path` — show local store path and data contract.
|
|
@@ -112,7 +113,8 @@ Actions:
|
|
|
112
113
|
|
|
113
114
|
Important behavior:
|
|
114
115
|
|
|
115
|
-
- `record` requires `summary`.
|
|
116
|
+
- `record` requires `summary` and rejects low-signal generic payloads such as `done`.
|
|
117
|
+
- `preview` returns `recordPreview`, `quality`, and `wouldRecord` without appending JSONL; use it before `record` when the candidate came from `self`, another tool, or a generic/friction-heavy moment.
|
|
116
118
|
- `severity` defaults to `medium`.
|
|
117
119
|
- `category` defaults to `other`.
|
|
118
120
|
- `recurrenceKey` may be supplied by the agent; otherwise it is derived from category + summary.
|
|
@@ -164,11 +166,11 @@ This heuristic intentionally errs toward surfacing review candidates, not assert
|
|
|
164
166
|
|
|
165
167
|
## Cross-package integration
|
|
166
168
|
|
|
167
|
-
`pi-agent-vent` remains separate from `pi-autonomous-session-control` by design:
|
|
169
|
+
`pi-agent-vent` remains separate from `pi-autonomous-session-control` by design. The detailed handoff is documented in [Self, toolbox, and agent_vent diagnostic boundary](2026-06-05-self-toolbox-agent-vent-diagnostic-boundary.md):
|
|
168
170
|
|
|
169
|
-
- ASC/`self` owns operational introspection, subagent/runtime control,
|
|
170
|
-
- `pi-agent-vent` owns local diagnostic vent records, redaction, recurrence grouping, and advisory candidate-incident heuristics.
|
|
171
|
+
- ASC/`self` owns operational introspection, subagent/runtime control, mirror-only handoff/progress summaries, and typed `self.diagnostic_candidate.v1` suggestions.
|
|
171
172
|
- `pi-toolbox-discovery` owns discovery/activation of the already-registered `agent_vent` tool through the same-named `agent_vent` bundle; `agent-vent` is not a runtime alias.
|
|
173
|
+
- `pi-agent-vent` owns local diagnostic vent records, preview quality checks, redaction, recurrence grouping, and advisory candidate-incident heuristics.
|
|
172
174
|
|
|
173
175
|
This keeps vent persistence from becoming hidden ASC state while still making the capability discoverable during autonomous work.
|
|
174
176
|
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Boundary contract for self diagnostic candidates, toolbox activation, and agent_vent local diagnostic records."
|
|
3
|
+
read_when:
|
|
4
|
+
- "Changing ASC self diagnostic-review output."
|
|
5
|
+
- "Changing toolbox agent_vent bundle discovery or activation guidance."
|
|
6
|
+
- "Changing agent_vent preview/record behavior or diagnostic authority wording."
|
|
7
|
+
system4d:
|
|
8
|
+
container: "Cross-package diagnostic handoff boundary."
|
|
9
|
+
compass: "Make recurring friction visible without turning diagnostics into authority."
|
|
10
|
+
engine: "self mirrors candidate -> toolbox activates bundle -> agent_vent previews/records local diagnostics -> human decides owner escalation."
|
|
11
|
+
fog: "Diagnostic candidates and local records can be mistaken for tasks, evidence, incidents, telemetry, or ASC state."
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Self, toolbox, and agent_vent diagnostic boundary
|
|
15
|
+
|
|
16
|
+
## Purpose
|
|
17
|
+
|
|
18
|
+
This note documents the intended handoff between three Pi extension surfaces:
|
|
19
|
+
|
|
20
|
+
1. `self` from `pi-autonomous-session-control` notices current-session friction and can return a typed `self.diagnostic_candidate.v1` payload.
|
|
21
|
+
2. `toolbox` from `pi-toolbox-discovery` can discover or activate the already-registered `agent_vent` tool on demand.
|
|
22
|
+
3. `agent_vent` from `pi-agent-vent` can preview or record minimized local diagnostic records in its append-only local store.
|
|
23
|
+
|
|
24
|
+
The chain is deliberately not an escalation pipeline. It is a low-cost local diagnostic path for repeated bugs, tool failures, workflow friction, context loss, missing affordances, and similar agent-experience problems.
|
|
25
|
+
|
|
26
|
+
## Ownership contract
|
|
27
|
+
|
|
28
|
+
| Surface | Owns | Does not own |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| `self` | Moment-level mirror of the current session; candidate diagnostic payloads; suggested next local actions. | Durable vent records, recurrence truth, AK evidence/tasks, GitHub issues, incidents, telemetry, or owner routing. |
|
|
31
|
+
| `toolbox` | Bundle discovery, risk posture, and active-tool-set changes for already-registered tools. | Registering missing owner tools, validating vent quality, storing diagnostics, or deciding escalation. |
|
|
32
|
+
| `agent_vent` | Local JSONL diagnostic records, preview quality checks, redaction, recurrence grouping, review state, curation, draft-only text, export, and retention lifecycle. | AK evidence/tasks, GitHub issues, real incidents, external telemetry, ASC/self state, publication, or owner-system lifecycle. |
|
|
33
|
+
|
|
34
|
+
## Safe handoff sequence
|
|
35
|
+
|
|
36
|
+
Use this sequence when a session notices recurring or high-friction behavior worth possible local memory:
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
self({ query: "What friction just happened?" })
|
|
40
|
+
toolbox({ action: "activate", bundle: "agent_vent" })
|
|
41
|
+
agent_vent({ action: "preview", summary: "...", category: "...", tool: "...", packageName: "..." })
|
|
42
|
+
agent_vent({ action: "record", summary: "...", category: "...", tool: "...", packageName: "..." })
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Rules:
|
|
46
|
+
|
|
47
|
+
- `self` may prefill or suggest an `agent_vent` payload, but it must not write the record internally.
|
|
48
|
+
- `toolbox` activation only makes the `agent_vent` tool callable; it does not create or preview a diagnostic record.
|
|
49
|
+
- `agent_vent action=preview` sanitizes the would-be record and runs the anti-junk quality check without writing the store.
|
|
50
|
+
- `agent_vent action=record` writes only if the local quality check accepts the payload.
|
|
51
|
+
- Generic low-signal summaries such as `done` are rejected for `record`; use `preview` to inspect issues and warnings before writing.
|
|
52
|
+
- Human/operator judgment still decides whether any recurrence should become an AK task, GitHub issue, incident review, evidence record, publication, or owner-surface handoff.
|
|
53
|
+
|
|
54
|
+
## Copy wording for boundaries
|
|
55
|
+
|
|
56
|
+
Recommended short wording:
|
|
57
|
+
|
|
58
|
+
> Diagnostic review is mirror/local only: `self` can propose a candidate, `toolbox` can activate the `agent_vent` capability, and `agent_vent` can preview or write local diagnostic memory. None of these actions create AK evidence/tasks, GitHub issues, incidents, external telemetry, publication, owner routing, or ASC/self state.
|
|
59
|
+
|
|
60
|
+
Use stronger wording when a durable local write happened:
|
|
61
|
+
|
|
62
|
+
> A local `agent_vent` record was written to the operator's Pi diagnostic store. This is recurrence memory for review, not canonical evidence, task truth, issue state, incident declaration, telemetry, publication, or owner-system mutation.
|
|
63
|
+
|
|
64
|
+
## Review and escalation posture
|
|
65
|
+
|
|
66
|
+
`agent_vent` recurrence groups and candidate incidents mean “worth human review,” not “incident declared.” Draft outputs are paste-ready text only. Exports are diagnostic projections only. If a human decides a local recurrence deserves owner action, use the owning surface directly and record evidence there according to that owner’s rules.
|
|
@@ -51,7 +51,7 @@ When an agent keeps hitting the same bug, missing affordance, brittle workflow,
|
|
|
51
51
|
|
|
52
52
|
- maturity: `local diagnostic alpha, review-and-retention safety hardened; privacy, review-command, outcome-follow-up, review-filter, review-compare, follow-up-scope, export-scope, export-follow-up, review-decision-legibility, destructive-selection, retention-history, public-contract parity, unpacked-artifact contract, installed-command smoke, installed shadow registered-tool smoke, and release-metadata alignment membranes verified`
|
|
53
53
|
- current capability baseline: local append-only vent capture with optional local tool/package facets, recurrence grouping, local facet summary, local operator review queue with fail-closed-before-store-read command syntax and read-only category/tag/tool/package facet filters, read-only per-state review outcome follow-up buckets, read-only cross-state review comparison without archive/restore tokens, explicit derived local decision-posture projections, curation-aware recurrence resolution for review-state commands and record feedback, filter-preserving supported follow-up commands including record/state-scoped facet export, export-local-follow-up guidance without archive/restore tokens, read-only reviewed-group retention candidate planning without archive tokens, read-only retention receipt history with rollback-candidate restore command reconstruction, advisory human-review hints, quoted state-aware local next-action guidance that round-trips legacy recurrence keys, bounded representative-sample detail, review-state events, append-only recurrence curation projections with remove/undo events, diagnostic-state load membrane with privacy metadata recomputation, facet-aware draft-only owner-surface text generation, lifecycle stats/export projections, lock/hash-guarded confirmation-gated retention archive/restore with duplicate-id-safe record selection, local backup receipts, and rollback safeguards, advisory candidate-incident heuristic, redaction/minimization, `/agent_vent` inspection command, toolbox discovery, ASC/self companion routing, self-contained public-artifact validation for advertised package scripts/docs, no-auth installed-artifact shadow registered-tool `agent_vent path` release smoke with isolated npm prefix/cache and vent storage, installed-tarball local-path package-discovery `/agent_vent path` release smoke with isolated Pi settings, npm prefix/cache, and vent store, explicit local `npm:<tarball>` install-source validation, and package-local release metadata alignment checks for `repository.directory`, `x-pi-template.workspacePath`, and `x-pi-template.releaseComponent`
|
|
54
|
-
- release posture: first published package release is `0.1.0` on npm
|
|
54
|
+
- release posture: first published package release is `0.1.0` on npm; `0.1.1` removed the `/agent-vent` command alias and kept runtime-facing naming singularly `agent_vent`; source/package version `0.1.2` hardens extension load against stale review-state imports during reload; unpacked tarball contract has artifact-local `npm install && npm run check` proof, artifact-only quick release checks install the packed tarball into an isolated npm prefix and execute the installed artifact's registered `agent_vent` tool `action=path` through a shadow import against isolated vent storage without Pi auth, full release checks additionally validate local `npm:<tarball>` as the install source and smoke the installed packed artifact through local-path Pi package discovery by running `/agent_vent path` with isolated Pi settings, isolated npm prefix/cache, and isolated vent storage, and package-local structure validation fails closed on release metadata drift against `.copier-answers.yml`; post-publication registry smoke installed `@tryinget/pi-agent-vent@0.1.0` into an isolated npm prefix and verified the installed artifact and shadow registered-tool `path` behavior
|
|
55
55
|
- current strategic line: harden the local review workflow before adding owner-surface escalation adapters
|
|
56
56
|
|
|
57
57
|
## Product success criteria
|
|
@@ -114,6 +114,8 @@ The highest-leverage product line is:
|
|
|
114
114
|
local vent capture -> operator review queue -> draft-only owner routing -> human-approved escalation
|
|
115
115
|
```
|
|
116
116
|
|
|
117
|
+
For visible self-evolution work, keep `agent_vent` as recurrence memory and review queue only. The DRY routing map lives in the root `docs/project/visible-self-evolution-spine.md` spine; orchestrator may project verified evidence, while AK/society owner surfaces retain durable authority.
|
|
118
|
+
|
|
117
119
|
Do not add automatic GitHub/AK/incident writers. The local facet summary, fail-closed facet-filtered local review queue, per-state review outcome follow-up, read-only cross-state review comparison, explicit local decision posture, filter-preserving supported follow-up commands, record/state-scoped facet export, export-local-follow-up guidance, read-only retention-candidate planning, read-only retention-history receipt projection, advisory human-review hints, quoted state-aware next-action guidance, bounded review-detail samples, curation-aware recurrence resolution, facet-aware draft-only routing, retention archive/restore, and privacy membrane now have package validation; remaining product depth should refine operator comprehension only where it does not broaden authority. Hard-delete beyond backup-backed archive is decided out of v0.1: permanent removal remains operator-owned filesystem/data-lifecycle control unless a future decision accepts a narrower purge design.
|
|
118
120
|
|
|
119
121
|
Current proof: `npm run check` passes with 80 package tests plus release dry-run, packaged Markdown link checks, an unpacked-tarball `npm install && npm run check` contract smoke that runs the packaged fallback gate from inside the artifact, an artifact-only no-auth installed shadow registered-tool `agent_vent path` no-store-read smoke, and a full installed-tarball local-path package-discovery `/agent_vent path` smoke using isolated `PI_CODING_AGENT_DIR`, isolated npm prefix/cache, and `PI_AGENT_VENT_DIR`; docs strict check passes, `git diff --check` passes, and historical dogfood covered curation resolution, export posture, and live `pi install` reload behavior. Validation now covers quoted rollback commands, complete retention token inputs, stale-token/stale-restore failures, path-escape/symlink backup failures, receipt-failure rollback, retention-history restore-candidate reconstruction without active-store reads, export follow-up command quoting without archive/restore tokens or owner-routing claims, review decision-posture projection without resolution/assignment/evidence/incident claims, curation-aware recurrence resolution for review state and record feedback, stale lock cleanup, backup restore, duplicate-id-safe retention archive selection, retention-candidate planning without archive tokens, retention-candidate and compare tool-schema/command-contract parity, filter-preserving supported compare follow-ups, record/state-scoped facet export without owner-routing claims, mixed-group export non-broadening, empty export filters failing closed before store reads, tag/facet privacy metadata recomputation, hostile legacy JSONL privacy recomputation, fail-closed review/outcome/compare/export/retention-candidate/history syntax before store reads including empty filters, invalid review category/state handling, explicit per-state outcome/compare limits, quoted legacy recurrence-key command round trips, tool-only maintainer-note hints, reference-style packaged Markdown links, fail-closed `files[]` wildcard handling, public artifact script viability, release metadata alignment with `.copier-answers.yml`, local `npm:<tarball>` install-source validation, isolated installed-command smoke output, local-path package-discovery loading from the installed artifact, shadow registered-tool execution from the installed artifact, and registered-tool `path` no-store-read/no-store-write behavior with symlinked active stores.
|
package/docs/project/vision.md
CHANGED
|
@@ -44,6 +44,10 @@ agent notices recurring friction
|
|
|
44
44
|
-> owner system receives a human-approved draft only when appropriate
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
+
For self-evolution loops, `agent_vent` is the recurrence-memory surface after ASC/self has produced a diagnostic candidate.
|
|
48
|
+
It is not the loop executor, evaluator, or escalation authority.
|
|
49
|
+
Use the root `docs/project/visible-self-evolution-spine.md` spine and the cross-package [self/toolbox/agent_vent diagnostic boundary](./2026-06-05-self-toolbox-agent-vent-diagnostic-boundary.md) for the DRY owner map.
|
|
50
|
+
|
|
47
51
|
Near-term product work should make the review step better rather than broadening authority. Useful next surfaces include:
|
|
48
52
|
|
|
49
53
|
- `/agent_vent review` for an operator-facing review queue;
|
package/extensions/agent-vent.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import type { ExtensionAPI } from "@
|
|
2
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
import { Type } from "typebox";
|
|
4
4
|
import {
|
|
5
5
|
appendCurationEvent,
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
appendVentRecord,
|
|
8
8
|
archiveRecurrenceGroup,
|
|
9
9
|
assertCanCurateRecurrence,
|
|
10
|
+
assessVentRecordQuality,
|
|
10
11
|
buildEscalationDraft,
|
|
11
12
|
buildFacetSummary,
|
|
12
13
|
buildLifecycleSnapshot,
|
|
@@ -48,17 +49,19 @@ import {
|
|
|
48
49
|
normalizeRetentionAction,
|
|
49
50
|
normalizeReviewState,
|
|
50
51
|
RETENTION_ACTIONS,
|
|
51
|
-
REVIEW_STATES,
|
|
52
52
|
readRetentionEvents,
|
|
53
|
+
resolveCategoryFilter,
|
|
53
54
|
resolveRecurrenceGroup,
|
|
54
55
|
restoreRetentionBackup,
|
|
55
56
|
SEVERITIES,
|
|
57
|
+
REVIEW_STATES as STORE_REVIEW_STATES,
|
|
56
58
|
summarizeRecords,
|
|
57
59
|
summarizeReviewQueue,
|
|
58
60
|
} from "../src/vent-store.js";
|
|
59
61
|
|
|
60
62
|
const ACTIONS = [
|
|
61
63
|
"record",
|
|
64
|
+
"preview",
|
|
62
65
|
"summary",
|
|
63
66
|
"list",
|
|
64
67
|
"path",
|
|
@@ -74,7 +77,24 @@ const ACTIONS = [
|
|
|
74
77
|
"retention",
|
|
75
78
|
] as const;
|
|
76
79
|
const EXPORT_FORMATS = ["markdown", "json"] as const;
|
|
80
|
+
const FALLBACK_REVIEW_STATES = ["new", "acknowledged", "dismissed", "escalation_drafted"] as const;
|
|
81
|
+
const REVIEW_STATES = Array.isArray(STORE_REVIEW_STATES)
|
|
82
|
+
? STORE_REVIEW_STATES
|
|
83
|
+
: FALLBACK_REVIEW_STATES;
|
|
77
84
|
const RETENTION_CANDIDATE_STATES = ["reviewed", "all", ...REVIEW_STATES] as const;
|
|
85
|
+
const CATEGORY_ALIAS_INPUTS = [
|
|
86
|
+
"workflow_friction",
|
|
87
|
+
"operator_friction",
|
|
88
|
+
"process_friction",
|
|
89
|
+
"missing_affordance",
|
|
90
|
+
"missing_feature",
|
|
91
|
+
"documentation_gap",
|
|
92
|
+
"docs_gap",
|
|
93
|
+
"context_window",
|
|
94
|
+
"context_friction",
|
|
95
|
+
"tooling_friction",
|
|
96
|
+
] as const;
|
|
97
|
+
const CATEGORY_INPUTS = [...CATEGORIES, ...CATEGORY_ALIAS_INPUTS] as const;
|
|
78
98
|
|
|
79
99
|
const AgentVentParams = Type.Object({
|
|
80
100
|
action: Type.Optional(
|
|
@@ -88,9 +108,10 @@ const AgentVentParams = Type.Object({
|
|
|
88
108
|
),
|
|
89
109
|
category: Type.Optional(
|
|
90
110
|
Type.Union(
|
|
91
|
-
|
|
111
|
+
CATEGORY_INPUTS.map((category) => Type.Literal(category)),
|
|
92
112
|
{
|
|
93
|
-
description:
|
|
113
|
+
description:
|
|
114
|
+
"Local category for the frustration pattern. Common aliases are accepted and normalized to canonical categories.",
|
|
94
115
|
},
|
|
95
116
|
),
|
|
96
117
|
),
|
|
@@ -231,11 +252,12 @@ export default function agentVentExtension(pi: ExtensionAPI) {
|
|
|
231
252
|
name: "agent_vent",
|
|
232
253
|
label: "Agent Vent",
|
|
233
254
|
description:
|
|
234
|
-
"Record, review, and inspect local agent frustration events so recurring bugs, workflow friction, and missing affordances become visible.",
|
|
255
|
+
"Record, preview, review, and inspect local agent frustration events so recurring bugs, workflow friction, and missing affordances become visible.",
|
|
235
256
|
promptSnippet:
|
|
236
|
-
"
|
|
257
|
+
"Preview or record minimized local frustration events and review recurring patterns without creating incidents, tasks, issues, evidence records, or telemetry.",
|
|
237
258
|
promptGuidelines: [
|
|
238
259
|
"Use agent_vent when you encounter recurring agent frustration, long-lived bugs, repeated tool/runtime failures, context-loss patterns, or missing affordances worth later human review.",
|
|
260
|
+
"Use action=preview before action=record when the diagnostic may be generic, low-signal, or copied from another tool; previews run the anti-junk quality check without writing the local store.",
|
|
239
261
|
"Use action=review to inspect the local recurrence review queue; include recurrenceKey to inspect bounded representative samples for one local group; optionally filter review by local category, tag, tool, or package facets; use action=set_review to mark a recurrence group as new, acknowledged, dismissed, or escalation_drafted.",
|
|
240
262
|
"Use action=outcomes for read-only post-review follow-up across local review-state buckets; outcome guidance is local diagnostic UX only, not owner routing or external completion.",
|
|
241
263
|
"Use action=compare for a read-only cross-state review comparison before export, retention planning, or draft-only handoff; comparison output emits no archive/restore tokens and mutates nothing.",
|
|
@@ -249,7 +271,8 @@ export default function agentVentExtension(pi: ExtensionAPI) {
|
|
|
249
271
|
"When calling agent_vent, summarize minimally and never include secrets, credentials, private user payloads, or long raw logs.",
|
|
250
272
|
],
|
|
251
273
|
parameters: AgentVentParams,
|
|
252
|
-
async execute(_toolCallId, params,
|
|
274
|
+
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
275
|
+
throwIfCancelled(signal);
|
|
253
276
|
const storePath = defaultStorePath();
|
|
254
277
|
const reviewPath = defaultReviewPath();
|
|
255
278
|
const curationPath = defaultCurationPath();
|
|
@@ -271,13 +294,29 @@ export default function agentVentExtension(pi: ExtensionAPI) {
|
|
|
271
294
|
);
|
|
272
295
|
}
|
|
273
296
|
|
|
274
|
-
if (action === "record") {
|
|
297
|
+
if (action === "preview" || action === "record") {
|
|
275
298
|
const sessionFile = ctx.sessionManager.getSessionFile();
|
|
276
299
|
const record = createVentRecord(params, {
|
|
277
300
|
cwd: ctx.cwd,
|
|
278
301
|
sessionFile: sessionFile ? path.basename(sessionFile) : undefined,
|
|
279
|
-
source: "agent_vent_tool",
|
|
302
|
+
source: action === "preview" ? "agent_vent_preview" : "agent_vent_tool",
|
|
280
303
|
});
|
|
304
|
+
const quality = assessVentRecordQuality(params, record);
|
|
305
|
+
if (action === "preview") {
|
|
306
|
+
return textResult(formatRecordPreview(record, quality), {
|
|
307
|
+
action,
|
|
308
|
+
storePath,
|
|
309
|
+
recordPreview: record,
|
|
310
|
+
quality,
|
|
311
|
+
wouldRecord: quality.recordable,
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
if (!quality.recordable) {
|
|
315
|
+
throw new Error(
|
|
316
|
+
`agent_vent record rejected by anti-junk quality check: ${quality.issues.join("; ")}`,
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
throwIfCancelled(signal);
|
|
281
320
|
appendVentRecord(storePath, record);
|
|
282
321
|
const state = loadDiagnosticState({
|
|
283
322
|
storePath,
|
|
@@ -327,6 +366,7 @@ export default function agentVentExtension(pi: ExtensionAPI) {
|
|
|
327
366
|
});
|
|
328
367
|
}
|
|
329
368
|
|
|
369
|
+
throwIfCancelled(signal);
|
|
330
370
|
const state = loadDiagnosticState({
|
|
331
371
|
storePath,
|
|
332
372
|
reviewPath,
|
|
@@ -363,6 +403,7 @@ export default function agentVentExtension(pi: ExtensionAPI) {
|
|
|
363
403
|
};
|
|
364
404
|
assertCanCurateRecurrence(records, curationEvents, input);
|
|
365
405
|
const event = createCurationEvent(input, { source: "agent_vent_tool" });
|
|
406
|
+
throwIfCancelled(signal);
|
|
366
407
|
appendCurationEvent(curationPath, event);
|
|
367
408
|
const targetText = event.targetRecurrenceKey ? ` -> ${event.targetRecurrenceKey}` : "";
|
|
368
409
|
const text = [
|
|
@@ -396,6 +437,7 @@ export default function agentVentExtension(pi: ExtensionAPI) {
|
|
|
396
437
|
},
|
|
397
438
|
{ source: "agent_vent_tool" },
|
|
398
439
|
);
|
|
440
|
+
throwIfCancelled(signal);
|
|
399
441
|
appendReviewEvent(reviewPath, event);
|
|
400
442
|
const text = [
|
|
401
443
|
`Set local review state for ${event.recurrenceKey} to ${event.state}.`,
|
|
@@ -606,6 +648,7 @@ export default function agentVentExtension(pi: ExtensionAPI) {
|
|
|
606
648
|
});
|
|
607
649
|
}
|
|
608
650
|
if (retentionAction === "archive") {
|
|
651
|
+
throwIfCancelled(signal);
|
|
609
652
|
const result = archiveRecurrenceGroup({
|
|
610
653
|
storePath,
|
|
611
654
|
reviewPath,
|
|
@@ -628,6 +671,7 @@ export default function agentVentExtension(pi: ExtensionAPI) {
|
|
|
628
671
|
retention: result,
|
|
629
672
|
});
|
|
630
673
|
}
|
|
674
|
+
throwIfCancelled(signal);
|
|
631
675
|
const result = restoreRetentionBackup({
|
|
632
676
|
storePath,
|
|
633
677
|
retentionPath,
|
|
@@ -733,15 +777,31 @@ function registerAgentVentCommand(pi: ExtensionAPI, name: string, description: s
|
|
|
733
777
|
description,
|
|
734
778
|
handler: async (args, ctx) => {
|
|
735
779
|
const output = handleCommand(args);
|
|
736
|
-
if (ctx.hasUI) {
|
|
737
|
-
ctx.ui.notify(output, "info");
|
|
738
|
-
} else {
|
|
780
|
+
if (!ctx.hasUI) {
|
|
739
781
|
console.log(output);
|
|
782
|
+
} else if (isLongCommandOutput(output)) {
|
|
783
|
+
pi.sendMessage({
|
|
784
|
+
customType: "agent-vent-command",
|
|
785
|
+
content: output,
|
|
786
|
+
display: true,
|
|
787
|
+
details: { command: name },
|
|
788
|
+
});
|
|
789
|
+
ctx.ui.notify("agent_vent output added to the session transcript", "info");
|
|
790
|
+
} else {
|
|
791
|
+
ctx.ui.notify(output, "info");
|
|
740
792
|
}
|
|
741
793
|
},
|
|
742
794
|
});
|
|
743
795
|
}
|
|
744
796
|
|
|
797
|
+
function isLongCommandOutput(output: string): boolean {
|
|
798
|
+
return output.length > 500 || output.split("\n").length > 8;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
function throwIfCancelled(signal: AbortSignal | undefined): void {
|
|
802
|
+
if (signal?.aborted) throw new Error("agent_vent cancelled");
|
|
803
|
+
}
|
|
804
|
+
|
|
745
805
|
function handleCommand(args: string) {
|
|
746
806
|
const tokens = splitCommandArgs(args);
|
|
747
807
|
const action = tokens[0] || "summary";
|
|
@@ -755,6 +815,7 @@ function handleCommand(args: string) {
|
|
|
755
815
|
return [
|
|
756
816
|
"agent_vent commands:",
|
|
757
817
|
" /agent_vent summary Show recurrence groups and candidate incidents.",
|
|
818
|
+
" LLM tool action=preview Preview a local diagnostic record and anti-junk quality check without writing the store.",
|
|
758
819
|
" /agent_vent list [limit] Show recent local vent records.",
|
|
759
820
|
" /agent_vent facets [limit] Show read-only local category/tag/tool/package facets.",
|
|
760
821
|
" /agent_vent review [state|all] [limit] [category=bug] [tag=reload] [tool=pi-reload] [package=tryinget-pi-agent-vent]",
|
|
@@ -1080,8 +1141,8 @@ function parseReviewListTokens(tokens: string[], options: { allowReviewedState?:
|
|
|
1080
1141
|
invalidFilters.push("category=");
|
|
1081
1142
|
continue;
|
|
1082
1143
|
}
|
|
1083
|
-
const
|
|
1084
|
-
if (
|
|
1144
|
+
const category = resolveCategoryFilter(value);
|
|
1145
|
+
if (category) filters.category = category;
|
|
1085
1146
|
else invalidFilters.push(`category=${value}`);
|
|
1086
1147
|
} else if (key === "tool") {
|
|
1087
1148
|
if (!value) {
|
|
@@ -1370,6 +1431,24 @@ function formatDiagnosticWarnings(state: Record<string, unknown>) {
|
|
|
1370
1431
|
: "";
|
|
1371
1432
|
}
|
|
1372
1433
|
|
|
1434
|
+
function formatRecordPreview(
|
|
1435
|
+
record: Record<string, unknown>,
|
|
1436
|
+
quality: { recordable?: boolean; issues?: string[]; warnings?: string[]; boundary?: string },
|
|
1437
|
+
) {
|
|
1438
|
+
const issues = quality.issues || [];
|
|
1439
|
+
const warnings = quality.warnings || [];
|
|
1440
|
+
return [
|
|
1441
|
+
`Agent vent preview: ${quality.recordable ? "recordable" : "not recordable"} (${record.severity || "medium"}/${record.category || "other"}) under ${record.recurrenceKey || "unknown"}.`,
|
|
1442
|
+
`Summary: ${record.summary || "(no summary)"}`,
|
|
1443
|
+
issues.length ? `Issues: ${issues.join("; ")}` : "Issues: none",
|
|
1444
|
+
warnings.length ? `Warnings: ${warnings.join("; ")}` : "Warnings: none",
|
|
1445
|
+
"No local diagnostic record was written. Use action=record only if this is a recurring or review-worthy diagnostic, not an ordinary progress update.",
|
|
1446
|
+
`Boundary: ${quality.boundary || "local diagnostic preview only"}`,
|
|
1447
|
+
].join("\n");
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
export const _test = { isLongCommandOutput, throwIfCancelled };
|
|
1451
|
+
|
|
1373
1452
|
function textResult(text: string, details: Record<string, unknown>) {
|
|
1374
1453
|
return {
|
|
1375
1454
|
content: [{ type: "text" as const, text }],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tryinget/pi-agent-vent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Local pi tool for agents to record recurring frustrations, bugs, and workflow friction without creating incidents or external telemetry",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"access": "public"
|
|
29
29
|
},
|
|
30
30
|
"engines": {
|
|
31
|
-
"node": ">=22"
|
|
31
|
+
"node": ">=22.19.0"
|
|
32
32
|
},
|
|
33
33
|
"scripts": {
|
|
34
34
|
"fix": "bash ./scripts/quality-gate.sh fix",
|
|
@@ -43,7 +43,13 @@
|
|
|
43
43
|
"docs:list:workspace": "bash ./scripts/docs-list.sh --workspace --discover",
|
|
44
44
|
"docs:list:json": "bash ./scripts/docs-list.sh --json",
|
|
45
45
|
"release:check": "bash ./scripts/release-check.sh",
|
|
46
|
-
"release:check:quick": "SKIP_PI_SMOKE=1 bash ./scripts/release-check.sh"
|
|
46
|
+
"release:check:quick": "SKIP_PI_SMOKE=1 bash ./scripts/release-check.sh",
|
|
47
|
+
"loop-doctor": "bash -lc 'node --version; npm --version; npm pkg get name version >/dev/null; git status --short -- . || true; exit 0'",
|
|
48
|
+
"loop-verify-fast": "npm run quality:pre-commit",
|
|
49
|
+
"loop-impact-plan": "bash -lc 'echo \"loop-impact-plan: package-local impact planner is coarse; run npm run loop-impact-run for the full package gate.\"; git status --short -- . || true'",
|
|
50
|
+
"loop-impact-run": "npm run check",
|
|
51
|
+
"loop-impact-wide": "npm run check",
|
|
52
|
+
"loop-landing-check": "npm run check"
|
|
47
53
|
},
|
|
48
54
|
"files": [
|
|
49
55
|
"extensions/agent-vent.ts",
|
|
@@ -60,6 +66,7 @@
|
|
|
60
66
|
"docs/project/product-posture.md",
|
|
61
67
|
"docs/project/2026-05-21-agent-vent-design.md",
|
|
62
68
|
"docs/project/2026-05-21-agent-vent-implementation-plan.md",
|
|
69
|
+
"docs/project/2026-06-05-self-toolbox-agent-vent-diagnostic-boundary.md",
|
|
63
70
|
"docs/project/extension-sop.md",
|
|
64
71
|
"docs/project/trusted-publishing.md",
|
|
65
72
|
"docs/adr/2026-05-22-agent-vent-retention-delete-policy.md"
|
|
@@ -79,17 +86,19 @@
|
|
|
79
86
|
"releaseConfigMode": "component"
|
|
80
87
|
},
|
|
81
88
|
"devDependencies": {
|
|
82
|
-
"@biomejs/biome": "2.3.14"
|
|
89
|
+
"@biomejs/biome": "2.3.14",
|
|
90
|
+
"@earendil-works/pi-ai": "0.80.6",
|
|
91
|
+
"@earendil-works/pi-coding-agent": "0.80.6"
|
|
83
92
|
},
|
|
84
93
|
"overrides": {
|
|
85
94
|
"fast-xml-parser": "5.3.6"
|
|
86
95
|
},
|
|
87
96
|
"peerDependencies": {
|
|
88
|
-
"@
|
|
89
|
-
"@
|
|
97
|
+
"@earendil-works/pi-ai": "*",
|
|
98
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
90
99
|
"typebox": "*"
|
|
91
100
|
},
|
|
92
101
|
"dependencies": {
|
|
93
|
-
"typebox": "
|
|
102
|
+
"typebox": "*"
|
|
94
103
|
}
|
|
95
104
|
}
|
|
@@ -17,6 +17,18 @@
|
|
|
17
17
|
"dependency-governance",
|
|
18
18
|
"specification-and-dsls",
|
|
19
19
|
"engineering-reasoning"
|
|
20
|
-
]
|
|
20
|
+
],
|
|
21
|
+
"loop_validation": {
|
|
22
|
+
"version": "repo-loop-validation-v1",
|
|
23
|
+
"contract_doc": "docs/engineering.local.md#repo-loop-validation",
|
|
24
|
+
"commands": {
|
|
25
|
+
"loop-doctor": "npm run loop-doctor",
|
|
26
|
+
"loop-verify-fast": "npm run loop-verify-fast",
|
|
27
|
+
"loop-impact-plan": "npm run loop-impact-plan",
|
|
28
|
+
"loop-impact-run": "npm run loop-impact-run",
|
|
29
|
+
"loop-impact-wide": "npm run loop-impact-wide",
|
|
30
|
+
"loop-landing-check": "npm run loop-landing-check"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
21
33
|
}
|
|
22
34
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
|
-
summary: "
|
|
2
|
+
summary: "pi-agent-vent implementation planning prompt template."
|
|
3
3
|
read_when:
|
|
4
4
|
- "Using or updating the monorepo package implementation-planning prompt template."
|
|
5
|
-
description: Draft an implementation plan for a requested change
|
|
5
|
+
description: Draft an implementation plan for a requested pi-agent-vent change
|
|
6
6
|
system4d:
|
|
7
7
|
container: "Prompt template for implementation planning."
|
|
8
8
|
compass: "Turn requests into actionable, risk-aware plans."
|
|
@@ -10,7 +10,7 @@ system4d:
|
|
|
10
10
|
fog: "Hidden constraints unless assumptions are surfaced."
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
Create
|
|
13
|
+
Create a pi-agent-vent implementation plan for this request: $@
|
|
14
14
|
|
|
15
15
|
Include:
|
|
16
16
|
- Scope and non-goals
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
|
-
summary: "
|
|
2
|
+
summary: "pi-agent-vent security review prompt template."
|
|
3
3
|
read_when:
|
|
4
4
|
- "Using or updating the monorepo package security-review prompt template."
|
|
5
|
-
description: Review a change for security risks and mitigations
|
|
5
|
+
description: Review a pi-agent-vent change for security risks and mitigations
|
|
6
6
|
system4d:
|
|
7
7
|
container: "Prompt template for security-focused review."
|
|
8
8
|
compass: "Identify practical vulnerabilities before release."
|
|
@@ -10,7 +10,7 @@ system4d:
|
|
|
10
10
|
fog: "Partial context can hide exploit paths."
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
Review this change for security concerns: $@
|
|
13
|
+
Review this pi-agent-vent change for security concerns: $@
|
|
14
14
|
|
|
15
15
|
Focus on:
|
|
16
16
|
- Input validation and injection risk
|