@wichayutdew/pi-workflows 2.6.0 → 2.7.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.
Files changed (47) hide show
  1. package/README.md +30 -0
  2. package/dist/index.js +141 -17
  3. package/examples/starter-kit/agents/planner.md +4 -0
  4. package/examples/starter-kit/agents/reviewer.md +4 -0
  5. package/examples/starter-kit/agents/scout.md +4 -0
  6. package/examples/starter-kit/agents/worker.md +4 -0
  7. package/examples/starter-kit/agents/workspace-preparer.md +4 -0
  8. package/examples/starter-kit/investigate.workflow.yaml +34 -64
  9. package/examples/starter-kit/jira.workflow.yaml +75 -0
  10. package/examples/starter-kit/mr-comment.workflow.yaml +48 -115
  11. package/examples/starter-kit/mr-review.workflow.yaml +36 -93
  12. package/examples/starter-kit/settings.yaml +2 -1
  13. package/examples/starter-kit/steps/investigate/investigate.md +18 -55
  14. package/examples/starter-kit/steps/investigate/retrieve.md +15 -50
  15. package/examples/starter-kit/steps/investigate/validate.md +10 -36
  16. package/examples/starter-kit/steps/jira/create.md +25 -0
  17. package/examples/starter-kit/steps/jira/draft.md +18 -0
  18. package/examples/starter-kit/steps/jira/plan.md +30 -0
  19. package/examples/starter-kit/steps/mr-comment/checkout-source.md +7 -60
  20. package/examples/starter-kit/steps/mr-comment/fetch.md +11 -36
  21. package/examples/starter-kit/steps/mr-comment/implement.md +10 -34
  22. package/examples/starter-kit/steps/mr-comment/plan.md +47 -70
  23. package/examples/starter-kit/steps/mr-comment/publish.md +11 -32
  24. package/examples/starter-kit/steps/mr-comment/verify.md +8 -42
  25. package/examples/starter-kit/steps/mr-review/fetch.md +8 -46
  26. package/examples/starter-kit/steps/mr-review/publish-approved.md +7 -38
  27. package/examples/starter-kit/steps/mr-review/review-for-approval.md +24 -113
  28. package/examples/starter-kit/steps/mr-review/verify-published.md +9 -30
  29. package/examples/starter-kit/steps/shared/prepare-workspace.md +9 -105
  30. package/examples/starter-kit/steps/shared/publish-remote.md +8 -37
  31. package/examples/starter-kit/steps/ticket/implement.md +11 -58
  32. package/examples/starter-kit/steps/ticket/plan.md +49 -171
  33. package/examples/starter-kit/steps/ticket/verify.md +12 -98
  34. package/examples/starter-kit/steps/work/implement.md +11 -58
  35. package/examples/starter-kit/steps/work/plan.md +42 -130
  36. package/examples/starter-kit/steps/work/verify.md +11 -58
  37. package/examples/starter-kit/ticket.workflow.yaml +38 -81
  38. package/examples/starter-kit/work.workflow.yaml +34 -72
  39. package/package.json +7 -4
  40. package/schemas/workflow.schema.json +61 -0
  41. package/scripts/patch-herdr-agent-state.mjs +36 -0
  42. package/src/config/types.ts +9 -0
  43. package/src/config/validation/step.ts +117 -0
  44. package/src/harness/artifact-contract.ts +46 -0
  45. package/src/harness/gate-submission-action.ts +28 -0
  46. package/src/harness/status-actions.ts +19 -0
  47. package/src/herdr-workflow-state.ts +65 -0
@@ -1,70 +1,23 @@
1
- You are the independent verification stage for local work. You are the active workflow step; do not modify files, amend commits, or delegate this work.
1
+ You are the independent verification stage for local work. Stay read-only in this delegated child; do not modify files, amend commits, or launch subagents.
2
2
 
3
3
  Original request:
4
4
  {{workflow.input}}
5
5
 
