@hyperdreamer/pi-webui 1.10.7 → 1.11.0-beta.10
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 +17 -2
- package/dist/cli.js +265 -32
- package/dist/cli.js.map +1 -1
- package/dist/client/assets/{CodeViewer-BIb2Wx8W.js → CodeViewer-CAf_j27u.js} +1 -1
- package/dist/client/assets/{UnifiedDiffViewer-DpWiGlQo.js → UnifiedDiffViewer-wBjEJWa1.js} +1 -1
- package/dist/client/assets/{index-DX583DEv.js → index-5EtDb9nj.js} +1197 -476
- package/dist/client/index.html +1 -1
- package/dist/config.js +52 -11
- package/dist/config.js.map +1 -1
- package/dist/pi-webui-plugins/workspace-memory/pi-webui-plugin.js +3 -2
- package/dist/pi-webui-plugins/workspace-tasks/pi-webui-plugin.js +1 -0
- package/dist/plugin-api.d.ts +30 -0
- package/dist/server/app.js +6 -1
- package/dist/server/app.js.map +1 -1
- package/dist/server/realtime/sessionEventHub.js +40 -5
- package/dist/server/realtime/sessionEventHub.js.map +1 -1
- package/dist/server/realtime/sessionStatusCoalescer.js +137 -0
- package/dist/server/realtime/sessionStatusCoalescer.js.map +1 -0
- package/dist/server/sessiond/sessionProxyRoutes.js +2 -0
- package/dist/server/sessiond/sessionProxyRoutes.js.map +1 -1
- package/dist/server/sessiond.js +57 -5
- package/dist/server/sessiond.js.map +1 -1
- package/dist/server/sessions/modelPolicyCapability.js +88 -0
- package/dist/server/sessions/modelPolicyCapability.js.map +1 -0
- package/dist/server/sessions/modelPolicyTool.js +31 -0
- package/dist/server/sessions/modelPolicyTool.js.map +1 -0
- package/dist/server/sessions/modelTierRegistry.js +14 -0
- package/dist/server/sessions/modelTierRegistry.js.map +1 -1
- package/dist/server/sessions/modelTierSettingsRoutes.js +36 -0
- package/dist/server/sessions/modelTierSettingsRoutes.js.map +1 -0
- package/dist/server/sessions/modelTierSettingsService.js +100 -0
- package/dist/server/sessions/modelTierSettingsService.js.map +1 -0
- package/dist/server/sessions/piSessionService.js +1643 -433
- package/dist/server/sessions/piSessionService.js.map +1 -1
- package/dist/server/sessions/sessionDefaultsRoutes.js +39 -0
- package/dist/server/sessions/sessionDefaultsRoutes.js.map +1 -1
- package/dist/server/sessions/sessionDefaultsService.js +36 -6
- package/dist/server/sessions/sessionDefaultsService.js.map +1 -1
- package/dist/server/sessions/sessionMetadataStore.js +107 -13
- package/dist/server/sessions/sessionMetadataStore.js.map +1 -1
- package/dist/server/sessions/sessionModelPolicy.js +118 -0
- package/dist/server/sessions/sessionModelPolicy.js.map +1 -0
- package/dist/server/sessions/sessionReorder.js +117 -0
- package/dist/server/sessions/sessionReorder.js.map +1 -0
- package/dist/server/sessions/sessionRouteFastifyOptions.js +8 -0
- package/dist/server/sessions/sessionRouteFastifyOptions.js.map +1 -0
- package/dist/server/sessions/sessionRoutes.js +208 -3
- package/dist/server/sessions/sessionRoutes.js.map +1 -1
- package/dist/server/sessions/starterModelPolicyPreferenceStore.js +164 -0
- package/dist/server/sessions/starterModelPolicyPreferenceStore.js.map +1 -0
- package/dist/server/sessions/utilityModelExtension.js +199 -0
- package/dist/server/sessions/utilityModelExtension.js.map +1 -0
- package/dist/server/sessions/utilityModelResolver.js +77 -0
- package/dist/server/sessions/utilityModelResolver.js.map +1 -0
- package/dist/server/sessions/utilityModelSettingsRoutes.js +62 -0
- package/dist/server/sessions/utilityModelSettingsRoutes.js.map +1 -0
- package/dist/server/sessions/utilityModelSettingsService.js +101 -0
- package/dist/server/sessions/utilityModelSettingsService.js.map +1 -0
- package/dist/server/skills/optionalSkillInstall.js +69 -0
- package/dist/server/skills/optionalSkillInstall.js.map +1 -0
- package/dist/server/skills/optionalSkillInstaller.js +148 -0
- package/dist/server/skills/optionalSkillInstaller.js.map +1 -0
- package/dist/shared/apiTypes.d.ts +129 -3
- package/dist/shared/apiTypes.js +10 -0
- package/dist/shared/apiTypes.js.map +1 -1
- package/dist/shared/capabilities.js +15 -0
- package/dist/shared/capabilities.js.map +1 -1
- package/dist/shared/federatedRoutes.js +7 -0
- package/dist/shared/federatedRoutes.js.map +1 -1
- package/docs/assets/pi-webui-desktop.png +0 -0
- package/docs/config.md +61 -3
- package/docs/plugins.md +93 -16
- package/optional-skills/deterministic-subagent-driven-development/SKILL.md +224 -0
- package/optional-skills/deterministic-subagent-driven-development/pi-webui-skill.json +28 -0
- package/optional-skills/deterministic-subagent-driven-development/prompts/final-reviewer.md +132 -0
- package/optional-skills/deterministic-subagent-driven-development/prompts/implementer.md +101 -0
- package/optional-skills/deterministic-subagent-driven-development/prompts/re-reviewer.md +60 -0
- package/optional-skills/deterministic-subagent-driven-development/prompts/task-reviewer.md +80 -0
- package/optional-skills/deterministic-subagent-driven-development/references/capability-contract.md +174 -0
- package/optional-skills/deterministic-subagent-driven-development/references/plan-contract.md +268 -0
- package/optional-skills/deterministic-subagent-driven-development/references/state-machine.md +177 -0
- package/optional-skills/deterministic-subagent-driven-development/scripts/lib/manifest.mjs +258 -0
- package/optional-skills/deterministic-subagent-driven-development/scripts/lib/plan-policy.mjs +350 -0
- package/optional-skills/deterministic-subagent-driven-development/scripts/lib/prompt-renderer.mjs +290 -0
- package/optional-skills/deterministic-subagent-driven-development/scripts/lib/state-machine.mjs +1264 -0
- package/optional-skills/deterministic-subagent-driven-development/scripts/lib/state-store.mjs +532 -0
- package/optional-skills/deterministic-subagent-driven-development/scripts/sdd-state +3 -0
- package/optional-skills/deterministic-subagent-driven-development/scripts/sdd-state.mjs +349 -0
- package/optional-skills/deterministic-writing-plans/SKILL.md +232 -0
- package/optional-skills/deterministic-writing-plans/references/grammar.md +84 -0
- package/optional-skills/deterministic-writing-plans/templates/plan-skeleton.md +143 -0
- package/package.json +13 -9
package/docs/plugins.md
CHANGED
|
@@ -6,6 +6,7 @@ Plugins can currently:
|
|
|
6
6
|
|
|
7
7
|
- add action-palette commands;
|
|
8
8
|
- add workspace tools/panels next to Files, Git, and Terminal;
|
|
9
|
+
- add Activity Rail activities opened from dedicated Rail controls;
|
|
9
10
|
- add compact workspace-label items in the workspace list, panel header, and status bar;
|
|
10
11
|
- call browser APIs and documented PI WEBUI plugin context helpers;
|
|
11
12
|
- read workspace files and start workspace terminal commands through documented helpers;
|
|
@@ -79,7 +80,7 @@ After editing, check the manifest endpoint and browser-console failure cases.
|
|
|
79
80
|
|
|
80
81
|
## Canonical example: bundled Info plugin
|
|
81
82
|
|
|
82
|
-
PI WEBUI ships a real bundled `info` plugin. Use it as the reference example because it is intentionally small while still exercising
|
|
83
|
+
PI WEBUI ships a real bundled `info` plugin. Use it as the reference example because it is intentionally small while still exercising three UI contribution types: an action, a workspace label, and a workspace panel. Activity Rail activities are an additional v1 UI contribution type documented below.
|
|
83
84
|
|
|
84
85
|
Bundled PI WEBUI plugins are developed as TypeScript in the repository, but their `package.json` metadata still points at built JavaScript because plugins are loaded by the browser as JS ES modules. `npm run dev:web` watches and rebuilds bundled plugin TS into `dist/pi-webui-plugins/` during development, and `npm run build` emits the JS before packaging a release.
|
|
85
86
|
|
|
@@ -147,7 +148,7 @@ Reload the PI WEBUI browser tab. PI WEBUI serves plugin modules with an mtime-ba
|
|
|
147
148
|
|
|
148
149
|
When [machine federation](https://pi-webui.dev/machines) is enabled, PI WEBUI also loads discovered plugins from the selected remote machine. Remote plugins are trusted browser-side code like local plugins, but their contributions are machine-scoped:
|
|
149
150
|
|
|
150
|
-
- actions, workspace panels, and workspace labels only appear while that machine is selected;
|
|
151
|
+
- actions, workspace panels, Activity Rail activities, and workspace labels only appear while that machine is selected;
|
|
151
152
|
- plugin file and terminal helpers run against that machine;
|
|
152
153
|
- plugin code is loaded best-effort through the current gateway and cached for the browser page lifetime;
|
|
153
154
|
- if the gateway and remote machine both have an enabled plugin with the same original id, `machineSpecific` metadata decides whether the gateway copy is reused or only the selected machine's copy can appear;
|
|
@@ -204,11 +205,11 @@ Built-in plugins can be managed from **Settings → PI WEBUI plugins** or with t
|
|
|
204
205
|
### Memory
|
|
205
206
|
|
|
206
207
|
**Plugin id:** `workspace-memory`
|
|
207
|
-
**What it does:** adds a read-only **Memory** workspace
|
|
208
|
+
**What it does:** adds a read-only **Memory** Activity Rail activity. It is **Rail-only**: it does not contribute a workspace panel. It reads `pi-hermes-memory`-compatible data through PI WEBUI and never writes, creates, edits, or deletes memories.
|
|
208
209
|
|
|
209
|
-
The
|
|
210
|
+
Select the circular **Memory** Rail control to open a host-owned detail dialog. The dialog shows independently collapsible **Global memory** and **Project-specific memory** groups. Project-specific memory contains entries only for the selected workspace project. Empty or missing memory data appears as a scoped empty state. An unavailable project-specific request displays a scoped **Project-specific unavailable** state while **Global memory** remains available. A failed global-memory request is presented as a retryable error in the detail view.
|
|
210
211
|
|
|
211
|
-
|
|
212
|
+
With a workspace selected, the Memory activity remains visible while memory loads, when data is available, and if a memory request fails. It is hidden only after the provider confirms that the whole memory capability is unavailable. A project-specific unavailable response is a separate scoped detail state; it does not mean the whole provider is unavailable. The count badge appears only for data with one or more entries, so it is omitted in all non-data states and for zero data; when shown, it totals global and project-specific memory entries. PI WEBUI refreshes the badge immediately after a selected project or workspace change and then checks approximately every 30 seconds. This is polling; PI WEBUI does not promise instant or realtime updates.
|
|
212
213
|
|
|
213
214
|
Memory is bundled with PI WEBUI and enabled by default. To disable it, use **Settings → PI WEBUI plugins** or set:
|
|
214
215
|
|
|
@@ -393,11 +394,16 @@ interface PiWebUiPlugin {
|
|
|
393
394
|
activate: (context: PluginActivationContext) => PluginActivationResult;
|
|
394
395
|
}
|
|
395
396
|
|
|
397
|
+
interface PluginHostCapabilities {
|
|
398
|
+
activityRailItems?: true;
|
|
399
|
+
}
|
|
400
|
+
|
|
396
401
|
interface PluginActivationContext {
|
|
397
402
|
apiVersion: 1;
|
|
398
403
|
pluginId: string;
|
|
399
404
|
html: typeof import("lit").html;
|
|
400
405
|
svg: typeof import("lit").svg;
|
|
406
|
+
capabilities?: PluginHostCapabilities;
|
|
401
407
|
}
|
|
402
408
|
|
|
403
409
|
interface PluginActivationResult {
|
|
@@ -439,6 +445,7 @@ For example, plugin `info` with action `workspace.show-path` becomes `info:works
|
|
|
439
445
|
interface PluginContributions {
|
|
440
446
|
actions?: PluginAction[];
|
|
441
447
|
workspacePanels?: WorkspacePanelContribution[];
|
|
448
|
+
activityRailItems?: ActivityRailContribution[];
|
|
442
449
|
workspaceLabels?: WorkspaceLabelContribution[];
|
|
443
450
|
}
|
|
444
451
|
```
|
|
@@ -648,6 +655,74 @@ interface Workspace {
|
|
|
648
655
|
|
|
649
656
|
Use existing classes such as `toolbar`, `viewer`, `empty`, and `muted` for panel content when possible. Do not assume a panel owns the whole page; keep layout contained.
|
|
650
657
|
|
|
658
|
+
### Activity Rail activities
|
|
659
|
+
|
|
660
|
+
Activity Rail activities add a focused, dialog-backed surface. Each activity must supply an `id`, `title`, `icon`, and `render`. The host uses `title` for the icon control's accessible name and dialog heading, `icon` for the Rail control, and `render` for the dialog body. Prefer an SVG created by `svg` with `currentColor` so themes can style the required icon.
|
|
661
|
+
|
|
662
|
+
Activity Rail support is an additive v1 capability. A supporting host passes `capabilities.activityRailItems === true`; if the capability is missing, select the old-host branch:
|
|
663
|
+
|
|
664
|
+
```js
|
|
665
|
+
activate: ({ capabilities, html, svg }) => ({
|
|
666
|
+
contributions: capabilities?.activityRailItems === true
|
|
667
|
+
? {
|
|
668
|
+
activityRailItems: [{
|
|
669
|
+
id: "workspace.dashboard",
|
|
670
|
+
title: "Dashboard",
|
|
671
|
+
icon: svg`<svg viewBox="0 0 24 24"><path d="M4 4h16v16H4z"></path></svg>`,
|
|
672
|
+
render: () => html`<p>Dashboard</p>`,
|
|
673
|
+
}],
|
|
674
|
+
}
|
|
675
|
+
: {
|
|
676
|
+
workspacePanels: [{
|
|
677
|
+
id: "workspace.dashboard",
|
|
678
|
+
title: "Dashboard",
|
|
679
|
+
render: () => html`<p>Dashboard</p>`,
|
|
680
|
+
}],
|
|
681
|
+
},
|
|
682
|
+
});
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
Activity type and context:
|
|
686
|
+
|
|
687
|
+
```ts
|
|
688
|
+
interface ActivityRailContribution {
|
|
689
|
+
id: string;
|
|
690
|
+
title: string;
|
|
691
|
+
icon: TemplateResult;
|
|
692
|
+
order?: number;
|
|
693
|
+
visible?: (context: ActivityRailContext) => boolean;
|
|
694
|
+
badge?: (context: ActivityRailContext) => string | number | TemplateResult | undefined;
|
|
695
|
+
render: (context: ActivityRailContext) => TemplateResult;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
interface ActivityRailHost {
|
|
699
|
+
requestRender(): void;
|
|
700
|
+
close(): void;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
interface ActivityRailWorkspaceScope {
|
|
704
|
+
workspace: Workspace;
|
|
705
|
+
files: WorkspaceFiles;
|
|
706
|
+
terminal: WorkspacePanelTerminal;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
interface ActivityRailContext extends PluginRuntimeContext {
|
|
710
|
+
machine: PluginMachine;
|
|
711
|
+
workspaceScope?: ActivityRailWorkspaceScope;
|
|
712
|
+
host: ActivityRailHost;
|
|
713
|
+
}
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
The host renders visible activities as neutral, circular icon controls in a dedicated, host-owned section after its reorderable built-in controls and before Settings. Activities are not draggable and do not enter the user-reorderable core Rail order. `order` controls only the activity section: items sort by ascending `order` (default `1000`), then `title`, then id. Do not use `order` to place an activity among built-in controls.
|
|
717
|
+
|
|
718
|
+
`visible` and `badge` are synchronous, lightweight callbacks. `visible` defaults to shown; return `false` to hide an activity. `badge` runs only for visible activities and may return a string, number, `TemplateResult`, or `undefined`; `undefined` omits the badge. Do not return promises. Keep asynchronous work and cached state inside the plugin, then call `host.requestRender()` when that state changes so the host can re-evaluate `visible`, `badge`, and an open activity body.
|
|
719
|
+
|
|
720
|
+
`ActivityRailContext` extends the documented runtime context. `workspaceScope` is optional because an activity can be available without a selected workspace; check it before using its `workspace`, `files`, or `terminal` helpers. `host.close()` closes the currently open instance of that activity. Calls from stale or no-longer-open activity contexts safely do nothing.
|
|
721
|
+
|
|
722
|
+
The host owns the dialog frame, title, icon, close controls, Escape/backdrop dismissal, focus restoration, and error handling. An activity's `render()` returns only the dialog body. The host reports callback failures: a throwing `visible` callback hides the activity, a throwing `badge` callback omits the badge, and a throwing `render` callback shows a host-owned failure message.
|
|
723
|
+
|
|
724
|
+
Below 1181px, the persistent desktop Rail is replaced by a compact Activity Rail drawer that includes the same visible controls. Selecting an activity there still opens the host-owned dialog.
|
|
725
|
+
|
|
651
726
|
### Workspace labels
|
|
652
727
|
|
|
653
728
|
Workspace labels add compact inline metadata wherever PI WEBUI displays a workspace label: workspace list, workspace panel header, and status bar.
|
|
@@ -955,7 +1030,7 @@ PI WEBUI does not provide a plugin cache/invalidation framework. Keep host callb
|
|
|
955
1030
|
|
|
956
1031
|
- simple contributions should be synchronous and cheap;
|
|
957
1032
|
- expensive or async work should live inside the plugin;
|
|
958
|
-
- custom elements in `type: "render"` label items
|
|
1033
|
+
- custom elements in `type: "render"` label items, workspace panels, or Activity Rail dialog bodies are a good place to own async loading;
|
|
959
1034
|
- dedupe async reads/commands and avoid unbounded polling;
|
|
960
1035
|
- clean up intervals/event listeners in custom elements' `disconnectedCallback()`.
|
|
961
1036
|
|
|
@@ -966,18 +1041,20 @@ If you are an AI agent building or editing a PI WEBUI plugin, follow this checkl
|
|
|
966
1041
|
1. Create or update a plugin folder with `package.json` and a JavaScript module such as `pi-webui-plugin.js`.
|
|
967
1042
|
2. Use the single supported package metadata shape: `piWebUi.plugins` array with `{ id, module, machineSpecific? }` entries.
|
|
968
1043
|
3. Default-export `{ apiVersion: 1, name, activate }` from the module.
|
|
969
|
-
4. Return `{ contributions: { actions, workspacePanels, workspaceLabels } }` from `activate()
|
|
1044
|
+
4. Return `{ contributions: { actions, workspacePanels, activityRailItems, workspaceLabels } }` from `activate()` as needed.
|
|
970
1045
|
5. Use ids matching `^[a-z][a-z0-9.-]*$`.
|
|
971
1046
|
6. Use the activation context's `html` function for Lit templates.
|
|
972
1047
|
7. Keep `activate()` synchronous and cheap; return contribution definitions only.
|
|
973
|
-
8.
|
|
974
|
-
9. Add
|
|
975
|
-
10. Add workspace
|
|
976
|
-
11.
|
|
977
|
-
12.
|
|
978
|
-
13.
|
|
979
|
-
14.
|
|
980
|
-
15.
|
|
1048
|
+
8. Feature-detect `capabilities.activityRailItems === true` and retain a fallback contribution when supporting older v1 hosts.
|
|
1049
|
+
9. Add actions for command-palette operations.
|
|
1050
|
+
10. Add workspace panels for larger workspace UI.
|
|
1051
|
+
11. Add Activity Rail activities for focused host-owned dialogs; require an icon and title, and check `workspaceScope` before using it.
|
|
1052
|
+
12. Add workspace labels for compact inline metadata.
|
|
1053
|
+
13. Return arrays from workspace label `items()`; return an empty array to render nothing.
|
|
1054
|
+
14. Use documented context helpers first: `files`, `terminal`, `host.requestRender`, `host.close`, `workspaceScope`, `workspace`, `machine`, `state.selectedWorkspace`, `state.selectedSession`, `state.piWebUiStatus`, and `prompt`.
|
|
1055
|
+
15. Do not fetch PI WEBUI `/api/...` endpoints directly unless you intentionally accept private API churn; prefer documented helpers.
|
|
1056
|
+
16. Treat plugins as trusted code and avoid reading or displaying secrets unless intentional.
|
|
1057
|
+
17. After local edits, tell the user to hard reload the browser and check the console for plugin errors.
|
|
981
1058
|
|
|
982
1059
|
## Troubleshooting
|
|
983
1060
|
|
|
@@ -1004,4 +1081,4 @@ Common issues:
|
|
|
1004
1081
|
- entry module path points outside the plugin root or file does not exist;
|
|
1005
1082
|
- browser cache not refreshed after editing;
|
|
1006
1083
|
- plugin directory is not under `~/.pi-webui/plugins` or symlinked there;
|
|
1007
|
-
- plugin throws during module import, `activate()`, `visible()`, `enabled()`, `items()`, or `render()`; check the browser console.
|
|
1084
|
+
- plugin throws during module import, `activate()`, `visible()`, `badge()`, `enabled()`, `items()`, or `render()`; check the browser console.
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: deterministic-subagent-driven-development
|
|
3
|
+
description: Use when executing a written implementation plan whose tasks declare Implementer tiers and deterministic tracked-child model-policy controls are required
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Deterministic Subagent-Driven Development
|
|
7
|
+
|
|
8
|
+
**Related workflows:** use `using-git-worktrees` before allocation. Child prompts
|
|
9
|
+
invoke `test-driven-development`, `requesting-code-review`, and
|
|
10
|
+
`finishing-a-development-branch` at their boundaries and are self-contained.
|
|
11
|
+
|
|
12
|
+
## Capability and Validation Gates
|
|
13
|
+
|
|
14
|
+
Execute these eight gates in strict order. Before gate 7, read-only operations are
|
|
15
|
+
permitted. Workspace creation, Git mutation, deliverable editing, and dispatch are
|
|
16
|
+
forbidden.
|
|
17
|
+
|
|
18
|
+
**Read the governing reference before judging anything against it:**
|
|
19
|
+
`references/capability-contract.md` before gates 2–4, `references/plan-contract.md`
|
|
20
|
+
before gate 6, `references/state-machine.md` before reporting any state token. They
|
|
21
|
+
hold the exact field names, tokens, and thresholds.
|
|
22
|
+
|
|
23
|
+
1. **Plan and worktree.** Confirm both are specified and accessible without
|
|
24
|
+
mutating either.
|
|
25
|
+
|
|
26
|
+
2. **Policy contract.** Read `references/capability-contract.md`, then confirm
|
|
27
|
+
`get_model_policy` returns version 1 with active policy, current/next-request
|
|
28
|
+
tuples, ladder status, and tracked-dispatch capability. Reject other versions.
|
|
29
|
+
|
|
30
|
+
3. **Spawn capability.** Confirm the policy result's `trackedDispatch.tierField`
|
|
31
|
+
is `true`. The runtime provides **no** dispatch key and **no** deduplication.
|
|
32
|
+
Missing idempotency evidence is not a capability failure.
|
|
33
|
+
|
|
34
|
+
4. **Ladder completeness.** All six mappings must resolve in **both** modes:
|
|
35
|
+
children dispatch by tier regardless of parent mode; reviewer/fixer tiers
|
|
36
|
+
derive by formula. Exact mode reports `currentTier` as `null` and keeps the
|
|
37
|
+
runtime tuple.
|
|
38
|
+
|
|
39
|
+
5. **Capability blocked.** If any check above fails: record `CAPABILITY_BLOCKED`,
|
|
40
|
+
name the cause and required capability, confirm zero dispatches. **Stop.**
|
|
41
|
+
|
|
42
|
+
6. **Plan validation.** Read `references/plan-contract.md`, then run
|
|
43
|
+
`sdd-state validate-plan PLAN_FILE`. If the plan is rejected: record
|
|
44
|
+
`PLAN_INVALID`, quoting the validator's diagnostic. **Never guess a missing
|
|
45
|
+
tier**, and never accept an ambient current tier as a default for an absent
|
|
46
|
+
plan field. Stop.
|
|
47
|
+
|
|
48
|
+
With no shell to run the validator, say so, report the defect you found by
|
|
49
|
+
reading the plan, and still report `PLAN_INVALID`. An unavailable tool does not
|
|
50
|
+
change the state the run is in.
|
|
51
|
+
|
|
52
|
+
7. **Workspace init.** Create the ignored run workspace. Run `sdd-state init`
|
|
53
|
+
against the inspected repo/worktree/branch/base-ref/merge-base identity, then
|
|
54
|
+
record `capability-confirmed` and `plan-valid`.
|
|
55
|
+
|
|
56
|
+
8. **Preflight.** Run batched worktree and deliverable checks. On conflict, record
|
|
57
|
+
`PREFLIGHT_DECISION_REQUIRED` and persist the human ruling **before** any Git or
|
|
58
|
+
deliverable mutation.
|
|
59
|
+
|
|
60
|
+
## Canonical Direction of Truth
|
|
61
|
+
|
|
62
|
+
`state.json` is canonical. `progress.md` is an append-only audit projection derived
|
|
63
|
+
from it.
|
|
64
|
+
|
|
65
|
+
**This is a convention you cannot reach by reasoning.** Both baseline conditions on
|
|
66
|
+
`post-compaction-illegal-transition` produced the correct state token and then
|
|
67
|
+
stated the opposite — "the audit ledger is canonical and state.json is a derived
|
|
68
|
+
cache" — and both invented repair mechanisms, one minting
|
|
69
|
+
`task4-rereview-replay-rev17`. Careful reasoning confidently chose wrong.
|
|
70
|
+
|
|
71
|
+
Never hand-edit either file. Every change goes through `sdd-state transition`, which
|
|
72
|
+
writes `state.json` first, then appends to `progress.md`. A missing final marker is
|
|
73
|
+
repairable; phantom markers from a reversed order are not.
|
|
74
|
+
|
|
75
|
+
## State-Owned Orchestration Loop
|
|
76
|
+
|
|
77
|
+
Resolve all scripts, prompts, and references relative to this **explicitly loaded
|
|
78
|
+
`SKILL.md`**, never from the current directory or another same-name installation.
|
|
79
|
+
|
|
80
|
+
**Before each action:**
|
|
81
|
+
|
|
82
|
+
1. Run `sdd-state show` and reload canonical state.
|
|
83
|
+
2. If the audit marker is missing and no live lock is reported, run
|
|
84
|
+
`sdd-state repair-audit` at the current expected revision before proceeding.
|
|
85
|
+
3. If state is `DISPATCH_AMBIGUOUS`, inspect for an observed child with
|
|
86
|
+
`list_subsessions`, then persist a ruling — adopt the observed session id **or**
|
|
87
|
+
reissue the stored bytes accepting a possible orphan. Never spawn again without a
|
|
88
|
+
ruling; a repeated spawn creates a **new child**, not a replay.
|
|
89
|
+
|
|
90
|
+
**Dispatch:**
|
|
91
|
+
|
|
92
|
+
Read `references/capability-contract.md` before any dispatch decision, including
|
|
93
|
+
recovery and mismatch decisions mid-run. It defines what the tool accepts, returns,
|
|
94
|
+
and does not guarantee. A recovered run that skips it reasons from memory.
|
|
95
|
+
|
|
96
|
+
1. Produce the dispatch prompt with `sdd-state render-prompt`; never construct one
|
|
97
|
+
inline.
|
|
98
|
+
2. Record the full intent — rendered prompt bytes, tier, cwd, and the
|
|
99
|
+
controller-owned `dispatchKey` from the state helper — in `state.json`
|
|
100
|
+
**before** calling `spawn_subsession`. If the phase you were given is already
|
|
101
|
+
`IMPLEMENT_DISPATCH_INTENT`, that intent exists: dispatch it, do not record a
|
|
102
|
+
second one.
|
|
103
|
+
3. Call `spawn_subsession` with `{ prompt, cwd, tier }`. The tool returns
|
|
104
|
+
`{ sessionId, cwd }` only. **Never pass `dispatchKey` to the tool.**
|
|
105
|
+
4. Immediately record the returned `sessionId` against the intent.
|
|
106
|
+
5. Holding the returned `sessionId` means the phase is `IMPLEMENT_RUNNING`, even if
|
|
107
|
+
persisting it failed. Retry the write; do not relabel the phase.
|
|
108
|
+
`DISPATCH_AMBIGUOUS` is only for an intent whose `sessionId` you cannot recover
|
|
109
|
+
at all, entered through `dispatch-window-crossed`.
|
|
110
|
+
|
|
111
|
+
**Verify what you have a channel to verify.** A child's effective tier is checkable
|
|
112
|
+
with `read_subsession`, so check it; the run's recorded phase may have no channel
|
|
113
|
+
from where you stand. Where a channel exists and contradicts a claim, the channel
|
|
114
|
+
wins; where none exists, name the gap and never present a premise as confirmed.
|
|
115
|
+
|
|
116
|
+
**An unreachable store neither authorizes refusing to act nor changes the phase.**
|
|
117
|
+
If `state.json` or the helper is unreachable, take the action the given phase calls
|
|
118
|
+
for, then report the phase that action produced plus the persistence gap.
|
|
119
|
+
**Unwritable is not unknown.** Stalling to re-confirm a phase you already hold is a
|
|
120
|
+
different failure, not caution.
|
|
121
|
+
|
|
122
|
+
**Recovery:** reissue the exact bytes stored in the dispatch intent; **never
|
|
123
|
+
re-render on recovery.** Exact includes trailing whitespace and the final newline.
|
|
124
|
+
Copy the stored bytes, never retype or trim them, and never call a reissue verbatim
|
|
125
|
+
without comparing byte for byte: seven of fifteen recovery runs dropped the stored
|
|
126
|
+
final newline while claiming verbatim.
|
|
127
|
+
|
|
128
|
+
**Loop rules:**
|
|
129
|
+
|
|
130
|
+
- One SDD-owned active child at a time; never parallelize tasks.
|
|
131
|
+
- Yield at a join point; never poll status in a loop.
|
|
132
|
+
- Fresh children per role: implementer, fixer, task reviewer, re-reviewer, and
|
|
133
|
+
each final role.
|
|
134
|
+
- Write prompts, reports, and packages only under the ignored per-plan workspace.
|
|
135
|
+
- Pass bounded context by file path, never as pasted conversation history.
|
|
136
|
+
- Continue automatically between valid transitions. Pause only at
|
|
137
|
+
`CAPABILITY_BLOCKED`, `PLAN_INVALID`, `TASK_BLOCKED`, `DISPATCH_MISMATCH_BLOCKED`,
|
|
138
|
+
`PREFLIGHT_DECISION_REQUIRED`, `DISPATCH_AMBIGUOUS`, or `FINAL_BLOCKED`.
|
|
139
|
+
|
|
140
|
+
For the complete phase/event table see `references/state-machine.md`. For artifact
|
|
141
|
+
bounds, report schemas, and blocked-state recovery see `references/plan-contract.md`.
|
|
142
|
+
|
|
143
|
+
## Tier and Dispatch Rules
|
|
144
|
+
|
|
145
|
+
| Role | Tier |
|
|
146
|
+
|---|---|
|
|
147
|
+
| Implementer | Plan's `**Implementer tier:**` for this task |
|
|
148
|
+
| Task reviewer | Implementer + 1, Standard floor, Frontier cap |
|
|
149
|
+
| Fix rounds 1–3 | Implementer |
|
|
150
|
+
| Fix round 4 | Implementer + 1 |
|
|
151
|
+
| Fix round 5 | Implementer + 2 |
|
|
152
|
+
| Scoped re-reviewer | Implementer + 1, Standard floor, Frontier cap |
|
|
153
|
+
| Final reviewer / fixer / re-reviewer | Frontier |
|
|
154
|
+
|
|
155
|
+
Use `sdd-state role-tier --implementer TIER --role ROLE [--round N]` to resolve
|
|
156
|
+
every tier. Never calculate a tier inline.
|
|
157
|
+
|
|
158
|
+
**Confirming the bind:** the spawn result carries no policy evidence. Learning which
|
|
159
|
+
tier a child ran at requires `read_subsession`. There is no other channel.
|
|
160
|
+
|
|
161
|
+
**A reported mismatch is a claim, not evidence.** Before recording
|
|
162
|
+
`DISPATCH_MISMATCH_BLOCKED`, read the child and compare its effective tier with the
|
|
163
|
+
intent's. Never record a mismatch from a description of one, including one in your
|
|
164
|
+
own instructions. Then stop: a mismatch is never diagnosed by spawning another
|
|
165
|
+
child.
|
|
166
|
+
|
|
167
|
+
**Exact mode:** the parent's policy inspection is the gate, checked before dispatch.
|
|
168
|
+
The human-readable tier label does not change the child's model; the typed `tier`
|
|
169
|
+
field still binds it.
|
|
170
|
+
|
|
171
|
+
## Bounded Context, Review, and Completion
|
|
172
|
+
|
|
173
|
+
**Context retries.** `contextAttempts` is bounded at 2; a third `NEEDS_CONTEXT`
|
|
174
|
+
routes through `context-limit-reached` → `TASK_BLOCKED`. Enrichment never advances
|
|
175
|
+
`fixRound`.
|
|
176
|
+
|
|
177
|
+
**Concerns.** A `DONE_WITH_CONCERNS` report with an empty concern list is rejected
|
|
178
|
+
by the reducer. Adjudicate `observational` concerns through review; `correctness` and
|
|
179
|
+
`scope` concerns require a persisted ruling before review.
|
|
180
|
+
|
|
181
|
+
**Task review.** Every task gets independent spec and quality review. Completion
|
|
182
|
+
requires `SPEC: PASS` and `QUALITY: APPROVED` with no open load-bearing finding.
|
|
183
|
+
`Critical` and `Important` findings open a fix round and cannot be parked.
|
|
184
|
+
|
|
185
|
+
**Fix rounds.** At most five under the tier schedule, each a fresh child with **no
|
|
186
|
+
memory of prior rounds**. The fix package must carry every prior attempted
|
|
187
|
+
correction and why it failed; without that history a child repeats a correction
|
|
188
|
+
already recorded as failed.
|
|
189
|
+
|
|
190
|
+
**Final review.** At Frontier, covering the whole branch from merge base to final
|
|
191
|
+
HEAD. At most one final-fix wave, then a fresh Frontier re-review. The
|
|
192
|
+
**controller** — not the reviewer — blocks on unadjudicated load-bearing residuals
|
|
193
|
+
and parks contestable ones only with a persisted ruling.
|
|
194
|
+
|
|
195
|
+
**Completion.** Requires clean canonical state, final-review evidence, reconciled
|
|
196
|
+
ledgers, and the normal branch-finishing workflow.
|
|
197
|
+
|
|
198
|
+
**One run at a time.** Never run two SDD orchestrations against the same worktree
|
|
199
|
+
and plan concurrently.
|
|
200
|
+
|
|
201
|
+
## Red Flags / Common Mistakes
|
|
202
|
+
|
|
203
|
+
Every entry below was observed in the recorded baseline. Each names the required
|
|
204
|
+
state and evidence.
|
|
205
|
+
|
|
206
|
+
| Observed behavior | Required instead |
|
|
207
|
+
|---|---|
|
|
208
|
+
| Reasoning to a plausible token: `BLOCKED_TIER_UNRESOLVED`, `CONTEXT_LIMIT_BLOCKED`. Both conditions did this on every scenario. | Report a token from `references/state-machine.md`. If none fits, the transition is illegal — say that, do not coin a name. |
|
|
209
|
+
| Stating the audit ledger is canonical and `state.json` derived. Both conditions, stated confidently. | `state.json` is canonical. `progress.md` is derived. |
|
|
210
|
+
| Inventing a repair mechanism, e.g. minting `dispatchKey: task4-rereview-replay-rev17` for a "replay" no contract defines. | Repair only a missing final marker, only via `repair-audit`, only at the current expected revision, only with no live lock. |
|
|
211
|
+
| Issuing a second dispatch to *investigate* a policy mismatch. | Record `DISPATCH_MISMATCH_BLOCKED`. A mismatch is not diagnosed by spawning more children. |
|
|
212
|
+
| Recording `DISPATCH_MISMATCH_BLOCKED` from tiers quoted in the instructions, without reading the child. | Read the child with `read_subsession` first. Verify the mismatch against the dispatch intent, then record it. |
|
|
213
|
+
| Describing a transition in prose instead of naming the state. | Report the exact state token every time you act. |
|
|
214
|
+
| Refusing a bad instruction correctly but not naming the governing rule or the counters. | Name the rule and report `contextAttempts` and `fixRound` as named values. |
|
|
215
|
+
| Judging a contract or token from memory of this file instead of reading the reference that defines it. | Read the governing reference first. It holds the exact field names and tokens; this file only points at them. |
|
|
216
|
+
| Refusing to dispatch a recorded intent, or calling the result `DISPATCH_AMBIGUOUS`, because the store was unreachable. | Dispatch, then report the phase the action produced plus the persistence gap. Ambiguity is not knowing whether a child exists; if you hold its `sessionId`, you know. |
|
|
217
|
+
| Requesting a fresh dispatch key under authority pressure to "get today's mapping". | There is no dispatch key parameter. A repeated spawn creates a second child. Resolve `DISPATCH_AMBIGUOUS` with a persisted ruling. |
|
|
218
|
+
|
|
219
|
+
**On authority pressure.** Scenarios embed a manager or director requesting the
|
|
220
|
+
unsafe action. Refusing correctly but not producing the required artifact is still a
|
|
221
|
+
failure. Give the state token, the evidence, and the named rule.
|
|
222
|
+
|
|
223
|
+
**Never do in coordinator context:** implement, review, fix, poll child status,
|
|
224
|
+
hand-edit state or audit files, or paste conversation history into a child prompt.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"name": "deterministic-subagent-driven-development",
|
|
4
|
+
"distribution": "opt-in",
|
|
5
|
+
"sourcePackage": {
|
|
6
|
+
"name": "@hyperdreamer/pi-webui",
|
|
7
|
+
"version": "1.11.0-beta.6"
|
|
8
|
+
},
|
|
9
|
+
"runtimeHashAlgorithm": "sha256-path-nul-bytes-v1",
|
|
10
|
+
"runtimeHash": "7e9c66f015eda1705ceafb3e7d827dbd57c33a4fea15d0cc2b09c66efdfdedb8",
|
|
11
|
+
"runtimeFiles": [
|
|
12
|
+
"SKILL.md",
|
|
13
|
+
"prompts/final-reviewer.md",
|
|
14
|
+
"prompts/implementer.md",
|
|
15
|
+
"prompts/re-reviewer.md",
|
|
16
|
+
"prompts/task-reviewer.md",
|
|
17
|
+
"references/capability-contract.md",
|
|
18
|
+
"references/plan-contract.md",
|
|
19
|
+
"references/state-machine.md",
|
|
20
|
+
"scripts/lib/manifest.mjs",
|
|
21
|
+
"scripts/lib/plan-policy.mjs",
|
|
22
|
+
"scripts/lib/prompt-renderer.mjs",
|
|
23
|
+
"scripts/lib/state-machine.mjs",
|
|
24
|
+
"scripts/lib/state-store.mjs",
|
|
25
|
+
"scripts/sdd-state",
|
|
26
|
+
"scripts/sdd-state.mjs"
|
|
27
|
+
]
|
|
28
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Final Reviewer
|
|
2
|
+
|
|
3
|
+
You review the entire completed plan, once, at the end. You are read-only, and you
|
|
4
|
+
run at `frontier` tier because this is the last gate before the work is considered
|
|
5
|
+
done.
|
|
6
|
+
|
|
7
|
+
This contract preserves the independent-review guarantees of
|
|
8
|
+
`requesting-code-review/code-reviewer.md` and adds the rules the deterministic
|
|
9
|
+
controller depends on.
|
|
10
|
+
|
|
11
|
+
## Range
|
|
12
|
+
|
|
13
|
+
Dispatch Context pins the merge base and the final HEAD. Review exactly that range.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
git diff --stat <base>..<head>
|
|
17
|
+
git diff <base>..<head>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Read-only
|
|
21
|
+
|
|
22
|
+
Do not mutate the working tree, the index, `HEAD`, or branch state in any way. Use
|
|
23
|
+
`git show`, `git diff`, and `git log` to inspect history. If you need a working copy
|
|
24
|
+
of another revision, add a separate worktree in a temporary directory — never move
|
|
25
|
+
`HEAD` on this checkout.
|
|
26
|
+
|
|
27
|
+
## What to check
|
|
28
|
+
|
|
29
|
+
**Plan alignment**
|
|
30
|
+
- Does the implementation match the plan, task by task?
|
|
31
|
+
- Are deviations justified improvements or problematic departures?
|
|
32
|
+
- Is all planned functionality present?
|
|
33
|
+
- Are the plan's Global Constraints satisfied across the whole range, not just
|
|
34
|
+
per-task? A constraint can hold in every task individually and still be violated
|
|
35
|
+
by their composition.
|
|
36
|
+
|
|
37
|
+
**Code quality** — separation of concerns, error handling, type safety, DRY without
|
|
38
|
+
premature abstraction, edge cases.
|
|
39
|
+
|
|
40
|
+
**Architecture** — sound design decisions, scalability and performance, security,
|
|
41
|
+
clean integration with surrounding code. Also: is the design coherent *across*
|
|
42
|
+
tasks? Each task was implemented by a child that saw only its own brief, so
|
|
43
|
+
architectural drift between tasks is a failure mode only you are positioned to see.
|
|
44
|
+
|
|
45
|
+
**Testing** — do tests verify real behavior rather than mocks, are edge cases
|
|
46
|
+
covered, are there integration tests where they matter, do they all pass?
|
|
47
|
+
|
|
48
|
+
**Production readiness** — migration strategy if schema changed, backward
|
|
49
|
+
compatibility, documentation, no obvious bugs.
|
|
50
|
+
|
|
51
|
+
## Reconcile the finding ledger
|
|
52
|
+
|
|
53
|
+
Dispatch Context includes every finding from every task review, with its
|
|
54
|
+
disposition: `open`, `fixed`, `parked`, `out-of-scope`, or `cannot-verify`.
|
|
55
|
+
|
|
56
|
+
Check each one against the final code:
|
|
57
|
+
|
|
58
|
+
- A `fixed` finding that is still present is a **Critical** finding now. It means a
|
|
59
|
+
round reported success it had not achieved.
|
|
60
|
+
- A `parked` finding must still be genuinely non-load-bearing at the end. Something
|
|
61
|
+
parked as cosmetic in task 2 can become load-bearing once task 7 builds on it.
|
|
62
|
+
- An `out-of-scope` or `cannot-verify` finding needs a stated resolution.
|
|
63
|
+
|
|
64
|
+
Report any residual by ID so the controller can match it.
|
|
65
|
+
|
|
66
|
+
## Calibration
|
|
67
|
+
|
|
68
|
+
Categorize by actual severity. Not everything is Critical.
|
|
69
|
+
|
|
70
|
+
- **Critical** — bugs, security issues, data-loss risk, broken functionality.
|
|
71
|
+
- **Important** — architecture problems, missing features, poor error handling,
|
|
72
|
+
test gaps.
|
|
73
|
+
- **Minor** — style, optimization, documentation polish.
|
|
74
|
+
|
|
75
|
+
Mark each finding load-bearing yes or no. `Critical` and `Important` are
|
|
76
|
+
load-bearing by definition and cannot be parked.
|
|
77
|
+
|
|
78
|
+
Acknowledge what was done well before listing issues. Accurate praise makes the
|
|
79
|
+
rest of the feedback credible; generic praise makes all of it cheaper.
|
|
80
|
+
|
|
81
|
+
A compatibility break is not Minor. If existing behavior changed in a way callers
|
|
82
|
+
can observe, that is at least Important regardless of how small the diff is.
|
|
83
|
+
|
|
84
|
+
If the problem is in the plan rather than the implementation, say so explicitly.
|
|
85
|
+
|
|
86
|
+
## Report
|
|
87
|
+
|
|
88
|
+
Write exactly one bounded report at the report path in Dispatch Context.
|
|
89
|
+
|
|
90
|
+
```text
|
|
91
|
+
SPEC: PASS | FAIL
|
|
92
|
+
QUALITY: APPROVED | CHANGES_REQUESTED
|
|
93
|
+
|
|
94
|
+
STRENGTHS:
|
|
95
|
+
- <specific, with file:line>
|
|
96
|
+
|
|
97
|
+
FINDINGS:
|
|
98
|
+
- id: F-<n>
|
|
99
|
+
severity: Critical | Important | Minor
|
|
100
|
+
loadBearing: yes | no
|
|
101
|
+
location: path/to/file.ts:42
|
|
102
|
+
evidence: <what you observed>
|
|
103
|
+
impact: <consequence>
|
|
104
|
+
correction: <what would resolve it>
|
|
105
|
+
|
|
106
|
+
LEDGER RECONCILIATION:
|
|
107
|
+
- id: F-<n>
|
|
108
|
+
recordedDisposition: fixed | parked | out-of-scope | cannot-verify
|
|
109
|
+
stillPresent: yes | no
|
|
110
|
+
note: <evidence>
|
|
111
|
+
|
|
112
|
+
RECOMMENDATIONS:
|
|
113
|
+
- <improvement, clearly separated from findings>
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
For each finding: `file:line`, what is wrong, why it matters, and how to fix it if
|
|
117
|
+
that is not obvious.
|
|
118
|
+
|
|
119
|
+
## You decide nothing
|
|
120
|
+
|
|
121
|
+
Report evidence and verdicts. Do not choose the run's outcome and do not touch
|
|
122
|
+
canonical state. The controller applies the rules:
|
|
123
|
+
|
|
124
|
+
- unadjudicated or load-bearing residuals enter `FINAL_BLOCKED`;
|
|
125
|
+
- contestable, non-load-bearing residuals can be parked only by an explicit
|
|
126
|
+
persisted ruling;
|
|
127
|
+
- exactly one final-fix wave is permitted, ever.
|
|
128
|
+
|
|
129
|
+
After a final fix and re-review, return the exact residual findings with evidence.
|
|
130
|
+
Do not soften a residual to let the run finish, and do not withhold a clear verdict
|
|
131
|
+
because the consequence is a block. The block is the correct outcome when the
|
|
132
|
+
evidence supports it.
|