@exaudeus/workrail 3.64.0 → 3.66.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 (62) hide show
  1. package/dist/console-ui/assets/{index-DGM664Gr.js → index-BynU38Vu.js} +9 -9
  2. package/dist/console-ui/assets/{index-DGj8EsFR.css → index-DHrKiMCf.css} +1 -1
  3. package/dist/console-ui/index.html +2 -2
  4. package/dist/manifest.json +44 -36
  5. package/dist/mcp/handlers/v2-advance-core/outcome-success.js +65 -0
  6. package/dist/mcp/handlers/v2-advance-events.d.ts +11 -0
  7. package/dist/mcp/handlers/v2-advance-events.js +19 -0
  8. package/dist/mcp/output-schemas.d.ts +4 -4
  9. package/dist/types/workflow-definition.d.ts +1 -0
  10. package/dist/v2/durable-core/constants.d.ts +1 -0
  11. package/dist/v2/durable-core/constants.js +1 -0
  12. package/dist/v2/durable-core/domain/prompt-renderer.d.ts +1 -0
  13. package/dist/v2/durable-core/domain/prompt-renderer.js +40 -0
  14. package/dist/v2/durable-core/schemas/export-bundle/index.d.ts +294 -0
  15. package/dist/v2/durable-core/schemas/session/events.d.ts +90 -0
  16. package/dist/v2/durable-core/schemas/session/events.js +16 -0
  17. package/dist/v2/projections/session-metrics.d.ts +15 -0
  18. package/dist/v2/projections/session-metrics.js +102 -0
  19. package/dist/v2/usecases/console-routes.js +59 -0
  20. package/dist/v2/usecases/console-service.js +18 -4
  21. package/dist/v2/usecases/console-types.d.ts +5 -0
  22. package/docs/authoring-v2.md +30 -7
  23. package/docs/authoring.md +28 -0
  24. package/package.json +1 -1
  25. package/spec/authoring-spec.json +37 -0
  26. package/spec/workflow.schema.json +5 -0
  27. package/workflows/adaptive-ticket-creation.json +2 -1
  28. package/workflows/architecture-scalability-audit.json +1 -0
  29. package/workflows/bug-investigation.agentic.v2.json +1 -0
  30. package/workflows/classify-task-workflow.json +1 -0
  31. package/workflows/coding-task-workflow-agentic.json +1 -0
  32. package/workflows/cross-platform-code-conversion.v2.json +8 -7
  33. package/workflows/document-creation-workflow.json +2 -1
  34. package/workflows/documentation-update-workflow.json +2 -1
  35. package/workflows/intelligent-test-case-generation.json +2 -1
  36. package/workflows/learner-centered-course-workflow.json +2 -1
  37. package/workflows/mr-review-workflow.agentic.v2.json +1 -0
  38. package/workflows/personal-learning-materials-creation-branched.json +1 -0
  39. package/workflows/presentation-creation.json +2 -1
  40. package/workflows/production-readiness-audit.json +1 -0
  41. package/workflows/relocation-workflow-us.json +1 -0
  42. package/workflows/routines/context-gathering.json +2 -1
  43. package/workflows/routines/design-review.json +1 -0
  44. package/workflows/routines/execution-simulation.json +2 -1
  45. package/workflows/routines/feature-implementation.json +4 -3
  46. package/workflows/routines/final-verification.json +1 -0
  47. package/workflows/routines/hypothesis-challenge.json +13 -3
  48. package/workflows/routines/ideation.json +1 -1
  49. package/workflows/routines/parallel-work-partitioning.json +1 -0
  50. package/workflows/routines/philosophy-alignment.json +2 -1
  51. package/workflows/routines/plan-analysis.json +2 -1
  52. package/workflows/routines/plan-generation.json +2 -1
  53. package/workflows/routines/tension-driven-design.json +1 -0
  54. package/workflows/scoped-documentation-workflow.json +2 -1
  55. package/workflows/test-artifact-loop-control.json +8 -2
  56. package/workflows/test-session-persistence.json +1 -0
  57. package/workflows/ui-ux-design-workflow.json +1 -0
  58. package/workflows/workflow-diagnose-environment.json +1 -0
  59. package/workflows/workflow-for-workflows.json +1 -0
  60. package/workflows/workflow-for-workflows.v2.json +28 -0
  61. package/workflows/wr.discovery.json +1 -0
  62. package/workflows/wr.shaping.json +21 -6
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.projectSessionMetricsV2 = projectSessionMetricsV2;
4
+ const constants_js_1 = require("../durable-core/constants.js");
5
+ function projectSessionMetricsV2(events) {
6
+ let runCompletedData = null;
7
+ let runCompletedRunId = null;
8
+ for (const e of events) {
9
+ const asUnknown = e;
10
+ if (asUnknown.kind === 'run_completed') {
11
+ runCompletedData = asUnknown.data;
12
+ runCompletedRunId = asUnknown.scope?.runId ?? null;
13
+ break;
14
+ }
15
+ }
16
+ if (runCompletedData === null) {
17
+ return null;
18
+ }
19
+ const metricsContext = {};
20
+ for (const e of events) {
21
+ if (e.kind !== constants_js_1.EVENT_KIND.CONTEXT_SET)
22
+ continue;
23
+ if (runCompletedRunId !== null && e.scope?.runId !== runCompletedRunId)
24
+ continue;
25
+ const ctx = e.data.context;
26
+ if (!ctx || typeof ctx !== 'object' || Array.isArray(ctx))
27
+ continue;
28
+ const ctxObj = ctx;
29
+ for (const [key, value] of Object.entries(ctxObj)) {
30
+ if (key.startsWith('metrics_')) {
31
+ metricsContext[key] = value;
32
+ }
33
+ }
34
+ }
35
+ const d = runCompletedData;
36
+ const startGitSha = typeof d.startGitSha === 'string' ? d.startGitSha : null;
37
+ const endGitSha = typeof d.endGitSha === 'string' ? d.endGitSha : null;
38
+ const gitBranch = typeof d.gitBranch === 'string' ? d.gitBranch : null;
39
+ const agentCommitShas = [];
40
+ if (Array.isArray(d.agentCommitShas)) {
41
+ for (const sha of d.agentCommitShas) {
42
+ if (typeof sha === 'string') {
43
+ agentCommitShas.push(sha);
44
+ }
45
+ }
46
+ }
47
+ const captureConfidenceRaw = d.captureConfidence;
48
+ const captureConfidence = captureConfidenceRaw === 'high' || captureConfidenceRaw === 'medium' || captureConfidenceRaw === 'none'
49
+ ? captureConfidenceRaw
50
+ : 'none';
51
+ const durationMs = typeof d.durationMs === 'number' && Number.isFinite(d.durationMs)
52
+ ? d.durationMs
53
+ : undefined;
54
+ const outcomeRaw = metricsContext['metrics_outcome'];
55
+ const outcome = outcomeRaw === 'success' || outcomeRaw === 'partial' || outcomeRaw === 'abandoned' || outcomeRaw === 'error'
56
+ ? outcomeRaw
57
+ : null;
58
+ const prNumbers = [];
59
+ const prNumbersRaw = metricsContext['metrics_pr_numbers'];
60
+ if (Array.isArray(prNumbersRaw)) {
61
+ for (const n of prNumbersRaw) {
62
+ if (typeof n === 'number' && Number.isFinite(n)) {
63
+ prNumbers.push(n);
64
+ }
65
+ }
66
+ }
67
+ const commitShasRaw = metricsContext['metrics_commit_shas'];
68
+ const metricCommitShas = [];
69
+ if (Array.isArray(commitShasRaw)) {
70
+ for (const sha of commitShasRaw) {
71
+ if (typeof sha === 'string') {
72
+ metricCommitShas.push(sha);
73
+ }
74
+ }
75
+ }
76
+ const finalAgentCommitShas = metricCommitShas.length > 0 ? metricCommitShas : agentCommitShas;
77
+ const filesChangedRaw = metricsContext['metrics_files_changed'];
78
+ const filesChanged = typeof filesChangedRaw === 'number' && Number.isFinite(filesChangedRaw)
79
+ ? filesChangedRaw
80
+ : null;
81
+ const linesAddedRaw = metricsContext['metrics_lines_added'];
82
+ const linesAdded = typeof linesAddedRaw === 'number' && Number.isFinite(linesAddedRaw)
83
+ ? linesAddedRaw
84
+ : null;
85
+ const linesRemovedRaw = metricsContext['metrics_lines_removed'];
86
+ const linesRemoved = typeof linesRemovedRaw === 'number' && Number.isFinite(linesRemovedRaw)
87
+ ? linesRemovedRaw
88
+ : null;
89
+ return {
90
+ startGitSha,
91
+ endGitSha,
92
+ gitBranch,
93
+ agentCommitShas: finalAgentCommitShas,
94
+ captureConfidence,
95
+ durationMs,
96
+ outcome,
97
+ prNumbers,
98
+ filesChanged,
99
+ linesAdded,
100
+ linesRemoved,
101
+ };
102
+ }
@@ -41,6 +41,8 @@ const express_1 = __importDefault(require("express"));
41
41
  const path_1 = __importDefault(require("path"));