6
- Immutable approved plan:
6
+ Approved plan:
7
7
  {{reviewed.artifact}}
8
8
 
9
9
  Approval feedback:
10
10
  {{reviewed.feedback}}
11
11
 
12
- Implementation ledger or blocked recovery handoff:
12
+ Implementation ledger:
13
13
  {{last.summary}}
14
14
 
15
- The approved plan is final authority. Do not ask a terminal question. If
16
- verification cannot follow the approved contract, diagnose and recover as
17
- described below; do not request a live decision.
15
+ ## Rules & Verification Criteria
18
16
 
19
- Re-read repository instructions and inspect the contracted repository, every
20
- approved criterion, diff, commit, caller, test, and current status. Run the
21
- exact standalone commands under `repositories[0].reviewer[].command`, including
22
- the complete repository test suite plus non-fixing format and lint checks.
23
- Confirm the actual child cwd, registered worktree, dedicated branch, and
24
- workspace manifest still identify the same prepared workspace; never create,
25
- switch, or replace it.
26
- Static Bash permissions are inspection-only; do not invent or broaden a
27
- command. Confirm exact commit titles, unchanged post-review snapshots,
28
- RED/GREEN evidence, and per-criterion outcomes. When preparation recorded a
29
- clean baseline, require a clean final worktree. When it recorded unrelated
30
- dirty resumable work, require that exact baseline state to remain unchanged and
31
- that no task-owned change remains uncommitted. Treat a skipped, stale,
32
- unavailable, timed-out, blocked, or failing required check as non-passing.
33
-
34
- Any regression, lint failure, formatting failure, or other actionable local
35
- verification finding must use outcome `failed`, with the exact evidence and
36
- smallest fix. The workflow transition returns `failed` directly to
37
- implementation. Do not use `retry` or `blocked` for such a finding.
38
-
39
- If the approved verification contract is exactly
40
- `Not applicable - read-only plan.`, the absence of repository test commands is
41
- intentional. Independently re-check every requested fact and acceptance
42
- criterion with non-mutating inspection, confirm the checkout stayed unchanged,
43
- and do not invent or require code-change tests, formatting, lint, commits, or
44
- RED/GREEN evidence that the approved read-only task does not call for.
45
-
46
- Do not stop at the first failed tool or command. Read the exact error, inspect
47
- current state, and try safe semantically equivalent read-only alternatives.
48
- Invocation-only repair is allowed when it preserves the exact check, target,
49
- flags, and side-effect scope; never turn a failing check into a different or
50
- weaker check. If a transient or context-bound failure has another safe attempt,
51
- use outcome `retry` with the exact call, error, attempts, current state, next
52
- alternative, and exact approved fenced `json` contract unchanged. Use `blocked`
53
- with exact evidence when reviewed intent, targets, commands, or authority are
54
- materially invalid, or after safe alternatives are exhausted and retry cannot
55
- resolve the environmental or access constraint.
56
-
57
- Call `workflow_complete_step` alone with outcome `passed` only when every
58
- criterion and required command passes with no actionable finding. The summary
59
- must repeat all approved criteria and contracts and provide fresh evidence.
60
- Use outcome `failed` for an actionable implementation or verification finding;
61
- include the full criteria, exact failure, location, evidence, and smallest
62
- required fix so the next implementation attempt has a complete handoff. For
63
- both `passed` and `failed`, include the exact approved fenced `json` repository
64
- contract unchanged so a retry retains only reviewed worker commands. Use
65
- `blocked` for an invalid approved contract or when offered recovery cannot make
66
- verification proceed safely.
67
- On a retry after `blocked`, re-check the blocked
68
- source or reconciliation issue and use any remaining safe relevant alternative;
69
- do not repeat an exhausted attempt without a changed precondition. Do not ask a
70
- terminal question.
17
+ 1. **Independent Verification**: Re-run all standalone commands under `repositories[0].reviewer[]` (`full-tests`, `lint`, `format`).
18
+ 2. **Strict Evidence**: Confirm exact commit title, clean status (or original dirty baseline preserved), and explicit criterion proofs. Any failing or skipped check is non-passing.
19
+ 3. **Outcomes**:
20
+ - `passed`: All acceptance criteria and automated checks verified.
21
+ - `failed`: Actionable failure or regression. Automatically returns to `implement` stage for fix.
22
+ - `retry`: Recoverable read-only environment failure.
23
+ - `blocked`: Corrupted workspace or missing review authority.
@@ -1,7 +1,7 @@
1
1
  version: 1
