@gtrabanco/pi-agentic-workflow 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -34,7 +34,31 @@ export function readSkillMeta(text, dir) {
34
34
  if (colon === -1)
35
35
  continue;
36
36
  const key = line.slice(0, colon).trim();
37
- const value = line.slice(colon + 1).trim().replace(/^["']|["']$/gu, "");
37
+ const rawValue = line.slice(colon + 1).trim();
38
+ const value = rawValue.replace(/^["']|["']$/gu, "");
39
+ // YAML block scalars: `description: >` (folded) / `description: |` (literal)
40
+ // carry their content on the following indented lines, not inline. Collect
41
+ // those continuation lines (they never start a top-level `key: value` line)
42
+ // and advance the loop past them. ">" is not a description, so the old
43
+ // line-oriented reader storing `>` is the bug (#165).
44
+ if (key === "description" && (value === ">" || value === "|")) {
45
+ const folded = value === ">";
46
+ const collected = [];
47
+ let cursor = index + 1;
48
+ for (; cursor < lines.length; cursor += 1) {
49
+ const next = lines[cursor];
50
+ if (next.trim() === "---")
51
+ break;
52
+ // A non-empty, non-indented line starts the next top-level key.
53
+ if (next !== "" && !/^[ \t]/u.test(next))
54
+ break;
55
+ collected.push(next);
56
+ }
57
+ meta.description = buildBlockScalar(collected, folded);
58
+ // Outer loop += 1 moves past the last consumed continuation line.
59
+ index = cursor - 1;
60
+ continue;
61
+ }
38
62
  if (key === "name" && value !== "")
39
63
  meta.name = value;
40
64
  else if (key === "description" && value !== "")
@@ -44,6 +68,40 @@ export function readSkillMeta(text, dir) {
44
68
  }
45
69
  return meta;
46
70
  }
71
+ /**
72
+ * Assemble a YAML block scalar from its collected, indented continuation lines.
73
+ *
74
+ * Strip the common leading indentation, then: folded (`>`) joins non-blank
75
+ * lines into a single space-separated string (blank lines become page breaks);
76
+ * literal (`|`) preserves the line breaks. Both are trimmed of outer blank
77
+ * whitespace so the value matches the frontmatter's intended text.
78
+ */
79
+ function buildBlockScalar(lines, folded) {
80
+ const nonEmpty = lines.filter((line) => line.length > 0);
81
+ const indent = nonEmpty.reduce((min, line) => {
82
+ const width = /^[ \t]*/u.exec(line)[0].length;
83
+ return Math.min(min, width);
84
+ }, Number.POSITIVE_INFINITY);
85
+ if (!Number.isFinite(indent))
86
+ return "";
87
+ const unindented = lines.map((line) => (line.length === 0 ? "" : line.slice(indent)));
88
+ if (!folded)
89
+ return unindented.join("\n").trim();
90
+ const parts = [];
91
+ let pendingBreak = false;
92
+ for (const raw of unindented) {
93
+ const line = raw.trimEnd();
94
+ if (line === "") {
95
+ pendingBreak = true;
96
+ continue;
97
+ }
98
+ if (pendingBreak && parts.length > 0)
99
+ parts.push("\n");
100
+ pendingBreak = false;
101
+ parts.push(line);
102
+ }
103
+ return parts.join(" ").replace(/ \n/g, "\n").trim();
104
+ }
47
105
  /**
48
106
  * Read a bundled skills directory. A duplicate `name:` is reported instead of
49
107
  * silently shadowing an alias: two skills claiming one command is a packaging
@@ -54,7 +112,14 @@ export function readCatalogue(skillsDir, readFile = (p) => readFileSync(p, "utf8
54
112
  const invocable = [];
55
113
  const issues = [];
56
114
  const taken = new Map();
57
- for (const dir of readdirSync(skillsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory())) {
115
+ // Iterate directories in a stable order: readdir order is filesystem-dependent
116
+ // (bun and node return different orders for the same directory), and the
117
+ // duplicate-name rule is "first owner claims the command". Sorting makes that
118
+ // owner deterministic across runtimes and platforms.
119
+ const dirs = readdirSync(skillsDir, { withFileTypes: true })
120
+ .filter((entry) => entry.isDirectory())
121
+ .sort((left, right) => left.name.localeCompare(right.name));
122
+ for (const dir of dirs) {
58
123
  let meta;
59
124
  try {
60
125
  meta = readSkillMeta(readFile(join(skillsDir, dir.name, SKILL_FILE)), dir.name);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gtrabanco/pi-agentic-workflow",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "Pi package: canonical agentic-workflow skills, friendly slash commands, and per-command model routing.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: execute-phase
3
3
  user-invocable: true
4
- version: 4.2.0
4
+ version: 4.3.0
5
5
  argument-hint: <NN> [P<k>] | --fix <n> [P<k>] | [--max-attempts N] [--force]
6
6
  allowed-tools: [Bash, Read, Edit, Write, MultiEdit]
7
7
  author: "Gabriel Trabanco <gtrabanco@users.noreply.github.com>"
@@ -54,6 +54,11 @@ Load and verify the **canonical** [Turn contract](.claude/skills/orchestration-e
54
54
  unit). Missing, stale, or wrong-stage stops the turn with the gate block; this is
55
55
  the one preflight gate `--force` does not reach — the block, no-forgery and legacy
56
56
  rules live in [pre-execution gate](references/PRE_EXECUTION_GATE.md).
57
+ - **Pre-write discovery before any repository write** — after the read-only gates
58
+ and before branch creation, planning commit, or source/test edit, settle the
59
+ mapper contract (`implementation-discovery`). It answers the seven evidence
60
+ questions, emits the fixed compact map, and routes `READY | REPLAN |
61
+ NEEDS-DESIGN | BLOCKED`; only `READY` authorizes the first write.
57
62
 
58
63
  ## Context budget (hard rule — context is repaid every turn)
59
64
 
@@ -76,6 +81,10 @@ the listed one-hop route resource immediately before its step.
76
81
  1. Every invocation: consume [verification contract](<../verification-contract/SKILL.md>),
77
82
  read/run [preflight gates](references/PREFLIGHT.md), and stop on a contracted
78
83
  blocker before editing. This route owns NRS and Architectural invariants gates.
84
+ After the read-only pre-execution gate and before any branch/planning/source
85
+ write, load and settle the pre-write mapper
86
+ [`implementation-discovery`](<../implementation-discovery/SKILL.md>) — it emits
87
+ the fixed map and routes READY | REPLAN | NEEDS-DESIGN | BLOCKED.
79
88
  2. Without explicit `P<n>`, read [unit loop](references/UNIT_LOOP.md), then
80
89
  [execution contract](references/EXECUTION_CONTRACT.md), then exactly one
81
90
  workflow: [feature](references/WORKFLOWS_FEATURE.md),
@@ -125,8 +125,11 @@ gate block, and **`--force` never reaches this gate** — it overrides ordering
125
125
  the user may re-order, not a verdict only a reviewer can produce. Fix units run the
126
126
  same check on their own receipt (`/review-plan fix-<N>`). Legacy `planned`/`in-progress`
127
127
  units follow the adoption route. The slot immediately after this gate and before the
128
- first write is reserved for feature 29's bounded implementation discovery — do not
129
- implement or imitate it here. Full rule, block text, no-forgery and legacy detail:
128
+ first write is owned by the pre-write mapper contract — load
129
+ [`implementation-discovery`](<../implementation-discovery/SKILL.md>) and settle it
130
+ before any branch/planning/source write; it routes READY | REPLAN | NEEDS-DESIGN
131
+ | BLOCKED and is the only contract allowed to confirm the map here. Full rule,
132
+ block text, no-forgery and legacy detail:
130
133
  [pre-execution gate](PRE_EXECUTION_GATE.md).
131
134
 
132
135
  ## Acceptance-manifest gate (after dependency/own-status, before phase-lint)
@@ -0,0 +1,209 @@
1
+ ---
2
+ name: implementation-discovery
3
+ user-invocable: false
4
+ version: 1.1.0
5
+ author: "Gabriel Trabanco <gtrabanco@users.noreply.github.com>"
6
+ license: MIT
7
+ description: >
8
+ Internal contract: the single owner of the bounded pre-write implementation
9
+ discovery step. One read-only mapper that closes seven evidence questions,
10
+ emits one fixed compact map, and routes READY | REPLAN | NEEDS-DESIGN |
11
+ BLOCKED before any branch, planning, or source write. Consumed only by
12
+ execute-phase on the pre-write route. Not a menu entry.
13
+ ---
14
+
15
+ # Implementation Discovery (internal)
16
+
17
+ The one authoritative owner of the bounded, read-only pre-write mapper consumed
18
+ by `execute-phase`. A phase does not touch the repository until this step has
19
+ closed its questions and said `READY`. Nothing else may define what a valid
20
+ pre-write discovery pass is.
21
+
22
+ ## When to use
23
+
24
+ - `execute-phase` — before any branch/planning/source write, after the read-only
25
+ dependency/status/acceptance/phase/feature-28 receipt checks.
26
+ - The step runs only on the pre-write route; it is never a general-purpose
27
+ orientation pass and never a substitute for planning.
28
+
29
+ ## Inputs (exact, only these)
30
+
31
+ The mapper receives only:
32
+
33
+ - the governing SPEC/fix obligations for the current phase;
34
+ - the current feature-28 SPEC and Plan receipt digests;
35
+ - the phase-relevant rows from frozen planning evidence, with source revision,
36
+ affected decision/obligation, freshness, and declared unknowns;
37
+ - the phase fingerprint, ordered tasks, acceptance/obligation ids, and the last
38
+ progress receipt;
39
+ - source HEAD plus clean-source / allowed-planning-path evidence;
40
+ - applicable NRS / decision / invariant evidence;
41
+ - the repository discovery tools available in this environment.
42
+
43
+ ## Advisory locators
44
+
45
+ Semantic/symbol navigation and Engram/memory tools are optional adapters that may
46
+ locate evidence faster; they are never authority. Direct repository/Git/search/
47
+ read/test fallback must satisfy the identical evidence contract, and only
48
+ repository bytes answer a map field. The tool that found a citation does not
49
+ excuse a missing `path:line` or a contradictory claim.
50
+
51
+ ## Seven evidence questions
52
+
53
+ Every pass must answer — each answer citing repository-relative `path:line`,
54
+ symbol, or test plus exact source revision / content identity:
55
+
56
+ 1. Which entry points and public/internal interfaces own current behaviour?
57
+ 2. Which callers, adapters, roles, compatibility surfaces, and failure paths
58
+ can this phase affect?
59
+ 3. Which helpers, patterns, decisions, and invariants constrain the change?
60
+ 4. Which tests, fixtures, probes, and production-like scenarios establish
61
+ current behaviour?
62
+ 5. Which exact writes are expected, and which reviewed obligation does each
63
+ serve?
64
+ 6. Which carried planning-evidence claims and Plan assumptions are directly
65
+ confirmed, refined, stale, missing, or contradicted by source?
66
+ 7. Which relevant unknowns remain, who owns them, and what evidence resolves
67
+ them?
68
+
69
+ The mapper records conclusions, not every search. Repeating a search/read
70
+ requires a new question, changed source, or insufficient cited evidence;
71
+ otherwise it stops (no-progress).
72
+
73
+ ## Inline and fresh routing
74
+
75
+ **Inline** is permitted only when behaviour is localized/familiar, targeted
76
+ evidence answers every question, no public/persistence/security/recovery/
77
+ compatibility boundary may change, and the executor can finish the map before
78
+ writing.
79
+
80
+ **A fresh read-only mapper** is required for cross-module/layer or unfamiliar
81
+ work, public/persistence/security/recovery/compatibility impact, competing
82
+ project patterns, an unproven material Plan assumption, prior failed
83
+ attempts/review bias, or any case where editing would begin before the map
84
+ closes. Same-model fresh context is useful but is not model diversity. Manual
85
+ sequential fresh conversations are the portable fallback.
86
+
87
+ No file-count threshold participates in the route or the verdict.
88
+
89
+ ## Fixed implementation map
90
+
91
+ ```text
92
+ IMPLEMENTATION MAP — unit-id phase-id
93
+ Map revision: opaque single-consumption id
94
+ Source identity: HEAD + clean-source proof + cited-evidence manifest digest
95
+ Authority: SPEC receipt + Plan receipt + phase fingerprint
96
+ Planning evidence: carried row ids + current confirmation/refinement/conflict
97
+ Obligations: ordered acceptance/fix/obligation ids
98
+ Entry points: path:line or symbol + role + exact evidence
99
+ Affected surfaces: callers/adapters/roles/compatibility/failure paths + evidence
100
+ Current behaviour: evidence-backed summary
101
+ Reuse and constraints: helper/pattern/decision/invariant/fixture + evidence
102
+ Expected writes: ordered path + obligation served + reason
103
+ Validation: falsification probe + TDD target + phase gate
104
+ Plan assumptions: confirmed items + evidence
105
+ Contradictions: none or exact Plan/source conflict
106
+ Unknowns: none or exact missing fact + owner + resolution evidence
107
+ Decision: READY | REPLAN | NEEDS-DESIGN | BLOCKED
108
+ ```
109
+
110
+ ## Verdicts
111
+
112
+ `READY` requires every field, question, and owned obligation covered, no
113
+ material contradiction/unknown, an observed falsification probe, and expected
114
+ writes inside phase authority. It also requires every carried planning-evidence
115
+ row to be confirmed or narrowly refined.
116
+
117
+ `REPLAN` means source disproves Engineering assumptions while Product remains
118
+ stable, or Plan-level topology/architecture/obligation/validator evidence is
119
+ absent.
120
+
121
+ `NEEDS-DESIGN` means Product, acceptance, authority, or architecture intent is
122
+ missing or conflicting.
123
+
124
+ `BLOCKED` names evidence that cannot currently be obtained.
125
+
126
+ No other verdict exists.
127
+
128
+ ## Routes and upstream owners
129
+
130
+ A verdict routes, it never repairs. Missing/contradicted Plan-level topology,
131
+ architecture, obligations, validators, or assumptions return to
132
+ `plan-feature`/`plan-fix` plus a fresh `review-plan`. Product/acceptance/
133
+ authority/architecture gaps return to `design-feature` then `review-spec`. A
134
+ verdict with unavailable evidence is one exact `BLOCKED` prerequisite. Mapping
135
+ does not decide code correctness — candidate review, verification, and audit
136
+ authority are unchanged, and a second repair/re-review cycle inherits feature
137
+ 28's `CONVERGENCE-ANOMALY` diagnosis.
138
+
139
+ Source-local findings stay local; Plan/Product defects return upstream. A
140
+ missing current-unit behaviour entailed by reviewed scope joins the obligation
141
+ map and routes upstream; it is never a follow-up issue and never calls the
142
+ forge.
143
+
144
+ ## Legacy and manual routes
145
+
146
+ The portable fallback uses sequential fresh conversations with exact
147
+ artifact/source bindings. It may not claim a machine receipt or a durable
148
+ guarantee it cannot produce; it says plainly what was observed and what was
149
+ not.
150
+
151
+ ## Early falsification
152
+
153
+ Before READY, run the cheapest relevant read-only probe: a focused existing
154
+ test, current parser/CLI output, public type/schema inspection, symbol callers,
155
+ or an existing fixture. Record the command/query, the observed result, and the
156
+ evidence. A failed probe informs REPLAN/NEEDS-DESIGN; unavailable high-risk
157
+ evidence is BLOCKED, never rewritten as confident evidence. This does not
158
+ replace TDD or later verification.
159
+
160
+ ## No-progress
161
+
162
+ Conclusion once. Do not re-read or re-search to reconfirm the same conclusion
163
+ without a new question, changed source, or insufficient cited evidence. On
164
+ repetition, stop with `BLOCKED` and name what is still missing. Re-read is
165
+ allowed only for a changed source revision, a new question, insufficient
166
+ evidence, or a contradiction.
167
+
168
+ ## Read-only boundary
169
+
170
+ The mapper reads; it may not write. It creates no forge issue, no committed
171
+ map, no planning unit, no schema, no source edit, and no test edit. It emits the
172
+ map and reuses `SkillOutcome v1`. A missing current-unit behaviour entailed by
173
+ reviewed scope joins the obligation map and routes upstream; it is not a
174
+ follow-up issue. Discovery never calls the forge.
175
+
176
+ ## Writer handoff
177
+
178
+ The writer receives frozen phase authority plus the fixed compact map. It does
179
+ not receive raw files, repeated summaries, raw planning discovery, raw
180
+ exploration history, or the authoring conversation unless a cited claim cannot
181
+ be interpreted without a focused excerpt. The map preserves the phase-relevant planning-evidence ids and
182
+ their current confirmation. The writer may only touch expected paths /
183
+ obligations; a newly discovered path or contradiction stops and remaps/routes
184
+ rather than expanding silently.
185
+
186
+ ## Source identity
187
+
188
+ Source identity is exact pre-map HEAD, proof that tracked/untracked changes
189
+ outside the allowed planning paths are absent, an ordered manifest digest of
190
+ every cited evidence path/content plus the current phase/receipt bindings, and
191
+ an opaque `mappingRevisionId` created for this mapping event.
192
+
193
+ ## Preparation continuity
194
+
195
+ After READY, deterministic setup may create the branch and commit only the
196
+ already-reviewed planning paths. Before the first source/test edit the executor
197
+ proves either HEAD is unchanged or the new commit is a direct descendant whose
198
+ entire diff is the allowed planning set and whose authority/content digests
199
+ match. Any other path, parent, receipt, phase, or evidence change invalidates
200
+ the map and routes again.
201
+
202
+ ## Consumption and recovery
203
+
204
+ READY is single-consumption: the first implementation write consumes it. A crash
205
+ before the write may resume only after freshness/no-consumption proof. A crash
206
+ after any partial write remaps current source during recovery. A new map
207
+ revision plus changed Git causal identity prevents reuse after revert; direct
208
+ out-of-protocol state manipulation cannot be claimed detectable without runtime
209
+ history.
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: pre-execution-review
3
3
  user-invocable: false
4
- version: 1.7.0
4
+ version: 2.0.0
5
5
  author: "Gabriel Trabanco <gtrabanco@users.noreply.github.com>"
6
6
  license: MIT
7
7
  description: >
@@ -43,10 +43,17 @@ Rules the builder enforces and no caller may improvise around:
43
43
  Passing a fix unit's own SPEC bytes off as a parent is refused by the contract,
44
44
  because the field means "the Product review I descend from".
45
45
  - **Context rows are the authorities actually consulted**, each `present` with its
46
- digest or `absent` with `null`: `roadmap-row`, `project-guide`,
47
- `normalized-repository-state`, `architectural-invariants` (the *project's* declared
48
- file — the portable workflow contract is not a project's rule set), plus
49
- `governing-issue` and `dependency-unit` when the unit has them.
46
+ digest or `absent` with `null`: `project-guide`, `normalized-repository-state`,
47
+ `architectural-invariants` (the *project's* declared file — the portable workflow
48
+ contract is not a project's rule set), plus `governing-issue` and
49
+ `dependency-unit` when the unit has them. **The roadmap row is deliberately not
50
+ bound:** `ROADMAP.md` is every unit's shared lifecycle ledger — rows for other
51
+ units land while a plan is in flight, and the status machine's own sanctioned
52
+ writes (`planned` → `in-progress` at P1, `done` at PR open) must never invalidate
53
+ a recorded receipt. Its safety-relevant content is owned by gates that re-read it
54
+ live (the own-status gate, and the dependency gate's fingerprint over the SPEC
55
+ `Depends on:` line plus the closure roadmap rows); the unit's artifacts and the
56
+ authorities above stay bound.
50
57
  - **A snapshot digest is not a git blob id.** `git hash-object` stays the convention
51
58
  for the frozen `ACCEPTANCE.md` manifest receipt only; comparing it to a snapshot
52
59
  digest proves nothing and a sensor that does so is wrong, not cheap.
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: review-spec
3
3
  user-invocable: true
4
- version: 1.5.0
4
+ version: 1.6.0
5
5
  argument-hint: <NN-slug | path/to/SPEC.md>
6
6
  author: "Gabriel Trabanco <gtrabanco@users.noreply.github.com>"
7
7
  license: MIT
@@ -27,7 +27,7 @@ A SPEC-stage snapshot is deliberately narrow:
27
27
  | `artifactRevisionId` | the author's current revision id from the handoff |
28
28
  | `artifacts` | **exactly one row**: `kind: spec`, `path` normalized repo-relative, `selector: spec-product-v1`, `byteLength`, lowercase SHA-256 `digest` |
29
29
  | `parentSpecSnapshotDigest` | `null` — a SPEC snapshot roots its own lineage |
30
- | `contexts` | each authoritative source actually consulted: `roadmap-row`, `governing-issue`, `normalized-repository-state`, `architectural-invariants`, `dependency-unit`, `project-guide` — `present` with its exact digest, or `absent` with `null` |
30
+ | `contexts` | each authoritative source actually consulted: `governing-issue`, `normalized-repository-state`, `architectural-invariants`, `dependency-unit`, `project-guide` — `present` with its exact digest, or `absent` with `null`. The roadmap row is read as routing data and deliberately unbound: the shared `ROADMAP.md` ledger moves for reasons this unit never reviewed (other units' rows, the status machine's own sanctioned writes) |
31
31
 
32
32
  `spec-product-v1` selects the title, `## Goal`, `## Branch`, `## Size`,
33
33
  `## Dependencies`, the whole Product half, and `## Design status` — never the