42
42
  const fs_1 = __importDefault(require("fs"));
43
43
  const os_1 = __importDefault(require("os"));
44
+ const child_process_1 = require("child_process");
45
+ const util_1 = require("util");
44
46
  const worktree_service_js_1 = require("./worktree-service.js");
45
47
  const workflow_js_1 = require("../../types/workflow.js");
46
48
  const dev_mode_js_1 = require("../../mcp/dev-mode.js");
@@ -467,6 +469,63 @@ function mountConsoleRoutes(app, consoleService, workflowService, timingRingBuff
467
469
  res.status(status).json({ success: false, error: error.message });
468
470
  });
469
471
  });
472
+ const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
473
+ const DIFF_GIT_TIMEOUT_MS = 10000;
474
+ function isDiffExecError(e) {
475
+ if (!(e instanceof Error))
476
+ return false;
477
+ if ('killed' in e)
478
+ return true;
479
+ const sys = e.syscall ?? '';
480
+ return sys.startsWith('spawn');
481
+ }
482
+ app.get('/api/v2/sessions/:sessionId/diff-summary', async (req, res) => {
483
+ const { sessionId } = req.params;
484
+ const sessionResult = await consoleService.getSessionDetail(sessionId);
485
+ if (sessionResult.isErr()) {
486
+ const status = sessionResult.error.code === 'SESSION_LOAD_FAILED' ? 404 : 500;
487
+ res.status(status).json({ success: false, error: sessionResult.error.message });
488
+ return;
489
+ }
490
+ const sessionDetail = sessionResult.value;
491
+ const metrics = sessionDetail.metrics;
492
+ if (!metrics) {
493
+ res.status(422).json({ success: false, error: 'No metrics available for this session' });
494
+ return;
495
+ }
496
+ const { startGitSha, endGitSha } = metrics;
497
+ if (!startGitSha || !endGitSha) {
498
+ res.status(422).json({ success: false, error: 'Git SHAs not available in session metrics' });
499
+ return;
500
+ }
501
+ const repoRoot = sessionDetail.repoRoot;
502
+ if (!repoRoot) {
503
+ res.status(422).json({ success: false, error: 'Repo root not available for this session' });
504
+ return;
505
+ }
506
+ try {
507
+ const { stdout } = await execFileAsync('git', ['diff', `${startGitSha}..${endGitSha}`, '--shortstat'], { cwd: repoRoot, encoding: 'utf-8', timeout: DIFF_GIT_TIMEOUT_MS });
508
+ const match = stdout.trim().match(/(\d+) files? changed(?:, (\d+) insertions?\(\+\))?(?:, (\d+) deletions?\(-\))?/);
509
+ if (!match) {
510
+ res.json({ success: true, data: { linesAdded: 0, linesRemoved: 0, filesChanged: 0 } });
511
+ return;
512
+ }
513
+ const filesChanged = parseInt(match[1] ?? '0', 10);
514
+ const linesAdded = parseInt(match[2] ?? '0', 10);
515
+ const linesRemoved = parseInt(match[3] ?? '0', 10);
516
+ res.json({ success: true, data: { linesAdded, linesRemoved, filesChanged } });
517
+ }
518
+ catch (e) {
519
+ if (isDiffExecError(e)) {
520
+ const errMsg = e instanceof Error && 'killed' in e && e.killed
521
+ ? 'Diff timed out: repository too large or slow'
522
+ : `Diff failed: git unavailable or invalid SHAs`;
523
+ res.status(503).json({ success: false, error: errMsg });
524
+ return;
525
+ }
526
+ throw e;
527
+ }
528
+ });
470
529
  if (workflowService) {
471
530
  app.get('/api/v2/workflows', async (_req, res) => {
472
531
  try {
@@ -47,6 +47,7 @@ const node_outputs_js_1 = require("../projections/node-outputs.js");
47
47
  const advance_outcomes_js_1 = require("../projections/advance-outcomes.js");
48
48
  const artifacts_js_1 = require("../projections/artifacts.js");
49
49
  const run_context_js_1 = require("../projections/run-context.js");
50
+ const session_metrics_js_1 = require("../projections/session-metrics.js");
50
51
  const sorted_event_log_js_1 = require("../durable-core/sorted-event-log.js");
51
52
  const run_execution_trace_js_1 = require("../projections/run-execution-trace.js");
52
53
  const constants_js_1 = require("../durable-core/constants.js");
@@ -198,18 +199,28 @@ class ConsoleService {
198
199
  message: `Failed to load session ${sessionIdStr}: ${storeErr.message}`,
199
200
  }))
200
201
  .andThen((truth) => {
202
+ const metrics = (0, session_metrics_js_1.projectSessionMetricsV2)(truth.events);
203
+ const repoRoot = extractRepoRoot(truth.events);
201
204
  const dagRes = (0, run_dag_js_1.projectRunDagV2)(truth.events);
202
205
  const detailRA = (() => {
203
206
  if (dagRes.isErr()) {
204
207
  return resolveRunCompletion(truth.events, this.ports.snapshotStore)
205
- .map((completionMap) => projectSessionDetail(sessionId, truth, completionMap, {}, {}));
208
+ .map((completionMap) => ({
209
+ ...projectSessionDetail(sessionId, truth, completionMap, {}, {}),
210
+ metrics,
211
+ repoRoot,
212
+ }));
206
213
  }
207
214
  const dag = dagRes.value;
208
215
  return neverthrow_1.ResultAsync.combine([
209
216
  resolveRunCompletion(truth.events, this.ports.snapshotStore),
210
217
  resolveStepLabels(dag, this.ports.snapshotStore, this.ports.pinnedWorkflowStore),
211
218
  resolveWorkflowNames(dag, this.ports.pinnedWorkflowStore),
212
- ]).map(([completionMap, stepLabels, workflowNames]) => projectSessionDetail(sessionId, truth, completionMap, stepLabels, workflowNames));
219
+ ]).map(([completionMap, stepLabels, workflowNames]) => ({
220
+ ...projectSessionDetail(sessionId, truth, completionMap, stepLabels, workflowNames),
221
+ metrics,
222
+ repoRoot,
223
+ }));
213
224
  })();
214
225
  const isLiveRA = neverthrow_1.ResultAsync.fromSafePromise(isSessionLiveFromEventLog(sessionIdStr));
215
226
  return neverthrow_1.ResultAsync.combine([detailRA, isLiveRA]).andThen(([detail, isLive]) => {
@@ -632,6 +643,7 @@ function projectSessionSummary(sessionId, truth, completionByRunId, workflowName
632
643
  return false;
633
644
  return Object.values(contextRes.value.byRunId).some((runCtx) => runCtx.context['is_autonomous'] === 'true');
634
645
  })();
646
+ const metrics = (0, session_metrics_js_1.projectSessionMetricsV2)(events);
635
647
  const runs = Object.values(dag.runsById);
636
648
  const run = runs[0];
637
649
  if (!run) {
@@ -656,6 +668,7 @@ function projectSessionSummary(sessionId, truth, completionByRunId, workflowName
656
668
  isAutonomous,
657
669
  isLive,
658
670
  parentSessionId,
671
+ metrics,
659
672
  };
660
673
  }
661
674
  const workflow = run.workflow;
@@ -702,6 +715,7 @@ function projectSessionSummary(sessionId, truth, completionByRunId, workflowName
702
715
  isAutonomous,
703
716
  isLive,
704
717
  parentSessionId,
718
+ metrics,
705
719
  };
706
720
  }
707
721
  function projectSessionDetail(sessionId, truth, completionByRunId, stepLabels, workflowNames, skippedStepsMap = {}) {
@@ -712,7 +726,7 @@ function projectSessionDetail(sessionId, truth, completionByRunId, stepLabels, w
712
726
  const sessionTitle = sortedEventsRes.isOk() ? deriveSessionTitle(sortedEventsRes.value) : null;
713
727
  const dagRes = (0, run_dag_js_1.projectRunDagV2)(events);
714
728
  if (dagRes.isErr()) {
715
- return { sessionId, sessionTitle, health: sessionHealth, runs: [] };
729
+ return { sessionId, sessionTitle, health: sessionHealth, runs: [], metrics: null, repoRoot: null };
716
730
  }
717
731
  const statusRes = sortedEventsRes.isOk() ? (0, run_status_signals_js_1.projectRunStatusSignalsV2)(sortedEventsRes.value) : (0, neverthrow_2.err)(sortedEventsRes.error);
718
732
  const gapsRes = sortedEventsRes.isOk() ? (0, gaps_js_1.projectGapsV2)(sortedEventsRes.value) : (0, neverthrow_2.err)(sortedEventsRes.error);
@@ -781,7 +795,7 @@ function projectSessionDetail(sessionId, truth, completionByRunId, stepLabels, w
781
795
  skippedSteps: skippedStepsMap[run.runId] ?? [],
782
796
  };
783
797
  });
784
- return { sessionId, sessionTitle, health: sessionHealth, runs };
798
+ return { sessionId, sessionTitle, health: sessionHealth, runs, metrics: null, repoRoot: null };
785
799
  }
786
800
  function deriveRunStatus(isBlocked, hasUnresolvedCriticalGaps, isComplete) {
787
801
  if (isBlocked)
@@ -1,3 +1,5 @@
1
+ import type { SessionMetricsV2 } from '../projections/session-metrics.js';
2
+ export type { SessionMetricsV2 };
1
3
  export type ConsoleRunStatus = 'in_progress' | 'complete' | 'complete_with_gaps' | 'blocked';
2
4
  export type ConsoleSessionStatus = ConsoleRunStatus | 'dormant';
3
5
  export type ConsoleSessionHealth = 'healthy' | 'corrupt';
@@ -21,6 +23,7 @@ export interface ConsoleSessionSummary {
21
23
  readonly isAutonomous: boolean;
22
24
  readonly isLive: boolean;
23
25
  readonly parentSessionId: string | null;
26
+ readonly metrics: SessionMetricsV2 | null;
24
27
  }
25
28
  export interface ConsoleSessionListResponse {
26
29
  readonly sessions: readonly ConsoleSessionSummary[];
@@ -90,6 +93,8 @@ export interface ConsoleSessionDetail {
90
93
  readonly runs: readonly ConsoleDagRun[];
91
94
  readonly isLive?: boolean;
92
95
  readonly liveActivity?: readonly ConsoleToolActivity[] | null;
96
+ readonly metrics: SessionMetricsV2 | null;
97
+ readonly repoRoot: string | null;
93
98
  }
94
99
  export type ConsoleValidationOutcome = 'pass' | 'fail';
95
100
  export interface ConsoleValidationResult {
@@ -219,22 +219,47 @@ Important implementation detail:
219
219
 
220
220
  ### Session analytics context keys (`metrics_*`)
221
221
 
222
- The `projectSessionMetricsV2` projection (planned -- not yet implemented) reads a set of `metrics_*` context keys to build session attribution data. These keys are not validated by the engine -- nothing will fail if they are absent or malformed. But absent or wrong data produces permanently incorrect analytics with no error or warning.
222
+ The engine reads `metrics_*` context keys from the final `continue_workflow` call to build session attribution data for the `run_completed` event. These keys feed `captureConfidence`, `agentCommitShas`, and related fields.
223
223
 
224
- Set these keys in your step's `Capture:` footer.
224
+ **Recommended approach: set `metricsProfile` at workflow level**
225
+
226
+ The simplest way to instrument a workflow is to declare `metricsProfile` as a top-level field in the workflow JSON. The engine then injects the appropriate footer instructions into step prompts automatically -- no per-step `Capture:` text needed.
227
+
228
+ ```json
229
+ {
230
+ "metricsProfile": "coding"
231
+ }
232
+ ```
233
+
234
+ Profile selection guide:
235
+
236
+ | Profile | When to use | What the engine injects |
237
+ |---|---|---|
238
+ | `"coding"` | Workflow produces git commits (implementation, refactoring, bug-fix) | SHA accumulation reminder on every step; outcome/PR/diff reminder on final step |
239
+ | `"review"` | Workflow produces a review decision on a PR or MR | PR numbers + outcome reminder on final step only |
240
+ | `"research"` | Workflow produces a finding or recommendation but no commits | Outcome-only reminder on final step only |
241
+ | `"none"` or absent | Meta-workflows, utilities, authoring tools | No injection -- existing behavior unchanged |
242
+
243
+ The engine does NOT derive the profile from tags automatically. Authors must set this field explicitly. When using `workflow-for-workflows` to author or modernize a workflow, the `phase-7b` step will prompt you for this decision.
244
+
245
+ **Final step detection**: The engine injects the final-step footer on the last top-level step, or on the exit step of a loop that is the last top-level step. A loop in a non-terminal position does not trigger the final-step footer on its exit step.
225
246
 
226
247
  **SHA accumulation rule (critical)**
227
248
 
228
249
  `context_set` uses shallow merge: each key is replaced, not merged. If you set `metrics_commit_shas: ["abc123"]` at step 5 and then set `metrics_commit_shas: ["def456"]` at step 9, the value at step 9 is `["def456"]` -- `abc123` is permanently gone.
229
250
 
230
- Every step that adds commits must send the **full accumulated list** -- read the current value from context, append new SHAs, and send the complete list.
251
+ Every step that adds commits must send the **full accumulated list** -- read the current value from context, append new SHAs, and send the complete list. The engine-injected footer includes an explicit reminder of this rule.
231
252
 
232
253
  ```
233
254
  Example (correct): metrics_commit_shas: ["abc123", "def456", "ghi789"]
234
255
  Example (wrong): metrics_commit_shas: ["ghi789"] -- loses abc123 and def456
235
256
  ```
236
257
 
237
- **Commit step `Capture:` footer** (copy this into every step that creates commits):
258
+ **Manual `Capture:` footers (if you cannot use `metricsProfile`)**
259
+
260
+ If `metricsProfile` is not appropriate for your workflow, add these footers manually.
261
+
262
+ Commit step `Capture:` footer (copy into every step that creates commits):
238
263
 
239
264
  ```
240
265
  Capture (every time you commit code):
@@ -248,7 +273,7 @@ Capture (every time you commit code):
248
273
  Example (wrong): metrics_commit_shas: ["ghi789"] -- loses abc123 and def456
249
274
  ```
250
275
 
251
- **Final handoff `Capture:` footer** (copy this into your final step):
276
+ Final handoff `Capture:` footer (copy into your final step):
252
277
 
253
278
  ```
254
279
  Capture (at final handoff only):
@@ -266,8 +291,6 @@ Capture (at final handoff only):
266
291
  (same accumulation rule as commit steps -- full list, not just final-step SHAs)
267
292
  ```
268
293
 
269
- Note: adding these keys to existing workflow JSON files (`coding-task-workflow-agentic.json` and others) is a separate follow-on PR. The templates above let you add them to new or custom workflows now.
270
-
271
294
  ### Assessment-gate authoring (v1)
272
295
 
273
296
  Assessment gates are now a shipped authoring/runtime feature, but the first slice is intentionally narrow.
package/docs/authoring.md CHANGED
@@ -731,6 +731,34 @@ Canonical current rules for authoring good WorkRail workflows. workflow.schema.j
731
731
  - Using a nested key context.metrics.commit_shas instead of the flat key metrics_commit_shas
732
732
  - Setting metrics_outcome at intermediate steps before the session outcome is known
733
733
 
734
+ ### metrics-profile-declaration
735
+ - **Level**: recommended
736
+ - **Status**: active
737
+ - **Scope**: workflow.definition, step.context-capture
738
+ - **Rule**: Declare metricsProfile at workflow level to enable engine-injected metrics instrumentation footers. Use 'coding' for implementation workflows, 'review' for code review workflows, 'research' for investigation workflows, 'design' for design/planning artifacts, 'ticket' for work-item creation. Omit or use 'none' for meta-workflows and utilities.
739
+ - **Why**: Without metricsProfile, captureConfidence is always 'none' and run_completed events carry no usable attribution data. The engine cannot auto-derive the profile from tags -- authors must set it explicitly.
740
+ - **Enforced by**: advisory
741
+
742
+ **Checks**
743
+ - Select 'coding' when the workflow produces git commits (implementation, refactoring, bug-fix, migration, documentation updates).
744
+ - Select 'review' when the workflow produces a review decision on a PR or MR.
745
+ - Select 'research' when the workflow produces a finding or recommendation but no commits (investigation, audit, analysis).
746
+ - Select 'design' when the workflow produces a design artifact (pitch, spec, ADR, architecture doc) but no commits.
747
+ - Select 'ticket' when the workflow creates or updates work items in an external system (Jira, GitHub Issues, Linear).
748
+ - Omit or use 'none' for authoring tools, meta-workflows, or workflows with no measurable outcome.
749
+ - Do not invent new profile values -- the closed set is: 'coding', 'review', 'research', 'design', 'ticket', 'none'.
750
+ - The engine does NOT derive the profile from spec/workflow-tags.json at runtime. Set the field explicitly.
751
+ - When using workflow-for-workflows to author or modernize a workflow, the phase-7b step will prompt for this decision.
752
+
753
+ **Anti-patterns**
754
+ - Leaving metricsProfile absent from a coding or review workflow and expecting automatic instrumentation
755
+ - Using metricsProfile 'coding' on a workflow that produces no commits (e.g., a documentation or planning workflow)
756
+ - Assuming the engine reads tags and derives the profile automatically
757
+
758
+ **Source refs**
759
+ - `src/v2/durable-core/domain/prompt-renderer.ts` (runtime) — buildMetricsSection() implements render-time footer injection based on metricsProfile.
760
+ - `spec/workflow.schema.json` (schema) — metricsProfile optional enum field definition.
761
+
734
762
 
735
763
  ## Artifacts and planning surfaces
736
764
  ### artifact-canonicality
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exaudeus/workrail",
3
- "version": "3.64.0",
3
+ "version": "3.66.0",
4
4
  "description": "Step-by-step workflow enforcement for AI agents via MCP",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1385,6 +1385,43 @@
1385
1385
  "Using a nested key context.metrics.commit_shas instead of the flat key metrics_commit_shas",
1386
1386
  "Setting metrics_outcome at intermediate steps before the session outcome is known"
1387
1387
  ]
1388
+ },
1389
+ {
1390
+ "id": "metrics-profile-declaration",
1391
+ "status": "active",
1392
+ "level": "recommended",
1393
+ "scope": ["workflow.definition", "step.context-capture"],
1394
+ "rule": "Declare metricsProfile at workflow level to enable engine-injected metrics instrumentation footers. Use 'coding' for implementation workflows, 'review' for code review workflows, 'research' for investigation workflows, 'design' for design/planning artifacts, 'ticket' for work-item creation. Omit or use 'none' for meta-workflows and utilities.",
1395
+ "why": "Without metricsProfile, captureConfidence is always 'none' and run_completed events carry no usable attribution data. The engine cannot auto-derive the profile from tags -- authors must set it explicitly.",
1396
+ "enforcement": ["advisory"],
1397
+ "checks": [
1398
+ "Select 'coding' when the workflow produces git commits (implementation, refactoring, bug-fix, migration, documentation updates).",
1399
+ "Select 'review' when the workflow produces a review decision on a PR or MR.",
1400
+ "Select 'research' when the workflow produces a finding or recommendation but no commits (investigation, audit, analysis).",
1401
+ "Select 'design' when the workflow produces a design artifact (pitch, spec, ADR, architecture doc) but no commits.",
1402
+ "Select 'ticket' when the workflow creates or updates work items in an external system (Jira, GitHub Issues, Linear).",
1403
+ "Omit or use 'none' for authoring tools, meta-workflows, or workflows with no measurable outcome.",
1404
+ "Do not invent new profile values -- the closed set is: 'coding', 'review', 'research', 'design', 'ticket', 'none'.",
1405
+ "The engine does NOT derive the profile from spec/workflow-tags.json at runtime. Set the field explicitly.",
1406
+ "When using workflow-for-workflows to author or modernize a workflow, the phase-7b step will prompt for this decision."
1407
+ ],
1408
+ "antiPatterns": [
1409
+ "Leaving metricsProfile absent from a coding or review workflow and expecting automatic instrumentation",
1410
+ "Using metricsProfile 'coding' on a workflow that produces no commits (e.g., a documentation or planning workflow)",
1411
+ "Assuming the engine reads tags and derives the profile automatically"
1412
+ ],
1413
+ "sourceRefs": [
1414
+ {
1415
+ "kind": "runtime",
1416
+ "path": "src/v2/durable-core/domain/prompt-renderer.ts",
1417
+ "note": "buildMetricsSection() implements render-time footer injection based on metricsProfile."
1418
+ },
1419
+ {
1420
+ "kind": "schema",
1421
+ "path": "spec/workflow.schema.json",
1422
+ "note": "metricsProfile optional enum field definition."
1423
+ }
1424
+ ]
1388
1425
  }
1389
1426
  ]
1390
1427
  },