2
2
  id: ticket
3
3
  command: ticket
4
- description: Prepare a dedicated workspace, plan, implement, and verify a Jira ticket
4
+ description: 'Prepare a dedicated workspace, plan, implement, and verify an issue-tracker ticket. Example: /ticket PROJ-123 Fix a missing client-id header'
5
5
  start: prepare-workspace
6
6
  maxStepVisits: 20
7
7
  summaryMaxChars: 30000
@@ -10,18 +10,19 @@ steps:
10
10
  title: Prepare dedicated branch and worktree
11
11
  prompt:
12
12
  file: steps/shared/prepare-workspace.md
13
- agent: worker
13
+ agent: workspace-preparer
14
14
  workspace:
15
- bindOn: [ready]
16
- allowedRoots: ['~/repositories/worktrees']
15
+ bindOn:
16
+ - ready
17
+ allowedRoots:
18
+ - ~/repositories/worktrees
17
19
  permissions:
18
20
  tools: [read, ls, bash]
19
- skills: [caveman, coding-standards, using-git-worktrees]
21
+ mcp: []
22
+ extensions: [/]
23
+ skills: [using-git-worktrees, caveman]
20
24
  bash:
21
25
  mode: unrestricted
22
- requires:
23
- tools: [read, ls, bash]
24
- skills: [caveman, coding-standards, using-git-worktrees]
25
26
  transitions:
26
27
  ready: plan
27
28
  retry: prepare-workspace
@@ -32,65 +33,38 @@ steps:
32
33
  file: steps/ticket/plan.md
33
34
  agent: planner
34
35
  permissions:
35
- tools: [read, ls, bash]
36
- mcp: &ticket-mcp
37
- - atlassian/atlassian_getAccessibleAtlassianResources
38
- - atlassian/atlassian_getJiraIssue
39
- - atlassian/atlassian_getJiraIssueRemoteIssueLinks
40
- - atlassian/atlassian_searchJiraIssuesUsingJql
41
- - context7/resolve-library-id
42
- - context7/query-docs
43
- - sourcegraph/code_finder
44
- - sourcegraph/commit_search
45
- - sourcegraph/diff_search
46
- - sourcegraph/keyword_search
47
- - sourcegraph/list_files
48
- - sourcegraph/list_repos
49
- - sourcegraph/nls_search
50
- - sourcegraph/read_file
51
- - gh_grep/searchGitHub
52
- extensions: [pi-web-tools]
36
+ tools: [read, ls, bash, mcp]
37
+ mcp: [atlassian, context7, sourcegraph, glean, gitlab]
38
+ extensions: [/]
53
39
  skills:
