@quantmind-br/pi-goal-x 0.0.0-stage → 0.35.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +131 -2
  3. package/assets/badge-dark.svg +18 -0
  4. package/assets/badge-light.svg +18 -0
  5. package/docs/advanced-usage.md +106 -0
  6. package/docs/agent-flow-design.md +306 -0
  7. package/docs/agentic-runtime-prd.md +773 -0
  8. package/docs/architecture.md +368 -0
  9. package/docs/controls.md +140 -0
  10. package/docs/pi-autoresearch-survey.md +50 -0
  11. package/docs/pi-goal-x-unified-dashboard-plan.md +1667 -0
  12. package/docs/prompt-caching.md +31 -0
  13. package/docs/unified-dashboard.md +286 -0
  14. package/extensions/auditor-selector.ts +74 -0
  15. package/extensions/goal-accounting.ts +107 -0
  16. package/extensions/goal-activity.ts +202 -0
  17. package/extensions/goal-auditor.ts +480 -0
  18. package/extensions/goal-commands.ts +866 -0
  19. package/extensions/goal-compaction.ts +197 -0
  20. package/extensions/goal-completion.ts +173 -0
  21. package/extensions/goal-context.ts +12 -0
  22. package/extensions/goal-contract.ts +58 -0
  23. package/extensions/goal-controls.ts +202 -0
  24. package/extensions/goal-core-tools.ts +549 -0
  25. package/extensions/goal-core.ts +78 -0
  26. package/extensions/goal-detail.ts +65 -0
  27. package/extensions/goal-dialog-controls.ts +31 -0
  28. package/extensions/goal-draft.ts +244 -0
  29. package/extensions/goal-drafting.ts +535 -0
  30. package/extensions/goal-events.ts +692 -0
  31. package/extensions/goal-format.ts +376 -0
  32. package/extensions/goal-interruption.ts +53 -0
  33. package/extensions/goal-ledger-index.ts +68 -0
  34. package/extensions/goal-ledger.ts +1007 -0
  35. package/extensions/goal-live-retention.ts +239 -0
  36. package/extensions/goal-oracle.ts +346 -0
  37. package/extensions/goal-policy.ts +370 -0
  38. package/extensions/goal-pool.ts +103 -0
  39. package/extensions/goal-prompt-cache.ts +80 -0
  40. package/extensions/goal-questionnaire.ts +1073 -0
  41. package/extensions/goal-record.ts +388 -0
  42. package/extensions/goal-recovery.ts +256 -0
  43. package/extensions/goal-runtime.ts +277 -0
  44. package/extensions/goal-scheduler-state.ts +100 -0
  45. package/extensions/goal-scheduler.ts +436 -0
  46. package/extensions/goal-service.ts +843 -0
  47. package/extensions/goal-session-health.ts +130 -0
  48. package/extensions/goal-session-safety.ts +65 -0
  49. package/extensions/goal-settings.ts +1370 -0
  50. package/extensions/goal-state.ts +1069 -0
  51. package/extensions/goal-status.ts +305 -0
  52. package/extensions/goal-task-confirmation.ts +174 -0
  53. package/extensions/goal-task-count.ts +59 -0
  54. package/extensions/goal-task-derive.ts +46 -0
  55. package/extensions/goal-task-index.ts +57 -0
  56. package/extensions/goal-task-tools.ts +595 -0
  57. package/extensions/goal-tool-inputs.ts +102 -0
  58. package/extensions/goal-tool-names.ts +73 -0
  59. package/extensions/goal-tools.ts +16 -0
  60. package/extensions/goal-widget.ts +455 -0
  61. package/extensions/goal.ts +42 -0
  62. package/extensions/network-error-backoff.ts +55 -0
  63. package/extensions/prompts/goal-prompts.ts +330 -0
  64. package/extensions/storage/atomic-rename.ts +52 -0
  65. package/extensions/storage/goal-files.ts +695 -0
  66. package/extensions/storage/goal-lock.ts +131 -0
  67. package/extensions/storage/goal-root.ts +95 -0
  68. package/extensions/widgets/auditor-dashboard-model.ts +174 -0
  69. package/extensions/widgets/dialog-scaffold.ts +26 -0
  70. package/extensions/widgets/goal-controls-dialog.ts +329 -0
  71. package/extensions/widgets/goal-dashboard-model.ts +530 -0
  72. package/extensions/widgets/goal-dashboard-renderer.ts +674 -0
  73. package/extensions/widgets/goal-escape-dialog.ts +148 -0
  74. package/extensions/widgets/goal-notifications.ts +9 -0
  75. package/extensions/widgets/goal-widget.ts +723 -0
  76. package/extensions/widgets/task-list-overlay.ts +409 -0
  77. package/extensions/widgets/text-cache.ts +30 -0
  78. package/package.json +117 -4
  79. package/scripts/recover-session-checkpoints.mjs +289 -0