@@ -200,6 +200,11 @@
200
200
  "minItems": 1,
201
201
  "maxItems": 6,
202
202
  "uniqueItems": true
203
+ },
204
+ "metricsProfile": {
205
+ "type": "string",
206
+ "enum": ["coding", "review", "research", "design", "ticket", "none"],
207
+ "description": "Metrics instrumentation profile for this workflow. When set, the engine injects a footer into step prompts instructing the agent to accumulate and report metrics context keys (metrics_commit_shas, metrics_outcome, etc.). 'coding' injects SHA accumulation on every step and outcome/PR reporting on the final step. 'review' injects PR numbers + outcome on the final step. 'research', 'design', and 'ticket' inject outcome-only on the final step (identical behavior today, distinct semantics). 'none' or absent field disables injection entirely."
203
208
  }
204
209
  },
205
210
  "required": [
@@ -2,6 +2,7 @@
2
2
  "id": "adaptive-ticket-creation",
3
3
  "name": "Adaptive Ticket Creation Workflow",
4
4
  "version": "1.0.0",
5
+ "metricsProfile": "ticket",
5
6
  "description": "Use this to create high-quality Jira tickets for features, tasks, or epics. Automatically selects the right complexity path (Simple, Standard, or Epic) and generates properly structured tickets with acceptance criteria and estimates.",
6
7
  "about": "## Adaptive Ticket Creation Workflow\n\nUse this to create well-structured Jira tickets for features, tasks, or epics. The workflow automatically selects the right complexity path (Simple, Standard, or Epic) based on the request, so you don't have to decide upfront how much process you need.\n\n### What it produces\n\n- **Simple path**: one complete, developer-ready Jira ticket with a context-rich description, checkbox-style acceptance criteria, and an effort estimate.\n- **Standard path**: a high-level plan plus a batch of related tickets covering all deliverables.\n- **Epic path**: everything in Standard, plus full epic decomposition, per-story estimates with risk ratings, dependency mapping, and a reusable team rules file at `.workflow_rules/ticket_creation.md` that future runs load automatically.\n\n### When to use it\n\n- You need to create one or more Jira tickets and want them to be genuinely developer-ready.\n- You have a feature request, bug, task, or epic that needs to be broken down and estimated.\n- Your team has specific ticket conventions (naming, sizing, labels) -- the workflow learns and stores these on the Epic path.\n\n### How to get good results\n\n- Provide as much context as you have: PRD links, design files, existing related tickets, and any known constraints.\n- If your team has a `.workflow_rules/ticket_creation.md` file, the workflow loads it automatically and applies your conventions.\n- On the Epic path, the workflow asks you to approve the high-level plan and the decomposition before generating tickets. Use these checkpoints to catch scope issues early.\n- Acceptance criteria are written as checkbox-style observable conditions, not restatements of requirements. If your team has a specific AC format, describe it in the rules file.",
7
8
  "examples": [
@@ -307,4 +308,4 @@
307
308
  "requireConfirmation": false
308
309
  }
309
310
  ]