54
- &ticket-plan-skills [
55
- caveman,
40
+ [
56
41
  jira-ticket,
57
42
  coding-standards,
58
- brainstorming,
43
+ writing-plans,
44
+ search-code-sourcegraph,
45
+ caveman,
59
46
  ]
60
47
  bash:
61
- mode: allow-list
62
- allow: &ticket-inspection-bash
63
- - executable: grep
64
- - executable: head
65
- - executable: ls
66
- - executable: pwd
67
- - executable: rg
68
- - executable: stat
69
- - executable: tail
70
- - executable: wc
71
- - executable: git
72
- argsPrefixes:
73
- [
74
- [status],
75
- [diff],
76
- [grep],
77
- [log],
78
- [ls-files],
79
- [rev-parse],
80
- [show],
81
- [merge-base],
82
- [rev-list],
83
- [worktree, list],
84
- ]
85
- requires:
86
- tools: [read, ls, bash, mcp]
87
- skills: *ticket-plan-skills
48
+ mode: unrestricted
88
49
  gate:
89
50
  provider: plannotator
90
51
  submitOutcome: submit
91
52
  approvedOutcome: approved
92
53
  rejectedOutcome: changes-requested
93
54
  timeoutMs: 30000
55
+ artifactContract:
56
+ maxChars: 10000
57
+ requiredSubstrings:
58
+ - '## Review summary'
59
+ - '## Review focus'
60
+ - '## Proposed approach'
61
+ - '## Validation'
62
+ - '## Risks'
63
+ - '## Execution appendix (machine-readable)'
64
+ - '## Publication contract'
65
+ forbiddenSubstrings:
66
+ - 'The complete gate artifact is the exact Markdown saved at'
67
+ onValidationFailure: retry
94
68
  transitions:
95
69
  approved: implement
96
70
  changes-requested: plan
@@ -103,23 +77,13 @@ steps:
103
77
  file: steps/ticket/implement.md
104
78
  agent: worker
105
79
  permissions:
106
- tools: [read, ls, bash, edit, write]
107
- mcp: *ticket-mcp
80
+ tools: [read, ls, bash, edit, write, mcp]
81
+ mcp: [context7]
82
+ extensions: [/]
108
83
  skills:
109
- &ticket-implement-skills [
110
- caveman,
111
- jira-ticket,
112
- coding-standards,
113
- systematic-debugging,
114
- test-driven-development,
115
- verification-before-completion,
116
- receiving-code-review,
117
- ]
84
+ [coding-standards, test-driven-development, lint-commands, caveman]
118
85
  bash:
119
86
  mode: unrestricted
120
- requires:
121
- tools: [read, ls, bash, edit, write, mcp]
122
- skills: *ticket-implement-skills
123
87
  transitions:
124
88
  ready: verify
125
89
  retry: implement
@@ -130,20 +94,13 @@ steps:
130
94
  file: steps/ticket/verify.md
131
95
  agent: reviewer
132
96
  permissions:
133
- tools: [read, ls, bash]
134
- mcp: *ticket-mcp
97
+ tools: [read, ls, bash, mcp]
98
+ mcp: [gitlab]
99
+ extensions: [/]
135
100
  skills:
136
- &ticket-verify-skills [
137
- caveman,
138
- jira-ticket,
139
- coding-standards,
140
- verification-before-completion,
141
- ]
101
+ [verification-before-completion, lint-commands, commit-format, caveman]
142
102
  bash:
143
103
  mode: unrestricted
144
- requires:
145
- tools: [read, ls, bash, mcp]
146
- skills: *ticket-verify-skills
147
104
  transitions:
148
105
  passed: $done
149
106
  failed: implement
@@ -1,7 +1,7 @@
1
1
  version: 1
2
2
  id: work
3
3
  command: work
4
- description: Prepare a dedicated workspace, plan, implement, and verify local work
4
+ description: 'Prepare a dedicated workspace, plan, implement, and verify local work. Example: /work Add rate limiting to user registration endpoint'
5
5
  start: prepare-workspace
6
6
  maxStepVisits: 20
7
7
  summaryMaxChars: 30000
@@ -10,18 +10,19 @@ steps:
10
10
  title: Prepare dedicated branch and worktree
11
11
  prompt:
12
12
  file: steps/shared/prepare-workspace.md
13
- agent: worker
13
+ agent: workspace-preparer
14
14
  workspace:
15
- bindOn: [ready]
16
- allowedRoots: ['~/repositories/worktrees']
15
+ bindOn:
16
+ - ready
17
+ allowedRoots:
18
+ - ~/repositories/worktrees
17
19
  permissions:
18
20
  tools: [read, ls, bash]
19
- skills: [caveman, coding-standards, using-git-worktrees]
21
+ mcp: []
22
+ extensions: [/]
23
+ skills: [using-git-worktrees, caveman]
20
24
  bash:
21
25
  mode: unrestricted
22
- requires:
23
- tools: [read, ls, bash]
24
- skills: [caveman, coding-standards, using-git-worktrees]
25
26
  transitions:
26
27
  ready: plan
27
28
  retry: prepare-workspace
@@ -32,55 +33,31 @@ steps:
32
33
  file: steps/work/plan.md
33
34
  agent: planner
34
35
  permissions:
35
- tools: [read, ls, bash]
36
- mcp: &work-mcp
37
- - context7/resolve-library-id
38
- - context7/query-docs
39
- - sourcegraph/code_finder
40
- - sourcegraph/commit_search
41
- - sourcegraph/diff_search
42
- - sourcegraph/keyword_search
43
- - sourcegraph/list_files
44
- - sourcegraph/list_repos
45
- - sourcegraph/nls_search
46
- - sourcegraph/read_file
47
- - gh_grep/searchGitHub
48
- extensions: [pi-web-tools]
49
- skills: &work-plan-skills [caveman, brainstorming, coding-standards]
36
+ tools: [read, ls, bash, mcp]
37
+ mcp: [context7, sourcegraph, glean, gh_grep]
38
+ extensions: [/]
39
+ skills:
40
+ [coding-standards, writing-plans, search-code-sourcegraph, caveman]
50
41
  bash:
51
- mode: allow-list
52
- allow: &work-inspection-bash
53
- - executable: grep
54
- - executable: head
55
- - executable: ls
56
- - executable: pwd
57
- - executable: rg
58
- - executable: stat
59
- - executable: tail
60
- - executable: wc
61
- - executable: git
62
- argsPrefixes:
63
- [
64
- [status],
65
- [diff],
66
- [grep],
67
- [log],
68
- [ls-files],
69
- [rev-parse],
70
- [show],
71
- [merge-base],
72
- [rev-list],
73
- [worktree, list],
74
- ]
75
- requires:
76
- tools: [read, ls, bash]
77
- skills: *work-plan-skills
42
+ mode: unrestricted
78
43
  gate:
79
44
  provider: plannotator
80
45
  submitOutcome: submit
81
46
  approvedOutcome: approved
82
47
  rejectedOutcome: changes-requested
83
48
  timeoutMs: 30000
49
+ artifactContract:
50
+ maxChars: 8000
51
+ requiredSubstrings:
52
+ - '## Review summary'
53
+ - '## Review focus'
54
+ - '## Proposed approach'
55
+ - '## Validation'
56
+ - '## Risks'
57
+ - '## Execution appendix (machine-readable)'
58
+ forbiddenSubstrings:
59
+ - 'The complete gate artifact is the exact Markdown saved at'
60
+ onValidationFailure: retry
84
61
  transitions:
85
62
  approved: implement
86
63
  changes-requested: plan
@@ -93,22 +70,13 @@ steps:
93
70
  file: steps/work/implement.md
94
71
  agent: worker
95
72
  permissions:
96
- tools: [read, ls, bash, edit, write]
97
- mcp: *work-mcp
73
+ tools: [read, ls, bash, edit, write, mcp]
74
+ mcp: [context7]
75
+ extensions: [/]
98
76
  skills:
99
- &work-implement-skills [
100
- caveman,
101
- coding-standards,
102
- systematic-debugging,
103
- test-driven-development,
104
- verification-before-completion,
105
- receiving-code-review,
106
- ]
77
+ [coding-standards, test-driven-development, lint-commands, caveman]
107
78
  bash:
108
79
  mode: unrestricted
109
- requires:
110
- tools: [read, ls, bash, edit, write]
111
- skills: *work-implement-skills
112
80
  transitions:
113
81
  ready: verify
114
82
  retry: implement
@@ -120,18 +88,12 @@ steps:
120
88
  agent: reviewer
121
89
  permissions:
122
90
  tools: [read, ls, bash]
123
- mcp: *work-mcp
91
+ mcp: []
92
+ extensions: [/]
124
93
  skills:
125
- &work-verify-skills [
126
- caveman,
127
- coding-standards,
128
- verification-before-completion,
129
- ]
94
+ [verification-before-completion, lint-commands, commit-format, caveman]
130
95
  bash:
131
96
  mode: unrestricted
132
- requires:
133
- tools: [read, ls, bash]
134
- skills: *work-verify-skills
135
97
  transitions:
136
98
  passed: $done
137
99
  failed: implement
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wichayutdew/pi-workflows",
3
- "version": "2.6.0",
3
+ "version": "2.7.0",
4
4
  "description": "A declarative, pauseable workflow harness for Pi",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -23,16 +23,19 @@
23
23
  "src",
24
24
  "examples",
25
25
  "schemas",
26
+ "scripts",
26
27
  "README.md",
27
28
  "LICENSE"
28
29
  ],
