pi-workflow-engine 0.11.0 → 0.12.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 (73) hide show
  1. package/.pi/extensions/pi-workflow-engine/index.ts +255 -97
  2. package/.pi/extensions/pi-workflow-engine/src/advisory-schema.ts +0 -4
  3. package/.pi/extensions/pi-workflow-engine/src/agent-attempt.ts +3 -1
  4. package/.pi/extensions/pi-workflow-engine/src/agent-limits.ts +35 -0
  5. package/.pi/extensions/pi-workflow-engine/src/agent-replay.ts +27 -4
  6. package/.pi/extensions/pi-workflow-engine/src/agent-retry.ts +116 -0
  7. package/.pi/extensions/pi-workflow-engine/src/agent-runner-types.ts +49 -45
  8. package/.pi/extensions/pi-workflow-engine/src/agent-runner.ts +95 -26
  9. package/.pi/extensions/pi-workflow-engine/src/agent-session-providers.ts +50 -0
  10. package/.pi/extensions/pi-workflow-engine/src/agent-session.ts +158 -203
  11. package/.pi/extensions/pi-workflow-engine/src/agent-skills.ts +48 -42
  12. package/.pi/extensions/pi-workflow-engine/src/agent-workspace.ts +11 -3
  13. package/.pi/extensions/pi-workflow-engine/src/background-workflow-tool.ts +75 -0
  14. package/.pi/extensions/pi-workflow-engine/src/background-workflows.ts +492 -0
  15. package/.pi/extensions/pi-workflow-engine/src/budget.ts +3 -3
  16. package/.pi/extensions/pi-workflow-engine/src/cancellation.ts +38 -0
  17. package/.pi/extensions/pi-workflow-engine/src/command-completions.ts +36 -0
  18. package/.pi/extensions/pi-workflow-engine/src/concurrency.ts +70 -4
  19. package/.pi/extensions/pi-workflow-engine/src/diff-capture.ts +16 -130
  20. package/.pi/extensions/pi-workflow-engine/src/discovery.ts +9 -5
  21. package/.pi/extensions/pi-workflow-engine/src/dynamax.ts +109 -60
  22. package/.pi/extensions/pi-workflow-engine/src/engine.ts +166 -18
  23. package/.pi/extensions/pi-workflow-engine/src/filesystem-error.ts +4 -0
  24. package/.pi/extensions/pi-workflow-engine/src/inline-workflow.ts +2 -2
  25. package/.pi/extensions/pi-workflow-engine/src/journal.ts +12 -6
  26. package/.pi/extensions/pi-workflow-engine/src/model-profile-command.ts +167 -0
  27. package/.pi/extensions/pi-workflow-engine/src/model-profiles.ts +310 -0
  28. package/.pi/extensions/pi-workflow-engine/src/options.ts +88 -1
  29. package/.pi/extensions/pi-workflow-engine/src/pi-compat.ts +32 -0
  30. package/.pi/extensions/pi-workflow-engine/src/progress-types.ts +50 -0
  31. package/.pi/extensions/pi-workflow-engine/src/progress.ts +72 -117
  32. package/.pi/extensions/pi-workflow-engine/src/provider-usage-limit.ts +189 -0
  33. package/.pi/extensions/pi-workflow-engine/src/research-contract.ts +89 -0
  34. package/.pi/extensions/pi-workflow-engine/src/research-evidence.ts +289 -0
  35. package/.pi/extensions/pi-workflow-engine/src/resume-context.ts +74 -38
  36. package/.pi/extensions/pi-workflow-engine/src/review/code-review-orchestration.ts +49 -0
  37. package/.pi/extensions/pi-workflow-engine/src/review/review-report.ts +1 -1
  38. package/.pi/extensions/pi-workflow-engine/src/review/review-results-flow.ts +2 -1
  39. package/.pi/extensions/pi-workflow-engine/src/review/review-results-viewer.ts +11 -30
  40. package/.pi/extensions/pi-workflow-engine/src/review/review-session-coordinator.ts +5 -5
  41. package/.pi/extensions/pi-workflow-engine/src/review/review-snapshot.ts +3 -4
  42. package/.pi/extensions/pi-workflow-engine/src/review-diff-target.ts +130 -0
  43. package/.pi/extensions/pi-workflow-engine/src/session-identity.ts +6 -0
  44. package/.pi/extensions/pi-workflow-engine/src/structured-output.ts +32 -0
  45. package/.pi/extensions/pi-workflow-engine/src/tool-capabilities.ts +44 -0
  46. package/.pi/extensions/pi-workflow-engine/src/tool-source-identity.ts +1 -4
  47. package/.pi/extensions/pi-workflow-engine/src/tree-fingerprint.ts +1 -4
  48. package/.pi/extensions/pi-workflow-engine/src/types.ts +49 -15
  49. package/.pi/extensions/pi-workflow-engine/src/ui/dynamax-editor-decoration.ts +220 -0
  50. package/.pi/extensions/pi-workflow-engine/src/ui/workflow-format.ts +26 -6
  51. package/.pi/extensions/pi-workflow-engine/src/ui/workflow-inspector.ts +88 -46
  52. package/.pi/extensions/pi-workflow-engine/src/ui/workflow-result-renderer.ts +2 -1
  53. package/.pi/extensions/pi-workflow-engine/src/ui/workflow-viewer-layout.ts +51 -0
  54. package/.pi/extensions/pi-workflow-engine/src/ui/workflow-widget.ts +12 -67
  55. package/.pi/extensions/pi-workflow-engine/src/usage.ts +124 -16
  56. package/.pi/extensions/pi-workflow-engine/src/workflow-advisory-utils.ts +23 -3
  57. package/.pi/extensions/pi-workflow-engine/src/workflow-execution.ts +1 -1
  58. package/.pi/extensions/pi-workflow-engine/src/workflow-run-background.ts +72 -0
  59. package/.pi/extensions/pi-workflow-engine/src/workflow-run-controller.ts +354 -0
  60. package/.pi/extensions/pi-workflow-engine/src/workflow-run-history.ts +162 -0
  61. package/.pi/extensions/pi-workflow-engine/src/workflow-run-record.ts +632 -0
  62. package/.pi/extensions/pi-workflow-engine/src/workflow-run-store.ts +172 -0
  63. package/.pi/extensions/pi-workflow-engine/src/workflow-usage-limit-scheduler.ts +80 -0
  64. package/.pi/extensions/pi-workflow-engine/src/workflows.ts +2 -0
  65. package/.pi/extensions/pi-workflow-engine/src/worktree.ts +40 -3
  66. package/.pi/extensions/pi-workflow-engine/workflows/code-review.ts +18 -42
  67. package/.pi/extensions/pi-workflow-engine/workflows/diagnose.ts +10 -17
  68. package/.pi/extensions/pi-workflow-engine/workflows/perf-review.ts +8 -15
  69. package/.pi/extensions/pi-workflow-engine/workflows/refactor-scout.ts +8 -15
  70. package/.pi/extensions/pi-workflow-engine/workflows/research.ts +170 -0
  71. package/README.md +72 -141
  72. package/USAGE.md +211 -17
  73. package/package.json +1 -1