310
- }
311
+ }
@@ -2,6 +2,7 @@
2
2
  "id": "architecture-scalability-audit",
3
3
  "name": "Architecture Scalability Audit",
4
4
  "version": "0.1.0",
5
+ "metricsProfile": "research",
5
6
  "description": "Use this to audit a bounded codebase scope for architecture scalability. Declare which scalability dimensions matter (load, data volume, team size, feature extensibility, operational); the workflow investigates each and produces evidence-grounded findings.",
6
7
  "about": "## Architecture Scalability Audit\n\nThis workflow audits a bounded codebase scope for scalability across the dimensions you care about. It does not produce generic \"won't scale\" warnings -- every finding must cite a specific file, class, method, or pattern, and every concern must name a concrete growth scenario (e.g. 10x traffic, 100x records, 3x team size).\n\n**What it does:**\nYou declare the scope boundary and the scalability dimensions that matter for your context. The workflow reads the codebase to understand the architecture, assigns one dedicated reviewer family per dimension, runs them in parallel from a shared fact packet, reconciles contradictions and blind spots through a synthesis loop, and delivers a per-dimension verdict (will_break / risk / fine) with an overall scalability readiness verdict.\n\n**The five scalability dimensions you can select:**\n- **load** -- handles more requests, users, or throughput\n- **data_volume** -- handles more records, storage, or query size\n- **team_org** -- more teams or developers working on this scope without friction\n- **feature_extensibility** -- more features added without rearchitecting\n- **operational** -- more deployments, environments, or operational complexity\n\n**When to use it:**\n- Before investing significantly in a component you expect to grow\n- When planning capacity for a new traffic tier or data volume increase\n- When evaluating a codebase acquired through a merger, partnership, or open-source adoption\n- When a team is growing and you want to know if the architecture will hold under parallel development\n\n**What it produces:**\nAn overall scalability verdict, per-dimension findings with specific code references and growth scenarios, cross-cutting concerns that span multiple dimensions, a prioritized concern list, and explicit callouts of what is already well-designed for scale.\n\n**How to get good results:**\nBe specific about the scope boundary -- name the service, module, or feature explicitly and say what is out of scope. Choose the dimensions relevant to your actual growth pressures; the workflow will not add dimensions you did not select. If you know a specific growth target (e.g. \"we expect 50x user growth in 18 months\"), mention it.",