29
30
  "pi": {
30
31
  "extensions": [
31
- "./src/index.ts"
32
+ "./src/index.ts",
33
+ "./src/herdr-workflow-state.ts"
32
34
  ]
33
35
  },
34
36
  "scripts": {
35
37
  "build": "bun build ./src/index.ts --outdir=dist --target=node --format=esm --packages=external",
38
+ "patch:herdr": "node ./scripts/patch-herdr-agent-state.mjs",
36
39
  "format": "bunx --bun prettier . --write",
37
40
  "format:check": "bunx --bun prettier . --check",
38
41
  "lint": "bun --bun eslint .",
@@ -56,7 +59,7 @@
56
59
  "@earendil-works/pi-coding-agent": "^0.81.1",
57
60
  "@earendil-works/pi-tui": "^0.81.1",
58
61
  "@eslint/js": "^10.0.1",
59
- "@types/bun": "^1.3.14",
62
+ "@types/bun": "^1.4.0",
60
63
  "@types/node": "^24.0.0",
61
64
  "eslint": "^10.7.0",
62
65
  "globals": "^17.7.0",
@@ -65,7 +68,7 @@
65
68
  "typescript": "^5.9.3",
66
69
  "typescript-eslint": "^8.64.0"
67
70
  },
68
- "packageManager": "bun@1.3.14",
71
+ "packageManager": "bun@1.4.0",
69
72
  "engines": {
70
73
  "node": ">=22.19.0"
71
74
  }