@@ -2,13 +2,14 @@ import { Type } from "typebox";
2
2
  import {
3
3
  AdvisoryReportSchema,
4
4
  type AdvisoryCandidate,
5
- type AdvisoryReport,
6
5
  type AdvisoryVerdict,
7
6
  } from "../src/advisory-schema.ts";
8
7
  import {
9
8
  backfillAdvisoryFindings,
9
+ emptyAdvisoryReport,
10
10
  formatEvidence,
11
11
  formatLocation,
12
+ publishVerifiedKeptProgress,
12
13
  runLensVerificationPipeline,
13
14
  DEFAULT_ADVISORY_TOOL_HINTS,
14
15
  DEFAULT_ADVISORY_TOOLS,
@@ -79,11 +80,11 @@ export default async function run(api: WorkflowApi): Promise<unknown> {
79
80
  "Inspect repository structure, the target path or module, and relevant AGENTS.md / project docs conventions. " +
80
81
  "Return the concrete files that should be considered, a short summary, and any conventions that affect refactor advice. " +
81
82
  `This workflow will fan out across ${REFACTOR_LENSES.length} lenses with up to ${PER_LENS} candidates per lens. Structured output only.`,
82
- { phase: "Scope", label: "scope", tools: TOOLS, toolHints: TOOL_HINTS, thinkingLevel: "medium", schema: ScopeSchema },
83
+ { phase: "Scope", label: "scope", tools: TOOLS, toolHints: TOOL_HINTS, profile: "medium", schema: ScopeSchema },
83
84
  );
84
85
 
85
86
  if (!scope || scope.files.length === 0) {
86
- return emptyReport(
87
+ return emptyAdvisoryReport(
87
88
  "No files were identified for refactor scouting.",
88
89
  ["Provide a target path, module, or subsystem to scout for refactor opportunities."],
89
90
  makeStats(0, 0),
@@ -136,14 +137,10 @@ export default async function run(api: WorkflowApi): Promise<unknown> {
136
137
  const verified = pipelineResult.verified;
137
138
  const surviving = verified.filter((finding) => finding.verdict !== "REFUTED");
138
139
  const stats = makeStats(verified.length, surviving.length);
139
- progress({ type: "counter", key: "verified", label: "verified", value: verified.length });
140
- progress({ type: "counter", key: "kept", label: "kept", value: surviving.length });
141
- progress({ type: "summary", key: "verified", value: verified.length });
142
- progress({ type: "summary", key: "kept", value: surviving.length });
143
- log(`${verified.length} verified → ${surviving.length} kept`);
140
+ publishVerifiedKeptProgress({ progress, log }, verified.length, surviving.length);
144
141
 
145
142
  if (surviving.length === 0) {
146
- return emptyReport("No refactor opportunities survived verification.", ["Leave the scoped code unchanged unless a human reviewer has additional context."], stats);
143
+ return emptyAdvisoryReport("No refactor opportunities survived verification.", ["Leave the scoped code unchanged unless a human reviewer has additional context."], stats);
147
144
  }
148
145
 
149
146
  phase("Synthesize");
@@ -166,13 +163,13 @@ export default async function run(api: WorkflowApi): Promise<unknown> {
166
163
  phase: "Synthesize",
167
164
  label: "synthesize",
168
165
  tools: [],
169
- thinkingLevel: "medium",
166
+ profile: "medium",
170
167
  resume: "read-only",
171
168
  schema: AdvisoryReportSchema,
172
169
  },
173
170
  );
174
171
 
175
- if (!report) return emptyReport("Synthesis produced no output.", ["Inspect verifier evidence manually or rerun the workflow with a narrower target."], stats);
172
+ if (!report) return emptyAdvisoryReport("Synthesis produced no output.", ["Inspect verifier evidence manually or rerun the workflow with a narrower target."], stats);
176
173
 
177
174
  const findings = backfillAdvisoryFindings(report.findings, ranked, {
178
175
  impact: "Impact not restated by synthesis.",
@@ -181,10 +178,6 @@ export default async function run(api: WorkflowApi): Promise<unknown> {
181
178
  return { ...report, findings, stats };
182
179
  }
183
180
 
184
- function emptyReport(summary: string, nextSteps: string[], stats: WorkflowRunStats): AdvisoryReport & { stats: WorkflowRunStats } {
185
- return { summary, findings: [], nextSteps, stats };
186
- }
187
-
188
181
  function rank(finding: Verified): number {
189
182
  const verdictRank = finding.verdict === "CONFIRMED" ? 0 : 1;
190
183
  const categoryRank = finding.category === "dead-code" || finding.category === "conventions" ? 2 : 0;
@@ -0,0 +1,170 @@
1
+ import { compactResults } from "../src/concurrency.ts";
2
+ import {
3
+ MAX_RESEARCH_LANES,
4
+ ResearchLaneResultSchema,
5
+ ResearchPlanSchema,
6
+ ResearchReportSchema,
7
+ ResearchVerificationSchema,
8
+ type ResearchClaimCandidate,
9
+ type ResearchReport,
10
+ type ResearchVerification,
11
+ } from "../src/research-contract.ts";
12
+ import {
13
+ buildClaimCandidates,
14
+ fallbackResearchReport,
15
+ normalizeResearchLanes,
16
+ sanitizeLaneResults,
17
+ sanitizeResearchReport,
18
+ sanitizeVerification,
19
+ unavailableResearchReport,
20
+ unavailableVerification,
21
+ } from "../src/research-evidence.ts";
22
+ import { WorkflowToolHintUnavailableError } from "../src/tool-capabilities.ts";
23
+ import type { WorkflowApi, WorkflowMeta } from "../src/types.ts";
24
+
25
+ export const meta: WorkflowMeta = {
26
+ name: "research",
27
+ description: "Source-grounded external research: decompose → gather direct-page evidence → independently verify claims → cited synthesis.",
28
+ phases: [{ title: "Plan" }, { title: "Gather" }, { title: "Verify" }, { title: "Synthesize" }],
29
+ };
30
+
31
+ const EXTERNAL_TOOLS: string[] = [];
32
+ const EXTERNAL_TOOL_HINTS = ["external-search"] as const;
33
+
34
+ export default async function run(api: WorkflowApi): Promise<ResearchReport> {
35
+ const { agent, parallel, phase, log, progress, args } = api;
36
+ const question = args.trim();
37
+ if (!question) return unavailableResearchReport("empty-question");
38
+
39
+ phase("Plan");
40
+ let plan;
41
+ try {
42
+ plan = await agent(
43
+ `Plan bounded, source-grounded research for the user's question and any scope constraints embedded in it.\n\n` +
44
+ `Question and constraints (verbatim):\n${question}\n\n` +
45
+ `Create at most ${MAX_RESEARCH_LANES} non-overlapping lanes. Each lane needs a stable short id, title, objective, and 1-4 concrete search queries. ` +
46
+ "Separate primary-source discovery, current status, counterevidence, or jurisdiction/timeframe only when relevant. " +
47
+ "Do not claim exhaustive coverage. Structured output only.",
48
+ {
49
+ phase: "Plan",
50
+ label: "plan",
51
+ tools: EXTERNAL_TOOLS,
52
+ toolHints: EXTERNAL_TOOL_HINTS,
53
+ requireToolHints: true,
54
+ profile: "medium",
55
+ resume: "off",
56
+ schema: ResearchPlanSchema,
57
+ },
58
+ );
59
+ } catch (error) {
60
+ if (error instanceof WorkflowToolHintUnavailableError) return unavailableResearchReport("missing-capability");
61
+ throw error;
62
+ }
63
+
64
+ if (!plan) return unavailableResearchReport("no-evidence");
65
+ const lanes = normalizeResearchLanes(plan);
66
+ if (lanes.length === 0) return unavailableResearchReport("no-evidence");
67
+ progress({ type: "counter", key: "research.lanes", label: "research lanes", value: lanes.length });
68
+ progress({ type: "summary", key: "research.question", value: question });
69
+
70
+ phase("Gather");
71
+ const gathered = compactResults(
72
+ await parallel(
73
+ lanes.map((lane) => async () => {
74
+ const result = await agent(
75
+ `Research one bounded lane using only installed external web-search, browsing, or URL-extraction tools.\n\n` +
76
+ `Question: ${question}\n` +
77
+ `Scope constraints: ${plan.scopeConstraints.join("; ") || "(none)"}\n` +
78
+ `Lane id: ${lane.id}\nLane: ${lane.title}\nObjective: ${lane.objective}\n` +
79
+ `Queries:\n${lane.queries.map((query) => `- ${query}`).join("\n")}\n\n` +
80
+ "Open the supporting pages instead of citing a search-results page. Prefer primary and authoritative sources; use independent sources when useful. " +
81
+ "Return concrete claims with importance, whether each page supports or conflicts with the claim, a short passage or precise paraphrase, and the exact page title and URL. " +
82
+ "State evidence gaps. Never invent a URL or claim that the opened page does not support. Structured output only.",
83
+ {
84
+ phase: "Gather",
85
+ label: `gather:${lane.id}`,
86
+ tools: EXTERNAL_TOOLS,
87
+ toolHints: EXTERNAL_TOOL_HINTS,
88
+ requireToolHints: true,
89
+ profile: "small",
90
+ resume: "off",
91
+ schema: ResearchLaneResultSchema,
92
+ },
93
+ );
94
+ if (!result) return null;
95
+ progress({ type: "counter_delta", key: "research.evidence", label: "evidence items", delta: result.evidence.length });
96
+ progress({
97
+ type: "lane_item",
98
+ lane: "Research lanes",
99
+ title: lane.title,
100
+ subtitle: `${result.evidence.length} evidence item(s)`,
101
+ status: result.evidence.length > 0 ? "success" : "warning",
102
+ details: result.gaps.join("; ") || lane.objective,
103
+ });
104
+ return result;
105
+ }),
106
+ ),
107
+ );
108
+
109
+ const laneResults = sanitizeLaneResults(gathered);
110
+ const candidates = buildClaimCandidates(laneResults);
111
+ if (candidates.length === 0) return unavailableResearchReport("no-evidence");
112
+ progress({ type: "counter", key: "research.claims", label: "claims to verify", value: candidates.length });
113
+ log(`${candidates.length} bounded claim(s) selected for independent verification`);
114
+
115
+ phase("Verify");
116
+ const verificationResults = await parallel(
117
+ candidates.map((candidate, index) => async () => {
118
+ const result = await agent(verificationPrompt(question, candidate), {
119
+ phase: "Verify",
120
+ label: `verify:${index + 1}`,
121
+ tools: EXTERNAL_TOOLS,
122
+ toolHints: EXTERNAL_TOOL_HINTS,
123
+ requireToolHints: true,
124
+ profile: "medium",
125
+ resume: "off",
126
+ schema: ResearchVerificationSchema,
127
+ });
128
+ return result ? sanitizeVerification(result, candidate) : null;
129
+ }),
130
+ );
131
+ const verifications = verificationResults.map((result, index) => result ?? unavailableVerification(candidates[index]!));
132
+ for (const verification of verifications) {
133
+ progress({ type: "counter_delta", key: `research.${verification.verdict.toLowerCase()}`, label: verification.verdict.toLowerCase(), delta: 1 });
134
+ }
135
+ const synthesisInputs = verifications.filter((verification) => verification.verdict !== "REJECTED");
136
+
137
+ phase("Synthesize");
138
+ const synthesis = await agent(
139
+ `Answer the research question using only the independently verified handoff below.\n\n` +
140
+ `Question: ${question}\nScope constraints: ${plan.scopeConstraints.join("; ") || "(none)"}\n\n` +
141
+ `Verified claims JSON:\n${JSON.stringify(synthesisInputs)}\n\n` +
142
+ "Keep SUPPORTED claims, CONFLICTED evidence, UNCERTAIN claims, and model INFERENCE in their separate fields. Exclude REJECTED claims. " +
143
+ "Copy each verified claim string exactly so its citations remain bound to that claim during validation. " +
144
+ "Every supported or conflicting claim must cite exact title/URL objects from its verification; do not add URLs, cite search-results pages, or turn inference into fact. " +
145
+ "Answer concisely, disclose limited coverage, and provide useful next steps. Structured output only.",
146
+ {
147
+ phase: "Synthesize",
148
+ label: "synthesize",
149
+ tools: [],
150
+ profile: "medium",
151
+ resume: "off",
152
+ schema: ResearchReportSchema,
153
+ },
154
+ );
155
+
156
+ return sanitizeResearchReport(
157
+ synthesis ?? fallbackResearchReport(synthesisInputs, "The model did not return a structured synthesis."),
158
+ synthesisInputs,
159
+ );
160
+ }
161
+
162
+ function verificationPrompt(question: string, candidate: ResearchClaimCandidate): string {
163
+ return `Independently verify one important research claim using installed external web-search, browsing, or URL-extraction tools.\n\n` +
164
+ `Question: ${question}\nClaim: ${candidate.claim}\nImportance: ${candidate.importance}\n\n` +
165
+ `Gather-stage evidence (context only; do not treat it as verified):\n${JSON.stringify(candidate.evidence)}\n\n` +
166
+ "Search independently and open direct supporting pages. Prefer primary/authoritative sources and actively look for credible counterevidence. " +
167
+ "Return SUPPORTED only when direct pages substantiate the claim, CONFLICTED when credible sources disagree, UNCERTAIN when evidence is insufficient, " +
168
+ "INFERENCE when the conclusion is reasoned rather than directly stated, or REJECTED when evidence refutes it. " +
169
+ "Include exact page titles and direct HTTP(S) URLs, never search-results URLs. Structured output only.";
170
+ }
package/README.md CHANGED
@@ -4,63 +4,48 @@
4
4
  [![npm](https://img.shields.io/npm/v/pi-workflow-engine)](https://www.npmjs.com/package/pi-workflow-engine)
5
5
  [![MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
6
6
 
7
- **A multi-agent workflow engine for [pi](https://pi.dev).**
7
+ **Multi-agent workflows for [pi](https://pi.dev).**
8
8
 
9
- One coding agent is usually enough. When a task needs independent opinions,
10
- competing hypotheses, or a verifier that did not write the first answer, this
11
- extension lets pi fan the work out and bring the evidence back together.
12
-
13
- The process is simple: **scope → fan out → verify → synthesize**. You see the work
14
- live in the TUI, concurrency stays bounded, and the final answer includes the
15
- subagents' combined usage and estimated cost when the provider exposes enough
16
- data to calculate them.
9
+ When a task benefits from independent review, competing hypotheses, or separate
10
+ verification, pi-workflow-engine fans it out to subagents and synthesizes one
11
+ result. Run a built-in workflow or add `dynamax` to a prompt so pi can compose a
12
+ one-off workflow for the task.
17
13
 
18
14
  ![A lead agent coordinating subagents](assets/preview.png)
19
15
 
20
16
  ## Quick start
21
17
 
18
+ Requires **pi 0.80.10 or newer**.
19
+
22
20
  ```bash
23
21
  pi install npm:pi-workflow-engine
24
22
  ```
25
23
 
26
- Restart pi or run `/reload`, then add `dynamax` to a prompt:
24
+ Restart pi or run `/reload`, then try either style:
27
25
 
28
26
  ```text
29
27
  dynamax investigate why typecheck started failing on this branch
30
- ```
31
-
32
- `dynamax` is a one-shot opt-in. It lets the host agent choose a saved workflow
33
- or author a temporary one for this task. Use `/workflow:dynamax on` when you
34
- want that permission to remain active for the session.
35
-
36
- Saved workflows are available directly:
37
28
 
38
- ```text
39
29
  /workflow code-review
40
30
  /workflow refactor-scout src/
41
31
  /workflow diagnose "the schema migration broke typecheck"
42
- /workflow perf-review "workflow startup latency"
43
32
  ```
44
33
 
45
- The package uses pi's bundled SDK and core packages; it does not install or
46
- bundle a second agent runtime.
47
-
48
- ## What it gives you
49
-
50
- - **Independent passes.** Different agents can inspect correctness, tests,
51
- coupling, performance, or any lenses you define.
52
- - **Typed handoffs.** A TypeBox schema becomes the agent's terminating tool
53
- contract—there is no JSON scraping.
54
- - **Live progress.** Phases, agents, findings, and logs are visible in the TUI,
55
- alongside usage and estimated cost when provider data is available.
56
- - **Bounded execution.** One semaphore covers nested fan-out, pipelines, and
57
- sub-workflows.
58
- - **Evidence before action.** Built-in workflows inspect and report by default;
59
- they do not edit your working tree.
60
- - **Reviewable mutation.** An author can opt a mutating agent into a disposable
61
- git worktree and receive its patch.
62
- - **Safe replay.** Interrupted runs reuse a completed call only when every
63
- captured observable surface and its effective execution identity still match.
34
+ Built-in workflows inspect and report by default; they do not edit your working
35
+ tree.
36
+
37
+ ## What you get
38
+
39
+ - **Independent analysis.** Give correctness, testing, performance, or other
40
+ concerns to separate agents instead of asking one agent to cover everything.
41
+ - **Verified results.** Workflows can check and rank findings before presenting
42
+ a single synthesis.
43
+ - **Live visibility.** Follow phases and agents in the TUI, with usage and cost
44
+ totals when the provider reports them.
45
+ - **Controlled execution.** Concurrency, timeouts, agent counts, and token
46
+ budgets keep fan-out bounded.
47
+ - **Safe follow-up.** Advisory runs leave the checkout alone, while selected
48
+ review fixes can return isolated patch previews.
64
49
 
65
50
  ## Built-in workflows
66
51
 
@@ -69,115 +54,63 @@ bundle a second agent runtime.
69
54
  | `code-review` | PRs, branch diffs, ref ranges, or focused targets |
70
55
  | `refactor-scout` | Small, defensible refactors without broad rewrites |
71
56
  | `diagnose` | Competing explanations for bugs or failing commands |
72
- | `perf-review` | Measured bottlenecks versus performance guesses |
57
+ | `perf-review` | Measured bottlenecks rather than performance guesses |
58
+ | `research` | Cited external evidence with independent claim verification |
73
59
 
74
- These are starting points, not a fixed menu. Dynamax can author a one-off
75
- workflow when the question needs different lenses or an adaptive second pass.
60
+ The `research` workflow needs an installed pi tool that can search or browse the
61
+ web. See the [built-in workflow guide](USAGE.md#built-in-workflows) for behavior
62
+ and requirements.
76
63
 
77
- ## The review experience
64
+ ## Use Dynamax for one-off workflows
78
65
 
79
- When reviewing a PR, `code-review` uses its cumulative diff, so superseded code
80
- from earlier commits does not become a finding. Candidate issues are
81
- independently verified, deduplicated, and ranked before synthesis.
66
+ Use `dynamax` when no saved workflow quite fits and independent passes are
67
+ likely to change the answer:
82
68
 
83
- Add `--result-viewer` to open the interactive findings view. It exposes a findings list for follow-up. Reopen the current session's latest review
84
- with `/workflow:results` or `ctrl+shift+r`—it does not rerun the workflow.
69
+ ```text
70
+ dynamax review this branch for correctness, tests, and maintainability; verify every finding
71
+ dynamax investigate this flaky test using separate timing, fixture, diff, and external-state hypotheses
72
+ dynamax argue both implementation options, then have another agent challenge the recommendation
73
+ ```
85
74
 
86
- The **Fix** action creates one disposable worktree per selected finding and
87
- returns separate patch previews without touching the active checkout. GitHub
88
- comments are available only for a verified PR target; the engine checks the
89
- snapshot and PR head again and skips exact duplicates before posting.
75
+ The token enables Dynamax for one turn. Sticky mode remains active for the pi
76
+ session:
90
77
 
91
- ## Prompts that benefit from Dynamax
78
+ ```text
79
+ /workflow:dynamax on
80
+ /workflow:dynamax off
81
+ /workflow:dynamax status
82
+ ```
92
83
 
93
- - **Review:** `dynamax` review this branch from correctness, test,
94
- security-boundary, and maintainability angles; verify every finding.
95
- - **Debug:** `dynamax` investigate this flaky test using separate hypotheses for
96
- timing, fixtures, recent diffs, and external state.
97
- - **Decide:** `dynamax` argue both implementation options, then have another
98
- agent attack the recommendation.
99
- - **Refactor:** `dynamax` find the smallest safe path through this module and
100
- identify what should not change.
84
+ In the TUI, a standalone `dynamax` token receives a short moving-shine sweep and
85
+ then stays highlighted. Use `PI_DYNAMAX_EFFECT=static` or
86
+ `PI_DYNAMAX_EFFECT=off` to reduce or disable the cue; the
87
+ [prompt editor guide](USAGE.md#prompt-editor-cue) has the full details.
101
88
 
102
89
  Tiny edits and straightforward questions are still better handled by one agent.
103
- Dynamax earns its cost when independence or breadth changes the answer.
104
-
105
- ## Write a workflow
106
-
107
- A saved workflow is a TypeScript module with metadata and one async function.
108
- The injected API supplies agents, concurrency primitives, phases, progress,
109
- budgets, cancellation, and sub-workflow composition.
110
-
111
- ```ts
112
- import { Type } from "typebox";
113
- import type { WorkflowApi, WorkflowMeta } from "../src/types.ts";
114
-
115
- export const meta: WorkflowMeta = {
116
- name: "two-angle-review",
117
- description: "Find issues independently, then synthesize.",
118
- };
119
-
120
- const Finding = Type.Object({
121
- summary: Type.String(),
122
- evidence: Type.Array(Type.String()),
123
- });
124
- const reviewTools = ["read", "grep", "find", "ls"];
125
-
126
- export default async function run(
127
- { agent, parallel, phase, args }: WorkflowApi,
128
- ) {
129
- phase("Find");
130
- const findings = await parallel([
131
- () => agent(`Review correctness: ${args}`, {
132
- schema: Finding,
133
- tools: reviewTools,
134
- thinkingLevel: "low",
135
- resume: "read-only",
136
- }),
137
- () => agent(`Review edge cases: ${args}`, {
138
- schema: Finding,
139
- tools: reviewTools,
140
- thinkingLevel: "low",
141
- resume: "read-only",
142
- }),
143
- ]);
144
-
145
- phase("Synthesize");
146
- return agent(`Merge and rank these findings: ${JSON.stringify(findings)}`, {
147
- tools: [],
148
- thinkingLevel: "medium",
149
- resume: "read-only",
150
- });
151
- }
90
+ Dynamax is useful when independence or breadth materially improves the result.
91
+
92
+ ## Review and inspect results
93
+
94
+ `code-review` verifies, deduplicates, and ranks candidate findings. Open the
95
+ interactive findings view for follow-up, or bring back the latest result without
96
+ rerunning the workflow:
97
+
98
+ ```text
99
+ /workflow code-review --result-viewer
100
+ /workflow:results
101
+ /workflow:inspector
152
102
  ```
153
103
 
154
- Set `thinkingLevel` on fan-out agents so they do not all inherit an expensive
155
- global setting. The [usage guide](USAGE.md#author-a-saved-workflow) covers
156
- schemas, tools, skills, pipelines, settled results, worktree isolation, inline
157
- workflows, and registration.
158
-
159
- ## Design choices
160
-
161
- - **Agent sessions:** each call uses an in-process pi `AgentSession` with an
162
- in-memory session manager.
163
- - **Structured output:** the schema is a terminating tool definition validated
164
- by pi.
165
- - **Recoverable failures:** a failed parallel branch becomes `null`; surviving
166
- work continues.
167
- - **Fatal failures:** cancellation aborts siblings and drains submitted work
168
- before rejection.
169
- - **Mutating agents:** disposable worktrees isolate edits and return
170
- baseline-relative patches.
171
- - **Resume:** journals bind workspace-aware calls to repository state and all
172
- calls to workflow, model, prompt, skill, and tool identity.
173
- - **Dependencies:** pi and TypeBox remain host-provided peers; the package ships
174
- no duplicate runtime stack.
175
-
176
- The replay contract deliberately fails closed. For workspace-aware calls,
177
- changed commits, dirty state, and declared ignored inputs invalidate a hit.
178
- Workflow source, effective model or prompt, selected skills, and executable
179
- tools remain part of the relevant identity; unsafe or unbounded surfaces run
180
- live instead.
104
+ The viewer can produce isolated patch previews for selected findings without
105
+ changing the active checkout. The [usage guide](USAGE.md#workflow-results)
106
+ covers review actions and recent run history.
107
+
108
+ ## Create your own workflows
109
+
110
+ Saved workflows are TypeScript modules for repeatable orchestration; inline
111
+ workflows are useful for one-off Dynamax tasks. The
112
+ [workflow authoring guide](USAGE.md#author-a-saved-workflow) covers the API,
113
+ typed handoffs, model profiles, tool access, composition, and registration.
181
114
 
182
115
  ## Develop locally
183
116
 
@@ -192,11 +125,9 @@ pi -ne -e .
192
125
  `pi -ne -e .` loads the working copy without also loading an installed global
193
126
  copy. There is no build step; pi loads the TypeScript extension directly.
194
127
 
195
- For the complete command reference, runtime controls, authoring rules, and
196
- troubleshooting, see [USAGE.md](USAGE.md). The public API lives in
197
- [types.ts](.pi/extensions/pi-workflow-engine/src/types.ts), and the built-in
198
- [code-review workflow](.pi/extensions/pi-workflow-engine/workflows/code-review.ts)
199
- is the most complete example.
128
+ For the complete command reference, model configuration, workflow authoring,
129
+ runtime controls, resume behavior, and troubleshooting, see
130
+ [USAGE.md](USAGE.md).
200
131
 
201
132
  Questions and ideas are welcome in
202
133
  [GitHub Issues](https://github.com/timbrinded/pi-workflow-engine/issues).