7
8
  "examples": [
@@ -14,6 +14,7 @@
14
14
  "recommendedAutonomy": "guided",
15
15
  "recommendedRiskPolicy": "conservative"
16
16
  },
17
+ "metricsProfile": "research",
17
18
  "preconditions": [
18
19
  "User has a specific bug report, failing test, or unexpected behavior to investigate.",
19
20
  "Agent has codebase access and can run tests, commands, or other deterministic evidence-gathering steps.",
@@ -2,6 +2,7 @@
2
2
  "id": "classify-task-workflow",
3
3
  "name": "Classify Task",
4
4
  "version": "0.1.0",
5
+ "metricsProfile": "none",
5
6
  "description": "Classifies a software task from the session goal into structured output variables used by coordinator scripts to decide which pipeline phases to run.",
6
7
  "about": "## Classify Task Workflow\n\nThis is a fast, single-step classification utility. It reads the session goal and outputs structured variables that coordinator scripts use to decide which pipeline phases to run.\n\n### What it does\n\nGiven a task description, the agent classifies the work along seven dimensions and recommends an ordered pipeline of workflow IDs to execute.\n\n### When to use it\n\nUse this workflow at the start of a coordinator pipeline when you need to decide which downstream workflows to run. It is intentionally fast and cheap -- one LLM step, no subagents, no codebase reads.\n\n### What it produces\n\nA structured classification block in the step notes containing all seven output variables:\n- `taskComplexity` -- Small / Medium / Large\n- `riskLevel` -- Low / Medium / High\n- `hasUI` -- true / false\n- `touchesArchitecture` -- true / false\n- `taskType` -- feature / bug-fix / refactor / investigation / docs / chore\n- `affectedDomains` -- array of likely codebase areas\n- `recommendedPipeline` -- ordered array of workflow IDs\n\n### How to get good results\n\nProvide a specific, concrete task description as the session goal. The more specific the goal, the more accurate the classification. When the goal is ambiguous, the workflow defaults to conservative (higher complexity, more pipeline phases).",
7
8
  "examples": [
@@ -14,6 +14,7 @@
14
14
  "recommendedAutonomy": "guided",
15
15
  "recommendedRiskPolicy": "conservative"
16
16
  },
17
+ "metricsProfile": "coding",
17
18
  "assessments": [
18
19
  {
19
20
  "id": "design-soundness-gate",
@@ -2,6 +2,7 @@
2
2
  "id": "cross-platform-code-conversion",
3
3
  "name": "Cross-Platform Code Conversion",
4
4
  "version": "0.1.0",
5
+ "metricsProfile": "coding",
5
6
  "description": "Use this to convert code from one platform to another (e.g. Android to iOS, iOS to Web). Triages files by difficulty, parallelizes easy translations, and handles platform-specific design decisions.",
6
7
  "about": "## Cross-Platform Code Conversion Workflow\n\nThis workflow guides an AI agent through converting code from one platform to another - for example, Android (Kotlin) to iOS (Swift), iOS to Web (TypeScript/React), or any similar migration. It handles everything from scoping and analysis through idiomatic conversion, build verification, and final handoff.\n\n### What it does\n\nThe workflow starts by scoping the migration and classifying its complexity (Small, Medium, or Large) and adaptation depth (low, moderate, or high). It then analyzes the source architecture to understand patterns, dependencies, concurrency models, and semantic contracts. Files are triaged into three buckets: mechanical translations delegated to subagents in parallel (Bucket A), library substitutions (Bucket B), and platform-specific code needing design decisions (Bucket C). For high-adaptation migrations, the workflow runs a full design generation phase to choose an idiomatic target-platform architecture before any code is written. Implementation proceeds batch by batch, with drift detection after each batch to catch files that turn out harder than classified. A final build-and-integration loop verifies the full converted codebase before handoff.\n\n### When to use it\n\nUse this workflow when migrating a module, feature, or full component from one platform to another. It is especially valuable when:\n- The source and target platforms have meaningfully different idioms (e.g., Kotlin coroutines vs Swift async/await, Hilt vs Swinject)\n- You want parallel delegation of mechanical work while keeping design-sensitive boundaries with the main agent\n- Semantic contracts (lifecycle, threading, cancellation, error handling) must be preserved across the migration\n- The target repo has existing architectural patterns the migrated code must fit into\n\nFor very small, straightforward file-by-file translations, the workflow includes a fast path that skips planning and triage.\n\n### What it produces\n\n- A triage matrix classifying every file into a conversion bucket\n- A semantic contract inventory for non-trivial migration boundaries\n- A target integration analysis mapping boundaries to their destination repo seams\n- Converted source files in the target platform's idioms\n- A passing build or typecheck on the full converted output\n- A handoff summary covering adaptation decisions, known gaps, and items needing manual review\n\n### How to get good results\n\n- Specify the exact scope of the migration - which files, modules, or features to convert\n- If the target repo is not in the same workspace, point the agent to it explicitly or configure the source-to-target path mapping\n- Review the triage and semantic contract inventory steps before conversion begins, especially for high-adaptation migrations\n- Flag any invariants that must survive the migration (API contracts, behavioral guarantees, threading assumptions)",
7
8
  "examples": [
@@ -78,7 +79,7 @@
78
79
  {
79
80
  "id": "phase-1-understand-source",
80
81
  "title": "Phase 1: Understand Source Code",
81
- "prompt": "Read and analyze the source code through a conversion lens \u2014 what will be easy to convert, what will be hard, and why.\n\nMap out:\n- Architecture and module structure\n- Key patterns used (MVI, MVVM, dependency injection, etc.)\n- External dependencies and what they do\n- Entry points and public API surface\n- Platform coupling depth: is the code cleanly layered or is platform-specific code smeared throughout? This directly determines how much falls into easy vs. hard buckets.\n- Concurrency model: Coroutines, Combine, RxJS, async/await? This is often the single hardest mapping decision.\n- DI approach: Dagger/Hilt, Swinject, Koin? DI frameworks rarely map 1:1.\n- Test coverage shape: unit tests on business logic (convert easily), UI tests (likely rewrite), integration tests (depends on infra).\n- Shared code boundaries: is there already a shared/common module that might not need conversion at all?\n- Non-trivial migration boundaries: public APIs, externally consumed module boundaries, and lifecycle/state/concurrency/resource boundaries that callers depend on.\n- Caller-visible guarantees for those boundaries. Examples include lifecycle/ownership, laziness vs eagerness, shared vs per-consumer behavior, cancellation/disposal, ordering/replay/buffering, failure behavior, threading/scheduling, or consistency/transaction guarantees.\n- Adaptation depth: classify whether the migration is `low`, `moderate`, or `high` adaptation based on architectural mismatch, missing target-side equivalents, lifecycle/state/concurrency mismatch, and the amount of adapter or redesign work needed.\n\nIdentify which files define or materially affect those boundaries and which of them will require target-repo integration analysis.\n\nCapture:\n- `sourceArchitecture`\n- `dependencies`\n- `publicApiSurface`\n- `platformCouplingAssessment`\n- `concurrencyModel`\n- `testCoverageShape`\n- `semanticBoundaryCandidates`\n- `boundaryCriticalFiles`\n- `adaptationProfile`",
82
+ "prompt": "Read and analyze the source code through a conversion lens what will be easy to convert, what will be hard, and why.\n\nMap out:\n- Architecture and module structure\n- Key patterns used (MVI, MVVM, dependency injection, etc.)\n- External dependencies and what they do\n- Entry points and public API surface\n- Platform coupling depth: is the code cleanly layered or is platform-specific code smeared throughout? This directly determines how much falls into easy vs. hard buckets.\n- Concurrency model: Coroutines, Combine, RxJS, async/await? This is often the single hardest mapping decision.\n- DI approach: Dagger/Hilt, Swinject, Koin? DI frameworks rarely map 1:1.\n- Test coverage shape: unit tests on business logic (convert easily), UI tests (likely rewrite), integration tests (depends on infra).\n- Shared code boundaries: is there already a shared/common module that might not need conversion at all?\n- Non-trivial migration boundaries: public APIs, externally consumed module boundaries, and lifecycle/state/concurrency/resource boundaries that callers depend on.\n- Caller-visible guarantees for those boundaries. Examples include lifecycle/ownership, laziness vs eagerness, shared vs per-consumer behavior, cancellation/disposal, ordering/replay/buffering, failure behavior, threading/scheduling, or consistency/transaction guarantees.\n- Adaptation depth: classify whether the migration is `low`, `moderate`, or `high` adaptation based on architectural mismatch, missing target-side equivalents, lifecycle/state/concurrency mismatch, and the amount of adapter or redesign work needed.\n\nIdentify which files define or materially affect those boundaries and which of them will require target-repo integration analysis.\n\nCapture:\n- `sourceArchitecture`\n- `dependencies`\n- `publicApiSurface`\n- `platformCouplingAssessment`\n- `concurrencyModel`\n- `testCoverageShape`\n- `semanticBoundaryCandidates`\n- `boundaryCriticalFiles`\n- `adaptationProfile`",
82
83
  "promptFragments": [
83
84
  {
84
85
  "id": "phase-1-small-light",
@@ -86,7 +87,7 @@
86
87
  "var": "conversionComplexity",
87
88
  "equals": "Small"
88
89
  },
89
- "text": "For Small conversions, keep this lightweight. A quick read of the files in scope is enough \u2014 don't map the entire architecture. Focus on identifying any platform-specific code that would prevent a straight translation."
90
+ "text": "For Small conversions, keep this lightweight. A quick read of the files in scope is enough don't map the entire architecture. Focus on identifying any platform-specific code that would prevent a straight translation."
90
91
  }
91
92
  ],
92
93
  "requireConfirmation": {
@@ -109,7 +110,7 @@
109
110
  }
110
111
  ]
111
112
  },
112
- "prompt": "For Small conversions, skip triage and planning \u2014 just convert.\n\n- Translate the files to the target platform idiomatically\n- Follow target platform naming and structure conventions\n- Map any dependencies to target equivalents\n- Convert tests if they exist\n- Run build or typecheck to verify\n\nIf something turns out harder than expected (deep platform coupling, no clean dependency equivalent, or meaningful architectural mismatch), update `conversionComplexity` to `Medium`, update `adaptationProfile` to `moderate` or `high` based on the newly discovered mismatch, and stop. The full triage and planning pipeline will activate for the remaining work.\n\nCapture:\n- `filesConverted`\n- `buildPassed`\n- `conversionComplexity`\n- `adaptationProfile`",
113
+ "prompt": "For Small conversions, skip triage and planning just convert.\n\n- Translate the files to the target platform idiomatically\n- Follow target platform naming and structure conventions\n- Map any dependencies to target equivalents\n- Convert tests if they exist\n- Run build or typecheck to verify\n\nIf something turns out harder than expected (deep platform coupling, no clean dependency equivalent, or meaningful architectural mismatch), update `conversionComplexity` to `Medium`, update `adaptationProfile` to `moderate` or `high` based on the newly discovered mismatch, and stop. The full triage and planning pipeline will activate for the remaining work.\n\nCapture:\n- `filesConverted`\n- `buildPassed`\n- `conversionComplexity`\n- `adaptationProfile`",
113
114
  "requireConfirmation": false
114
115
  },
115
116
  {
@@ -127,7 +128,7 @@
127
128
  }
128
129
  ]
