@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.
- package/LICENSE +21 -0
- package/README.md +131 -2
- package/assets/badge-dark.svg +18 -0
- package/assets/badge-light.svg +18 -0
- package/docs/advanced-usage.md +106 -0
- package/docs/agent-flow-design.md +306 -0
- package/docs/agentic-runtime-prd.md +773 -0
- package/docs/architecture.md +368 -0
- package/docs/controls.md +140 -0
- package/docs/pi-autoresearch-survey.md +50 -0
- package/docs/pi-goal-x-unified-dashboard-plan.md +1667 -0
- package/docs/prompt-caching.md +31 -0
- package/docs/unified-dashboard.md +286 -0
- package/extensions/auditor-selector.ts +74 -0
- package/extensions/goal-accounting.ts +107 -0
- package/extensions/goal-activity.ts +202 -0
- package/extensions/goal-auditor.ts +480 -0
- package/extensions/goal-commands.ts +866 -0
- package/extensions/goal-compaction.ts +197 -0
- package/extensions/goal-completion.ts +173 -0
- package/extensions/goal-context.ts +12 -0
- package/extensions/goal-contract.ts +58 -0
- package/extensions/goal-controls.ts +202 -0
- package/extensions/goal-core-tools.ts +549 -0
- package/extensions/goal-core.ts +78 -0
- package/extensions/goal-detail.ts +65 -0
- package/extensions/goal-dialog-controls.ts +31 -0
- package/extensions/goal-draft.ts +244 -0
- package/extensions/goal-drafting.ts +535 -0
- package/extensions/goal-events.ts +692 -0
- package/extensions/goal-format.ts +376 -0
- package/extensions/goal-interruption.ts +53 -0
- package/extensions/goal-ledger-index.ts +68 -0
- package/extensions/goal-ledger.ts +1007 -0
- package/extensions/goal-live-retention.ts +239 -0
- package/extensions/goal-oracle.ts +346 -0
- package/extensions/goal-policy.ts +370 -0
- package/extensions/goal-pool.ts +103 -0
- package/extensions/goal-prompt-cache.ts +80 -0
- package/extensions/goal-questionnaire.ts +1073 -0
- package/extensions/goal-record.ts +388 -0
- package/extensions/goal-recovery.ts +256 -0
- package/extensions/goal-runtime.ts +277 -0
- package/extensions/goal-scheduler-state.ts +100 -0
- package/extensions/goal-scheduler.ts +436 -0
- package/extensions/goal-service.ts +843 -0
- package/extensions/goal-session-health.ts +130 -0
- package/extensions/goal-session-safety.ts +65 -0
- package/extensions/goal-settings.ts +1370 -0
- package/extensions/goal-state.ts +1069 -0
- package/extensions/goal-status.ts +305 -0
- package/extensions/goal-task-confirmation.ts +174 -0
- package/extensions/goal-task-count.ts +59 -0
- package/extensions/goal-task-derive.ts +46 -0
- package/extensions/goal-task-index.ts +57 -0
- package/extensions/goal-task-tools.ts +595 -0
- package/extensions/goal-tool-inputs.ts +102 -0
- package/extensions/goal-tool-names.ts +73 -0
- package/extensions/goal-tools.ts +16 -0
- package/extensions/goal-widget.ts +455 -0
- package/extensions/goal.ts +42 -0
- package/extensions/network-error-backoff.ts +55 -0
- package/extensions/prompts/goal-prompts.ts +330 -0
- package/extensions/storage/atomic-rename.ts +52 -0
- package/extensions/storage/goal-files.ts +695 -0
- package/extensions/storage/goal-lock.ts +131 -0
- package/extensions/storage/goal-root.ts +95 -0
- package/extensions/widgets/auditor-dashboard-model.ts +174 -0
- package/extensions/widgets/dialog-scaffold.ts +26 -0
- package/extensions/widgets/goal-controls-dialog.ts +329 -0
- package/extensions/widgets/goal-dashboard-model.ts +530 -0
- package/extensions/widgets/goal-dashboard-renderer.ts +674 -0
- package/extensions/widgets/goal-escape-dialog.ts +148 -0
- package/extensions/widgets/goal-notifications.ts +9 -0
- package/extensions/widgets/goal-widget.ts +723 -0
- package/extensions/widgets/task-list-overlay.ts +409 -0
- package/extensions/widgets/text-cache.ts +30 -0
- package/package.json +117 -4
- 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.
|
package/docs/controls.md
ADDED
|
@@ -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
|
+
```
|