gentle-pi 2.4.0 → 2.5.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 +170 -12
- package/assets/agents/gentle-ai-worker.md +9 -0
- package/assets/orchestrator-delegation.md +19 -9
- package/assets/orchestrator.md +5 -5
- package/docs/delegated-verification.md +25 -0
- package/docs/telemetry.md +38 -0
- package/extensions/ask-user-choice.ts +26 -20
- package/extensions/codegraph-tools.ts +94 -5
- package/extensions/gentle-agents.ts +588 -0
- package/extensions/gentle-ai.ts +898 -79
- package/extensions/gentle-shell.ts +547 -0
- package/extensions/gentle-todo.ts +199 -0
- package/extensions/quiet-tools.ts +1 -1
- package/lib/agents-config.ts +318 -0
- package/lib/agents-history.ts +80 -0
- package/lib/agents-protocol.ts +429 -0
- package/lib/agents-runner.ts +490 -0
- package/lib/agents-transcript.ts +87 -0
- package/lib/agents-view.ts +557 -0
- package/lib/agents-widget.ts +222 -0
- package/lib/gentle-ai-renderer.ts +142 -26
- package/lib/native-choice-list.ts +194 -0
- package/lib/native-fullscreen-interaction.ts +47 -0
- package/lib/native-pointer-region.ts +164 -0
- package/lib/native-review-cli.ts +88 -12
- package/lib/review-candidate-view-owner.ts +177 -0
- package/lib/review-candidate-view.ts +127 -35
- package/lib/review-consent-ui.ts +65 -0
- package/lib/review-integration-v2.ts +58 -8
- package/lib/review-last-event-controller.ts +1 -0
- package/lib/review-relay-contract.ts +11 -0
- package/lib/review-repository.ts +2 -2
- package/lib/review-risk-assessment.ts +339 -0
- package/lib/review-session-standing-permission-ipc.ts +309 -0
- package/lib/review-session-standing-permission.ts +219 -0
- package/lib/shell-bar.ts +138 -0
- package/lib/shell-card.ts +136 -0
- package/lib/shell-changes-view.ts +205 -0
- package/lib/shell-changes.ts +210 -0
- package/lib/shell-gauge.ts +40 -0
- package/lib/shell-prompt.ts +119 -0
- package/lib/shell-todo.ts +280 -0
- package/lib/shell-usage-view.ts +76 -0
- package/lib/shell-usage.ts +246 -0
- package/lib/telemetry-trigger.ts +151 -0
- package/package.json +4 -4
- package/runtime/native-review-cli.mjs +87 -11
- package/runtime/review-integration-v2.mjs +58 -8
- package/runtime/review-relay-contract.mjs +11 -0
- package/runtime/review-risk-assessment.mjs +340 -0
- package/runtime/telemetry-trigger.mjs +152 -0
- package/scripts/build-runtime-modules.mjs +2 -0
- package/scripts/gentle-ai-installer.mjs +10 -10
- package/scripts/test-packed-runner.mjs +22 -0
- package/scripts/verify-package-files.mjs +6 -2
- package/skills/_shared/review-ledger-contract.md +3 -1
- package/tests/agents-config.test.ts +143 -0
- package/tests/agents-fake-child.ts +52 -0
- package/tests/agents-history.test.ts +54 -0
- package/tests/agents-protocol.test.ts +153 -0
- package/tests/agents-runner-process.test.ts +111 -0
- package/tests/agents-runner.test.ts +402 -0
- package/tests/agents-transcript.test.ts +30 -0
- package/tests/agents-view.test.ts +274 -0
- package/tests/agents-widget.test.ts +111 -0
- package/tests/ask-user-choice.test.ts +157 -3
- package/tests/codegraph-tools.test.ts +110 -1
- package/tests/devbinary/native-review-parity.devtest.ts +108 -0
- package/tests/fixtures/agents-process-child.mjs +23 -0
- package/tests/gentle-agents.test.ts +741 -0
- package/tests/gentle-ai-binary.test.ts +1 -1
- package/tests/gentle-ai-installer.test.ts +47 -47
- package/tests/gentle-ai-renderer.test.ts +65 -0
- package/tests/gentle-ai.test.ts +28 -12
- package/tests/gentle-card-text.ts +35 -0
- package/tests/gentle-shell.test.ts +527 -0
- package/tests/gentle-todo.test.ts +182 -0
- package/tests/native-choice-list.test.ts +202 -0
- package/tests/native-fullscreen-interaction.test.ts +125 -0
- package/tests/native-pointer-region.test.ts +245 -0
- package/tests/native-review-capability-contract.test.ts +16 -1
- package/tests/native-review-cli.test.ts +40 -0
- package/tests/native-review-consent.test.ts +91 -0
- package/tests/native-review-parity-runtime.test.ts +8 -2
- package/tests/native-review-parity.test.ts +29 -22
- package/tests/orchestrator-budget.test.ts +69 -0
- package/tests/orchestrator-rdd-ownership.test.ts +9 -0
- package/tests/package-manifest.test.ts +17 -6
- package/tests/quiet-tool-rendering.test.ts +96 -37
- package/tests/rdd-aware-verification-contract.test.ts +216 -0
- package/tests/rdd-status-line.test.ts +286 -0
- package/tests/review-candidate-view.test.ts +452 -6
- package/tests/review-contract-prompt.test.ts +3 -0
- package/tests/review-controller-native-recovery.test.ts +29 -4
- package/tests/review-controller-native-routing.test.ts +321 -4
- package/tests/review-controller-workspace-root.test.ts +45 -2
- package/tests/review-controller.test.ts +25 -0
- package/tests/review-host-relay-routing.test.ts +20 -4
- package/tests/review-integration-v2.test.ts +112 -0
- package/tests/review-last-event-closure.test.ts +7 -2
- package/tests/review-relay-contract.test.ts +26 -0
- package/tests/review-repository.test.ts +28 -1
- package/tests/review-risk-assessment.test.ts +626 -0
- package/tests/review-session-standing-permission-controller.test.ts +608 -0
- package/tests/review-session-standing-permission-ipc.test.ts +233 -0
- package/tests/review-session-standing-permission-runtime.test.ts +212 -0
- package/tests/review-session-standing-permission.test.ts +126 -0
- package/tests/shell-bar.test.ts +176 -0
- package/tests/shell-card.test.ts +118 -0
- package/tests/shell-changes-view.test.ts +146 -0
- package/tests/shell-changes.test.ts +182 -0
- package/tests/shell-prompt.test.ts +118 -0
- package/tests/shell-todo.test.ts +170 -0
- package/tests/shell-usage-view.test.ts +62 -0
- package/tests/shell-usage.test.ts +197 -0
- package/tests/telemetry-trigger.test.ts +349 -0
package/README.md
CHANGED
|
@@ -76,15 +76,39 @@ Most coding-agent sessions fail for operational reasons, not model reasons:
|
|
|
76
76
|
| **Lazy SDD preflight** | Resolves SDD mode, artifact store, delivery strategy, and review budget once per session; prompts only when a choice is genuinely unresolved. |
|
|
77
77
|
| **Subagent orchestration** | Keeps one parent session responsible while child agents explore, implement, test, or review with focused context. |
|
|
78
78
|
| **Strict TDD support** | When project config declares a test command, apply/verify phases must record RED → GREEN → TRIANGULATE → REFACTOR evidence. |
|
|
79
|
+
| **Closed choice prompts** | Per-option hover/click/wheel in fullscreen; keyboard selection in either TUI mode. |
|
|
80
|
+
| **Native pointer regions** | Compose hover, press, click, and wheel behavior around public TUI components. |
|
|
79
81
|
| **Reviewer protection** | Surfaces review workload risk before a task turns into an oversized PR. |
|
|
80
82
|
| **Per-agent model assignment** | Pi-native modal for assigning stronger or cheaper models to specific SDD/custom agents. |
|
|
81
83
|
| **Skill discovery registry** | Maintains `.atl/skill-registry.md` from project and user skills so review/comment/PR workflows do not silently miss the right skill. |
|
|
82
84
|
| **Skill creation workflow** | Provides the `gentle-ai-skill-creator`/`gentle-ai-skill-improver` skills, `/skill-creation` prompt, and packaged style guide for LLM-first skills. |
|
|
83
85
|
| **Delivery skills** | Includes issue-first PRs, chained PRs, work-unit commits, cognitive docs, comment writing, and Judgment Day review. |
|
|
84
86
|
| **Bounded native review** | Freezes one candidate, dispatches only controller-selected lenses, and records native authority. Review outcomes are informational; delivery follows ordinary repository policy. |
|
|
85
|
-
| **Verified native runtime** | Provisions the exact package-local Gentle AI v2.
|
|
87
|
+
| **Verified native runtime** | Provisions the exact package-local Gentle AI v2.7.0 runtime: signed, SHA-256-pinned release archives on Darwin/Linux and a Go SumDB-verified source build on Windows x64/arm64. It validates package-local integrity and rejects PATH, global, sibling, symlink, and mode fallbacks. |
|
|
86
88
|
| **Runtime safety** | Blocks destructive shell commands, asks for confirmation for sensitive operations, and blocks direct read/write/edit access to sensitive paths. |
|
|
87
89
|
|
|
90
|
+
## Native pointer regions
|
|
91
|
+
|
|
92
|
+
Compose pointer behavior around public `Text`, `Box`, or custom content without making it a keyboard target:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
const scope = createNativePointerScope();
|
|
96
|
+
const openInput = scope.wrap(new Text("Open input", 0, 0), {
|
|
97
|
+
onClick: () => {
|
|
98
|
+
openInputEditor();
|
|
99
|
+
return { handled: true };
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
const panel = new Container();
|
|
103
|
+
panel.addChild(openInput);
|
|
104
|
+
const observer = scope.createMouseObserver(() => tui.requestRender());
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Pass `observer` around the root's native mouse dispatch; reuse `panel` as custom or overlay content.
|
|
108
|
+
Pointer input is fullscreen-only. Regions preserve a consuming child's native result and do not focus
|
|
109
|
+
`Text`, activate on press or wheel, synthesize outside leave events, or alter terminal tracking.
|
|
110
|
+
Callers own keyboard policy, theme state, and business actions.
|
|
111
|
+
|
|
88
112
|
**Migration note:** Do not enable `pi-tool-cards` and `quiet-tools` together: Pi rejects duplicate `bash`, `read`, `edit`, and `write` registrations. Disable or remove the standalone package during migration; gentle-pi does not alter user configuration or delete that repository.
|
|
89
113
|
|
|
90
114
|
## Install
|
|
@@ -105,17 +129,15 @@ pi install npm:gentle-pi@0.14.0
|
|
|
105
129
|
pi install npm:gentle-pi@latest
|
|
106
130
|
```
|
|
107
131
|
|
|
108
|
-
The latest RDD package installs Gentle AI only into its private `.gentle-ai/` directory. Darwin and Linux use pinned release assets with asset and executable SHA-256 verification (signed archives for stable pins such as the current v2.
|
|
132
|
+
The latest RDD package installs Gentle AI only into its private `.gentle-ai/` directory. Darwin and Linux use pinned release assets with asset and executable SHA-256 verification (signed archives for stable pins such as the current v2.7.0; raw prerelease binaries only under a prerelease pin). Windows x64 and arm64 build the exact `v2.7.0` source tag with a local Go 1.25.10+ toolchain, a sealed Go environment, `GOTOOLCHAIN=local`, and `GOSUMDB=sum.golang.org`; it does not download Go automatically. Windows provenance is Go-toolchain plus SumDB evidence and postinstall tamper detection, **not** Authenticode or protection against a malicious joint binary-and-manifest replacement. Package-private locks coordinate cooperative concurrent or crashed installers; their tombstones fail closed. A malicious same-user process with write access to package-private `node_modules` is outside that protocol because it can already replace package code, binary, or manifest, and portable Node has no pathname-delete CAS. It never uses `PATH` or a global `gentle-ai` installation. For development or offline installs only, set `GENTLE_PI_SKIP_GENTLE_AI_INSTALL=1`; native review operations then fail closed with an actionable `package-local-binary-missing` error until the package is reinstalled normally.
|
|
109
133
|
|
|
110
134
|
Recommended companion packages:
|
|
111
135
|
|
|
112
136
|
```bash
|
|
113
|
-
pi install npm:pi-subagents-j0k3r
|
|
114
137
|
pi install npm:pi-intercom
|
|
115
138
|
pi install npm:gentle-engram
|
|
116
139
|
pi install npm:pi-web-access
|
|
117
140
|
pi install npm:pi-lens
|
|
118
|
-
pi install npm:@juicesharp/rpiv-todo
|
|
119
141
|
pi install npm:@juicesharp/rpiv-ask-user-question
|
|
120
142
|
```
|
|
121
143
|
|
|
@@ -172,7 +194,7 @@ The goal is not ceremony. The goal is to avoid accidental chaos. Once a task sto
|
|
|
172
194
|
|
|
173
195
|
### Delegation triggers
|
|
174
196
|
|
|
175
|
-
`gentle-pi` keeps the parent session thin and delegates at the narrowest useful point. When the Pi Subagents extension is installed, the preferred runtime is the `subagent_*` tool family because it runs the user's configured project/global subagent definitions and preserves history/background behavior.
|
|
197
|
+
`gentle-pi` keeps the parent session thin and delegates at the narrowest useful point. When the Pi Subagents extension is installed, the preferred runtime is the `subagent_*` tool family because it runs the user's configured project/global subagent definitions and preserves history/background behavior. With the background policy on, delegations default to background mode: the terminal stays free and each result comes back as a message that starts a new turn; task mode is reserved for delegations that must ask the user something mid-flight. If those tools are unavailable, the parent should fall back to Pi's native `Agent` tool or another available delegation mechanism. The requirement is delegation; the runtime is capability-dependent.
|
|
176
198
|
|
|
177
199
|
| Trigger | Required behavior |
|
|
178
200
|
| --------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
|
|
@@ -261,13 +283,13 @@ flowchart TD
|
|
|
261
283
|
|
|
262
284
|
VALIDATE is informational. Commit, push, PR, and release commands follow ordinary repository policy; RDD never authorizes, rewrites, consumes review state for, or blocks them. Dangerous-command safety and destructive-review consent remain independent.
|
|
263
285
|
|
|
264
|
-
Native contract pairing is exact: this adapter resolves only the integrity-verified package-local Gentle AI v2.
|
|
286
|
+
Native contract pairing is exact: this adapter resolves only the integrity-verified package-local Gentle AI v2.7.0 executable, independently hashes it, then negotiates `gentle-ai.review-integration/v2` outside the repository. Capabilities are cached by that executable digest. Every START, target status, FINALIZE, validate, and BIND-SDD request passes the same contract identifier. Negotiated envelopes decode exactly against the vendored schemas; `recover` routes only the provider-selected `action_disposition`, and optional additions require a future compatible schema/minor that the provider explicitly advertises and the consumer negotiates.
|
|
265
287
|
|
|
266
288
|
Contract `/v2` replaces the Base64 `candidate_diff` reviewer transport of `/v1` with immutable `base_tree`/`candidate_tree` plus an ordered `changed_path_manifest` and never an inline patch. `gentle-pi` negotiates `/v2` only, with no dual-lane fallback; the cutover landed as one atomic commit against gentle-ai v2.2.2 (tracked by the `migrate-review-integration-v2` change), and the `/v1` schemas stay packaged because the `/v2` schemas `$ref` into their fragments. This provider contract version is unrelated to Pi's own internal "compact-v2" review-authority naming used below — the shared digit is coincidental, not a version pairing.
|
|
267
289
|
|
|
268
290
|
Target status owns `current_target`, `unrelated`, `ambiguous`, and `corrupted` applicability and returns one native action. Pi does not reconstruct ordinary authority from provider-private files or choose a lineage from repository-wide history. Restart recovery rebuilds only the derived candidate view from the native Git/content projection, including intended-untracked paths, symlinks, and immutable gitlink identities. Native failure envelopes retain their exact mutation outcome, replayability, required inputs, request digest, and next action. After an unknown or lost mutating result, Pi calls target status before any replay decision and returns only the provider-declared action.
|
|
269
291
|
|
|
270
|
-
Once the pinned gentle-ai runtime (currently v2.
|
|
292
|
+
Once the pinned gentle-ai runtime (currently v2.7.0) has written review authority, rollback MUST preserve every native store and receipt and MUST NOT run a downgraded binary against that repository. Disable the Pi route or roll forward to a compatible authority-aware release instead; deleting authority data or reinstalling an older binary is not a rollback path.
|
|
271
293
|
|
|
272
294
|
### FINALIZE wrapper input
|
|
273
295
|
|
|
@@ -325,9 +347,11 @@ Judgment Day alone may iterate discovery and scoped re-judgment, for at most two
|
|
|
325
347
|
|
|
326
348
|
Findings surviving round two escalate; no third-round transition exists.
|
|
327
349
|
|
|
328
|
-
Native review mode and candidate
|
|
350
|
+
Native review mode and the two candidate choices remain provider-owned lifecycle semantics. For a validated `consent/v3` envelope in the interactive parent TUI, Pi displays those two choices unchanged and adds a clearly separate host-owned action: **Run this review and allow reviews for this Pi session**. Only direct human selection creates this process-memory grant. Its scope is the coordinating live SessionManager session and the canonical Git common-directory identity of the selected repository: it runs the current envelope's exact provider `granted` invocation through the existing one-shot `answer-consent` path, then does the same for later fresh validated envelopes in sibling worktrees of that same clone, including package-owned children. An unrelated repository requires a separate explicit human grant. Reload preserves it; `/tree` retains it; revoke removes the current repository grant; quit, new, resume, fork, or process restart removes all session grants. The command's `status` action reports the in-memory state without changing provider mode or authority.
|
|
329
351
|
|
|
330
|
-
|
|
352
|
+
The host grant is held only in a schema-checked `globalThis[Symbol.for(...)]` WeakMap registry keyed by session and canonical Git common-directory digest. It is never written through session entries, settings, environment variables, or the old asked latch. A package-owned Gentle Agents child can request one bounded parent-owned stdio authorization for its own validated pending ordinary START; it sends only that target's canonical repository digest, and the parent rechecks the live task, digest, and current parent session grant before the child replays its exact provider grant locally. No candidate bytes, provider vectors, paths, local child grant, or delivery authority crosses that channel. External or legacy `pi-subagents` launchers do not receive this channel and remain unsupported. Headless/RPC/unsupported UI, external processes, model prose, tool arguments, cancellation, identity drift, malformed identity, and uncertain native results cannot create or consume the grant. Native workspace binding remains canonical and target-specific; session-wide consent never authorizes an unselected target or an unrelated repository. The grant conveys no review verdict, forecast/cost approval, acknowledgement, maintenance, delivery, or cross-repository authority. When the host cannot resolve the choice, `gentle_review` returns the original unresolved two-choice provider envelope unchanged for the normal lossless relay. SessionManager binding isolates simultaneous SDK sessions; Pi does not claim universal same-process agent-principal isolation because the SDK exposes no principal identity.
|
|
353
|
+
|
|
354
|
+
When RDD is on and an agent loop ends with an unreviewed candidate, `gentle-pi` sends one read-only reminder pointing the agent back to `gentle_review {"operation":"inspect"}` before it reports completion. This nudge is idempotent (at most once per target identity per session), never fires for a headless session or a subagent's own loop, and never runs START or answers consent itself. Pi treats a child `agent_end` as a latest-answer update, not completion: queued retry, compaction, follow-up, required verification, and legitimate post-correction verification remain live until `agent_settled`. It does not claim ready or RDD-ready first, but this ordering rule does not impose a universal full-suite requirement or turn a receipt into a delivery gate. At session start, `gentle-pi` records the current target identity as a baseline, so a candidate that already existed before the session began (the user's own prior work, not this session's output) never draws the reminder.
|
|
331
355
|
|
|
332
356
|
Review outcomes and receipt state are informational; commit, push, pull-request, and release delivery follow ordinary repository policy. No one-shot command authorization, publication-target revalidation, or receipt gate is required for delivery, and Pi does not inspect RDD mode or native authority to decide a Bash delivery command.
|
|
333
357
|
|
|
@@ -543,8 +567,7 @@ A project can still override the global default with:
|
|
|
543
567
|
The modal discovers:
|
|
544
568
|
|
|
545
569
|
- project agents in `.pi/subagents/`, `.pi/agents/`, and `.agents/`;
|
|
546
|
-
- user agents in `~/.pi/agent/subagents/`, `~/.pi/agent/agents/`, and `~/.agents
|
|
547
|
-
- built-in agents from `pi-subagents-j0k3r` when present.
|
|
570
|
+
- user agents in `~/.pi/agent/subagents/`, `~/.pi/agent/agents/`, and `~/.agents/`.
|
|
548
571
|
|
|
549
572
|
When applying routing, project agents write runtime profiles to `.pi/subagents.json`; global and built-in agents write profiles to `~/.pi/agent/subagents.json`.
|
|
550
573
|
|
|
@@ -584,6 +607,124 @@ Config shape (per agent):
|
|
|
584
607
|
|
|
585
608
|
Legacy string entries are still accepted and treated as `model`-only config.
|
|
586
609
|
|
|
610
|
+
## Gentle Shell
|
|
611
|
+
|
|
612
|
+
Gentle Shell is the visual layer gentle-pi puts on top of pi. It follows the Gentle themes: one border language, champagne titles, rose for whatever is alive.
|
|
613
|
+
|
|
614
|
+
The status bar replaces pi's three-line footer with a single line of segments:
|
|
615
|
+
|
|
616
|
+
```text
|
|
617
|
+
✿ gentle-pi ⟡ ~/work/gentle-pi main ⟡ gpt-5.5 · medium ⟡ ctx ▰▰▰▰▱▱▱▱ 45% ⟡ $9.49 sub ⟡ MCP: 3 servers enabled Release notes
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
- Context is a gauge, not a number. It turns amber at 80% and red at 95%; after compaction it shows `?%` until the next response.
|
|
621
|
+
- Cost carries `sub` when the active model runs on a subscription login.
|
|
622
|
+
- Statuses other extensions publish through `setStatus` are appended as trailing segments; the session name sits at the right edge.
|
|
623
|
+
- On narrow terminals the session name is dropped first, then trailing segments, before the line is truncated.
|
|
624
|
+
|
|
625
|
+
The prompt wraps pi's editor in a rounded frame with a petal that shows what the agent is doing:
|
|
626
|
+
|
|
627
|
+
```text
|
|
628
|
+
╭─ ✿ working ──────────────────────────────────────────╮
|
|
629
|
+
│ type, or / for commands │
|
|
630
|
+
╰──────────────────────────────────────────────────────╯
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
- The petal is still while pi waits, spins with a `working` label while the agent works, and turns amber with a `queued` label when messages are waiting behind the current turn. pi's own "Working" row above the editor is hidden, since the frame already says it.
|
|
634
|
+
- The frame uses the theme's border color over the panel background, so the prompt reads as one panel with the cards around it; the editor's scroll indicators stay inside the frame.
|
|
635
|
+
- The hint appears only while the editor is empty.
|
|
636
|
+
- If another extension already installed a custom editor, Gentle Shell leaves it alone.
|
|
637
|
+
|
|
638
|
+
Working-tree changes show up below the editor as soon as a file differs from HEAD, and as `±N` next to the branch in the bar:
|
|
639
|
+
|
|
640
|
+
```text
|
|
641
|
+
✎ 3 files · +42 −7 · extensions/gentle-shell.ts, lib/shell-bar.ts, tests/x.test.ts · /gentle:changes
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
- It is plain `git diff` against HEAD plus untracked files, so a resumed session shows the same picture as a fresh one.
|
|
645
|
+
- Counts refresh after every tool call, at the end of each turn, and every 5 seconds in the background, so edits made from nvim or another agent show up without touching pi. `GENTLE_PI_SHELL_CHANGES_WATCH_MS` changes the interval; `off` leaves only the tool-driven refresh. Outside a git repository the widget stays hidden.
|
|
646
|
+
- On narrow terminals the file list is dropped before the summary is truncated.
|
|
647
|
+
|
|
648
|
+
`/gentle:changes` or `alt+g` opens the changes as an overlay: files on the left, the selected file's diff on the right.
|
|
649
|
+
|
|
650
|
+
- `j`/`k` or the arrows move between files, `ctrl+j`/`ctrl+k` or `pgdn`/`pgup` scroll the diff, `esc` or `q` closes.
|
|
651
|
+
- While the overlay is open, git is polled every 2 seconds, so edits made from nvim, another agent, or a checkout show up in place. The selection sticks to the file, and a diff reloads only when its counts move.
|
|
652
|
+
- `GENTLE_PI_SHELL_CHANGES_KEY` rebinds the shortcut (pi key syntax, for example `ctrl+shift+g`); `off` disables it. On macOS, `alt+g` needs the terminal to send Option as Meta.
|
|
653
|
+
- `o` (or `enter`) opens the selected file in `$VISUAL` or `$EDITOR` and returns to pi when the editor exits, so a jump into nvim and back never leaves the session.
|
|
654
|
+
- Untracked files are diffed against an empty file so new files show their full content.
|
|
655
|
+
|
|
656
|
+
Subscription usage shows in the bar after the cost, and `/gentle:usage` opens a panel with every window per provider:
|
|
657
|
+
|
|
658
|
+
```text
|
|
659
|
+
✿ gentle-pi ⟡ … ⟡ $9.49 sub ⟡ codex 5h ▰▰▰▰▰▱▱▱ 62% · week 31%
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
- For Codex, usage comes from the same account usage endpoint the Codex CLI reads, using the OAuth token pi already holds. It is fetched at session start, at most every 5 minutes after a turn, and on `r` in the panel. Rate-limit headers on SSE responses are picked up too.
|
|
663
|
+
- For Claude Pro/Max, usage arrives in the rate-limit headers of every response, so the 5h and weekly windows appear after the first turn.
|
|
664
|
+
- The bar names the subscription it shows (`codex`, `claude`) and always follows the active model. The panel puts the active provider first, marked with the petal, and says why it has no data when it does not: API-key providers have no subscription windows, Claude reports after the first response, Codex waits for a fetch.
|
|
665
|
+
- Only the plan name and the windows are kept; account details in the payload are discarded.
|
|
666
|
+
- Gauges turn amber at 80% and red at 95%, like the context gauge.
|
|
667
|
+
|
|
668
|
+
Gentle notices are drawn as cards: the same rounded frame as the prompt, with the left rail and the title in the tone of the notice and the rest of the frame in the theme's border color.
|
|
669
|
+
|
|
670
|
+
```text
|
|
671
|
+
╭─ ✿ Gentle AI · review preflight ─────────────────────────────────────╮
|
|
672
|
+
│ Receipt-driven development is enabled, and this worktree holds an… │
|
|
673
|
+
╰──────────────────────────────────────────────────────────────────────╯
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
- Every call into the gentle-ai binary and every `gentle_review` tool renders as a card under the rose, `🌹︎ Gentle AI`: the rail is amber while it runs, green when it finished, red when it failed; the expand key sits in the top rule once the tool finished, and the collapsed result shows only its line count. Reviewer captures name their lens (`review capture · risk`; the group lists all four).
|
|
677
|
+
- The review preflight reminder renders as a card in the transcript with the expand key in its top rule.
|
|
678
|
+
- An active dev-binary override shows above the editor at startup, in amber, naming the binary and its digest, and leaves with the first prompt; an invalid override shows in red with the reason.
|
|
679
|
+
- Subagents draw their own card; see Gentle Agents below.
|
|
680
|
+
|
|
681
|
+
### Gentle Agents
|
|
682
|
+
|
|
683
|
+
The current package requires Pi 0.85.1 or newer (development tests pin 0.85.1). Use the latest Pi release; gentle-pi does not update your installed Pi automatically. Children, including any `GENTLE_PI_AGENTS_PI` override, must emit `agent_settled`: `agent_end` records a run's output but is not completion because retries or queued continuations may follow.
|
|
684
|
+
|
|
685
|
+
The `subagent_*` tools and the agents card replace the third-party subagents package (remove `npm:pi-subagents-j0k3r` from your pi packages; while it is still installed the tools stay unregistered and a warning says so at startup). Agent definitions and settings are the ones you already have: markdown agents in `~/.pi/agent/agents/`, `~/.pi/agent/subagents/`, `<cwd>/.pi/agents/`, `<cwd>/.pi/subagents/` (project beats global, `subagents/` beats `agents/`), and `subagents.json` at the global and project level (`default_model`, `default_effort`, `default_mode`, `model_profiles`, `stall_timeout_ms`, `max_concurrency`, `history_max_tasks`).
|
|
686
|
+
|
|
687
|
+
Agent paths follow `GENTLE_PI_AGENT_HOME`, then `PI_CODING_AGENT_DIR`, then `~/.pi/agent` for definitions, config, history, child sessions, and transcripts. These overrides select the agent profile; they do not sandbox project or shared global resources.
|
|
688
|
+
|
|
689
|
+
```text
|
|
690
|
+
╭─ ❀ Agents · 1 active · 1 done ─────────────────────────────── 1m24s ╮
|
|
691
|
+
│ ✓ sdd-explore map footer data sources gpt-5.6-terra · 34k · $0.27 · 25s │
|
|
692
|
+
│ ◐ sdd-apply write gentle-shell footer gpt-5.6-terra · 12k · $0.09 · 41s │
|
|
693
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
Every subagent is its own `pi --mode rpc` child process, so the terminal never runs subagent work: the host reads JSON lines, applies each one as a small delta to a bounded per-task thread, and notifies only the listeners of that task. A task-mode child's question (`ctx.ui.select`, `confirm`, `input`, `editor`) reaches you as an ordinary pi dialog; a background child's question is dismissed. Subagents have no automatic total execution timeout: a long-running child remains live while it continues emitting RPC events. A silent child still times out through the configurable `stall_timeout_ms` watchdog (default four minutes). Closing pi stops the children that are still running.
|
|
697
|
+
|
|
698
|
+
- `subagent_list_agents`, `subagent_run` (`agent`, `task`, `label?`, `context?`, `mode?` task or background), `subagent_status`, `subagent_result`, `subagent_list_tasks`, `subagent_cancel`, `subagent_send_message` (steer a running child), `subagent_continue` (resume a finished task in its own session).
|
|
699
|
+
- A background task's result comes back to the model as a `gentle-agents.result` message, drawn as a rose card, and starts a new turn when the agent is idle; the model never polls.
|
|
700
|
+
- The card shows the active session's tasks only: after `/new` or `/resume` the earlier session's tasks leave it and come back with their session. Finished rows stay for one minute (three at most), and the card spends at most a quarter of the terminal (three to eight rows) on tasks; beyond that the rest fold into one `… N more · alt+a to view` line so the editor never leaves the screen. Questions and running work keep their rows first.
|
|
701
|
+
- `/gentle:agents` or `alt+a` opens the overlay: tasks on the left, the selected task's thread on the right. The thread shows every event the child streamed, in full: text, thinking, and each tool call with its whole output (the store keeps the last 16 KB per call and marks a cut with a leading `…`). It opens on this session (active tasks plus those finished in the last fifteen minutes); `a` widens the list to every task of every session, including the stored history, and back. The list scrolls with the selection. In fullscreen mode, hovering only highlights a task row; clicking selects it without opening its session or cancelling it; and the wheel scrolls the list or thread under the pointer independently. When the footer key hints fit, its `Follow` button returns the selected thread to its tail and `Open session` opens a markdown transcript in `$EDITOR` for a task with a session file; it does not resume the child session. `j`/`k` move, `ctrl+j`/`ctrl+k` or `pgdn`/`pgup` scroll the thread (`f` follows the tail again), `s` stops the selected task (`c` is a legacy alias), and `o` opens the same transcript (written under `~/.pi/agent/gentle-agents/transcripts/`). `esc` or `q` only closes the overlay. Only the selected task is subscribed while it is open.
|
|
702
|
+
- `alt+s` confirms stopping the current active or queued subagents owned by the current process. `GENTLE_PI_AGENTS_STOP_KEY` rebinds it; `off` disables it.
|
|
703
|
+
- Finished tasks are written to `~/.pi/agent/gentle-agents/tasks/` (one JSON per task, newest `history_max_tasks` kept, default 200) and come back on demand for `subagent_result`, `subagent_continue`, and the overlay. Child sessions live under `~/.pi/agent/gentle-agents/sessions/`.
|
|
704
|
+
- `ctrl+shift+a` collapses the card to its first row (`GENTLE_PI_AGENTS_KEY`), `GENTLE_PI_AGENTS_VIEW_KEY` rebinds the overlay, `GENTLE_PI_AGENTS_PI` overrides the pi command used for children, and `GENTLE_PI_AGENTS=0` disables the tools and the card.
|
|
705
|
+
|
|
706
|
+
### Gentle Todo
|
|
707
|
+
|
|
708
|
+
The `todo` tool and its card replace the third-party todo extension (remove `npm:@juicesharp/rpiv-todo` from your pi packages; sessions written by it replay into the new card).
|
|
709
|
+
|
|
710
|
+
```text
|
|
711
|
+
╭─ ❀ Todos · 1 of 3 ──────────────────────────────────────╮
|
|
712
|
+
│ ✓ Add quiet tool rendering │
|
|
713
|
+
│ ◐ Fix quiet tools conflict · fixing conflict │
|
|
714
|
+
│ ○ Show git bash tails │
|
|
715
|
+
╰─────────────────────────────────────────────────────────╯
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
Three things keep the list current, which a static tool description cannot:
|
|
719
|
+
|
|
720
|
+
- `write` replaces the whole list in one call, so the model rewrites the plan instead of patching it; `add`, `update`, `clear`, and `list` remain for single moves.
|
|
721
|
+
- Every turn's system prompt carries the open tasks and the rules: in_progress before starting, done right after finishing, update before ending the turn.
|
|
722
|
+
- A list that goes two turns untouched while tasks stay open turns amber with `stale · N turns`, and the prompt says so, so the model brings it up to date.
|
|
723
|
+
|
|
724
|
+
A finished list stays on screen for the turn it finished in and clears at the next. `ctrl+shift+t` collapses the card to the task in progress (`GENTLE_PI_TODO_KEY` rebinds it, `off` disables it); `GENTLE_PI_TODO=0` disables the tool and the card.
|
|
725
|
+
|
|
726
|
+
Set `GENTLE_PI_SHELL=0` to keep pi's built-in footer and editor.
|
|
727
|
+
|
|
587
728
|
## Commands
|
|
588
729
|
|
|
589
730
|
| Command | What it does |
|
|
@@ -593,6 +734,7 @@ Legacy string entries are still accepted and treated as `model`-only config.
|
|
|
593
734
|
| `/gentle:models` | Opens global model + effort assignment UI. Press `x` to export and `r` to restore saved routing. |
|
|
594
735
|
| `/gentle:persona` | Switches global persona mode, with project override support. |
|
|
595
736
|
| `/gentle:background-subagents` | Shows or sets the managed background-subagents policy (`status\|enable\|disable`), naming the source that decided it. |
|
|
737
|
+
| `/gentle:telemetry` | Shows or changes the local Gentle AI telemetry trigger (`status\|enable\|disable\|preview`). |
|
|
596
738
|
| `/gentle:banner` | Configures startup banner rose, text logo, and color preset. |
|
|
597
739
|
| `/gentle:toggle-rose` | Toggles the startup rose. |
|
|
598
740
|
| `/gentle:toggle-text-logo` | Toggles the startup text logo. |
|
|
@@ -626,7 +768,7 @@ Four sources can decide the policy, and the first hit wins:
|
|
|
626
768
|
|
|
627
769
|
Both files use the strict shape `{"schema":"gentle-pi.background-subagents/v1","policy":"on"}`. A file that is present but malformed fails closed to `off` and is **not** skipped in favor of a lower-priority source, so a typo in the project file disables background subagents rather than silently handing the decision to the global file. The command reports that case as a warning instead of an ordinary `off`.
|
|
628
770
|
|
|
629
|
-
Because the project file outranks the global one, `enable` still writes the global file but reports plainly when a project file keeps the effective policy unchanged. The resolved capability (`ready` or `absent`) reports whether `subagent_run` is actually callable in this session; a policy of `on` with capability `absent` means the subagents package is
|
|
771
|
+
Because the project file outranks the global one, `enable` still writes the global file but reports plainly when a project file keeps the effective policy unchanged. The resolved capability (`ready` or `absent`) reports whether `subagent_run` is actually callable in this session; a policy of `on` with capability `absent` means Gentle Agents is disabled or the retired subagents package is still installed.
|
|
630
772
|
|
|
631
773
|
Startup banner settings are global and default to the current pink rose + text logo. Supported color presets are `pink`, `cyan`, `yellow`, and `green`.
|
|
632
774
|
|
|
@@ -670,6 +812,22 @@ Memory contract for SDD delegation:
|
|
|
670
812
|
- subagents should save significant discoveries, decisions, bug fixes, and completed SDD phase artifacts before returning when memory tools are available;
|
|
671
813
|
- in memory/hybrid mode, SDD artifacts use stable topic keys such as `sdd/<change>/proposal`, `sdd/<change>/spec`, `sdd/<change>/design`, `sdd/<change>/tasks`, `sdd/<change>/apply-progress`, and `sdd/<change>/verify-report`.
|
|
672
814
|
|
|
815
|
+
## Telemetry
|
|
816
|
+
|
|
817
|
+
`gentle-pi` does not collect anything itself. [gentle-ai](https://github.com/Gentleman-Programming/gentle-ai) owns anonymous usage telemetry end to end — install and heartbeat events, what fields are sent, rate limiting, and every opt-out. See its README/docs for the exact contract.
|
|
818
|
+
|
|
819
|
+
At session start, for a primary session only (never for a named or SDD sub-agent), Gentle Pi asks the local `gentle-ai` binary to send its own telemetry: it spawns `gentle-ai telemetry trigger --json` detached, with a 3 s deadline, discards its output, and never blocks session start or surfaces an error — an older binary without the verb is silently treated as nothing to do. This runs at most once per process.
|
|
820
|
+
|
|
821
|
+
Install counts for `gentle-pi` and `gentle-engram` come from npm download statistics; the package itself never emits an install event.
|
|
822
|
+
|
|
823
|
+
To opt out:
|
|
824
|
+
|
|
825
|
+
- `/gentle:telemetry disable` — asks the local `gentle-ai` binary to disable telemetry (also `status` and `preview` to inspect it without leaving Pi).
|
|
826
|
+
- `DO_NOT_TRACK=1` — Gentle Pi itself will not spawn the trigger, and `gentle-ai` also honors this standard on its own.
|
|
827
|
+
- `GENTLE_AI_TELEMETRY=0` — same effect, `gentle-ai`'s own environment switch.
|
|
828
|
+
|
|
829
|
+
`CI=true` also suppresses the trigger, since automated runs are not a real usage signal.
|
|
830
|
+
|
|
673
831
|
## Package contents
|
|
674
832
|
|
|
675
833
|
| Path | Purpose |
|
|
@@ -63,6 +63,15 @@ RED/GREEN evidence is required only when the parent explicitly activates strict
|
|
|
63
63
|
|
|
64
64
|
Run focused tests first. Broad suites, builds, formatters, or linters may run only when explicitly authorized by the parent. Keep every command exact and verify its scope before execution. Do not claim completion while required validation is failing.
|
|
65
65
|
|
|
66
|
+
## Verification
|
|
67
|
+
|
|
68
|
+
When the parent task carries a `## Verification` heading, that heading is the delegated verification contract for this task (gentle-pi#661, RDD-aware pilot):
|
|
69
|
+
|
|
70
|
+
- Run every command listed under it exactly as written, one at a time, in the foreground. Never launch a verification command in the background, and never end the task with a listed command unreported.
|
|
71
|
+
- Report each one as `<exact command>: <observed result>` in `validation`.
|
|
72
|
+
- `## Known environmental failures` in the parent task (this is the canonical definition; other assets reference it, they do not restate it) lists exact test names or exact command lines that already fail on the base, before this task's changes. Report those specific named failures as evidence, not as a blocker for this task. Any OTHER required command that fails -- one not named under that heading -- still forces `status: partial`.
|
|
73
|
+
- When receipt-driven development is on, this report is the verification of record for the change, and the native review remains the independent check the writer cannot influence: never report `status: completed` while a required command under `## Verification` is failing, unless that exact failure is named under `## Known environmental failures`.
|
|
74
|
+
|
|
66
75
|
## Interaction contract
|
|
67
76
|
|
|
68
77
|
When any human input is required, stop editing and return the full schema in the Return contract with `status: interaction_required` and the nested `interaction_required` payload completed. Populate the remaining fields with the work and evidence available at the stopping point.
|
|
@@ -7,7 +7,7 @@ Bind this to the parent Pi session only, on delegation or routing triggers. Not
|
|
|
7
7
|
When a sub-agent or tool returns a user-facing blocking prompt or menu, preserve its complete user-facing choice envelope: why input is required; every group and question in original order, including every group header; every option label and description; the selection mode; and the exact allowed-answer domain. Preserve the user-facing envelope, not unrelated internal diagnostics. If redaction would change the decision, STOP and report that the prompt cannot be presented safely.
|
|
8
8
|
|
|
9
9
|
- Never summarize, abbreviate, reorder, relabel, merge, or omit choices. Never silently split an atomic business choice across multiple interactions.
|
|
10
|
-
- Native route: For every strictly closed single-select envelope, use `ask_user_choice` only when it is available in the current interactive TUI and the complete envelope is exactly representable as one question with 2-4 ordered options. Pass each option's user-facing label and description plus its envelope-owned canonical option token as opaque `value`. The native selector exposes no custom/free-text or multi-select path and returns exactly one `value`; map it to the envelope-owned choice once, then select any envelope-owned continuation or invocation once where present. Do not re-parse its label or ordinal. `ask_user_question` is the externally owned open/free-text questionnaire: use it only for an open/free-text envelope it can represent, never for a closed domain. Otherwise fall through to the Fallback clause below. For `gentle-ai.review-integration.consent/v3`, the selected continuation remains the exact captured provider-owned choice invocation; never synthesize it.
|
|
10
|
+
- Native route: For every strictly closed single-select envelope, use `ask_user_choice` only when it is available in the current interactive TUI and the complete envelope is exactly representable as one question with 2-4 ordered options. Pass each option's user-facing label and description plus its envelope-owned canonical option token as opaque `value`. The native selector exposes no custom/free-text or multi-select path and returns exactly one `value`; map it to the envelope-owned choice once, then select any envelope-owned continuation or invocation once where present. Do not re-parse its label or ordinal. `ask_user_question` is the externally owned open/free-text questionnaire: use it only for an open/free-text envelope it can represent, never for a closed domain. Otherwise fall through to the Fallback clause below. For an unresolved `gentle-ai.review-integration.consent/v3`, the selected continuation remains the exact captured provider-owned choice invocation; never synthesize it. The eligible Pi runtime may instead consume that envelope before it reaches the model through a three-action UI whose first two actions are the unchanged provider choices and whose third action is host-owned session permission. Never append that host action to the decoded or relayed provider envelope. If the runtime returns the envelope unresolved, the original two-choice fallback above applies unchanged.
|
|
11
11
|
- Fallback: If a native UI is unavailable, denied, the runtime is noninteractive, or the complete envelope is oversized or otherwise unrepresentable because of question-count, option-count, or text-length limits, emit the COMPLETE choice envelope as a plain chat or terminal response. Include the required answer syntax and why the input blocks progress. Then STOP. Do not choose, default, infer, launch dependent work, or continue. Native-tool-only wording elsewhere never disables this fallback.
|
|
12
12
|
- Answer validation: Accept an answer only when each response belongs to the exact allowed-answer domain presented for its group. Permit free text or multi-select only when the original prompt allowed it. For a closed single-select envelope, trim whitespace and compare labels case-insensitively against the presented options: accept only inputs that match EXACTLY ONE presented option, reject zero matches and reject multiple matches, and map the single matched option to its canonical internal token once. Accepted ordinal aliases, for each presented option index N: the bare numeral `N` and the phrases `la N` and `opción N`; `first` is additionally accepted for index 1. Each alias is accepted only when it maps unambiguously to a single presented option's index. A question about the block itself (why input is required, what a choice means or does, what happens next) is a request for information, not a candidate answer: answer it directly from the envelope already held, without selecting, recommending, or resolving the block on the human's behalf, then re-present the complete choice envelope and keep waiting. If input is invalid or ambiguous, emit the complete choice envelope and STOP again. Return a valid answer to the same blocked actor exactly once.
|
|
13
13
|
|
|
@@ -112,7 +112,16 @@ The bounded multi-file writer precedence in rule 3 overrides that general runtim
|
|
|
112
112
|
2. **Multi-file write rule**: for bounded multi-file writes, prefer the installed package-owned `gentle-ai-worker`, then a user-configured `worker`. If neither worker definition exists, fall back to the native `Agent` even when `subagent_*` tools are available. If no delegation mechanism is available, stop and explain the blocker.
|
|
113
113
|
3. **Incident rule**: after wrong `cwd`, accidental repository/worktree mutation, failed merge recovery, confusing test command, or environment workaround, stop and diagnose the incident separately before resuming.
|
|
114
114
|
4. **Long-session rule**: if accumulating work is no longer clearly local — roughly 20 tool calls, 5 exploratory file reads, or 2 non-mechanical edits without delegation — pause and delegate the remaining work instead of silently continuing monolithically.
|
|
115
|
-
5. **Verification rule
|
|
115
|
+
5. **Verification rule** (gentle-pi#661/#662, RDD-aware; normative -- referenced, not restated, elsewhere in this file): read the rendered `Receipt-driven development:` line next to `Background subagent policy`. The bounded writer always runs the exact parent-authorized commands under the delegated task's `## Verification` heading, synchronously and in the foreground, and reports each as `<command>: <observed result>` -- see `gentle-ai-worker`'s Verification contract for the exact rules, including how `## Known environmental failures` (exact pre-existing base failures) differs from any other failing required command, which still forces `status: partial`. When the line reads `on`, that writer report is the verification of record, and the native review is the independent check the writer cannot influence: `gentle-ai-verify` (or the native `Agent` fallback, with the same read-only verification task and exact parent-authorized commands) becomes on-demand -- reach for it only when the writer reports `partial`/`blocked`, the check is expensive or external (E2E runs, installs) and the parent wants a cheaper profile, or the parent wants an independent spot check. That `on` branch holds only while the native review actually reaches a terminal outcome for this candidate (gentle-pi#668): a human decline of the consent envelope for this candidate (candidate-scoped, never the RDD kill switch), a clone-local RDD disable discovered mid-flow, or a refused START/STATUS all fall back to the risk-gated path exactly as `off` -- call `gentle_review` with `{"operation":"assess"}` (pass `nativeReviewOutcome` when the parent already knows it; the tool derives it from what it itself observed for the candidate otherwise, failing closed to `unknown` when it cannot) and follow the returned plan. When the line reads `off` or `unknown`, after the writer returns, call `gentle_review` with `{"operation":"assess"}` over the writer's diff and follow the returned plan instead of judging non-triviality from the task description: the operation resolves the native risk tier and states exactly who verifies next. The tier table (stated once, here):
|
|
116
|
+
|
|
117
|
+
| Native risk tier | Verification when RDD is `off`/`unknown` |
|
|
118
|
+
|---|---|
|
|
119
|
+
| passive | structural readback by the parent; no separate verifier, no tests |
|
|
120
|
+
| medium | writer self-verification stands; a separate `gentle-ai-verify` run is added only when the writer profile is a small model (mini or low effort) |
|
|
121
|
+
| high | writer self-verification plus a separate `gentle-ai-verify` run, always |
|
|
122
|
+
| unknown / assess failed | treated as high |
|
|
123
|
+
|
|
124
|
+
The small-model bias raises the tier by one for verification purposes (medium becomes high); an unknown `Receipt-driven development:` line never lowers a tier below `off`. The parent spot check (re-running one reported command before delivery) stays required in every tier. Only truly local read-only checking of 1–3 known files stays inline.
|
|
116
125
|
|
|
117
126
|
### Work Routing Ladder
|
|
118
127
|
|
|
@@ -137,19 +146,20 @@ Background execution is policy-gated: the always-on orchestrator prompt renders
|
|
|
137
146
|
|
|
138
147
|
When the policy is on and `subagent_run` is available:
|
|
139
148
|
|
|
140
|
-
-
|
|
141
|
-
-
|
|
142
|
-
-
|
|
143
|
-
-
|
|
144
|
-
-
|
|
145
|
-
-
|
|
149
|
+
- Default to `subagent_run` `mode: "background"`. It returns a task id at once; the terminal stays free and the human keeps typing. Pass a `label` of three to six words naming the work.
|
|
150
|
+
- A child `agent_end` retains its latest answer but is not completion: Pi may still retry, compact, or run a queued follow-up. Treat the task as finished only at `agent_settled`; only then release its queue slot, publish its background result, or terminate it. If it exits first, report failure with its retained answer as diagnostics.
|
|
151
|
+
- When a background task settles, its result arrives as a message in this session (custom type `gentle-agents.result`, one per task) and starts a new turn if you are idle. Wait for it: end the turn once launches and any non-overlapping work are done. Never poll, sleep, or call `subagent_status`/`subagent_result` for completion.
|
|
152
|
+
- Do not claim an implementation ready or RDD-ready while its required verification or correction follow-up remains queued. Run the required focused verification before that claim, and retain legitimate post-correction verification. This does not invent a universal full-suite requirement or make a receipt a delivery gate.
|
|
153
|
+
- Use `mode: "task"` only when the subagent must ask the human something mid-flight (task-mode dialogs reach the human; background dialogs are dismissed) or when the human asked to wait.
|
|
154
|
+
- Launch as many independent tasks as the work has; the runner queues beyond `max_concurrency`. Do not duplicate launches or work, and do not overlap files or topics. Never run parallel writers in one worktree.
|
|
155
|
+
- Finished tasks persist across restarts; running ones are stopped when pi exits and must be relaunched, never claimed as recovered.
|
|
146
156
|
<!-- /gentle-pi:background-subagents -->
|
|
147
157
|
|
|
148
158
|
For generic non-SDD exploration and mapping, first attempt the installed package-owned `gentle-ai-explore`. If that individual role is missing or unusable, fall back to Pi's native `Agent` with the same read-only mapping constraints and report the fallback.
|
|
149
159
|
|
|
150
160
|
For bounded multi-file writes, prefer the installed package-owned `gentle-ai-worker`, then a user-configured `worker`. If neither worker definition exists, fall back to the native `Agent` even when `subagent_*` tools are available. If no delegation mechanism is available, stop and explain the blocker. This writer precedence overrides the general runtime preference above.
|
|
151
161
|
|
|
152
|
-
|
|
162
|
+
Delegate generic non-SDD verification that executes or delegates commands per the RDD-aware Verification rule (trigger 5 under Mandatory Delegation Triggers, gentle-pi#661) -- the normative on/off/unknown routing lives there, not here: the bounded writer always self-verifies via `## Verification`, and `gentle-ai-verify` (or the native `Agent` fallback, with the same read-only verification constraints, exact parent-authorized commands, and fallback reporting) is on-demand only when the rendered `Receipt-driven development:` line reads `on`; when the line reads `off` or `unknown`, the `gentle_review` `assess` operation's returned plan decides it by native risk tier instead of a blanket non-trivial rule (gentle-pi#662). `## Known environmental failures` follows the same definition as `gentle-ai-worker`'s Verification contract: exact pre-existing base failures reported as evidence, never blockers -- any other failing required command still forces `status: partial`. Truly local read-only checking of 1–3 known files may remain inline. Separate exploration stays reserved for when the parent needs the map to decide or route; reading that prepares a write belongs with the writer making the change, consistent with the Delegation Rules table above.
|
|
153
163
|
|
|
154
164
|
Use `sdd-explore` and `sdd-verify` only inside SDD.
|
|
155
165
|
|
package/assets/orchestrator.md
CHANGED
|
@@ -41,7 +41,7 @@ Route work through the smallest harness that is safe. Three tiers:
|
|
|
41
41
|
|
|
42
42
|
1. **Inline Direct** — small, mechanical, parent has context (typo, one-file edit, read-only check of 1-3 known files, bash for state). No SDD ceremony; stop when it is no longer small.
|
|
43
43
|
2. **Simple Delegation** — generic non-SDD exploration → `gentle-ai-explore`; bounded implementation → `gentle-ai-worker`; command-running generic non-SDD verification → `gentle-ai-verify`. Try its package role; if missing/unusable, use native `Agent` under the same read-only mapping/verification constraints and report fallback. SDD roles stay inside SDD.
|
|
44
|
-
3. **SDD (optional)** — selected only by an explicit request (`/gentle-sdd-new`/`/gentle-sdd-ff`/`/gentle-sdd-continue` or a direct ask) or an accepted proposal; size, file count, or risk alone never selects
|
|
44
|
+
3. **SDD (optional)** — selected only by an explicit request (`/gentle-sdd-new`/`/gentle-sdd-ff`/`/gentle-sdd-continue` or a direct ask) or an accepted proposal; size, file count, or risk alone never selects it. Suggest it when proposal/spec/design/tasks would meaningfully reduce ambiguity. Once selected, create artifacts and gate for approval before implementing.
|
|
45
45
|
|
|
46
46
|
## Delegation Rules
|
|
47
47
|
|
|
@@ -49,7 +49,7 @@ Core question: does this inflate parent context without need?
|
|
|
49
49
|
|
|
50
50
|
Before launching bounded writer (`gentle-ai-worker` or `worker`), task/context needs nonempty `## Allowed edit surfaces`: narrow repository-relative paths/globs; never `.`, bare repo root, or absolute. Parent derives surfaces, maps unknown targets read-only, shows derived candidates only for genuine scope choices. Do not ask the human to author paths or globs.
|
|
51
51
|
|
|
52
|
-
Mandatory Delegation Triggers —
|
|
52
|
+
Mandatory Delegation Triggers — once fired, delegate through the best available runtime (prefer `subagent_run`, else native `Agent`):
|
|
53
53
|
|
|
54
54
|
1. **4-file rule** — 4+ files to understand → delegate a scout/mapping task.
|
|
55
55
|
2. **Multi-file write rule** — 2+ non-trivial files touched → delegate one writer.
|
|
@@ -59,7 +59,7 @@ Mandatory Delegation Triggers — stop rules; once fired, delegate through the b
|
|
|
59
59
|
|
|
60
60
|
{{GENTLE_PI_BACKGROUND_POLICY}}; rules: the background-subagents block in the delegation contract.
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
Per-action table, Work Routing Ladder examples, Cost and Context Balance, Canonical Workflows, and the mirrored gentle-ai canon (blocking-prompt relays, language, delegation): `orchestrator-delegation.md`.
|
|
63
63
|
|
|
64
64
|
## SDD Workflow (lazy-loaded)
|
|
65
65
|
|
|
@@ -73,7 +73,7 @@ Hard preflight invariant: `openspec/config.yaml`, existing SDD changes, installe
|
|
|
73
73
|
|
|
74
74
|
## Memory Contract
|
|
75
75
|
|
|
76
|
-
When memory is available, the parent selects context and subagents save discoveries before returning. Phase table
|
|
76
|
+
When memory is available, the parent selects context and subagents save discoveries before returning. Phase table and artifact keys: `orchestrator-memory.md`.
|
|
77
77
|
|
|
78
78
|
## Skill Registry Protocol
|
|
79
79
|
|
|
@@ -89,7 +89,7 @@ This package injects the mirrored provider-bundle review execution contract into
|
|
|
89
89
|
|
|
90
90
|
## Safety
|
|
91
91
|
|
|
92
|
-
-
|
|
92
|
+
- An eligible interactive Pi host may resolve `gentle-ai.review-integration.consent/v3` before the envelope reaches the model. Permission: host-owned. If `gentle_review` returns the envelope unresolved, it is still the original provider-owned two-choice contract. Use `ask_user_choice` exactly or relay losslessly and stop. Never add the host action to a decoded or relayed provider envelope.
|
|
93
93
|
- Never commit unless the user explicitly asks.
|
|
94
94
|
- Ask before destructive git operations, publishing, or irreversible file changes.
|
|
95
95
|
- Keep writes single-threaded unless isolated worktrees are explicitly approved.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Delegated verification
|
|
2
|
+
|
|
3
|
+
How the Gentle Pi orchestrator decides who verifies a bounded writer's work. The always-on parent prompt renders a `Receipt-driven development: on|off|unknown` line; the delegation overlay (`assets/orchestrator-delegation.md`, trigger 5) keys the verification rule on it. This page is package-owned; `docs/review-integration.md` mirrors the Gentle AI contract and must stay byte-identical to it.
|
|
4
|
+
|
|
5
|
+
## Receipt-driven development on
|
|
6
|
+
|
|
7
|
+
The bounded writer runs the exact commands the parent lists under `## Verification`, in the foreground, and reports each as `<command>: <observed result>`. That report is the verification of record and the native review is the independent check. `gentle-ai-verify` is on-demand: a `partial` or `blocked` writer, an expensive or external check the parent wants on a cheaper profile, or a parent spot check.
|
|
8
|
+
|
|
9
|
+
This `on` path holds only while the native review actually reaches a terminal outcome for the current candidate (gentle-pi#668). A human decline of the consent envelope for this candidate (candidate-scoped, never the RDD kill switch), a clone-local RDD disable discovered mid-flow, or a refused START/STATUS all mean the review never ran, so the parent falls back to the exact risk-gated path below, as if RDD were `off` -- declining a review never lowers the bar below the RDD-off path. `gentle_review`'s `assess` operation accepts an optional `nativeReviewOutcome` (`closed`, `declined`, `unavailable`, or `unknown`) so the caller can state this directly. `closed` is never auto-derived: only a caller that itself just acknowledged the approved review for this exact candidate may pass it, right after that acknowledgement. When `nativeReviewOutcome` is omitted, `assess` only ever tries to auto-derive `declined`/`unavailable`, and only for the exact candidate the event was bound to -- keyed by that candidate's own target identity, never by repository alone, so one candidate's recorded outcome can never leak into a different candidate's `assess` call in the same clone. A missing or mismatched identity fails closed to `unknown`, verified exactly like `off`. The result's `outcome_source` (`explicit`, `derived`, or `unknown`) states which of these produced the value, so a stale or missing derivation is visible rather than silently indistinguishable from a real `unknown`.
|
|
10
|
+
|
|
11
|
+
## Receipt-driven development off or unknown (gentle-pi#662)
|
|
12
|
+
|
|
13
|
+
The host exposes one read-only native operation: `gentle-ai review assess --cwd <repo> [--base-ref <ref> --committed-only] --json` (gentle-ai#4295). It is decoded by `lib/review-risk-assessment.ts` and wired through `lib/native-review-cli.ts` exactly like the existing `reviewMode` STATUS reader -- a bounded subprocess with a typed decode, never a mutation. A non-zero exit, a failure envelope, or an older binary without the verb all fail closed to `high` risk.
|
|
14
|
+
|
|
15
|
+
The `gentle_review` tool's `assess` operation (`extensions/gentle-ai.ts`) combines that assessment with the rendered `Receipt-driven development:` line to decide whether a delegated writer's change needs a separate `gentle-ai-verify` run, following this tier table:
|
|
16
|
+
|
|
17
|
+
| Native risk tier | Verification when RDD is `off`/`unknown` |
|
|
18
|
+
| --- | --- |
|
|
19
|
+
| passive | structural readback by the parent; no separate verifier, no tests |
|
|
20
|
+
| medium | writer self-verification stands; a separate `gentle-ai-verify` run is added only when the writer profile is a small model (mini or low effort) |
|
|
21
|
+
| high | writer self-verification plus a separate `gentle-ai-verify` run, always |
|
|
22
|
+
| unknown / assess failed | treated as high |
|
|
23
|
+
|
|
24
|
+
When RDD is `on` and the native review closed for this candidate, the writer's own self-verification is the record and the closed native review is the independent check, except a passive-risk change, which still gets a structural readback instead; any other `nativeReviewOutcome` under `on` follows this same tier table instead (gentle-pi#668). The small-model bias raises the medium tier to high for verification purposes only; an unknown RDD line never lowers a tier below `off`. The parent's own spot check (re-running one reported command before delivery) stays required in every tier.
|
|
25
|
+
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Telemetry
|
|
2
|
+
|
|
3
|
+
`gentle-pi` does not collect anything itself. [`gentle-ai`](https://github.com/Gentleman-Programming/gentle-ai) (issue [#4309](https://github.com/Gentleman-Programming/gentle-ai/issues/4309)) owns anonymous usage telemetry end to end: install and heartbeat events, the exact fields sent, rate limiting, and every opt-out. See gentle-ai's own README/docs for that contract. Gentle Pi's only involvement is a best-effort nudge that asks the local binary to act.
|
|
4
|
+
|
|
5
|
+
## What Gentle Pi does
|
|
6
|
+
|
|
7
|
+
On activation of a primary session (never for a named agent or an SDD phase executor), Gentle Pi resolves the package-local `gentle-ai` binary (honoring a registered dev-binary override, same as every other native call) and spawns:
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
gentle-ai telemetry trigger --json
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
- detached, with stdout/stderr discarded (`stdio: "ignore"`);
|
|
14
|
+
- a 3 s deadline: a runaway process is killed, but Gentle Pi never waits for it to exit;
|
|
15
|
+
- at most once per process, regardless of how many sessions or sub-agents run afterward.
|
|
16
|
+
|
|
17
|
+
Rate limiting, enrollment, and every opt-out live entirely in `gentle-ai`; calling the trigger once per session start is safe by construction. A missing binary, an older binary without the `telemetry` verb (which prints `unknown telemetry command` and exits non-zero), or a spawn failure are all treated as "nothing to do" and never affect activation or surface an error to the user.
|
|
18
|
+
|
|
19
|
+
Install counts for `gentle-pi` and `gentle-engram` come from npm download statistics; neither package emits an install event of its own.
|
|
20
|
+
|
|
21
|
+
## The trigger contract
|
|
22
|
+
|
|
23
|
+
`gentle-ai telemetry trigger --json` always exits `0` and prints one line of JSON:
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{"schema":"gentle-ai.telemetry-trigger/v1","decision":"enrolled|sent_install|sent_heartbeat|rate_limited|backoff|disabled","source":"<deciding source>"}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`gentle-ai telemetry status|enable|disable|preview [--json]` exist for the opt-out flow; `status --json` prints `gentle-ai.telemetry-status/v1`. Gentle Pi's `/gentle:telemetry` slash command runs these in the foreground (bounded to 5 s) through the same binary resolver and relays the result.
|
|
30
|
+
|
|
31
|
+
## Opting out
|
|
32
|
+
|
|
33
|
+
Any of the following disables the nudge or the underlying telemetry:
|
|
34
|
+
|
|
35
|
+
- `/gentle:telemetry disable` — asks the local `gentle-ai` binary to disable telemetry. `/gentle:telemetry status` and `/gentle:telemetry preview` inspect it without leaving Pi.
|
|
36
|
+
- `DO_NOT_TRACK=1` — Gentle Pi does not spawn the trigger at all; `gentle-ai` also honors this standard independently.
|
|
37
|
+
- `GENTLE_AI_TELEMETRY=0` — same effect, `gentle-ai`'s own environment switch.
|
|
38
|
+
- `CI=true` — Gentle Pi does not spawn the trigger in automated/CI runs, since they are not a real usage signal.
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { DynamicBorder } from "@earendil-works/pi-coding-agent";
|
|
3
|
-
import {
|
|
3
|
+
import { Text } from "@earendil-works/pi-tui";
|
|
4
4
|
import { type Static, Type } from "typebox";
|
|
5
|
+
import { NativeChoiceList } from "../lib/native-choice-list.ts";
|
|
6
|
+
import { createNativeFullscreenInteraction } from "../lib/native-fullscreen-interaction.ts";
|
|
5
7
|
|
|
6
8
|
const CHOICE_TOOL_NAME = "ask_user_choice";
|
|
7
9
|
const ASK_USER_CHOICE_BLOCKED_EVENT = "gentle-pi:ask-user-choice:blocked";
|
|
@@ -72,41 +74,45 @@ export default function askUserChoice(pi: ExtensionAPI): void {
|
|
|
72
74
|
throw new Error("ask_user_choice is unavailable outside the interactive TUI");
|
|
73
75
|
}
|
|
74
76
|
|
|
75
|
-
const items
|
|
76
|
-
|
|
77
|
+
const items = params.options.map((option, index) => ({
|
|
78
|
+
id: `choice-${index}`,
|
|
77
79
|
label: option.label,
|
|
78
80
|
description: option.description,
|
|
79
81
|
}));
|
|
80
82
|
let selection: ChoiceSelection | undefined;
|
|
81
83
|
try {
|
|
82
84
|
pi.events.emit(ASK_USER_CHOICE_BLOCKED_EVENT, { active: true });
|
|
83
|
-
selection = await ctx.ui.custom<ChoiceSelection | undefined>((tui, theme,
|
|
84
|
-
const
|
|
85
|
-
container.addChild(new DynamicBorder((text: string) => theme.fg("accent", text)));
|
|
86
|
-
container.addChild(new Text(theme.fg("accent", theme.bold(params.question)), 1, 0));
|
|
87
|
-
const list = new SelectList(items, items.length, {
|
|
85
|
+
selection = await ctx.ui.custom<ChoiceSelection | undefined>((tui, theme, keybindings, done) => {
|
|
86
|
+
const list = new NativeChoiceList(items, {
|
|
88
87
|
selectedPrefix: (text) => theme.fg("accent", text),
|
|
89
88
|
selectedText: (text) => theme.fg("accent", text),
|
|
90
89
|
description: (text) => theme.fg("muted", text),
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
hoverBackground: (text) => theme.bg("toolPendingBg", text),
|
|
91
|
+
}, keybindings);
|
|
92
|
+
const container = createNativeFullscreenInteraction({
|
|
93
|
+
keyboardTarget: list,
|
|
94
|
+
requestRender: () => tui.requestRender(),
|
|
95
|
+
mouseObserver: list.createMouseObserver(() => tui.requestRender()),
|
|
93
96
|
});
|
|
97
|
+
let completed = false;
|
|
98
|
+
const finish = (result: ChoiceSelection | undefined) => {
|
|
99
|
+
if (completed) return;
|
|
100
|
+
completed = true;
|
|
101
|
+
list.setDisabled(true);
|
|
102
|
+
done(result);
|
|
103
|
+
};
|
|
94
104
|
list.onSelect = (item) => {
|
|
95
105
|
const index = items.indexOf(item);
|
|
96
|
-
|
|
106
|
+
const option = params.options[index];
|
|
107
|
+
if (option) finish({ value: option.value, label: option.label, index: index + 1 });
|
|
97
108
|
};
|
|
98
|
-
list.onCancel = () =>
|
|
109
|
+
list.onCancel = () => finish(undefined);
|
|
110
|
+
container.addChild(new DynamicBorder((text: string) => theme.fg("accent", text)));
|
|
111
|
+
container.addChild(new Text(theme.fg("accent", theme.bold(params.question)), 1, 0));
|
|
99
112
|
container.addChild(list);
|
|
100
113
|
container.addChild(new Text(theme.fg("dim", "↑↓ navigate • Enter select • Esc cancel"), 1, 0));
|
|
101
114
|
container.addChild(new DynamicBorder((text: string) => theme.fg("accent", text)));
|
|
102
|
-
return
|
|
103
|
-
render: (width) => container.render(width),
|
|
104
|
-
invalidate: () => container.invalidate(),
|
|
105
|
-
handleInput: (data) => {
|
|
106
|
-
list.handleInput(data);
|
|
107
|
-
tui.requestRender();
|
|
108
|
-
},
|
|
109
|
-
};
|
|
115
|
+
return container;
|
|
110
116
|
});
|
|
111
117
|
} finally {
|
|
112
118
|
pi.events.emit(ASK_USER_CHOICE_BLOCKED_EVENT, { active: false });
|