129
130
  },
130
- "prompt": "Classify every file or module in scope into one of three buckets:\n\n**Bucket A \u2014 Literal translation**: Platform-agnostic business logic, data models, utilities, pure functions. These use no platform-specific APIs or libraries. Conversion is mechanical: translate the language syntax, follow target naming conventions, done. These will be delegated to subagents.\n\n**Bucket B \u2014 Library substitution**: Code that uses platform-specific libraries (networking, persistence, serialization, DI) but follows standard patterns. These need dependency mapping but the structure stays the same.\n\n**Bucket C \u2014 Platform-specific**: Code deeply tied to the platform (UI layer, lifecycle management, concurrency/threading, navigation, platform APIs). These need design decisions about target-platform idioms.\n\nFor each file or module, list:\n- File/module name\n- Bucket (A, B, or C)\n- One-line reason for classification\n- Dependencies it has on other files in scope (so we know conversion order)\n- Whether it is `boundaryCritical` for a non-trivial migration boundary\n- Which semantic boundaries it affects from `semanticBoundaryCandidates`\n- Whether it will require target-repo integration analysis\n\nBoundary-critical files must not be treated as blind mechanical translation just because the syntax looks simple. If a file materially affects a semantic boundary or destination-repo seam, keep it with main-agent review.\n\nSort the work items within each bucket by dependency order (convert dependencies first).\n\nGroup Bucket A files into parallel batches of 3-5 files each. Each batch should contain files with no cross-dependencies so subagents can work independently.\n\nGroup Bucket B and C files into sequential batches by dependency order.\n\nEach batch should have: `name` (short label), `bucket` (A, B, or C), and `files` (list of file paths).\n\nCapture:\n- `bucketABatches` (parallel batches for subagent delegation)\n- `bucketBCBatches` (sequential batches for main agent)\n- `bucketACounts`\n- `bucketBCounts`\n- `bucketCCounts`\n- `boundaryCriticalItems`",
131
+ "prompt": "Classify every file or module in scope into one of three buckets:\n\n**Bucket A Literal translation**: Platform-agnostic business logic, data models, utilities, pure functions. These use no platform-specific APIs or libraries. Conversion is mechanical: translate the language syntax, follow target naming conventions, done. These will be delegated to subagents.\n\n**Bucket B Library substitution**: Code that uses platform-specific libraries (networking, persistence, serialization, DI) but follows standard patterns. These need dependency mapping but the structure stays the same.\n\n**Bucket C Platform-specific**: Code deeply tied to the platform (UI layer, lifecycle management, concurrency/threading, navigation, platform APIs). These need design decisions about target-platform idioms.\n\nFor each file or module, list:\n- File/module name\n- Bucket (A, B, or C)\n- One-line reason for classification\n- Dependencies it has on other files in scope (so we know conversion order)\n- Whether it is `boundaryCritical` for a non-trivial migration boundary\n- Which semantic boundaries it affects from `semanticBoundaryCandidates`\n- Whether it will require target-repo integration analysis\n\nBoundary-critical files must not be treated as blind mechanical translation just because the syntax looks simple. If a file materially affects a semantic boundary or destination-repo seam, keep it with main-agent review.\n\nSort the work items within each bucket by dependency order (convert dependencies first).\n\nGroup Bucket A files into parallel batches of 3-5 files each. Each batch should contain files with no cross-dependencies so subagents can work independently.\n\nGroup Bucket B and C files into sequential batches by dependency order.\n\nEach batch should have: `name` (short label), `bucket` (A, B, or C), and `files` (list of file paths).\n\nCapture:\n- `bucketABatches` (parallel batches for subagent delegation)\n- `bucketBCBatches` (sequential batches for main agent)\n- `bucketACounts`\n- `bucketBCounts`\n- `bucketCCounts`\n- `boundaryCriticalItems`",
131
132
  "requireConfirmation": true