@@ -514,6 +514,61 @@
514
514
  }
515
515
  }
516
516
  },
517
+ "artifactContract": {
518
+ "type": "object",
519
+ "additionalProperties": false,
520
+ "required": [
521
+ "maxChars",
522
+ "requiredSubstrings",
523
+ "forbiddenSubstrings",
524
+ "equalOccurrenceGroups"
525
+ ],
526
+ "properties": {
527
+ "maxChars": {
528
+ "type": "integer",
529
+ "minimum": 1,
530
+ "maximum": 200000
531
+ },
532
+ "requiredSubstrings": {
533
+ "type": "array",
534
+ "maxItems": 32,
535
+ "uniqueItems": true,
536
+ "items": {
537
+ "type": "string",
538
+ "minLength": 1,
539
+ "maxLength": 1024
540
+ }
541
+ },
542
+ "forbiddenSubstrings": {
543
+ "type": "array",
544
+ "maxItems": 32,
545
+ "uniqueItems": true,
546
+ "items": {
547
+ "type": "string",
548
+ "minLength": 1,
549
+ "maxLength": 1024
550
+ }
551
+ },
552
+ "equalOccurrenceGroups": {
553
+ "type": "array",
554
+ "maxItems": 32,
555
+ "items": {
556
+ "type": "array",
557
+ "minItems": 2,
558
+ "maxItems": 32,
559
+ "uniqueItems": true,
560
+ "items": {
561
+ "type": "string",
562
+ "minLength": 1,
563
+ "maxLength": 1024
564
+ }
565
+ }
566
+ },
567
+ "onValidationFailure": {
568
+ "const": "retry"
569
+ }
570
+ }
571
+ },
517
572
  "gate": {
518
573
  "oneOf": [
519
574
  {
@@ -533,6 +588,9 @@
533
588
  },
534
589
  "rejectedOutcome": {
535
590
  "$ref": "#/$defs/identifier"
591
+ },
592
+ "artifactContract": {
593
+ "$ref": "#/$defs/artifactContract"
536
594
  }
537
595
  }
538
596
  },
