gentle-pi 0.10.8 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/agents/sdd-apply.md +4 -4
- package/assets/agents/sdd-archive.md +3 -3
- package/assets/agents/sdd-design.md +2 -2
- package/assets/agents/sdd-explore.md +2 -2
- package/assets/agents/sdd-init.md +2 -2
- package/assets/agents/sdd-onboard.md +2 -2
- package/assets/agents/sdd-proposal.md +2 -2
- package/assets/agents/sdd-spec.md +2 -2
- package/assets/agents/sdd-status.md +4 -3
- package/assets/agents/sdd-sync.md +2 -2
- package/assets/agents/sdd-tasks.md +2 -2
- package/assets/agents/sdd-verify.md +3 -3
- package/assets/orchestrator.md +10 -150
- package/assets/sdd-orchestrator-workflow.md +153 -0
- package/assets/support/sdd-status-contract.md +1 -1
- package/extensions/gentle-ai.ts +9 -17
- package/extensions/skill-registry.ts +21 -13
- package/lib/sdd-preflight.ts +1 -6
- package/lib/sdd-status.ts +2 -2
- package/package.json +1 -1
- package/tests/artifact-language.test.ts +21 -5
- package/tests/runtime-harness.mjs +19 -0
- package/tests/skill-registry.test.ts +31 -1
|
@@ -26,15 +26,15 @@ If skill paths are missing, explicit fallback loading is allowed only as degrade
|
|
|
26
26
|
|
|
27
27
|
Read your own input artifacts directly from the active backend before doing the phase work; do not wait for the parent to inline them. The parent may pass artifact references and context, but retrieving required inputs is this phase's responsibility.
|
|
28
28
|
|
|
29
|
-
Inputs to read (`engram`/`both`:
|
|
29
|
+
Inputs to read (`engram`/`both`: use the injected Engram memory read tools for the topic key, then fetch the full observation; `openspec`: read the file under `openspec/changes/{change}/`):
|
|
30
30
|
- Tasks (required): `sdd/{change}/tasks`
|
|
31
31
|
- Spec (required): `sdd/{change}/spec`
|
|
32
32
|
- Design (required): `sdd/{change}/design`
|
|
33
33
|
- Previous apply-progress (if it exists): `sdd/{change}/apply-progress` — read and MERGE with your new progress; do NOT overwrite.
|
|
34
34
|
|
|
35
35
|
Persist this phase's artifact to the active backend before returning (mandatory):
|
|
36
|
-
- `engram`/`both`: call
|
|
37
|
-
- Also update the tasks artifact checkboxes via
|
|
36
|
+
- `engram`/`both`: call the injected Engram save tool with title and `topic_key` `"sdd/{change}/apply-progress"`, `type: "architecture"`, `project` from context, and `capture_prompt: false` when the tool schema supports it (omit the field if an older schema rejects it).
|
|
37
|
+
- Also update the tasks artifact checkboxes via the injected Engram update tool (`engram`/`both`) or file edit (`openspec`).
|
|
38
38
|
- `openspec`: write/update the apply-progress and tasks files under `openspec/changes/{change}/`.
|
|
39
39
|
- `none`: return progress inline.
|
|
40
40
|
|
|
@@ -45,7 +45,7 @@ Never claim persistence you did not perform.
|
|
|
45
45
|
Before writing code, consume structured SDD status from the parent prompt. If missing, produce the same fields using this lookup order: project override `.pi/gentle-ai/support/sdd-status-contract.md`, then globally installed `~/.pi/agent/gentle-ai/support/sdd-status-contract.md`, then the embedded status contract. Do not use `assets/support/...` as a runtime path; that is only the package source path before installation.
|
|
46
46
|
|
|
47
47
|
**Non-authoritative store carve-out:** when the native status JSON shows `nextRecommended: "resolve-via-engram"` (covers `artifactStore: engram`, `artifactStore: none`, and `artifactStore: both` without an `openspec/` directory), the status is non-authoritative. Do not treat `applyState`, `dependencies`, or `blockedReasons` from that status as real blockers. Resolve readiness as follows:
|
|
48
|
-
- `engram` (or `both` without openspec/): search Engram for `sdd/{change}/tasks`, `sdd/{change}/spec`, and `sdd/{change}/design` using
|
|
48
|
+
- `engram` (or `both` without openspec/): search Engram for `sdd/{change}/tasks`, `sdd/{change}/spec`, and `sdd/{change}/design` using the Engram memory tools injected by the memory provider. Proceed with implementation once those artifacts are confirmed present.
|
|
49
49
|
- `none`: there is no persistent backend. Return artifacts inline and ask the user to provide required inputs (tasks, spec, design) or acknowledge that no persistent artifact store is available.
|
|
50
50
|
|
|
51
51
|
Stop with `blocked` before editing if:
|
|
@@ -25,11 +25,11 @@ If skill paths are missing, explicit fallback loading is allowed only as degrade
|
|
|
25
25
|
|
|
26
26
|
Read your own input artifacts directly from the active backend before doing the phase work; do not wait for the parent to inline them. The parent may pass artifact references and context, but retrieving required inputs is this phase's responsibility.
|
|
27
27
|
|
|
28
|
-
Inputs to read (`engram`/`both`:
|
|
28
|
+
Inputs to read (`engram`/`both`: use the injected Engram memory read tools for the topic key, then fetch the full observation; `openspec`: read the files under `openspec/changes/{change}/`):
|
|
29
29
|
- All change artifacts: `sdd/{change}/proposal`, `sdd/{change}/spec`, `sdd/{change}/design`, `sdd/{change}/tasks`, `sdd/{change}/apply-progress`, `sdd/{change}/verify-report`, and `sdd/{change}/sync-report` if present.
|
|
30
30
|
|
|
31
31
|
Persist this phase's artifact to the active backend before returning (mandatory):
|
|
32
|
-
- `engram`/`both`: call
|
|
32
|
+
- `engram`/`both`: call the injected Engram save tool with title and `topic_key` `"sdd/{change}/archive-report"`, `type: "architecture"`, `project` from context, and `capture_prompt: false` when the tool schema supports it (omit the field if an older schema rejects it).
|
|
33
33
|
- `openspec`: write the archive report and perform the file moves described in the sections below.
|
|
34
34
|
- `none`: return the archive report inline.
|
|
35
35
|
|
|
@@ -44,7 +44,7 @@ Archive a completed SDD change. In file-backed modes, this requires canonical sp
|
|
|
44
44
|
Before archive work, consume structured SDD status from the parent prompt. If missing, produce the same fields using this lookup order: project override `.pi/gentle-ai/support/sdd-status-contract.md`, then globally installed `~/.pi/agent/gentle-ai/support/sdd-status-contract.md`, then the embedded status contract. Do not use `assets/support/...` as a runtime path; that is only the package source path before installation.
|
|
45
45
|
|
|
46
46
|
**Non-authoritative store carve-out:** when the native status JSON shows `nextRecommended: "resolve-via-engram"` (covers `artifactStore: engram`, `artifactStore: none`, and `artifactStore: both` without an `openspec/` directory), the status is non-authoritative. Do not treat `dependencies` or `blockedReasons` (including `not_applicable` dependency states) from that status as real blockers. Resolve readiness as follows:
|
|
47
|
-
- `engram` (or `both` without openspec/): refer to the Artifact Store Modes section — resolve readiness by checking Engram for `sdd/{change}/verify-report` using
|
|
47
|
+
- `engram` (or `both` without openspec/): refer to the Artifact Store Modes section — resolve readiness by checking Engram for `sdd/{change}/verify-report` using the Engram memory tools injected by the memory provider, then record the archive report in Engram without filesystem sync or folder moves.
|
|
48
48
|
- `none`: there is no persistent backend. Return a closure summary inline and ask the user to confirm that verification has passed before proceeding.
|
|
49
49
|
|
|
50
50
|
Stop with `blocked` if:
|
|
@@ -29,11 +29,11 @@ If skill paths are missing, explicit fallback loading is allowed only as degrade
|
|
|
29
29
|
|
|
30
30
|
Read your own input artifacts directly from the active backend before doing the phase work; do not wait for the parent to inline them. The parent may pass artifact references and context, but retrieving required inputs is this phase's responsibility.
|
|
31
31
|
|
|
32
|
-
Inputs to read (`engram`/`both`:
|
|
32
|
+
Inputs to read (`engram`/`both`: use the injected Engram memory read tools for the topic key, then fetch the full observation; `openspec`: read the file under `openspec/changes/{change}/`):
|
|
33
33
|
- Proposal (required): `sdd/{change}/proposal`
|
|
34
34
|
|
|
35
35
|
Persist this phase's artifact to the active backend before returning (mandatory):
|
|
36
|
-
- `engram`/`both`: call
|
|
36
|
+
- `engram`/`both`: call the injected Engram save tool with title and `topic_key` `"sdd/{change}/design"`, `type: "architecture"`, `project` from context, and `capture_prompt: false` when the tool schema supports it (omit the field if an older schema rejects it).
|
|
37
37
|
- `openspec`: write/update `openspec/changes/{change}/design.md`.
|
|
38
38
|
- `none`: return the design inline.
|
|
39
39
|
|
|
@@ -26,11 +26,11 @@ If skill paths are missing, explicit fallback loading is allowed only as degrade
|
|
|
26
26
|
|
|
27
27
|
Read any input artifacts directly from the active backend before doing the phase work; do not wait for the parent to inline them. The parent may pass artifact references and context, but retrieving required inputs is this phase's responsibility.
|
|
28
28
|
|
|
29
|
-
Inputs to read (`engram`/`both`:
|
|
29
|
+
Inputs to read (`engram`/`both`: use the injected Engram memory read tools for the topic key, then fetch the full observation; `openspec`: read the file under `openspec/changes/{change}/`):
|
|
30
30
|
- None — exploration has no upstream artifacts. If iterating on a prior exploration, read `sdd/{change}/explore`.
|
|
31
31
|
|
|
32
32
|
Persist this phase's artifact to the active backend before returning (mandatory):
|
|
33
|
-
- `engram`/`both`: call
|
|
33
|
+
- `engram`/`both`: call the injected Engram save tool with title and `topic_key` `"sdd/{change}/explore"`, `type: "architecture"`, `project` from context, and `capture_prompt: false` when the tool schema supports it (omit the field if an older schema rejects it).
|
|
34
34
|
- `openspec`: write the exploration file under `openspec/changes/{change}/`.
|
|
35
35
|
- `none`: return the exploration inline.
|
|
36
36
|
|
|
@@ -32,11 +32,11 @@ If skill paths are missing, explicit fallback loading is allowed only as degrade
|
|
|
32
32
|
|
|
33
33
|
Read any existing project context directly from the active backend before bootstrapping; do not wait for the parent to inline it. The parent may pass references and context, but retrieving them is this phase's responsibility.
|
|
34
34
|
|
|
35
|
-
Inputs to read (`engram`/`both`:
|
|
35
|
+
Inputs to read (`engram`/`both`: use the injected Engram memory read tools for the topic key, then fetch the full observation; `openspec`: read the file under `openspec/`):
|
|
36
36
|
- Existing project context (if re-initializing): `sdd-init/{project}`
|
|
37
37
|
|
|
38
38
|
Persist this phase's artifact to the active backend before returning (mandatory):
|
|
39
|
-
- `engram`/`both`: call
|
|
39
|
+
- `engram`/`both`: call the injected Engram save tool with title and `topic_key` `"sdd-init/{project}"`, `type: "architecture"`, `project` from context, and `capture_prompt: false` when the tool schema supports it (omit the field if an older schema rejects it).
|
|
40
40
|
- `openspec`: write the project context file under `openspec/`.
|
|
41
41
|
- `none`: return the project context inline.
|
|
42
42
|
|
|
@@ -32,11 +32,11 @@ If skill paths are missing, explicit fallback loading is allowed only as degrade
|
|
|
32
32
|
|
|
33
33
|
This is a guided walkthrough. For each phase you demonstrate, read that phase's input artifacts directly from the active backend (do not wait for the parent to inline them) and persist the artifact you produce, using the same topic-key scheme as the real phases.
|
|
34
34
|
|
|
35
|
-
Inputs to read (`engram`/`both`:
|
|
35
|
+
Inputs to read (`engram`/`both`: use the injected Engram memory read tools for the topic key, then fetch the full observation; `openspec`: read the file under `openspec/changes/{change}/`):
|
|
36
36
|
- Whichever upstream artifacts the demonstrated step requires, named `sdd/{change}/<phase>` (e.g. `sdd/{change}/proposal`, `sdd/{change}/spec`).
|
|
37
37
|
|
|
38
38
|
Persist each demonstrated artifact to the active backend before moving on (mandatory):
|
|
39
|
-
- `engram`/`both`: call
|
|
39
|
+
- `engram`/`both`: call the injected Engram save tool with title and `topic_key` `"sdd/{change}/<phase>"`, `type: "architecture"`, `project` from context, and `capture_prompt: false` when the tool schema supports it (omit the field if an older schema rejects it).
|
|
40
40
|
- `openspec`: write/update the corresponding file under `openspec/changes/{change}/`.
|
|
41
41
|
- `none`: walk through the artifacts inline.
|
|
42
42
|
|
|
@@ -42,11 +42,11 @@ If skill paths are missing, explicit fallback loading is allowed only as degrade
|
|
|
42
42
|
|
|
43
43
|
Read your own input artifacts directly from the active backend before doing the phase work; do not wait for the parent to inline them. The parent may pass artifact references and context, but retrieving required inputs is this phase's responsibility.
|
|
44
44
|
|
|
45
|
-
Inputs to read (`engram`/`both`:
|
|
45
|
+
Inputs to read (`engram`/`both`: use the injected Engram memory read tools for the topic key, then fetch the full observation; `openspec`: read the file under `openspec/changes/{change}/`):
|
|
46
46
|
- Exploration (optional): `sdd/{change}/explore`
|
|
47
47
|
|
|
48
48
|
Persist this phase's artifact to the active backend before returning (mandatory):
|
|
49
|
-
- `engram`/`both`: call
|
|
49
|
+
- `engram`/`both`: call the injected Engram save tool with title and `topic_key` `"sdd/{change}/proposal"`, `type: "architecture"`, `project` from context, and `capture_prompt: false` when the tool schema supports it (omit the field if an older schema rejects it).
|
|
50
50
|
- `openspec`: write/update `openspec/changes/{change}/proposal.md`.
|
|
51
51
|
- `none`: return the proposal inline.
|
|
52
52
|
|
|
@@ -24,11 +24,11 @@ If skill paths are missing, explicit fallback loading is allowed only as degrade
|
|
|
24
24
|
|
|
25
25
|
Read your own input artifacts directly from the active backend before doing the phase work; do not wait for the parent to inline them. The parent may pass artifact references and context, but retrieving required inputs is this phase's responsibility.
|
|
26
26
|
|
|
27
|
-
Inputs to read (`engram`/`both`:
|
|
27
|
+
Inputs to read (`engram`/`both`: use the injected Engram memory read tools for the topic key, then fetch the full observation; `openspec`: read the file under `openspec/changes/{change}/`):
|
|
28
28
|
- Proposal (required): `sdd/{change}/proposal`
|
|
29
29
|
|
|
30
30
|
Persist this phase's artifact to the active backend before returning (mandatory):
|
|
31
|
-
- `engram`/`both`: call
|
|
31
|
+
- `engram`/`both`: call the injected Engram save tool with title and `topic_key` `"sdd/{change}/spec"`, `type: "architecture"`, `project` from context, and `capture_prompt: false` when the tool schema supports it (omit the field if an older schema rejects it).
|
|
32
32
|
- `openspec`: write/update the spec files under `openspec/changes/{change}/`.
|
|
33
33
|
- `none`: return the spec inline.
|
|
34
34
|
|
|
@@ -22,9 +22,10 @@ If skill paths are missing, explicit fallback loading is allowed only as degrade
|
|
|
22
22
|
|
|
23
23
|
## Memory Contract
|
|
24
24
|
|
|
25
|
-
This phase is READ-ONLY. Read the change artifacts directly from the active backend to compute status; do not wait for the parent to inline them, and do NOT write or
|
|
25
|
+
This phase is READ-ONLY. Read the change artifacts directly from the active backend to compute status; do not wait for the parent to inline them, and do NOT write files or call the injected Engram save tool.
|
|
26
|
+
|
|
27
|
+
Inputs to read (`engram`/`both`: use the injected Engram memory read tools for the topic key, then fetch the full observation; `openspec`: read the files under `openspec/changes/{change}/`):
|
|
26
28
|
|
|
27
|
-
Inputs to read (`engram`/`both`: `mem_search("<topic-key>")` then `mem_get_observation`; `openspec`: read the files under `openspec/changes/{change}/`):
|
|
28
29
|
- Whichever change artifacts are needed to compute status, named `sdd/{change}/<phase>` (proposal, spec, design, tasks, apply-progress, verify-report, sync-report).
|
|
29
30
|
|
|
30
31
|
Do not persist anything — status is a read-only report. Never claim persistence.
|
|
@@ -104,7 +105,7 @@ If parent context reports `workspace-planning` and no `allowedEditRoots`, mark a
|
|
|
104
105
|
- `sync` is `ready` when verify-report exists and has no unresolved `FAIL`, `BLOCKED`, `CRITICAL`, or verification blockers; it is `not_applicable` for `engram`/`none` modes.
|
|
105
106
|
- `archive` is `ready` only when verify-report is passing, sync-report exists or sync is not applicable, and no unchecked implementation tasks remain. CRITICAL verification issues have no override. Explicit recorded exceptions are limited to non-critical partial archives or stale-checkbox reconciliation when apply-progress/verify-report prove completion.
|
|
106
107
|
|
|
107
|
-
**Non-authoritative carve-out:** when `nextRecommended: "resolve-via-engram"` or `isNonAuthoritative: true` is set on the status object, the `dependencies`, `applyState`, and `blockedReasons` fields are non-authoritative — they must not be treated as real blockers. This condition applies when the artifact store is `engram`, `none`, or `both` without an `openspec/` directory present on disk. For `engram`/`both-without-openspec`, resolve readiness directly from Engram using
|
|
108
|
+
**Non-authoritative carve-out:** when `nextRecommended: "resolve-via-engram"` or `isNonAuthoritative: true` is set on the status object, the `dependencies`, `applyState`, and `blockedReasons` fields are non-authoritative — they must not be treated as real blockers. This condition applies when the artifact store is `engram`, `none`, or `both` without an `openspec/` directory present on disk. For `engram`/`both-without-openspec`, resolve readiness directly from Engram using the Engram memory tools injected by the memory provider on the change topic keys (`sdd/{change}/proposal`, `sdd/{change}/spec`, `sdd/{change}/design`, `sdd/{change}/tasks`, etc.). For `none`, return inline status or ask the user — do not use the engine's `not_applicable`/`blockedReasons` as real gate failures.
|
|
108
109
|
|
|
109
110
|
## Output
|
|
110
111
|
|
|
@@ -26,11 +26,11 @@ If skill paths are missing, explicit fallback loading is allowed only as degrade
|
|
|
26
26
|
|
|
27
27
|
Read the change artifacts directly from the active backend before syncing; do not wait for the parent to inline them. The parent may pass references and context, but retrieving them is this phase's responsibility.
|
|
28
28
|
|
|
29
|
-
Inputs to read (`engram`/`both`:
|
|
29
|
+
Inputs to read (`engram`/`both`: use the injected Engram memory read tools for the topic key, then fetch the full observation; `openspec`: read the files under `openspec/changes/{change}/`):
|
|
30
30
|
- Core change artifacts: `sdd/{change}/proposal`, `sdd/{change}/spec`, `sdd/{change}/design`, `sdd/{change}/tasks`, and `sdd/{change}/verify-report`.
|
|
31
31
|
|
|
32
32
|
Persist this phase's artifact to the active backend before returning (mandatory):
|
|
33
|
-
- `engram`/`both`: call
|
|
33
|
+
- `engram`/`both`: call the injected Engram save tool with title and `topic_key` `"sdd/{change}/sync-report"`, `type: "architecture"`, `project` from context, and `capture_prompt: false` when the tool schema supports it (omit the field if an older schema rejects it).
|
|
34
34
|
- `openspec`: write/update the canonical specs and sync report under `openspec/`.
|
|
35
35
|
- `none`: return the sync report inline.
|
|
36
36
|
|
|
@@ -24,12 +24,12 @@ If skill paths are missing, explicit fallback loading is allowed only as degrade
|
|
|
24
24
|
|
|
25
25
|
Read your own input artifacts directly from the active backend before doing the phase work; do not wait for the parent to inline them. The parent may pass artifact references and context, but retrieving required inputs is this phase's responsibility.
|
|
26
26
|
|
|
27
|
-
Inputs to read (`engram`/`both`:
|
|
27
|
+
Inputs to read (`engram`/`both`: use the injected Engram memory read tools for the topic key, then fetch the full observation; `openspec`: read the file under `openspec/changes/{change}/`):
|
|
28
28
|
- Spec (required): `sdd/{change}/spec`
|
|
29
29
|
- Design (required): `sdd/{change}/design`
|
|
30
30
|
|
|
31
31
|
Persist this phase's artifact to the active backend before returning (mandatory):
|
|
32
|
-
- `engram`/`both`: call
|
|
32
|
+
- `engram`/`both`: call the injected Engram save tool with title and `topic_key` `"sdd/{change}/tasks"`, `type: "architecture"`, `project` from context, and `capture_prompt: false` when the tool schema supports it (omit the field if an older schema rejects it).
|
|
33
33
|
- `openspec`: write/update `openspec/changes/{change}/tasks.md`.
|
|
34
34
|
- `none`: return the tasks inline.
|
|
35
35
|
|
|
@@ -25,13 +25,13 @@ If skill paths are missing, explicit fallback loading is allowed only as degrade
|
|
|
25
25
|
|
|
26
26
|
Read your own input artifacts directly from the active backend before doing the phase work; do not wait for the parent to inline them. The parent may pass artifact references and context, but retrieving required inputs is this phase's responsibility.
|
|
27
27
|
|
|
28
|
-
Inputs to read (`engram`/`both`:
|
|
28
|
+
Inputs to read (`engram`/`both`: use the injected Engram memory read tools for the topic key, then fetch the full observation; `openspec`: read the file under `openspec/changes/{change}/`):
|
|
29
29
|
- Spec (required): `sdd/{change}/spec`
|
|
30
30
|
- Tasks (required): `sdd/{change}/tasks`
|
|
31
31
|
- Apply-progress (required): `sdd/{change}/apply-progress`
|
|
32
32
|
|
|
33
33
|
Persist this phase's artifact to the active backend before returning (mandatory):
|
|
34
|
-
- `engram`/`both`: call
|
|
34
|
+
- `engram`/`both`: call the injected Engram save tool with title and `topic_key` `"sdd/{change}/verify-report"`, `type: "architecture"`, `project` from context, and `capture_prompt: false` when the tool schema supports it (omit the field if an older schema rejects it).
|
|
35
35
|
- `openspec`: write/update `openspec/changes/{change}/verify-report.md`.
|
|
36
36
|
- `none`: return the verify report inline.
|
|
37
37
|
|
|
@@ -42,7 +42,7 @@ Never claim persistence you did not perform.
|
|
|
42
42
|
Before verification, consume structured SDD status from the parent prompt. If missing, produce the same fields using this lookup order: project override `.pi/gentle-ai/support/sdd-status-contract.md`, then globally installed `~/.pi/agent/gentle-ai/support/sdd-status-contract.md`, then the embedded status contract. Do not use `assets/support/...` as a runtime path; that is only the package source path before installation.
|
|
43
43
|
|
|
44
44
|
**Non-authoritative store carve-out:** when the native status JSON shows `nextRecommended: "resolve-via-engram"` (covers `artifactStore: engram`, `artifactStore: none`, and `artifactStore: both` without an `openspec/` directory), the status is non-authoritative. Do not treat `dependencies` or `blockedReasons` from that status as real blockers. Resolve readiness as follows:
|
|
45
|
-
- `engram` (or `both` without openspec/): check Engram for `sdd/{change}/tasks` and `sdd/{change}/apply-progress` using
|
|
45
|
+
- `engram` (or `both` without openspec/): check Engram for `sdd/{change}/tasks` and `sdd/{change}/apply-progress` using the Engram memory tools injected by the memory provider. Proceed with verification once those artifacts are confirmed present.
|
|
46
46
|
- `none`: there is no persistent backend. Return the verification report inline and ask the user to provide required inputs (tasks, apply-progress) or acknowledge that no persistent artifact store is available.
|
|
47
47
|
|
|
48
48
|
Stop with `blocked` if:
|
package/assets/orchestrator.md
CHANGED
|
@@ -188,103 +188,15 @@ stop writes → parent captures git status → selected review lens audits affec
|
|
|
188
188
|
|
|
189
189
|
If multiple rows match, run the narrow set that covers the risk. Example: shell integration that mutates live state should use `review-reliability` plus `review-resilience`, not `review-readability` by default.
|
|
190
190
|
|
|
191
|
-
## SDD Workflow
|
|
191
|
+
## SDD Workflow (lazy-loaded)
|
|
192
192
|
|
|
193
|
-
SDD
|
|
193
|
+
The detailed SDD workflow is intentionally not embedded in this always-on parent prompt. Before handling any `/sdd-*` command, natural-language SDD request, SDD continuation/routing, apply/verify/sync/archive work, or SDD/Judgment-Day phase delegation, read this package asset first:
|
|
194
194
|
|
|
195
|
-
|
|
196
|
-
init → explore → proposal → spec → design → tasks → apply → verify → sync → archive
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
Dependency graph:
|
|
200
|
-
|
|
201
|
-
```text
|
|
202
|
-
proposal → spec ─┬→ tasks → apply → verify → sync → archive
|
|
203
|
-
proposal → design ┘
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
`/sdd-status [change]` is the read-only status action for resolving the active change, artifact paths, task progress, dependency readiness, and action context before apply/verify/sync/archive.
|
|
207
|
-
|
|
208
|
-
## Native SDD Dispatcher
|
|
209
|
-
|
|
210
|
-
The user expresses intent; they should not have to administer phases manually. For natural-language SDD requests and `/sdd-continue`, the parent/orchestrator must use the native status engine as the state authority, decide the next phase, and delegate only the phase that status marks ready.
|
|
211
|
-
|
|
212
|
-
Flow:
|
|
213
|
-
|
|
214
|
-
```text
|
|
215
|
-
user intent → preflight/init guard → native status engine → phase decision → subagent gets status JSON + generated instructions → artifact/progress write → status recalculation → continue or stop
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
Rules:
|
|
219
|
-
|
|
220
|
-
- `/sdd-status` is a debug/status command, not the main UX.
|
|
221
|
-
- `/sdd-continue` is the native dispatcher command: resolve status, choose the next ready phase, and carry status/instructions into the subagent prompt.
|
|
222
|
-
- `sdd-apply`, `sdd-verify`, `sdd-sync`, and `sdd-archive` must obey parent-provided native status; they must not reconstruct readiness from prompt inference when status JSON is present.
|
|
223
|
-
- Do not launch a phase when native status marks that dependency `blocked`.
|
|
224
|
-
- `sdd-archive` cannot proceed unless native status says `dependencies.archive` is `ready` or `all_done` — UNLESS the store carve-out is active (`nextRecommended: "resolve-via-engram"`), in which case resolve archive readiness from Engram instead of treating `not_applicable` as a gate failure.
|
|
225
|
-
- **Non-authoritative store carve-out:** when `nextRecommended: "resolve-via-engram"` is set, native status is **not authoritative**. This applies to `artifactStore: engram`, `artifactStore: none`, and `artifactStore: both` when the `openspec/` directory does not exist. For non-authoritative stores: resolve readiness from Engram using `mem_search` + `mem_get_observation` on the change topic keys (`sdd/{change-name}/proposal`, `sdd/{change-name}/spec`, `sdd/{change-name}/design`, `sdd/{change-name}/tasks`, etc.). Do **not** treat `blockedReasons` or `not_applicable` dependency states from the native engine as real blockers when the store carve-out is active.
|
|
226
|
-
|
|
227
|
-
## SDD Status Contract
|
|
228
|
-
|
|
229
|
-
Before `/sdd-continue`, `sdd-apply`, `sdd-verify`, `sdd-sync`, or `sdd-archive`, resolve and carry structured status. Lookup order: parent-provided status, then project override `.pi/gentle-ai/support/sdd-status-contract.md`, then globally installed `~/.pi/agent/gentle-ai/support/sdd-status-contract.md`, then the embedded `sdd-status` prompt contract. Do not use `assets/support/...` as a runtime path; that is only the package source path before installation.
|
|
230
|
-
|
|
231
|
-
Status must include:
|
|
232
|
-
|
|
233
|
-
- active change selection and how it was resolved;
|
|
234
|
-
- artifact store and paths/topics for proposal, specs, design, tasks, apply-progress, verify-report, and sync-report;
|
|
235
|
-
- task progress with exact unchecked `- [ ]` implementation task lines;
|
|
236
|
-
- dependency states for apply, verify, sync, and archive;
|
|
237
|
-
- `actionContext` with mode, workspace root, allowed edit roots, and warnings;
|
|
238
|
-
- next recommended action.
|
|
239
|
-
|
|
240
|
-
Do not guess the active change. If change selection is ambiguous, ask the user and stop. If `actionContext.mode: workspace-planning` and no allowed edit roots are provided, stop before apply/verify/sync/archive and ask for an explicit implementation/edit scope.
|
|
241
|
-
|
|
242
|
-
## Lazy SDD Preflight
|
|
243
|
-
|
|
244
|
-
Do not ask SDD setup questions on session start. The first time the user initiates an SDD process in a Pi session, run the SDD preflight once and keep those choices for the rest of that session. Runtime trigger detection is intentionally deterministic: slash SDD flows and `/sdd-init` run preflight automatically; for natural-language requests, the parent/orchestrator decides semantically whether SDD is needed and must run/reuse `/gentle-ai:sdd-preflight` before continuing.
|
|
245
|
-
|
|
246
|
-
**Hard gate:** `openspec/config.yaml`, existing SDD changes, installed `.pi`/global SDD assets, or a todo named "preflight" are not session preflight. They are project context only. Do not mark SDD preflight complete, start `sdd-init`, launch SDD subagents/chains, or move to explore/proposal/spec/design/tasks until this session has either:
|
|
247
|
-
|
|
248
|
-
1. an injected `## SDD Session Preflight` block, or
|
|
249
|
-
2. an explicit user answer in the current conversation covering all four preflight choices below.
|
|
250
|
-
|
|
251
|
-
If neither exists and `/gentle-ai:sdd-preflight` cannot be invoked from the current context, ask the four choices manually with `ask_user_question` before any SDD phase work. Treat missing Engram availability as a reason to ask/confirm artifact store, not as permission to assume defaults.
|
|
252
|
-
|
|
253
|
-
The preflight captures:
|
|
254
|
-
|
|
255
|
-
- execution mode: `interactive` or `auto`;
|
|
256
|
-
- artifact store: `openspec`, `engram`, or `both` when callable memory tools are available;
|
|
257
|
-
- chained PR strategy: `auto-forecast`, `ask-always`, `single-pr-default`, or `force-chained`;
|
|
258
|
-
- review budget in changed lines.
|
|
259
|
-
|
|
260
|
-
The package should ensure SDD assets are present as global Pi runtime assets without the user needing to remember per-project setup commands. If assets are missing, install them non-destructively into:
|
|
261
|
-
|
|
262
|
-
```text
|
|
263
|
-
~/.pi/agent/agents/sdd-*.md
|
|
264
|
-
~/.pi/agent/chains/sdd-*.chain.md
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
Manual install commands are recovery/debug paths, not the happy path. `/gentle-ai:sdd-preflight` and `/gentle:sdd-preflight` are the explicit preflight commands for agent/orchestrator use. If the user explicitly changes SDD preferences later in the same session, follow the new instruction.
|
|
195
|
+
`{{GENTLE_PI_SDD_WORKFLOW_PATH}}`
|
|
268
196
|
|
|
269
|
-
|
|
197
|
+
That lazy surface contains the SDD phases, native dispatcher rules, status contract, preflight/init guards, artifact-store policy, execution mode, Strict TDD forwarding, phase result contract, and review workload guard.
|
|
270
198
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
In this Pi package, the default local artifact is:
|
|
274
|
-
|
|
275
|
-
```text
|
|
276
|
-
openspec/config.yaml
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
If it is missing, ask the user for the minimal information needed or run `/sdd-init` if available. This init guard runs after the session preflight gate above; project config presence or absence never substitutes for session preflight choices. Do not proceed with a substantial SDD flow while pretending project context, testing capability, or session preflight choices are known.
|
|
280
|
-
|
|
281
|
-
## Artifact Store Policy
|
|
282
|
-
|
|
283
|
-
This package does not provide persistent memory by itself.
|
|
284
|
-
|
|
285
|
-
- Default: `openspec` artifacts in the repo.
|
|
286
|
-
- If a separate memory package is installed and callable, memory/hybrid flows may be used.
|
|
287
|
-
- Never claim memory exists because Gentle AI is installed.
|
|
199
|
+
Hard preflight invariant: `openspec/config.yaml`, existing SDD changes, installed `.pi`/global SDD assets, or a todo named "preflight" are not session preflight. Do not mark SDD preflight complete, start `sdd-init`, launch SDD subagents/chains, or move to explore/proposal/spec/design/tasks until this session has either an injected `## SDD Session Preflight` block or an explicit user answer covering the preflight choices.
|
|
288
200
|
|
|
289
201
|
## Memory Contract
|
|
290
202
|
|
|
@@ -292,8 +204,8 @@ When Engram or another callable memory package is available, the parent owns con
|
|
|
292
204
|
|
|
293
205
|
### Non-SDD delegation
|
|
294
206
|
|
|
295
|
-
- Read context: the parent/orchestrator searches memory (
|
|
296
|
-
- Write context: the subagent MUST save significant discoveries, decisions, or bug fixes via
|
|
207
|
+
- Read context: the parent/orchestrator searches memory (the injected Engram search tool), selects relevant observations, and passes them into the subagent prompt. The subagent does NOT search memory itself.
|
|
208
|
+
- Write context: the subagent MUST save significant discoveries, decisions, or bug fixes via the injected Engram save tool before returning when memory tools are available.
|
|
297
209
|
- Prompt forwarding: when delegating, add a concrete instruction such as: `If you make important discoveries, decisions, or fix bugs, save them to Engram via the available memory save tool with project: '<project>' before returning.`
|
|
298
210
|
|
|
299
211
|
### SDD phases
|
|
@@ -318,44 +230,12 @@ Each SDD phase subagent reads its own required inputs directly from the active b
|
|
|
318
230
|
|
|
319
231
|
Memory lifecycle rule (when Engram exposes lifecycle metadata/tooling):
|
|
320
232
|
|
|
321
|
-
- At session start or before architecture-sensitive work, call
|
|
322
|
-
- If
|
|
233
|
+
- At session start or before architecture-sensitive work, call the injected Engram review tool with action `list` for the current project when the tool is available.
|
|
234
|
+
- If the injected Engram review tool is unavailable, do not fail the task. Continue with the injected Engram context/search tools, and still apply lifecycle metadata from any returned observations when present.
|
|
323
235
|
- `active` memories may be used normally.
|
|
324
236
|
- `needs_review` memories are stale context, not trusted facts.
|
|
325
237
|
- When a retrieved memory is marked `needs_review`, surface that stale context to the user and verify it against current evidence before relying on it.
|
|
326
|
-
- Do NOT call
|
|
327
|
-
|
|
328
|
-
## Execution Mode
|
|
329
|
-
|
|
330
|
-
Use the session's SDD preflight choice:
|
|
331
|
-
|
|
332
|
-
- `interactive`: default, pause between major phases and ask whether to continue.
|
|
333
|
-
- `auto`: run phases back-to-back when the user explicitly wants speed and trusts the flow.
|
|
334
|
-
|
|
335
|
-
In interactive mode, between phases:
|
|
336
|
-
|
|
337
|
-
1. show concise phase result;
|
|
338
|
-
2. state next phase;
|
|
339
|
-
3. ask whether to continue or adjust.
|
|
340
|
-
|
|
341
|
-
Interactive approval is phase-scoped. A user response such as "continue", "dale", or "go on" approves only the immediate next phase, not the rest of the SDD pipeline. Do not treat a generated artifact as approved until the user has had a chance to review or explicitly delegate that review.
|
|
342
|
-
|
|
343
|
-
Before `sdd-proposal` in interactive mode, offer the user a proposal question round instead of silently deciding whether the proposal is clear enough. Explain that the questions are meant to improve the PRD/proposal by uncovering business understanding, business rules, implications, impact, edge cases, and product tradeoffs. Prefer 3–5 concrete product questions per round, then summarize the resulting assumptions and ask whether the user wants to correct anything or run a second question round. Cover business/product/PRD decisions: business problem, target users and situations, business rules, product outcome, current-state gap, implications and impact, edge cases, decision gaps, first-slice scope boundaries, non-goals, product constraints, and business tradeoffs. Do not ask about test commands, PR shape, changed-line budget, or other harness mechanics at proposal time unless the user explicitly asks to discuss delivery.
|
|
344
|
-
|
|
345
|
-
## Result Contract
|
|
346
|
-
|
|
347
|
-
Every phase result should include:
|
|
348
|
-
|
|
349
|
-
```text
|
|
350
|
-
status
|
|
351
|
-
executive_summary
|
|
352
|
-
artifacts
|
|
353
|
-
next_recommended
|
|
354
|
-
risks
|
|
355
|
-
skill_resolution
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
The parent should synthesize these envelopes, not paste long raw reports unless needed.
|
|
238
|
+
- Do NOT call the injected Engram review tool with action `mark_reviewed` automatically. Only call `mark_reviewed` after explicit user confirmation or through a dedicated memory maintenance command.
|
|
359
239
|
|
|
360
240
|
## Skill Registry Protocol
|
|
361
241
|
|
|
@@ -403,26 +283,6 @@ Common intent hints, not hard routing:
|
|
|
403
283
|
|
|
404
284
|
Keep this lightweight: loading a skill should improve the immediate task, not force extra ceremony.
|
|
405
285
|
|
|
406
|
-
## Strict TDD Forwarding
|
|
407
|
-
|
|
408
|
-
For `sdd-apply` and `sdd-verify`, read `openspec/config.yaml` when present.
|
|
409
|
-
|
|
410
|
-
If it declares strict TDD and a test command, include a non-negotiable instruction in the phase prompt:
|
|
411
|
-
|
|
412
|
-
```text
|
|
413
|
-
STRICT TDD MODE IS ACTIVE. Test runner: <command>. Follow RED, GREEN, TRIANGULATE, REFACTOR. Record evidence.
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
Do not rely on the child agent to discover this independently.
|
|
417
|
-
|
|
418
|
-
## Review Workload Guard
|
|
419
|
-
|
|
420
|
-
After `sdd-tasks` and before `sdd-apply`, inspect the task output for review workload risk.
|
|
421
|
-
|
|
422
|
-
If estimated changed lines exceed 400, chained PRs are recommended, or a decision is needed, pause and ask unless the user already approved a delivery strategy.
|
|
423
|
-
|
|
424
|
-
Automatic mode does not override reviewer burnout protection.
|
|
425
|
-
|
|
426
286
|
## Safety
|
|
427
287
|
|
|
428
288
|
- Never commit unless the user explicitly asks.
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# SDD Orchestrator Workflow
|
|
2
|
+
|
|
3
|
+
This is the lazy-loaded SDD workflow surface for el Gentleman on Pi. Read this file before handling `/sdd-*`, natural-language SDD requests, SDD continuation/routing, apply/verify/sync/archive work, or SDD/Judgment-Day phase delegation.
|
|
4
|
+
|
|
5
|
+
## SDD Workflow
|
|
6
|
+
|
|
7
|
+
SDD phases:
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
init → explore → proposal → spec → design → tasks → apply → verify → sync → archive
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Dependency graph:
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
proposal → spec ─┬→ tasks → apply → verify → sync → archive
|
|
17
|
+
proposal → design ┘
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`/sdd-status [change]` is the read-only status action for resolving the active change, artifact paths, task progress, dependency readiness, and action context before apply/verify/sync/archive.
|
|
21
|
+
|
|
22
|
+
## Native SDD Dispatcher
|
|
23
|
+
|
|
24
|
+
The user expresses intent; they should not have to administer phases manually. For natural-language SDD requests and `/sdd-continue`, the parent/orchestrator must use the native status engine as the state authority, decide the next phase, and delegate only the phase that status marks ready.
|
|
25
|
+
|
|
26
|
+
Flow:
|
|
27
|
+
|
|
28
|
+
```text
|
|
29
|
+
user intent → preflight/init guard → native status engine → phase decision → subagent gets status JSON + generated instructions → artifact/progress write → status recalculation → continue or stop
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Rules:
|
|
33
|
+
|
|
34
|
+
- `/sdd-status` is a debug/status command, not the main UX.
|
|
35
|
+
- `/sdd-continue` is the native dispatcher command: resolve status, choose the next ready phase, and carry status/instructions into the subagent prompt.
|
|
36
|
+
- `sdd-apply`, `sdd-verify`, `sdd-sync`, and `sdd-archive` must obey parent-provided native status; they must not reconstruct readiness from prompt inference when status JSON is present.
|
|
37
|
+
- Do not launch a phase when native status marks that dependency `blocked`.
|
|
38
|
+
- `sdd-archive` cannot proceed unless native status says `dependencies.archive` is `ready` or `all_done` — UNLESS the store carve-out is active (`nextRecommended: "resolve-via-engram"`), in which case resolve archive readiness from Engram instead of treating `not_applicable` as a gate failure.
|
|
39
|
+
- **Non-authoritative store carve-out:** when `nextRecommended: "resolve-via-engram"` is set, native status is **not authoritative**. This applies to `artifactStore: engram`, `artifactStore: none`, and `artifactStore: both` when the `openspec/` directory does not exist. For non-authoritative stores: resolve readiness from Engram using the Engram memory tools injected by the memory provider on the change topic keys (`sdd/{change-name}/proposal`, `sdd/{change-name}/spec`, `sdd/{change-name}/design`, `sdd/{change-name}/tasks`, etc.). Do **not** treat `blockedReasons` or `not_applicable` dependency states from the native engine as real blockers when the store carve-out is active.
|
|
40
|
+
|
|
41
|
+
## SDD Status Contract
|
|
42
|
+
|
|
43
|
+
Before `/sdd-continue`, `sdd-apply`, `sdd-verify`, `sdd-sync`, or `sdd-archive`, resolve and carry structured status. Lookup order: parent-provided status, then project override `.pi/gentle-ai/support/sdd-status-contract.md`, then globally installed `~/.pi/agent/gentle-ai/support/sdd-status-contract.md`, then the embedded `sdd-status` prompt contract. Do not use `assets/support/...` as a runtime path; that is only the package source path before installation.
|
|
44
|
+
|
|
45
|
+
Status must include:
|
|
46
|
+
|
|
47
|
+
- active change selection and how it was resolved;
|
|
48
|
+
- artifact store and paths/topics for proposal, specs, design, tasks, apply-progress, verify-report, and sync-report;
|
|
49
|
+
- task progress with exact unchecked `- [ ]` implementation task lines;
|
|
50
|
+
- dependency states for apply, verify, sync, and archive;
|
|
51
|
+
- `actionContext` with mode, workspace root, allowed edit roots, and warnings;
|
|
52
|
+
- next recommended action.
|
|
53
|
+
|
|
54
|
+
Do not guess the active change. If change selection is ambiguous, ask the user and stop. If `actionContext.mode: workspace-planning` and no allowed edit roots are provided, stop before apply/verify/sync/archive and ask for an explicit implementation/edit scope.
|
|
55
|
+
|
|
56
|
+
## Lazy SDD Preflight
|
|
57
|
+
|
|
58
|
+
Do not ask SDD setup questions on session start. The first time the user initiates an SDD process in a Pi session, run the SDD preflight once and keep those choices for the rest of that session. Runtime trigger detection is intentionally deterministic: slash SDD flows and `/sdd-init` run preflight automatically; for natural-language requests, the parent/orchestrator decides semantically whether SDD is needed and must run/reuse `/gentle-ai:sdd-preflight` before continuing.
|
|
59
|
+
|
|
60
|
+
**Hard gate:** `openspec/config.yaml`, existing SDD changes, installed `.pi`/global SDD assets, or a todo named "preflight" are not session preflight. They are project context only. Do not mark SDD preflight complete, start `sdd-init`, launch SDD subagents/chains, or move to explore/proposal/spec/design/tasks until this session has either:
|
|
61
|
+
|
|
62
|
+
1. an injected `## SDD Session Preflight` block, or
|
|
63
|
+
2. an explicit user answer in the current conversation covering all four preflight choices below.
|
|
64
|
+
|
|
65
|
+
If neither exists and `/gentle-ai:sdd-preflight` cannot be invoked from the current context, ask the four choices manually with `ask_user_question` before any SDD phase work. Treat missing Engram availability as a reason to ask/confirm artifact store, not as permission to assume defaults.
|
|
66
|
+
|
|
67
|
+
The preflight captures:
|
|
68
|
+
|
|
69
|
+
- execution mode: `interactive` or `auto`;
|
|
70
|
+
- artifact store: `openspec`, `engram`, or `both` when callable memory tools are available;
|
|
71
|
+
- chained PR strategy: `auto-forecast`, `ask-always`, `single-pr-default`, or `force-chained`;
|
|
72
|
+
- review budget in changed lines.
|
|
73
|
+
|
|
74
|
+
The package should ensure SDD assets are present as global Pi runtime assets without the user needing to remember per-project setup commands. If assets are missing, install them non-destructively into:
|
|
75
|
+
|
|
76
|
+
```text
|
|
77
|
+
~/.pi/agent/agents/sdd-*.md
|
|
78
|
+
~/.pi/agent/chains/sdd-*.chain.md
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Manual install commands are recovery/debug paths, not the happy path. `/gentle-ai:sdd-preflight` and `/gentle:sdd-preflight` are the explicit preflight commands for agent/orchestrator use. If the user explicitly changes SDD preferences later in the same session, follow the new instruction.
|
|
82
|
+
|
|
83
|
+
## Init Guard
|
|
84
|
+
|
|
85
|
+
Before any SDD flow, make sure project context exists.
|
|
86
|
+
|
|
87
|
+
In this Pi package, the default local artifact is:
|
|
88
|
+
|
|
89
|
+
```text
|
|
90
|
+
openspec/config.yaml
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
If it is missing, ask the user for the minimal information needed or run `/sdd-init` if available. This init guard runs after the session preflight gate above; project config presence or absence never substitutes for session preflight choices. Do not proceed with a substantial SDD flow while pretending project context, testing capability, or session preflight choices are known.
|
|
94
|
+
|
|
95
|
+
## Artifact Store Policy
|
|
96
|
+
|
|
97
|
+
This package does not provide persistent memory by itself.
|
|
98
|
+
|
|
99
|
+
- Default: `openspec` artifacts in the repo.
|
|
100
|
+
- If a separate memory package is installed and callable, memory/hybrid flows may be used.
|
|
101
|
+
- Never claim memory exists because Gentle AI is installed.
|
|
102
|
+
|
|
103
|
+
## Execution Mode
|
|
104
|
+
|
|
105
|
+
Use the session's SDD preflight choice:
|
|
106
|
+
|
|
107
|
+
- `interactive`: default, pause between major phases and ask whether to continue.
|
|
108
|
+
- `auto`: run phases back-to-back when the user explicitly wants speed and trusts the flow.
|
|
109
|
+
|
|
110
|
+
In interactive mode, between phases:
|
|
111
|
+
|
|
112
|
+
1. show concise phase result;
|
|
113
|
+
2. state next phase;
|
|
114
|
+
3. ask whether to continue or adjust.
|
|
115
|
+
|
|
116
|
+
Interactive approval is phase-scoped. A user response such as "continue", "dale", or "go on" approves only the immediate next phase, not the rest of the SDD pipeline. Do not treat a generated artifact as approved until the user has had a chance to review or explicitly delegate that review.
|
|
117
|
+
|
|
118
|
+
Before `sdd-proposal` in interactive mode, offer the user a proposal question round instead of silently deciding whether the proposal is clear enough. Explain that the questions are meant to improve the PRD/proposal by uncovering business understanding, business rules, implications, impact, edge cases, and product tradeoffs. Prefer 3–5 concrete product questions per round, then summarize the resulting assumptions and ask whether the user wants to correct anything or run a second question round. Cover business/product/PRD decisions: business problem, target users and situations, business rules, product outcome, current-state gap, implications and impact, edge cases, decision gaps, first-slice scope boundaries, non-goals, product constraints, and business tradeoffs. Do not ask about test commands, PR shape, changed-line budget, or other harness mechanics at proposal time unless the user explicitly asks to discuss delivery.
|
|
119
|
+
|
|
120
|
+
## Result Contract
|
|
121
|
+
|
|
122
|
+
Every phase result should include:
|
|
123
|
+
|
|
124
|
+
```text
|
|
125
|
+
status
|
|
126
|
+
executive_summary
|
|
127
|
+
artifacts
|
|
128
|
+
next_recommended
|
|
129
|
+
risks
|
|
130
|
+
skill_resolution
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
The parent should synthesize these envelopes, not paste long raw reports unless needed.
|
|
134
|
+
|
|
135
|
+
## Strict TDD Forwarding
|
|
136
|
+
|
|
137
|
+
For `sdd-apply` and `sdd-verify`, read `openspec/config.yaml` when present.
|
|
138
|
+
|
|
139
|
+
If it declares strict TDD and a test command, include a non-negotiable instruction in the phase prompt:
|
|
140
|
+
|
|
141
|
+
```text
|
|
142
|
+
STRICT TDD MODE IS ACTIVE. Test runner: <command>. Follow RED, GREEN, TRIANGULATE, REFACTOR. Record evidence.
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Do not rely on the child agent to discover this independently.
|
|
146
|
+
|
|
147
|
+
## Review Workload Guard
|
|
148
|
+
|
|
149
|
+
After `sdd-tasks` and before `sdd-apply`, inspect the task output for review workload risk.
|
|
150
|
+
|
|
151
|
+
If estimated changed lines exceed 400, chained PRs are recommended, or a decision is needed, pause and ask unless the user already approved a delivery strategy.
|
|
152
|
+
|
|
153
|
+
Automatic mode does not override reviewer burnout protection.
|
|
@@ -95,7 +95,7 @@ The orchestrator MUST carry `actionContext` into any phase launch.
|
|
|
95
95
|
## Engine Authority by Store
|
|
96
96
|
|
|
97
97
|
- `openspec` and `both` (when `openspec/` directory exists): the native status engine resolves artifact state from disk and is authoritative. Phase executors must obey it.
|
|
98
|
-
- `engram`, `none`, and `both` (when `openspec/` directory does NOT exist): the native status engine cannot read Engram artifacts. It returns `nextRecommended: "resolve-via-engram"` and empty `blockedReasons`. This output is **non-authoritative**. The orchestrator must resolve readiness directly from Engram using
|
|
98
|
+
- `engram`, `none`, and `both` (when `openspec/` directory does NOT exist): the native status engine cannot read Engram artifacts. It returns `nextRecommended: "resolve-via-engram"` and empty `blockedReasons`. This output is **non-authoritative**. The orchestrator must resolve readiness directly from Engram using the Engram memory tools injected by the memory provider on the change topic keys (`sdd/{change-name}/proposal`, `sdd/{change-name}/spec`, etc.) instead of relying on the engine's dependency states. The `artifactStore` field still reflects the real chosen store value (e.g. `"both"`) and must not be rewritten.
|
|
99
99
|
|
|
100
100
|
## Status Output
|
|
101
101
|
|
package/extensions/gentle-ai.ts
CHANGED
|
@@ -43,7 +43,6 @@ import {
|
|
|
43
43
|
} from "../lib/sdd-status.ts";
|
|
44
44
|
import {
|
|
45
45
|
evaluateEvent,
|
|
46
|
-
matchPathGlobs,
|
|
47
46
|
type ChangedDiff,
|
|
48
47
|
type TriggerEvent,
|
|
49
48
|
} from "../lib/review-triggers.ts";
|
|
@@ -124,12 +123,18 @@ function sddLocalOverrideDriftCount(cwd: string): number {
|
|
|
124
123
|
}
|
|
125
124
|
|
|
126
125
|
let orchestratorPromptCache: string | null = null;
|
|
126
|
+
function getSddWorkflowPath(): string {
|
|
127
|
+
return join(ASSETS_DIR, "sdd-orchestrator-workflow.md");
|
|
128
|
+
}
|
|
129
|
+
|
|
127
130
|
function getOrchestratorPrompt(): string {
|
|
128
131
|
if (orchestratorPromptCache === null) {
|
|
129
132
|
orchestratorPromptCache = readFileSync(
|
|
130
133
|
join(ASSETS_DIR, "orchestrator.md"),
|
|
131
134
|
"utf8",
|
|
132
|
-
)
|
|
135
|
+
)
|
|
136
|
+
.replaceAll("{{GENTLE_PI_SDD_WORKFLOW_PATH}}", getSddWorkflowPath())
|
|
137
|
+
.trim();
|
|
133
138
|
}
|
|
134
139
|
return orchestratorPromptCache;
|
|
135
140
|
}
|
|
@@ -219,14 +224,6 @@ const DENIED_BASH_PATTERNS: RegExp[] = [
|
|
|
219
224
|
/\bchown\s+-R\b/,
|
|
220
225
|
];
|
|
221
226
|
|
|
222
|
-
const CONFIRM_BASH_PATTERNS: RegExp[] = [
|
|
223
|
-
/\bgit\s+push\b/,
|
|
224
|
-
/\bgit\s+rebase\b/,
|
|
225
|
-
/\bgit\s+branch\s+(?:-[a-zA-Z]*D[a-zA-Z]*|-[a-zA-Z]*d[a-zA-Z]*f[a-zA-Z]*|-[a-zA-Z]*f[a-zA-Z]*d[a-zA-Z]*|--delete\b[^\n]*--force\b|--force\b[^\n]*--delete\b)/,
|
|
226
|
-
/\bnpm\s+publish\b/,
|
|
227
|
-
/\bpi\s+remove\b/,
|
|
228
|
-
];
|
|
229
|
-
|
|
230
227
|
// ---------------------------------------------------------------------------
|
|
231
228
|
// Autonomous guard — runtime guardrails config
|
|
232
229
|
// ---------------------------------------------------------------------------
|
|
@@ -577,12 +574,7 @@ function hasWritableEngramTool(pi: ExtensionAPI): boolean {
|
|
|
577
574
|
: isRecord(tool) && typeof tool.name === "string"
|
|
578
575
|
? tool.name
|
|
579
576
|
: "";
|
|
580
|
-
return (
|
|
581
|
-
name === "mem_save" ||
|
|
582
|
-
name === "engram_mem_save" ||
|
|
583
|
-
name.endsWith(".mem_save") ||
|
|
584
|
-
name.endsWith(".engram_mem_save")
|
|
585
|
-
);
|
|
577
|
+
return name === "mem_save" || name.endsWith(".mem_save");
|
|
586
578
|
});
|
|
587
579
|
} catch {
|
|
588
580
|
return false;
|
|
@@ -1992,7 +1984,7 @@ function computeDiffForEvent(event: TriggerEvent, cwd: string): ChangedDiff | nu
|
|
|
1992
1984
|
const gitOpts = {
|
|
1993
1985
|
cwd,
|
|
1994
1986
|
encoding: "utf8" as const,
|
|
1995
|
-
stdio:
|
|
1987
|
+
stdio: "pipe" as const,
|
|
1996
1988
|
// Bound synchronous git calls so a slow/large repo cannot freeze the extension process.
|
|
1997
1989
|
// The existing outer try/catch returns null (fail-open) when this throws.
|
|
1998
1990
|
timeout: 2000,
|
|
@@ -21,7 +21,7 @@ const EXCLUDE_NAMES = new Set(["_shared", "skill-registry"]);
|
|
|
21
21
|
const EXCLUDE_PREFIXES = ["sdd-"];
|
|
22
22
|
const ATL_IGNORE_ENTRY = ".atl/";
|
|
23
23
|
const WATCH_DEBOUNCE_MS = 500;
|
|
24
|
-
const REGISTRY_SCHEMA_VERSION =
|
|
24
|
+
const REGISTRY_SCHEMA_VERSION = 6;
|
|
25
25
|
const NO_SKILL_REGISTRY_FLAG = "no-skill-registry";
|
|
26
26
|
const NO_SKILL_REGISTRY_ENV = "GENTLE_PI_NO_SKILL_REGISTRY";
|
|
27
27
|
const LEGACY_PROJECT_REGISTRY_REL_PATH = ".pi/extensions/skill-registry.ts";
|
|
@@ -96,23 +96,30 @@ function projectSkillDirs(cwd: string): string[] {
|
|
|
96
96
|
|
|
97
97
|
async function findSkillFiles(root: string): Promise<string[]> {
|
|
98
98
|
if (!(await pathExists(root))) return [];
|
|
99
|
+
let entries;
|
|
100
|
+
try {
|
|
101
|
+
entries = await readdir(root, { withFileTypes: true });
|
|
102
|
+
} catch {
|
|
103
|
+
return [];
|
|
104
|
+
}
|
|
105
|
+
|
|
99
106
|
const out: string[] = [];
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
let entries;
|
|
107
|
+
for (const entry of entries) {
|
|
108
|
+
const skillDir = join(root, entry.name);
|
|
109
|
+
let dirInfo;
|
|
104
110
|
try {
|
|
105
|
-
|
|
111
|
+
dirInfo = await stat(skillDir);
|
|
106
112
|
} catch {
|
|
107
113
|
continue;
|
|
108
114
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
115
|
+
if (!dirInfo.isDirectory()) continue;
|
|
116
|
+
|
|
117
|
+
const candidate = join(skillDir, "SKILL.md");
|
|
118
|
+
try {
|
|
119
|
+
const skillInfo = await stat(candidate);
|
|
120
|
+
if (skillInfo.isFile()) out.push(candidate);
|
|
121
|
+
} catch {
|
|
122
|
+
// Missing or unreadable skill files are ignored; the registry is best-effort.
|
|
116
123
|
}
|
|
117
124
|
}
|
|
118
125
|
return out.sort();
|
|
@@ -512,6 +519,7 @@ async function startSkillRegistryWatcher(
|
|
|
512
519
|
export const __testing = {
|
|
513
520
|
projectSkillDirs,
|
|
514
521
|
userSkillDirs,
|
|
522
|
+
findSkillFiles,
|
|
515
523
|
uniqueExistingDirs,
|
|
516
524
|
dedupeBySkillName,
|
|
517
525
|
scopeForPath,
|
package/lib/sdd-preflight.ts
CHANGED
|
@@ -229,12 +229,7 @@ function hasWritableEngramTool(pi: ExtensionAPI): boolean {
|
|
|
229
229
|
: isRecord(tool) && typeof tool.name === "string"
|
|
230
230
|
? tool.name
|
|
231
231
|
: "";
|
|
232
|
-
return (
|
|
233
|
-
name === "mem_save" ||
|
|
234
|
-
name === "engram_mem_save" ||
|
|
235
|
-
name.endsWith(".mem_save") ||
|
|
236
|
-
name.endsWith(".engram_mem_save")
|
|
237
|
-
);
|
|
232
|
+
return name === "mem_save" || name.endsWith(".mem_save");
|
|
238
233
|
});
|
|
239
234
|
} catch {
|
|
240
235
|
return false;
|
package/lib/sdd-status.ts
CHANGED
|
@@ -545,7 +545,7 @@ export function renderNativeSddPhasePrompt(status: SddStatus, phase?: SddPhase):
|
|
|
545
545
|
? `This status is non-authoritative (artifact store: ${status.artifactStore}). The orchestrator must resolve readiness from Engram instead.`
|
|
546
546
|
: "The parent/orchestrator resolved this status deterministically. Treat it as authoritative over prompt inference.";
|
|
547
547
|
const blockLine = isNonAuthoritative
|
|
548
|
-
? `Do not block phase work based on this status — resolve readiness from Engram using
|
|
548
|
+
? `Do not block phase work based on this status — resolve readiness from Engram using the injected Engram memory read tools on the change topic keys (sdd/{change}/proposal, sdd/{change}/spec, sdd/{change}/design, sdd/{change}/tasks, etc.) instead.`
|
|
549
549
|
: "Do not run phase work when this status marks the phase blocked; return the blockers instead.";
|
|
550
550
|
return [
|
|
551
551
|
"## Native SDD Status Engine",
|
|
@@ -567,7 +567,7 @@ export function renderSddDispatcherMarkdown(status: SddStatus): string {
|
|
|
567
567
|
? [
|
|
568
568
|
"### Non-authoritative store — resolve via Engram",
|
|
569
569
|
`This status is non-authoritative (artifact store: ${status.artifactStore}).`,
|
|
570
|
-
"Resolve readiness directly from Engram using
|
|
570
|
+
"Resolve readiness directly from Engram using the injected Engram memory read tools on the change topic keys:",
|
|
571
571
|
`- sdd/${status.changeName ?? "<change>"}/proposal`,
|
|
572
572
|
`- sdd/${status.changeName ?? "<change>"}/spec`,
|
|
573
573
|
`- sdd/${status.changeName ?? "<change>"}/design`,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gentle-pi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Turn Pi into el Gentleman: a senior-architect development harness with SDD/OpenSpec, subagents, strict TDD evidence, review guardrails, and skill discovery.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -89,19 +89,20 @@ test("orchestrator Memory Contract carries the Engram memory lifecycle rule", as
|
|
|
89
89
|
|
|
90
90
|
// Mirrors gentle-ai's engram-protocol/engram-convention lifecycle rule (PRs #842 + #844),
|
|
91
91
|
// in its final availability-gated form: agents must treat needs_review memories as stale,
|
|
92
|
-
//
|
|
92
|
+
// use the memory-provider-injected lifecycle tool when present, fall back safely when it is not,
|
|
93
|
+
// and never auto-mark reviewed.
|
|
93
94
|
for (const required of [
|
|
94
95
|
"when Engram exposes lifecycle metadata/tooling",
|
|
95
96
|
"At session start or before architecture-sensitive work",
|
|
96
|
-
"call
|
|
97
|
+
"call the injected Engram review tool with action `list`",
|
|
97
98
|
"for the current project when the tool is available",
|
|
98
|
-
"If
|
|
99
|
-
"Continue with
|
|
99
|
+
"If the injected Engram review tool is unavailable, do not fail the task",
|
|
100
|
+
"Continue with the injected Engram context/search tools",
|
|
100
101
|
"still apply lifecycle metadata from any returned observations when present",
|
|
101
102
|
"`active` memories may be used normally",
|
|
102
103
|
"`needs_review` memories are stale context, not trusted facts",
|
|
103
104
|
"verify it against current evidence before relying on it",
|
|
104
|
-
"Do NOT call
|
|
105
|
+
"Do NOT call the injected Engram review tool with action `mark_reviewed` automatically",
|
|
105
106
|
"Only call `mark_reviewed` after explicit user confirmation or through a dedicated memory maintenance command",
|
|
106
107
|
]) {
|
|
107
108
|
assert.ok(
|
|
@@ -145,6 +146,21 @@ test("SDD chain assets distinguish interactive gates from auto execution", async
|
|
|
145
146
|
assert.match(fullChain, /must stop at each phase boundary/i);
|
|
146
147
|
});
|
|
147
148
|
|
|
149
|
+
test("orchestrator lazy-loads detailed SDD workflow", async () => {
|
|
150
|
+
const orchestrator = await readFile(join(ROOT, "assets/orchestrator.md"), "utf8");
|
|
151
|
+
const workflow = await readFile(join(ROOT, "assets/sdd-orchestrator-workflow.md"), "utf8");
|
|
152
|
+
|
|
153
|
+
assert.match(orchestrator, /## SDD Workflow \(lazy-loaded\)/);
|
|
154
|
+
assert.match(orchestrator, /\{\{GENTLE_PI_SDD_WORKFLOW_PATH\}\}/);
|
|
155
|
+
assert.doesNotMatch(orchestrator, /## Native SDD Dispatcher/);
|
|
156
|
+
assert.match(workflow, /## Native SDD Dispatcher/);
|
|
157
|
+
assert.match(workflow, /## SDD Status Contract/);
|
|
158
|
+
assert.match(workflow, /## Execution Mode/);
|
|
159
|
+
assert.match(workflow, /## Strict TDD Forwarding/);
|
|
160
|
+
assert.match(workflow, /## Review Workload Guard/);
|
|
161
|
+
assert.match(workflow, /## Result Contract/);
|
|
162
|
+
});
|
|
163
|
+
|
|
148
164
|
test("persistent harness prompt assets do not hardcode Spanish SDD artifact copy", async () => {
|
|
149
165
|
const files = [
|
|
150
166
|
...(await collectTextFiles(join(ROOT, "assets"))),
|
|
@@ -203,6 +203,11 @@ async function run() {
|
|
|
203
203
|
assert.doesNotMatch(promptResult.systemPrompt, /default\s*\|\s*sonnet\s*\|\s*Non-SDD general delegation/);
|
|
204
204
|
assert.match(promptResult.systemPrompt, /openspec\/config\.yaml.*not session preflight/s);
|
|
205
205
|
assert.match(promptResult.systemPrompt, /Do not mark SDD preflight complete/);
|
|
206
|
+
assert.match(
|
|
207
|
+
promptResult.systemPrompt,
|
|
208
|
+
new RegExp(`${ROOT.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}.*assets.*sdd-orchestrator-workflow\\.md`),
|
|
209
|
+
);
|
|
210
|
+
assert.doesNotMatch(promptResult.systemPrompt, /\{\{GENTLE_PI_SDD_WORKFLOW_PATH\}\}/);
|
|
206
211
|
await writeFile(
|
|
207
212
|
join(globalConfigHome, "persona.json"),
|
|
208
213
|
'{"mode":"neutral"}\n',
|
|
@@ -637,6 +642,17 @@ async function run() {
|
|
|
637
642
|
await rm(engramSddCwd, { recursive: true, force: true });
|
|
638
643
|
}
|
|
639
644
|
|
|
645
|
+
const directEngramToolCwd = await tempWorkspace();
|
|
646
|
+
try {
|
|
647
|
+
pi.setActiveTools(["read", "bash", "edit", "write", "engram_mem_save"]);
|
|
648
|
+
const ctx = createCtx(directEngramToolCwd, true, "direct-engram-session");
|
|
649
|
+
await commands.get("gentle-ai:sdd-preflight").handler("", ctx);
|
|
650
|
+
assert.deepEqual(ctx.ui.selections[1].options, ["openspec"]);
|
|
651
|
+
} finally {
|
|
652
|
+
pi.setActiveTools(["read", "bash", "edit", "write"]);
|
|
653
|
+
await rm(directEngramToolCwd, { recursive: true, force: true });
|
|
654
|
+
}
|
|
655
|
+
|
|
640
656
|
const installCwd = await tempWorkspace();
|
|
641
657
|
try {
|
|
642
658
|
const ctx = createCtx(installCwd, true);
|
|
@@ -669,6 +685,9 @@ async function run() {
|
|
|
669
685
|
pi.setActiveTools([{ name: "engram.mem_save" }]);
|
|
670
686
|
await commands.get("gentle-ai:doctor").handler("", ctx);
|
|
671
687
|
assert.match(ctx.ui.notifications.at(-1).message, /Engram memory tools active/);
|
|
688
|
+
pi.setActiveTools([{ name: "engram_mem_save" }]);
|
|
689
|
+
await commands.get("gentle-ai:doctor").handler("", ctx);
|
|
690
|
+
assert.match(ctx.ui.notifications.at(-1).message, /Engram memory tools not active in this session/);
|
|
672
691
|
pi.setActiveTools(["read", "bash", "edit", "write"]);
|
|
673
692
|
} finally {
|
|
674
693
|
await rm(staleAssetsCwd, { recursive: true, force: true });
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
|
-
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { mkdirSync, readFileSync, symlinkSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { dirname, join } from "node:path";
|
|
5
5
|
import test from "node:test";
|
|
@@ -114,6 +114,36 @@ test("uniqueExistingDirs normalizes duplicates and ignores missing roots", async
|
|
|
114
114
|
);
|
|
115
115
|
});
|
|
116
116
|
|
|
117
|
+
test("findSkillFiles scans one skill directory level only", async () => {
|
|
118
|
+
const root = join(tmpdir(), `gentle-pi-shallow-${Date.now()}`);
|
|
119
|
+
const skillPath = join(root, "docs", "SKILL.md");
|
|
120
|
+
const nestedSkillPath = join(root, "fixtures", "nested", "SKILL.md");
|
|
121
|
+
mkdirSync(dirname(skillPath), { recursive: true });
|
|
122
|
+
mkdirSync(dirname(nestedSkillPath), { recursive: true });
|
|
123
|
+
writeFileSync(skillPath, "---\nname: docs\ndescription: Docs.\n---\n");
|
|
124
|
+
writeFileSync(nestedSkillPath, "---\nname: nested\ndescription: Nested fixture.\n---\n");
|
|
125
|
+
|
|
126
|
+
assert.deepEqual(await __testing.findSkillFiles(root), [skillPath]);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test("findSkillFiles follows symlinked skill directories", async (t) => {
|
|
130
|
+
const root = join(tmpdir(), `gentle-pi-symlink-root-${Date.now()}`);
|
|
131
|
+
const realSkillDir = join(tmpdir(), `gentle-pi-symlink-target-${Date.now()}`);
|
|
132
|
+
const linkedSkillDir = join(root, "linked");
|
|
133
|
+
const skillPath = join(linkedSkillDir, "SKILL.md");
|
|
134
|
+
mkdirSync(root, { recursive: true });
|
|
135
|
+
mkdirSync(realSkillDir, { recursive: true });
|
|
136
|
+
writeFileSync(join(realSkillDir, "SKILL.md"), "---\nname: linked\ndescription: Linked skill.\n---\n");
|
|
137
|
+
try {
|
|
138
|
+
symlinkSync(realSkillDir, linkedSkillDir, "dir");
|
|
139
|
+
} catch (error) {
|
|
140
|
+
t.skip(`symlink creation unavailable: ${error instanceof Error ? error.message : String(error)}`);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
assert.deepEqual(await __testing.findSkillFiles(root), [skillPath]);
|
|
145
|
+
});
|
|
146
|
+
|
|
117
147
|
test("skill registry watchers close on shutdown", async () => {
|
|
118
148
|
const root = join(tmpdir(), `gentle-pi-watchers-${Date.now()}`);
|
|
119
149
|
const skillPath = join(root, "skills", "docs", "SKILL.md");
|