132
133
  },
133
134
  {
@@ -274,7 +275,7 @@
274
275
  "var": "conversionComplexity",
275
276
  "equals": "Medium"
276
277
  },
277
- "text": "For Medium conversions, focus the plan on the items that actually need design decisions. Don't exhaustively map every dimension \u2014 only the ones relevant to the files in scope."
278
+ "text": "For Medium conversions, focus the plan on the items that actually need design decisions. Don't exhaustively map every dimension only the ones relevant to the files in scope."
278
279
  },
279
280
  {
280
281
  "id": "phase-3f-high-adaptation",
@@ -519,7 +520,7 @@
519
520
  {
520
521
  "id": "phase-6a-full-build",
521
522
  "title": "Full Build and Integration Check",
522
- "prompt": "Run a full build or typecheck on the entire converted codebase \u2014 both subagent-converted and main-agent-converted code together.\n\nCheck for:\n- Build/compile errors from cross-batch integration issues\n- Inconsistencies between subagent output and main agent output (naming, patterns)\n- Non-idiomatic patterns that slipped through\n- Missing error handling at module boundaries\n- Threading or concurrency issues across modules\n- Broken public API contracts\n- Contract inventory drift: every row in `semanticContractInventory` is still accounted for, no `uncertain` rows remain, preserved contracts still look preserved, and intentional changes are still justified\n- Target integration drift: code landed in the intended target layer/module, reuse/adaptation decisions still fit the observed target seams, and no unresolved target integration uncertainties remain\n- High-adaptation architecture drift: if `adaptationProfile` is `high`, the final code still matches `architectureAdaptationPlan` and any deviations are explicit and justified\n\nFix each issue. If a fix is a band-aid over a deeper mapping problem, go back and fix the mapping.\n\nCapture:\n- `fullBuildPassed`\n- `integrationIssues`\n- `issuesFixed`",
523
+ "prompt": "Run a full build or typecheck on the entire converted codebase both subagent-converted and main-agent-converted code together.\n\nCheck for:\n- Build/compile errors from cross-batch integration issues\n- Inconsistencies between subagent output and main agent output (naming, patterns)\n- Non-idiomatic patterns that slipped through\n- Missing error handling at module boundaries\n- Threading or concurrency issues across modules\n- Broken public API contracts\n- Contract inventory drift: every row in `semanticContractInventory` is still accounted for, no `uncertain` rows remain, preserved contracts still look preserved, and intentional changes are still justified\n- Target integration drift: code landed in the intended target layer/module, reuse/adaptation decisions still fit the observed target seams, and no unresolved target integration uncertainties remain\n- High-adaptation architecture drift: if `adaptationProfile` is `high`, the final code still matches `architectureAdaptationPlan` and any deviations are explicit and justified\n\nFix each issue. If a fix is a band-aid over a deeper mapping problem, go back and fix the mapping.\n\nCapture:\n- `fullBuildPassed`\n- `integrationIssues`\n- `issuesFixed`",
523
524
  "requireConfirmation": false
524
525
  },
525
526
  {
@@ -544,7 +545,7 @@
544
545
  "var": "conversionComplexity",
545
546
  "equals": "Small"
546
547
  },
547
- "text": "For Small conversions, keep the summary brief \u2014 just list what was converted, build status, and any issues."
548
+ "text": "For Small conversions, keep the summary brief just list what was converted, build status, and any issues."
548
549
  },