@@ -563,6 +621,9 @@
563
621
  "minimum": 1000,
564
622
  "maximum": 30000,
565
623
  "default": 30000
624
+ },
625
+ "artifactContract": {
626
+ "$ref": "#/$defs/artifactContract"
566
627
  }
567
628
  }
568
629
  }
@@ -0,0 +1,36 @@
1
+ import { readFile, writeFile } from 'node:fs/promises';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+
5
+ const target =
6
+ process.env.HERDR_PI_EXTENSION_PATH ??
7
+ join(homedir(), '.pi', 'agent', 'extensions', 'herdr-agent-state.ts');
8
+ const source = await readFile(target, 'utf8');
9
+ if (source.includes('pi-workflows-herdr-lifecycle-patch:start')) {
10
+ console.log(`Herdr workflow patch already present: ${target}`);
11
+ process.exit(0);
12
+ }
13
+ const state =
14
+ ' // pi-workflows-herdr-lifecycle-patch:start\n let workflowActive = false;\n let workflowMessage: string | undefined;\n // pi-workflows-herdr-lifecycle-patch:end\n';
15
+ const listener =
16
+ ' // pi-workflows-herdr-lifecycle-patch:start\n pi.events.on("pi-workflows:state", (data) => {\n if (!rootSession || !data || typeof data !== "object") return;\n const event = data as { state?: string; message?: string };\n workflowActive = event.state === "working";\n workflowMessage = event.message;\n publishState();\n });\n // pi-workflows-herdr-lifecycle-patch:end\n\n';
17
+ let patched = source.replace(
18
+ ' let blockedCount = 0;',
19
+ `${state} let blockedCount = 0;`,
20
+ );
21
+ patched = patched.replace(
22
+ ' if (agentActive) {\n return { state: "working" as const, message: undefined };',
23
+ ' if (agentActive || workflowActive) {\n return { state: "working" as const, message: workflowMessage };',
24
+ );
25
+ patched = patched.replace(
26
+ ' return { state: "idle" as const, message: undefined };',
27
+ ' return { state: "idle" as const, message: workflowMessage };',
28
+ );
29
+ patched = patched.replace(
30
+ ' pi.events.on("herdr:blocked",',
31
+ `${listener} pi.events.on("herdr:blocked",`,
32
+ );
33
+ if (patched === source)
34
+ throw new Error(`Unsupported Herdr integration layout: ${target}`);
35
+ await writeFile(target, patched);
36
+ console.log(`Patched Herdr workflow lifecycle reporting: ${target}`);
@@ -49,10 +49,19 @@ export type StepAgent = {
49
49
  export type PromptSpec =
50
50
  { readonly inline: string } | { readonly file: string };
51
51
 
52
+ export type ArtifactContract = {
53
+ readonly maxChars: number;
54
+ readonly requiredSubstrings: ReadonlyArray<string>;
55
+ readonly forbiddenSubstrings: ReadonlyArray<string>;
56
+ readonly equalOccurrenceGroups: ReadonlyArray<ReadonlyArray<string>>;
57
+ readonly onValidationFailure?: 'retry';
58
+ };
59
+
52
60
  type GateDefinition = {
53
61
  readonly submitOutcome: string;
54
62
  readonly approvedOutcome: string;
55
63
  readonly rejectedOutcome: string;
64
+ readonly artifactContract?: ArtifactContract;
56
65
  };
57
66
 
58
67
  export type PromptGate = GateDefinition & {