@@ -0,0 +1,368 @@
1
+ # pi-goal Architecture
2
+
3
+ This document describes the shipped `pi-goal` extension as it exists now. It focuses on implemented behavior.
4
+
5
+ ## Runtime shape
6
+
7
+ `extensions/goal.ts` is a thin installer (under 50 lines). It registers the two
8
+ custom message renderers, builds the shared `GoalCore` (goal-state.ts), and
9
+ registers the command palette, the tool surface, and the lifecycle event
10
+ handlers from their dedicated modules:
11
+
12
+ | Module | Responsibility |
13
+ |---|---|
14
+ | `goal.ts` | Thin installer: renderers + module registration only |
15
+ | `goal-state.ts` | `GoalCore`: all mutable state (pool, focus, audit/UI flags), `GoalService`/`GoalRuntime`/`GoalAccounting` wiring, persistence and reconciliation closures, widget status |
16
+ | `goal-tools.ts` | Registration composition only: a 14-line installer that wires `registerCoreTools` + `registerTaskTools` |
17
+ | `goal-core-tools.ts` | `create_goal` / `get_goal` / `update_goal` executors plus the blocked flow |
18
+ | `goal-completion.ts` | The completion transaction: `runGoalCompletionFlow` (audit orchestration) + shared `commitGoalCompletion` |
19
+ | `goal-task-tools.ts` | `set_goal_tasks` / `update_goal_task` executors plus flat parent-linked conversion, id-stable merge, `countTasks` |
20
+ | `goal-task-confirmation.ts` | Task-only result boundary (`{decision}`, no auditor toggle) with neutral Confirm task list / Keep current tasks labels |
21
+ | `goal-commands.ts` | The curated fourteen-command palette and its handlers |
22
+ | `goal-events.ts` | Lifecycle and provider event handlers (`context`, `before_provider_request`, `turn_start`, `tool_call`, `tool_execution_end`, `turn_end`, `message_end`, `session_start`, `session_before_compact`, `session_compact`, `session_tree`, `before_agent_start`, `agent_end`, `agent_settled`, `session_shutdown`) |
23
+ | `goal-widget.ts` | Terminal input keybindings (Esc pause / abort-audit, Ctrl+Shift+T overlay) and the hidden debug helpers |
24
+ | `goal-format.ts` | Pure formatting/message-introspection helpers and renderers |
25
+ | `goal-service.ts` | `GoalService` — the sole mutation boundary: ordered reconcile → id/focus-revision validation → clone-mutate → write/archive → ledger → memory commit → returned effects |
26
+ | `goal-runtime.ts` | `GoalRuntime` — continuation scheduling, stale checkpoint state, turn-stop guard, one-shot steering reminders |
27
+ | `goal-accounting.ts` | `GoalAccounting` — serialized idempotent token/time accounting, budget helpers |
28
+ | `goal-record.ts` | Goal record types, creation, cloning, usage normalization, persisted-record migration |
29
+ | `goal-pool.ts` | Open-goal pool helpers, focus resolution, list output, selector labels, unfocused summaries |
30
+ | `goal-core.ts` | Compact display formatting, status labels, objective title cleanup |
31
+ | `goal-contract.ts` | Record/input parser: verification-contract extraction and objective prompt-safety |
32
+ | `goal-policy.ts` | Lifecycle policy and validation (completion/blocked/resume/task gates), task-tree helpers, compaction policy, result reports |
33
+ | `goal-auditor.ts` | Independent pi auditor agent prompt/config/decision parsing and completion audit execution |
34
+ | `goal-ledger.ts` | Single-file goal ledger append/read/reconstruction (18 event types incl. `task_reopened`) |
35
+ | `goal-draft.ts` | Drafting prompt/confirmation text helpers (goalDraftingPrompt, buildDraftConfirmationText, renderConfirmationTasks, GoalDraftingFocus) |
36
+ | `goal-drafting.ts` | Guided drafting orchestration: durable `pi-goal-draft` session entries (survive compaction/tree navigation), resume/replace/cancel protection, fixed advertised drafting tools with execution-time gates, `goal_question`/`goal_questionnaire`/`propose_goal_draft` tools, per-draft auditor selection |
37
+ | `goal-questionnaire.ts` | Structured question/answer UI (`runGoalQuestionnaire`, `showProposalDialog`) used by the drafting tools and confirmations |
38
+ | `goal-tool-names.ts` | Execution/drafting tool-name constants, fixed task-enabled/disabled profiles, work/progress classification, post-stop allowlist |
39
+ | `goal-detail.ts` | Lossless objective/task/history paging with content-bound cursors |
40
+ | `goal-ledger-index.ts` | Incremental per-goal activity, audit, lifecycle, and Oracle projections |
41
+ | `goal-task-index.ts` | Content-keyed task snapshots shared by prompts, tools, and dashboard models |
42
+ | `prompts/goal-prompts.ts` | Bounded five-tool steering prompts (active-goal, continuation, stale-checkpoint, unfocused, budget-limited) |
43
+ | `storage/goal-files.ts` | Goal path safety, serialization/parsing, active-file scanning, active-file writes, archive writes, prompt-body merge from disk |
44
+ | `widgets/goal-widget.ts` | Above-editor Goal Beacon component |
45
+ | `widgets/goal-notifications.ts` | Widget-style notification text for goal lifecycle toasts |
46
+
47
+ The runtime is a focused-goal view over a project goal pool:
48
+
49
+ ```ts
50
+ let goalsById: Map<string, GoalRecord>;
51
+ let focusedGoalId: string | null;
52
+ ```
53
+
54
+ `goalsById` is reconstructed from `.pi/goals/active_goal_*.md` plus compatible
55
+ legacy session entries. `focusedGoalId` is reconstructed from branch-local
56
+ `pi-goal-focus` session entries. The focused id is not serialized into goal
57
+ markdown.
58
+
59
+ ## Sole mutation boundary
60
+
61
+ `GoalService` owns the ordered mutation pipeline. Every goal-file write,
62
+ archive, and ledger append routes through it:
63
+
64
+ ```text
65
+ reconcile (disk wins over stale memory)
66
+ → expected-id / focus-revision validation (async operations invalidated on focus change)
67
+ → mutate a clone (never the live object)
68
+ → write or archive the active file
69
+ → append ledger events (best-effort; failure emits a warning diagnostic)
70
+ → commit to memory + focus
71
+ → return effects (ok, goal, focusChanged, messages)
72
+ ```
73
+
74
+ If the write fails, nothing commits and nothing is appended. If the ledger
75
+ append fails after a successful write, the transition still stands and the
76
+ failure is surfaced through the `onDiagnostic` hook (an observable
77
+ `severity: warning, source: ledger` diagnostic) without rolling back the
78
+ authoritative state write. Handlers keep validation and
79
+ runtime/UI effects; they never touch storage directly. `goal.ts` has zero
80
+ direct write or ledger calls.
81
+
82
+ ## Lifecycle
83
+
84
+ ```text
85
+ /user command or explicit create_goal request
86
+ ├─ /goal [seed] or /sisyphus [seed]
87
+ │ └─ guided draft: clarify/questionnaire → objective + optional task proposal → explicit confirmation
88
+ ├─ /goal-direct <objective> or /sisyphus-direct <objective>
89
+ │ └─ direct creation: objective (1–4000 chars) → active goal file → focused → autoContinue
90
+ ├─ focused active goal
91
+ │ ├─ autoContinue queues checkpoint turns
92
+ │ ├─ update_goal({status:"blocked"}) records a distinct blocked state after the same
93
+ │ │ blocker recurs on three consecutive turns
94
+ │ └─ update_goal({status:"complete"}) starts the independent auditor; <approved/> archives
95
+ ├─ paused/blocked goal
96
+ │ ├─ /goal-resume restarts autoContinue
97
+ │ └─ update_goal(complete) can complete from existing evidence
98
+ ├─ multiple open goals
99
+ │ ├─ /goal-list shows the project goal pool
100
+ │ ├─ /goal-focus chooses the session focus
101
+ │ ├─ /goal-unfocus clears only the session focus and leaves the shared goal open
102
+ │ └─ unfocused sessions guide the user to choose instead of letting the agent decide
103
+ └─ /goal-clear archives the focused goal after confirmation (cancel is a durable no-op)
104
+ ```
105
+
106
+ ## Goal pool and session focus
107
+
108
+ The disk layout supports multiple active files. The extension treats those
109
+ files as the durable project-level open goal pool:
110
+
111
+ ```text
112
+ .pi/goals/active_goal_<timestamp>_<id>.md
113
+ ```
114
+
115
+ `readActiveGoalPool(ctx)` scans that directory, ignores invalid files and
116
+ symlinks, parses each safe active file, sanitizes metadata paths, drops
117
+ completed records, and returns a deterministic `Map<goalId, GoalRecord>`.
118
+
119
+ Session focus is separate. Focus changes append a custom session entry:
120
+
121
+ ```ts
122
+ {
123
+ version: 1,
124
+ focusedGoalId: string | null,
125
+ reason: "created" | "selected" | "unfocused" | "resumed" | "completed" | "cleared" | "migrated"
126
+ }
127
+ ```
128
+
129
+ Because this is stored with `pi.appendEntry("pi-goal-focus", ...)`, it is
130
+ session/branch-local and is not sent to the LLM. On `session_start` and
131
+ `session_tree`, `loadState(ctx)` scans `ctx.sessionManager.getBranch()` for the
132
+ latest focus entry, scans active goal files, and resolves focus as follows:
133
+
134
+ 1. Use a valid focused id from the latest focus entry.
135
+ 2. If the latest focus entry explicitly has `focusedGoalId: null`, or points at
136
+ a missing/stale goal, remain unfocused.
137
+ 3. If no focus entry exists, merge a compatible legacy `pi-goal-state { version: 3, goal }`
138
+ goal and focus it. If disk already has the same id, the disk record wins and
139
+ the legacy session record only supplies focus.
140
+ 4. If no focus entry exists and `autoSelectSingleGoal` is enabled, auto-focus
141
+ the sole open goal for compatibility. The default is disabled.
142
+ 5. Otherwise remain unfocused until the user explicitly selects a goal.
143
+ `/goal-unfocus` appends a null focus entry so the current session stays
144
+ detached without modifying the shared goal or appending a project-global
145
+ focus event.
146
+
147
+ Focus is human-owned. No agent tool can switch focus. Lifecycle tools operate
148
+ only on the focused goal.
149
+
150
+ ## Goal styles
151
+
152
+ ### Regular goal
153
+
154
+ Regular goals are open-ended objectives. The agent decides the next concrete
155
+ action each checkpoint turn, then completes only after the objective is
156
+ actually satisfied.
157
+
158
+ ### Sisyphus goal
159
+
160
+ Sisyphus is a light variant of the same goal lifecycle. It does not have a
161
+ separate execution state machine or step counter. The only differences are
162
+ prompt/criteria level:
163
+
164
+ - the objective is written as numbered ordered steps with per-step done criteria;
165
+ - continuations remind the agent not to rush, skip, or invent preflight steps;
166
+ - completion still uses `update_goal(status="complete")`, with the stricter
167
+ expectation that the whole ordered objective is actually satisfied.
168
+
169
+ ## Creation and tweaking
170
+
171
+ `/goal [seed]` and `/sisyphus [seed]` begin guided drafting without changing
172
+ the advertised tools; the five execution goal tools are blocked until the draft
173
+ ends, and the question/questionnaire/proposal tools do the work. The agent
174
+ clarifies intent, proposes the full objective and an optional task tree, and
175
+ the user explicitly confirms or continues refining. `/goal-direct` and
176
+ `/sisyphus-direct` bypass this only when the objective is already final.
177
+
178
+ `/goal-tweak <change>` starts the same guided-confirmation process for the
179
+ focused goal. It preserves the task list when no replacement is proposed and
180
+ records `goal_tweaked` (plus `task_list_set` if applicable) only after the
181
+ user confirms.
182
+
183
+ ## Command focus behavior
184
+
185
+ - `/goal [seed]` starts a regular guided draft; bare `/goal` asks what to accomplish.
186
+ - `/sisyphus [seed]` starts a Sisyphus guided draft.
187
+ - `/goal-direct <objective>` and `/sisyphus-direct <objective>` create directly without drafting.
188
+ - `/goal-list` prints all open goals with id, status, mode, usage, objective title, path, and a focus marker.
189
+ - `/goal-status health` performs a read-only coherence check for focus, lifecycle, goal-file presence, malformed ledger entries, task progress, and token-budget pressure; it never acts as a completion verdict.
190
+ - `/goal-focus` uses `ctx.ui.select` when multiple goals are open and updates only session focus.
191
+ - `/goal-unfocus` writes a null session focus entry, clears continuation/runtime state, aborts in-flight work and audits for that session, and leaves the shared active goal file and project-global focus ledger unchanged. Focus revision tokens prevent pending completion and task-list results from mutating a goal after detachment.
192
+ - `/goal-resume` resumes the focused paused goal; when unfocused with multiple open goals, it asks the user to choose. Choosing an already active goal only focuses it.
193
+ - `/goal-clear` asks for confirmation (with the goal's one-line summary) and archives only the focused/selected goal; cancelling is a byte-for-byte no-op with no file, focus, or ledger change, and headless runs return guidance without mutating anything.
194
+ - `/goal-pause` pauses the focused active goal; it asks the user to choose when unfocused with open goals.
195
+ - `/goal-settings` renders and dispatches every persisted field from one declarative row table: booleans (`disableTasks`, `disableContracts`, `autoSelectSingleGoal`, `disabled`) toggle directly, `provider`/`model` edit and clear, `thinkingLevel` accepts every level and rejects unknown values, and `subtaskDepth` validates the full input string (whole positive safe integers).
196
+
197
+ ## Tool surface
198
+
199
+ The extension registers five normal-execution tools and three drafting-only tools:
200
+
201
+ | Tool | Purpose |
202
+ |---|---|
203
+ | `create_goal` | Create and focus a new goal after an explicit user request (objective 1–4000 chars, optional `mode` regular/sisyphus and `token_budget`). |
204
+ | `get_goal` | Compact summary by default; lossless objective/tasks/history pages (up to 4,000 content characters), optional task selection, legacy verbose/history forms. |
205
+ | `update_goal` | Run outcomes: `complete` (audited from actual evidence; optional `completion_summary` is an untrusted claim), `blocked` (after three consecutive identical blockers), or `paused` (immediate agent pause with required `reason`). |
206
+ | `set_goal_tasks` | Create or structurally replace the task tree (flat parent-linked input, confirmation dialog, id-stable merge). |
207
+ | `update_goal_task` | Update one task or an ordered atomic batch: start, complete (evidence for contracted tasks), skipped (reason), pending (reopens skipped). |
208
+ | `goal_question` | Drafting-only structured clarification question. |
209
+ | `goal_questionnaire` | Drafting-only multi-question clarification UI. |
210
+ | `propose_goal_draft` | Drafting-only objective/task proposal with Confirm or Continue Chatting. |
211
+
212
+ The goal tool profile is fixed: the five execution tools, or the three core tools
213
+ when tasks are disabled, plus the three drafting tools. Goal status, focus, task
214
+ presence, and draft start/confirm/cancel never change it, so tool declarations,
215
+ which providers cache as part of the prompt prefix, stay stable. Only a
216
+ `disableTasks` change alters it. Drafting tools reject calls without an active
217
+ user-started draft. The `tool_call` guard blocks the five execution tools while a
218
+ draft is active and for the rest of the turn in which a proposal confirmed or
219
+ cancelled it. Executors still validate lifecycle state, including stale calls made
220
+ after a transition. Ordinary pi work tools remain available, and the SDK active
221
+ profile changes only when membership changes.
222
+
223
+ Normal prompt/dashboard reads use per-goal ledger indexes: 12 recent events,
224
+ 64 activity candidates in stable timestamp order, pinned audit/lifecycle state,
225
+ and blocker-fingerprint Oracle state. Appends extend these indexes without
226
+ copying history. Version 3 derived checkpoints use UTF-8 byte offsets and retain
227
+ reconstructed Oracle advice; old or
228
+ corrupt checkpoints rebuild from the authoritative JSONL ledger. Full history
229
+ is loaded for explicit history/diagnostic requests. Saved goal/session formats
230
+ remain compatible. Task presentation caches use content snapshots; usage changes
231
+ do not rebuild task trees. Stable prompt rules precede changing goal data and
232
+ usage counters, with retrieval instructions beside bounded excerpts.
233
+
234
+ Warm settings resolution is cached by layer identity and applicable environment
235
+ values; public resolved values remain independently editable. Task and prompt
236
+ caches compare content fields without repeatedly serializing long contracts.
237
+ Compiled detail pages reuse their source and cursor hash; history sources are
238
+ invalidated by an opaque ledger generation on append or refresh. Cache size
239
+ limits bound retained data; larger requirements remain available losslessly.
240
+ Pure ANSI text wrapping/truncation is cached by text and layout arguments across
241
+ widgets and dialogs. Live auditor previews scan only the report tail, while the
242
+ complete final report remains available. Measurements and the module audit are
243
+ in `specs/2026-09-07-comprehensive-optimization/`.
244
+
245
+ The `tool_call` interceptor blocks work tools after a stop tool has fired in
246
+ the same turn, and blocks work tools when the checkpoint that triggered the
247
+ turn is no longer actionable (stale checkpoint).
248
+
249
+ ## Accounting, runtime, and token budgets
250
+
251
+ `GoalAccounting` (goal-accounting.ts) charges serialized, idempotent
252
+ token/time intervals per turn; a goal never double-charges the same interval.
253
+ `GoalRuntime` (goal-runtime.ts) owns continuation scheduling, the stale
254
+ checkpoint state, the turn-stop guard, and one-shot steering reminders.
255
+
256
+ `GoalScheduler` persists dispatch intent and allowance consumption. Default
257
+ continuation is immediate. Explicit `idleContinuationBackoff=true` also records a
258
+ bounded idle streak and earliest next attempt: one immediate continuation, then
259
+ 30 seconds doubling to five minutes. Work accumulates over the whole logical run;
260
+ content snapshots exclude usage, revisions and scheduler writes. Disabled pacing
261
+ skips those snapshots. Settings are rechecked at scheduling and admission; opting
262
+ out removes saved delay metadata without renewing consumption. Resume and genuine
263
+ host input reset pacing; strict waits and provider recovery remain independent.
264
+
265
+ Pi 1.4 prepares goal-triggered turns natively. The extension uses
266
+ `context_with_system` to filter its messages and add current goal state after
267
+ Pi has restored the system prompt and tool declarations. System messages stay
268
+ at their original history boundaries, including deltas from other extensions.
269
+ `agent_settled.aborted` stops continuation/recovery and pauses the associated
270
+ goal. Rejected stale checkpoints settle without changing the replacement goal.
271
+
272
+ Audit display messages flush only at idle settlement and remain scoped to their
273
+ session. If Pi has invalidated a settlement context, the handler skips it before
274
+ consuming continuation intent or changing the replacement session's queue.
275
+
276
+ An optional `token_budget` may be set at creation. When accounted usage
277
+ reaches the budget, `accountProgress` transitions the goal to the distinct
278
+ `budget_limited` status exactly once (status leaves `active`, so accounting
279
+ stops and the transition cannot re-fire), emits a `goal_budget_limited` ledger
280
+ event, arms the one-time wrap-up steering, and cancels pending continuations.
281
+ `budget_limited` never implies completion.
282
+
283
+ ## Completion output
284
+
285
+ Completion is explicit and checked by an independent auditor agent.
286
+ `update_goal(status="complete")` is valid for active and paused goals; paused
287
+ goals do not need to be resumed just to record completion when existing
288
+ evidence is sufficient. There is no verification-summary parameter — the
289
+ auditor derives the requirements from the objective and any verification
290
+ contract and inspects the actual workspace.
291
+
292
+ Before archiving, the tool starts a separate in-memory pi session with a
293
+ focused auditor prompt. The auditor receives the objective, executor
294
+ completion claim, and goal metadata, can inspect the workspace with `read`,
295
+ `grep`, `find`, `ls`, and `bash`, and must end with exactly one marker:
296
+
297
+ - `<approved/>` allows archiving;
298
+ - `<disapproved/>`, no marker, an error, or abort rejects completion and leaves
299
+ the goal open.
300
+
301
+ The auditor uses the current/default model unless
302
+ `.pi/pi-goal-x-settings.json` overrides `provider`, `model`, or `thinkingLevel`.
303
+ The user can Escape an in-flight audit to choose "complete without audit" or
304
+ "continue working". Archival is deferred to `turn_end` so the agent can see the
305
+ auditor result before the goal is archived. The global `disabled` setting is
306
+ an explicit user-owned switch: completion skips the auditor, records
307
+ `audit_skipped`, and proceeds through the normal deferred-completion path.
308
+
309
+ ## Disk format and old-data reads
310
+
311
+ Active and archived goal files live under `.pi/goals/`. Each file has
312
+ extension-owned metadata and a user-editable `# Goal Prompt` section. Before
313
+ focused commands, tools, and lifecycle hooks act, the runtime re-reads the
314
+ focused active file and reconciles lifecycle state from disk; prompt-body
315
+ edits are picked up from `# Goal Prompt`. Path safety checks reject absolute
316
+ paths, traversal, NUL bytes, symlinks, and paths outside the goal directories.
317
+
318
+ Old readers remain for backward-compatible reads of existing data:
319
+ `readActiveGoalPool`, `readGoalLedger`, `mergeGoalPromptFromDisk`,
320
+ `latestAuditorResultForGoal`, and `normalizeGoalRecord` are all retained and in
321
+ use. The ledger is append-only JSONL and is never rewritten in place.
322
+
323
+ ## Tests
324
+
325
+ Local tests live in `tests/` and run with:
326
+
327
+ ```bash
328
+ npm run test:all
329
+ npm run check
330
+ ```
331
+
332
+ `test:unit`, `test:integration`, and `test:all` automatically discover test
333
+ entries and run them with small test-only adapters for the
334
+ SDK values used by handlers. This avoids loading unrelated model-provider and
335
+ TUI media modules. The fast path requires Node 22.19+; `test:serial` remains
336
+ the slow, real-SDK, process-isolated alternative. The suites cover: surface baselines (lifecycle-dependent goal tool
337
+ profile and fourteen commands), golden file/ledger fixtures, stale-continuation behavior,
338
+ GoalService mutation boundary, runtime/accounting, token-budget transitions,
339
+ task-tool consolidation, verification contracts, the independent auditor,
340
+ compaction recovery, and the bounded steering prompts. The separate
341
+ `tests/e2e/run.ts` real-model path is manual and opt-in. In `experiments/`,
342
+ C20-C26 are the release set and B1-B2/C1-C19 are migrated compatibility cases.
343
+
344
+ ## Hardening
345
+
346
+ The 2026-08-04 hardening plan
347
+ ([`specs/2026-08-04-goal-simplification-hardening`](../specs/2026-08-04-goal-simplification-hardening/TECH.md))
348
+ is implemented: paused-status normalization (status authoritative, legacy
349
+ `autoContinue: true` records stay paused), disk-fresh task transactions with
350
+ structural-field clearing, token-budget integer validation, `task_reopened`
351
+ ledger semantics with observable diagnostics, the lifecycle-dependent tool
352
+ profile, and the supported integration/experiment coverage described above.
353
+ (the interim drafting-surface removal was later reversed by the product
354
+ correction in the runtime follow-up, which restores guided drafting as a
355
+ first-class workflow; see the follow-up section below.)
356
+
357
+ The runtime follow-up
358
+ ([`specs/2026-08-04-goal-runtime-follow-up`](../specs/2026-08-04-goal-runtime-follow-up/TECH.md))
359
+ then shipped the remaining work: guided drafting is restored as a
360
+ first-class, transient user-invoked workflow (questionnaire, proposal
361
+ confirmation, atomic creation, durable draft sessions, `/goal-cancel`,
362
+ `/goal-status`, per-draft auditor selection); the settings menu is fully
363
+ operable; `/goal-clear` confirms; task confirmation uses neutral labels;
364
+ completion commits are failure-checked; and cross-process mutations are
365
+ serialized with persisted revisions plus per-goal filesystem locks that
366
+ return typed conflicts to stale writers instead of overwriting blindly.
367
+
368
+ Prompt layout and explicit provider cache handling are documented in [prompt caching](prompt-caching.md). Live goal state is constructed in the context hook; before_agent_start performs lifecycle preflight without modifying the system prompt.
@@ -0,0 +1,140 @@
1
+ # Commands and keys
2
+
3
+ Open `/goal-settings` and choose **Controls**, or run `/goal-settings controls`.
4
+ The screen has three sections: **Commands**, **Keys** and **Pausing**. Type to
5
+ filter, use the arrow keys and Enter to edit, and Tab to switch sections.
6
+ Page Up/Down moves through long lists; Home/End jumps to the first/last row.
7
+ Ctrl+S switches between **This project** and **All projects**. The selected row shows
8
+ whether its value comes from the project, global settings or the default.
9
+
10
+ Changes are saved when you choose Save or confirm a recorded key. Escape backs
11
+ out of an edit without saving. **Use inherited value** removes a project
12
+ override; **Remove global override** restores the default. **Use default** pins
13
+ the default in the selected scope. Each section also has a reset action that
14
+ removes only that section's overrides in the selected scope.
15
+
16
+ ## Commands
17
+
18
+ Each action has a preferred command followed by any aliases. Choose **Edit
19
+ command paths** to replace them, **Add an alias** to keep the current spellings,
20
+ or **Disable** to remove its command invocations. For example, add `/goal edit`
21
+ to **Revise the goal** to use the existing confirmation workflow with that
22
+ spelling. Arguments after the command path are passed through to the action.
23
+ Subcommands appear in argument completion; the longest matching complete path
24
+ wins. A routing-only root lists its available subcommands when called without
25
+ a matching action.
26
+
27
+ Command changes need a reload. The screen shows when changes are pending;
28
+ Ctrl+R applies them while Pi is idle when controls were opened through a slash
29
+ command. If controls were opened from a shortcut, close them and run `/reload`.
30
+ Keys and pause order take effect immediately.
31
+
32
+ `/goal-settings` always remains available as a recovery entry. You can give the
33
+ settings action other spellings, but this entry cannot be removed. Pi command
34
+ roots such as `/reload` and `/settings` are reserved. The editor checks conflicts
35
+ with other commands before saving.
36
+ For settings, **Recovery entry only** removes additional aliases while keeping
37
+ `/goal-settings` available.
38
+
39
+ The settings keys below are stable action IDs, even after renaming an invocation:
40
+
41
+ | Action ID | Action |
42
+ | --- | --- |
43
+ | `goal` | Guided goal draft |
44
+ | `sisyphus` | Guided Sisyphus draft |
45
+ | `goal-direct` | Immediate goal creation |
46
+ | `sisyphus-direct` | Immediate Sisyphus creation |
47
+ | `goal-tweak` | Confirmed revision |
48
+ | `goal-pause` | Pause goal and stop turn |
49
+ | `goal-resume` | Resume and renew the run allowance |
50
+ | `goal-clear` | Confirmed archival |
51
+ | `goal-list` | List open goals |
52
+ | `goal-status` | Status; also accepts `verbose` or `health` |
53
+ | `goal-refresh` | Read state and settings again |
54
+ | `goal-recovery` | Recovery report; also accepts `repair` |
55
+ | `goal-focus` | Choose a goal |
56
+ | `goal-unfocus` | Detach this session |
57
+ | `goal-settings` | Settings and controls |
58
+ | `goal-cancel` | Cancel a draft |
59
+
60
+ ## Keys
61
+
62
+ Choose an action under **Keys**, then record a key or edit its Pi key names.
63
+ **Record another key** adds a second binding. **Disable** leaves it unbound.
64
+ Conflicts are checked before saving; errors leave your input available to fix.
65
+ Use a free key or change a conflicting Pi binding in its `keybindings.json`.
66
+
67
+ Every public goal shortcut is listed: pause, audit interruption, auditor toggle,
68
+ dashboard expansion, compact scrolling, expanded navigation, and goal dialog
69
+ controls. Each command action can also have a shortcut, independently of its
70
+ slash command names. A shortcut for direct creation or revision asks for the
71
+ objective or change before invoking the usual workflow.
72
+
73
+ Goal dialog controls apply to questionnaires and confirmation dialogs. They
74
+ have their own context, so the same key can confirm a dialog and pause a live
75
+ goal. Text editing and the settings screen use Pi's usual UI controls. The
76
+ settings screen remains usable when you change goal dialog navigation.
77
+ While typing an answer, letters and Pi's editing keys keep editing text. Escape
78
+ leaves the answer editor; free custom keys such as F7 can do the same.
79
+
80
+ Pi key names include `escape`, `f6`, `ctrl+alt+p`, `pageUp` and `super+k`. Multiple
81
+ keys can be separated with commas. For a comma key combined with other bindings,
82
+ the text editor also accepts a JSON key list, for example `["ctrl+,", "f6"]`.
83
+ Existing comma-key lists reopen in this form so they can be saved unchanged.
84
+ Terminals must report a key before Pi can use it; some modifier combinations
85
+ require the Kitty keyboard protocol. See [Pi's keybinding reference](https://github.com/earendil-works/pi/blob/v1.4.0/packages/coding-agent/docs/keybindings.md).
86
+
87
+ ## Pausing
88
+
89
+ The default is still Escape, with **Goal and turn together**. An open dialog
90
+ owns its input; closing the expanded dashboard or interrupting an audit takes
91
+ priority over pausing in that view.
92
+
93
+ | Pause order | First press | Next press |
94
+ | --- | --- | --- |
95
+ | Goal and turn together | Pause the goal and stop the turn | Pi's normal interrupt |
96
+ | Goal first | Pause the goal; let the current turn finish | Stop the remaining turn |
97
+ | Turn first | Stop the turn and wait for the user, keeping the goal active | Pause the goal |
98
+
99
+ Goal first finishes the current Pi turn, then stops before another model
100
+ request. A turn-only stop holds automatic continuation, provider recovery and wake-ups.
101
+ It does not spend another run allowance. Resume or send a new user message to
102
+ continue. Reloading an interrupted autonomous run does not replay it.
103
+
104
+ When you move the pause key away from Pi's interrupt key, Pi's interrupt stops
105
+ the turn and waits for you without pausing the goal. The configured pause key
106
+ uses the selected order. The explicit **Pause the goal** command always stops
107
+ both the goal and its turn, including a turn left running by **Goal first**.
108
+
109
+ ## Settings files
110
+
111
+ The UI writes the existing sparse settings layers:
112
+
113
+ - Global: `${PI_CODING_AGENT_DIR:-~/.pi/agent}/pi-goal-x-settings.json`.
114
+ - Project: `<project>/.pi/pi-goal-x-settings.json`.
115
+
116
+ Project leaves override global leaves. Missing leaves inherit; an empty list
117
+ explicitly disables an action. Existing `keybindings.dashboard` settings keep
118
+ their meaning. For example:
119
+
120
+ ```json
121
+ {
122
+ "commands": {
123
+ "goal-tweak": ["goal-tweak", "goal edit"],
124
+ "goal-resume": ["work continue"]
125
+ },
126
+ "pauseOrder": "turn-first",
127
+ "keybindings": {
128
+ "pause": ["f6", "ctrl+alt+p"],
129
+ "toggleAuditor": "ctrl+alt+a",
130
+ "interruptAudit": "escape",
131
+ "dashboard": { "toggleExpand": "ctrl+alt+t" },
132
+ "dialog": { "confirm": "enter", "cancel": "escape" },
133
+ "commands": { "goal-settings": "f10", "goal-status": [] }
134
+ }
135
+ }
136
+ ```
137
+
138
+ Use `/goal-refresh` after external key or pause-order edits, and `/reload` after
139
+ external command edits. Verbose goal status reports the effective controls and
140
+ their sources. Developer-only `PI_GOAL_DEBUG` shortcuts are unchanged.
@@ -0,0 +1,50 @@
1
+ # Implemented Borrowed Patterns
2
+
3
+ > **Historical document (superseded 2026-08-03).** This survey describes the
4
+ > earlier drafting interface and is retained as design provenance, not current
5
+ > product documentation. See [`docs/architecture.md`](architecture.md) and the
6
+ > [2026-08-04 hardening plan](../specs/2026-08-04-goal-simplification-hardening/TECH.md).
7
+
8
+ This document records external patterns that are actually implemented in `pi-goal` today.
9
+
10
+ ## From pi-codex-goal
11
+
12
+ `pi-goal` uses several goal-loop stability patterns inspired by `pi-codex-goal`:
13
+
14
+ - **Goal-id continuation markers**: continuation prompts include a goal id so stale prompts can be detected.
15
+ - **Context interceptor**: stale continuation context is neutralized instead of letting an old goal keep driving the agent.
16
+ - **Abort pause**: user abort / Ctrl-C pauses the active goal rather than leaving it in a misleading active state.
17
+ - **Disk-backed active goal file**: the current objective is materialized on disk and can be audited outside the chat.
18
+
19
+ ## From pi-autoresearch
20
+
21
+ `pi-goal` uses several autonomous-loop safety patterns inspired by `pi-autoresearch`:
22
+
23
+ - **Empty-turn gate**: auto-continue does not advance when the agent did no meaningful goal-work tool activity.
24
+ - **Post-compaction reminder**: after compaction, the next agent turn is reminded to re-read the objective and continue from actual artifacts/state.
25
+
26
+ ## pi-goal-specific work
27
+
28
+ The current extension also adds behavior specific to goal drafting and lifecycle safety:
29
+
30
+ - **Intent-before-run**: `/goals` and `/sisyphus` start a drafting discussion instead of immediate execution.
31
+ - **Direct set shortcut**: `/goals-set` and `/sisyphus-set` immediately create a goal when the user already knows the final objective.
32
+ - **Confirm-before-commit for discussions**: `propose_goal_draft` is the normal discussion-based creation path; `create_goal` stays hidden.
33
+ - **Sisyphus as style**: `/sisyphus` and `/sisyphus-set` use the same lifecycle and tools as regular goals; they only change drafting/continuation wording and completion expectations.
34
+ - **Full draft confirmation and creation output**: draft confirmation uses a plain-text report, and after confirmation the finalized objective is printed directly into the conversation.
35
+ - **Full completion output**: completion prints a report directly into the conversation, including optional evidence and full goal details.
36
+ - **Built-in question tools**: `goal_question` and `goal_questionnaire` provide package-local user-dialogue tools with `goal_` prefixes.
37
+ - **Centralized tool names**: published tool names and allowlists live in `goal-tool-names.ts`.
38
+ - **Questionnaire componentization**: normalization, answer formatting, proposal confirmation, and question-tool registration live in `goal-questionnaire.ts`.
39
+ - **Widget module split**: the above-editor Goal Beacon and widget-style notification text live under `extensions/widgets/`.
40
+ - **Record/prompt/storage split**: goal record normalization, prompt construction, and disk serialization now live in separate tested modules instead of the orchestration file.
41
+
42
+ ## Current validation
43
+
44
+ Run locally:
45
+
46
+ ```bash
47
+ npm test
48
+ npm run check
49
+ npm pack --dry-run
50
+ ```