549
550
  {
550
551
  "id": "phase-7-full-summary",
@@ -2,6 +2,7 @@
2
2
  "id": "document-creation-workflow",
3
3
  "name": "Document Creation Workflow",
4
4
  "version": "1.0.0",
5
+ "metricsProfile": "coding",
5
6
  "description": "Use this to create broad or comprehensive documentation spanning multiple components or systems — project READMEs, complete API docs, user guides, or technical specifications.",
6
7
  "about": "## Document Creation Workflow\n\nThis workflow guides you through creating new documentation from scratch -- ranging from a simple project README to a full technical specification spanning multiple systems. It automatically calibrates depth to match the complexity of your request: simple tasks go straight to writing, while complex documentation gets a full analysis-and-planning phase first.\n\n### What it produces\n\nA complete, saved documentation file ready for use. Depending on complexity, it may also include a quality review pass covering accuracy, completeness, audience fit, usability, and style consistency.\n\n### When to use it\n\n- You need to create a **new** document (not update an existing one -- see the Documentation Update workflow for that).\n- The document spans one or more systems, components, or audiences.\n- Examples: project READMEs, API reference docs, user guides, onboarding docs, technical specifications, architecture overviews.\n\n### When NOT to use it\n\n- You want to update or refresh an existing doc -- use the Documentation Update workflow instead.\n- You need tight scope discipline for a single class or mechanism -- the Scoped Documentation workflow is better suited.\n\n### How to get good results\n\n- Be specific about the document type and intended audience upfront. The workflow probes for these, but the clearer your initial goal, the less back-and-forth.\n- If your project has existing documentation or style conventions, mention them -- the workflow will follow them.\n- For complex documentation, the workflow asks a small number of targeted questions it cannot answer from the codebase. Answer these concisely to keep momentum.",
7
8
  "examples": [
@@ -148,4 +149,4 @@
148
149
  "requireConfirmation": false
149
150
  }
150
151
  ]
151
- }
152
+ }