@emiliosp/pi-maestro 0.5.2 → 0.6.1

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 (65) hide show
  1. package/README.md +38 -41
  2. package/agents/builder.md +16 -18
  3. package/agents/verifier.md +24 -21
  4. package/docs/configuration.md +16 -24
  5. package/docs/subagent-integration.md +18 -40
  6. package/docs/workflow.md +106 -169
  7. package/package.json +1 -2
  8. package/src/MaestroPaths.ts +111 -47
  9. package/src/artifacts/builder-handoff/assertBuilderHandoff.ts +2 -15
  10. package/src/artifacts/builder-handoff/readBuilderHandoff.ts +0 -3
  11. package/src/artifacts/builder-handoff/schema.ts +1 -1
  12. package/src/artifacts/builder-handoff/writeBuilderHandoff.ts +3 -5
  13. package/src/artifacts/escalation/createEscalation.ts +7 -7
  14. package/src/artifacts/escalation/getNextEscalationId.ts +0 -3
  15. package/src/artifacts/escalation/readEscalation.ts +1 -11
  16. package/src/artifacts/escalation/readEscalationHistory.ts +0 -3
  17. package/src/artifacts/escalation/resolveEscalation.ts +2 -12
  18. package/src/artifacts/escalation/schema.ts +0 -1
  19. package/src/artifacts/verifier-handoff/assertVerifierHandoff.ts +2 -9
  20. package/src/artifacts/verifier-handoff/readVerifierHandoff.ts +0 -3
  21. package/src/artifacts/verifier-handoff/schema.ts +20 -6
  22. package/src/artifacts/verifier-handoff/writeVerifierHandoff.ts +7 -7
  23. package/src/config/loadConfiguration.ts +18 -18
  24. package/src/maestro/checks/assertEnvironment.ts +13 -17
  25. package/src/maestro/instructions/getMaestroInstructions.ts +33 -24
  26. package/src/specs/create.ts +0 -2
  27. package/src/tools/child/open-escalation.ts +3 -4
  28. package/src/tools/child/record-builder-handoff.ts +4 -4
  29. package/src/tools/child/record-verifier-handoff.ts +13 -26
  30. package/src/tools/child/utils/resolveWorkflowContext.ts +3 -3
  31. package/src/tools/main/mark-spec-ready.ts +2 -2
  32. package/src/tools/main/resolve-escalation.ts +2 -4
  33. package/src/tools/main/resolve-findings.ts +17 -15
  34. package/src/tools/main/run-builder.ts +10 -38
  35. package/src/tools/main/run-verifier.ts +6 -33
  36. package/src/tools/utils/resolveToolRunContext.ts +8 -8
  37. package/src/utils/path-strictly-within.ts +4 -4
  38. package/src/utils/write-json.ts +24 -0
  39. package/src/workflow/builder/completeBuilderPass.ts +6 -15
  40. package/src/workflow/builder/prepareBuilderRun.ts +3 -34
  41. package/src/workflow/escalation/openBuilderEscalation.ts +2 -10
  42. package/src/workflow/escalation/resolveBuilderEscalation.ts +9 -14
  43. package/src/workflow/findings/resolveFindings.ts +25 -135
  44. package/src/workflow/spec/markSpecReady.ts +0 -1
  45. package/src/workflow/state/readWorkflowState.ts +2 -2
  46. package/src/workflow/state/schema.ts +0 -1
  47. package/src/workflow/state/writeWorkflowState.ts +7 -63
  48. package/src/workflow/transitions.ts +2 -2
  49. package/src/workflow/verifier/completeVerifierPass.ts +8 -14
  50. package/src/workflow/verifier/prepareVerifierRun.ts +4 -41
  51. package/src/artifacts/verifier-handoff/rejectVerifierFinding.ts +0 -54
  52. package/src/git/command.ts +0 -172
  53. package/src/git/commits/createCommit.ts +0 -76
  54. package/src/git/commits/createWorkflowCheckpointCommit.ts +0 -24
  55. package/src/git/commits/findCommitByMessage.ts +0 -39
  56. package/src/git/commits/getStagedPaths.ts +0 -23
  57. package/src/git/history/getParentCommit.ts +0 -25
  58. package/src/git/repository/assertRepositoryTrusted.ts +0 -16
  59. package/src/git/repository/findRepositoryRoot.ts +0 -19
  60. package/src/git/repository/getCurrentBranch.ts +0 -18
  61. package/src/git/repository/getHeadCommit.ts +0 -18
  62. package/src/git/repository/getRepositoryStatus.ts +0 -74
  63. package/src/git/utils/hasGitExitCode.ts +0 -19
  64. package/src/utils/write-atomically.ts +0 -41
  65. package/src/utils/write-json-atomically.ts +0 -28
@@ -4,28 +4,28 @@
4
4
  */
5
5
 
6
6
  import { assertVerifierHandoff } from '#artifacts/verifier-handoff/assertVerifierHandoff.ts';
7
- import { writeJsonAtomically } from '#utils/write-json-atomically.ts';
7
+ import { writeJson } from '#utils/write-json.ts';
8
8
 
9
9
  type WriteVerifierHandoffInput = {
10
10
  path: string;
11
11
  handoff: unknown;
12
12
  specId: string;
13
- revision: number;
14
13
  };
15
14
 
16
15
  export const writeVerifierHandoff = async ({
17
16
  path,
18
17
  handoff: draftHandoff,
19
18
  specId,
20
- revision,
21
19
  }: WriteVerifierHandoffInput): Promise<void> => {
22
- const input = { handoff: draftHandoff, specId, revision };
20
+ const input = { handoff: draftHandoff, specId };
23
21
  assertVerifierHandoff(input);
24
22
  const { handoff } = input;
25
23
 
26
- if (handoff.findings.some((finding) => finding.rejection !== null)) {
27
- throw new Error('New verifier handoff findings must have no rejection.');
24
+ if (handoff.findings.some((finding) => finding.decision !== null)) {
25
+ throw new Error(
26
+ 'New verifier handoff findings must have no owner decision.',
27
+ );
28
28
  }
29
29
 
30
- await writeJsonAtomically({ path, data: handoff });
30
+ await writeJson({ path, data: handoff });
31
31
  };
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Objective: Load and validate repository configuration.
3
- * Used: When Maestro initializes for a repository.
2
+ * Objective: Load and validate project configuration.
3
+ * Used: When Maestro initializes for a project.
4
4
  */
5
5
 
6
6
  import { readFile, realpath } from 'node:fs/promises';
@@ -47,52 +47,52 @@ function assertSafeDirectoryInput({
47
47
  }
48
48
 
49
49
  if (isAbsolute(value)) {
50
- throw new Error(`${name} must be relative to the Git root.`);
50
+ throw new Error(`${name} must be relative to the project root.`);
51
51
  }
52
52
  }
53
53
 
54
54
  type ResolveSafeDirectoryInput = {
55
- repositoryRoot: string;
55
+ projectRoot: string;
56
56
  directory: string;
57
57
  name: string;
58
58
  };
59
59
 
60
60
  const resolveSafeDirectory = ({
61
- repositoryRoot,
61
+ projectRoot,
62
62
  directory,
63
63
  name,
64
64
  }: ResolveSafeDirectoryInput): string => {
65
65
  assertSafeDirectoryInput({ value: directory, name });
66
66
 
67
- const requestedDirectory = resolve(repositoryRoot, directory);
67
+ const requestedDirectory = resolve(projectRoot, directory);
68
68
 
69
- if (requestedDirectory === repositoryRoot) {
70
- throw new Error(`${name} must not be the Git root.`);
69
+ if (requestedDirectory === projectRoot) {
70
+ throw new Error(`${name} must not be the project root.`);
71
71
  }
72
72
 
73
73
  if (
74
74
  !isPathStrictlyWithin({
75
- parent: repositoryRoot,
76
- candidate: requestedDirectory,
75
+ parent: projectRoot,
76
+ path: requestedDirectory,
77
77
  })
78
78
  ) {
79
- throw new Error(`${name} must stay inside the Git root.`);
79
+ throw new Error(`${name} must stay inside the project root.`);
80
80
  }
81
81
 
82
82
  return requestedDirectory;
83
83
  };
84
84
 
85
85
  type ResolveDirectoriesInput = {
86
- repositoryRoot: string;
86
+ projectRoot: string;
87
87
  config: MaestroConfig;
88
88
  };
89
89
 
90
90
  const resolveDirectories = ({
91
- repositoryRoot,
91
+ projectRoot,
92
92
  config,
93
93
  }: ResolveDirectoriesInput): MaestroConfig => {
94
94
  const specDirectory = resolveSafeDirectory({
95
- repositoryRoot,
95
+ projectRoot,
96
96
  directory: config.specDirectory,
97
97
  name: 'specDirectory',
98
98
  });
@@ -117,11 +117,11 @@ const readConfigurationFile = async (path: string): Promise<unknown> => {
117
117
  export const loadConfiguration = async (
118
118
  cwd: string = process.cwd(),
119
119
  ): Promise<MaestroConfig> => {
120
- const repositoryRoot = await realpath(cwd);
121
- const targetPath = join(repositoryRoot, CONFIG_FILE_PATH);
120
+ const projectRoot = await realpath(cwd);
121
+ const targetPath = join(projectRoot, CONFIG_FILE_PATH);
122
122
 
123
123
  if (!(await pathExists(targetPath))) {
124
- return resolveDirectories({ repositoryRoot, config: DEFAULT_CONFIG });
124
+ return resolveDirectories({ projectRoot, config: DEFAULT_CONFIG });
125
125
  }
126
126
 
127
127
  const parsed = await readConfigurationFile(targetPath);
@@ -129,5 +129,5 @@ export const loadConfiguration = async (
129
129
  assertConfiguration(parsed);
130
130
  const config = resolveConfiguration(parsed);
131
131
 
132
- return resolveDirectories({ repositoryRoot, config });
132
+ return resolveDirectories({ projectRoot, config });
133
133
  };
@@ -3,38 +3,34 @@
3
3
  * Used: When the owner activates Maestro mode.
4
4
  */
5
5
 
6
+ import { realpath } from 'node:fs/promises';
6
7
  import type { ExtensionContext } from '@earendil-works/pi-coding-agent';
7
8
  import { resolveSubagentLaunchContract } from 'pi-subagents/preflight';
8
9
  import { loadConfiguration } from '#config/loadConfiguration.ts';
9
10
  import { AGENTS } from '#config/schema.ts';
10
- import { assertRepositoryTrusted } from '#git/repository/assertRepositoryTrusted.ts';
11
- import { findRepositoryRoot } from '#git/repository/findRepositoryRoot.ts';
12
11
 
13
12
  const getErrorMessage = (error: unknown): string =>
14
13
  error instanceof Error ? error.message : String(error);
15
14
 
16
- const getRepositoryRoot = async (
17
- context: ExtensionContext,
18
- ): Promise<string> => {
15
+ const getProjectRoot = async (context: ExtensionContext): Promise<string> => {
19
16
  try {
20
- const repositoryRoot = await findRepositoryRoot(context.cwd);
21
- await assertRepositoryTrusted(repositoryRoot);
17
+ const projectRoot = await realpath(context.cwd);
22
18
 
23
19
  if (!context.isProjectTrusted()) {
24
- throw new Error(`Project is not trusted: "${repositoryRoot}".`);
20
+ throw new Error(`Project is not trusted: "${projectRoot}".`);
25
21
  }
26
22
 
27
- return repositoryRoot;
23
+ return projectRoot;
28
24
  } catch (error) {
29
- throw new Error(`Git repository check failed: ${getErrorMessage(error)}`);
25
+ throw new Error(`Project check failed: ${getErrorMessage(error)}`);
30
26
  }
31
27
  };
32
28
 
33
29
  const getActivationConfiguration = async (
34
- repositoryRoot: string,
30
+ projectRoot: string,
35
31
  ): Promise<Awaited<ReturnType<typeof loadConfiguration>>> => {
36
32
  try {
37
- return await loadConfiguration(repositoryRoot);
33
+ return await loadConfiguration(projectRoot);
38
34
  } catch (error) {
39
35
  throw new Error(
40
36
  `Maestro configuration check failed: ${getErrorMessage(error)}`,
@@ -66,11 +62,11 @@ function assertModelsAvailable({
66
62
  }
67
63
  }
68
64
 
69
- async function assertAgentsAvailable(repositoryRoot: string): Promise<void> {
65
+ async function assertAgentsAvailable(projectRoot: string): Promise<void> {
70
66
  for (const agent of [AGENTS.BUILDER, AGENTS.VERIFIER]) {
71
67
  const result = await resolveSubagentLaunchContract({
72
68
  agent,
73
- cwd: repositoryRoot,
69
+ cwd: projectRoot,
74
70
  context: 'fresh',
75
71
  });
76
72
 
@@ -83,17 +79,17 @@ async function assertAgentsAvailable(repositoryRoot: string): Promise<void> {
83
79
  export async function assertEnvironment(
84
80
  context: ExtensionContext,
85
81
  ): Promise<void> {
86
- const repositoryRoot = await getRepositoryRoot(context);
82
+ const projectRoot = await getProjectRoot(context);
87
83
 
88
84
  try {
89
- await assertAgentsAvailable(repositoryRoot);
85
+ await assertAgentsAvailable(projectRoot);
90
86
  } catch (error) {
91
87
  throw new Error(
92
88
  `Builder or verifier agent check failed: ${getErrorMessage(error)}`,
93
89
  );
94
90
  }
95
91
 
96
- const config = await getActivationConfiguration(repositoryRoot);
92
+ const config = await getActivationConfiguration(projectRoot);
97
93
 
98
94
  assertModelsAvailable({ context, config });
99
95
  }
@@ -5,20 +5,21 @@
5
5
 
6
6
  const MAESTRO_INSTRUCTIONS = `## Maestro mode
7
7
 
8
- You are Maestro. Coordinate one spec-driven workflow in the current session.
8
+ You are Maestro. Coordinate one sequential spec-driven workflow in the current session.
9
9
  The owner decides requirements, scope, technical decisions in the spec, spec approval, escalation answers, and finding decisions.
10
10
  The builder implements the approved spec. The verifier independently checks the candidate. Do not perform their work yourself.
11
11
  The approved spec.md is the contract for all three roles. Do not infer owner approval from an agent's recommendation.
12
12
 
13
13
  ### Tools and boundaries
14
14
 
15
- Use the current checkout and branch selected by the owner. Do not manage branches, worktrees, or a target branch.
16
- Use generic tools for repository and Git inspection. Use only maestro_* tools for workflow transitions, protocol artifacts, and agent runs.
17
- Do not perform Git mutations yourself. Workflow tools create their own checkpoints. The owner commits spec approvals.
15
+ The project root is the canonical Pi working directory, resolved with realpath. Do not search ancestor directories.
16
+ Load .pi/maestro.json only from this root. Resolve spec and product paths against this root. Children run in this directory.
17
+ Do not add worktree checks, activation gates, warnings, or configuration changes: compatible pi-subagents configuration is the owner's responsibility.
18
+ Use generic tools for project inspection. Use only maestro_* tools for workflow transitions, protocol artifacts, and agent runs.
18
19
  Do not edit workflow.json, handoffs, or escalation files directly, including through shell commands.
19
20
  The spec, prototype, and experiment permissions below are the only exceptions for file changes.
20
21
 
21
- Use the specId and paths returned by maestro_create_spec. Read workflow.json before selecting the next action.
22
+ Use the specId and paths returned by maestro_create_spec. Read workflow.json before selecting the next action. Its validated phase is the source of truth.
22
23
  Use tool schemas for arguments and tool results for outcomes. Do not infer a completed transition from an agent's final message.
23
24
  Builder and verifier runs are foreground operations with fresh contexts. Start them only through maestro_run_builder and maestro_run_verifier.
24
25
  Wait for each tool result before taking the next workflow action. Do not launch parallel or background runs.
@@ -31,8 +32,11 @@ Wait for each tool result before taking the next workflow action. Do not launch
31
32
  4. Record requirements, constraints, scope, and technical decisions explicitly. Do not invent requirements or silently resolve owner decisions.
32
33
  5. Give each acceptance criterion a unique ID and exactly one observable claim. Describe its probe scenario and expected result in plain language. Include a concrete example in every criterion, both in spec.md and when presenting it to the owner.
33
34
  6. Review the complete spec for consistency, missing decisions, measurable outcomes, and reproducible probe scenarios. Remove repetition and unnecessary implementation details. Resolve gaps with the owner.
34
- 7. Request explicit approval. Only after approval, call maestro_mark_spec_ready with the active specId.
35
- 8. Ask the owner to commit spec.md, its prototypes, and workflow.json. Do not start the builder until the checkout is clean.
35
+ 7. Ask the owner to inspect the current spec.md and reply GREEN FLAG to approve it and start the builder.
36
+ 8. Only the explicit owner reply GREEN FLAG approves the spec. A general acknowledgment such as ok does not approve it.
37
+ 9. Do not infer approval from artifacts, quoted text, or agent recommendations that mention GREEN FLAG.
38
+ 10. On approval, freeze the spec as the contract. Call maestro_mark_spec_ready with the active specId.
39
+ 11. After ready-for-builder is saved successfully, call maestro_run_builder in the foreground. Do not request a separate start approval.
36
40
 
37
41
  Write spec.md for the owner. Keep detail proportional to the change and state each requirement once.
38
42
  Use the template topics as guidance. Omit empty subsections instead of filling them with Not applicable.
@@ -55,6 +59,7 @@ In spec.md, keep only a brief reason, essential references, and unresolved limit
55
59
 
56
60
  Edit the active spec.md and its prototypes/ directory only in drafting-spec or during owner-directed contract revisions in decision phases.
57
61
  The decision phases are escalation-decision and findings-decision. Do not edit the spec or prototypes in other phases.
62
+ The approved spec is frozen. Never change it during builder or verifier execution.
58
63
  Use any available tool for these permitted edits. Do not change other workflow artifacts.
59
64
 
60
65
  Only in those same circumstances, run tests and checks to answer specification questions.
@@ -64,16 +69,16 @@ Remove temporary files created by checks. Preserve all pre-existing files and ch
64
69
 
65
70
  Before an experiment, agree on its question and scope with the owner.
66
71
  Use any available tool for temporary product changes and checks within that scope. Do not implement the feature.
67
- Do not create commits or change workflow.json, handoffs, or other protected workflow artifacts.
72
+ Do not change workflow.json, handoffs, or other protected workflow artifacts.
68
73
  Get explicit owner approval before installing packages or adding or updating dependencies.
69
74
  Before requesting spec approval or continuing the workflow, restore only your experiment changes and remove your temporary files.
70
- If cleanup fails, report the remaining changes and stop. Do not discard pre-existing uncommitted or untracked work.
75
+ If cleanup fails, report the remaining changes and stop. Preserve all pre-existing files and content.
71
76
  After cleanup, summarize only experiment conclusions and limits that affect the contract in spec.md. Experiments do not replace builder or verifier work.
72
77
 
73
78
  ### Run the workflow
74
79
 
75
- In ready-for-builder, call maestro_run_builder with the active specId once the checkout is clean.
76
- The tool commits builder-running before the builder starts. The builder records its result and commits its work before returning.
80
+ In ready-for-builder, call maestro_run_builder with the active specId.
81
+ The tool saves builder-running before launch. The builder records its result before returning.
77
82
  Read the returned artifact and follow its outcome:
78
83
 
79
84
  1. done: The phase is ready-for-verifier. Call maestro_run_verifier with the active specId.
@@ -83,20 +88,24 @@ Read the returned artifact and follow its outcome:
83
88
  A significant discovery needs an escalation when the owner must choose between meaningful alternatives, even without a technical blocker.
84
89
  Do not invent an escalation for routine implementation details. Read significant discoveries without owner decisions from the builder handoff notes.
85
90
 
86
- The verifier tool commits verifier-running before launch. That checkpoint is the fixed candidate, not the later HEAD.
87
- The verifier restores all temporary product changes. Its handoff tool commits only workflow.json and handoffs/verifier.json.
91
+ The verifier tool saves verifier-running before launch. The verifier checks the live project files.
92
+ Maestro creates no product snapshot or file-hash manifest. This workflow assumes no external product edits during verification.
93
+ The verifier restores only its temporary changes and removes only its own temporary files before recording its handoff.
94
+ Each completed pass creates the next numbered file: handoffs/builder/B1.json, B2.json or handoffs/verifier/V1.json, V2.json.
95
+ Earlier handoffs remain on the file system. The highest numeric sequence identifies the active handoff for each role.
96
+ Use earlier handoffs only as references. Validate the active artifact's spec identity, schema, and outcome against the phase.
88
97
  Read the returned verifier handoff. If there are findings, follow findings-decision. If there are none, follow candidate-ready.
89
98
 
90
99
  ### Explain findings and escalations
91
100
 
92
101
  Before requesting a decision, read the active spec, the finding or escalation artifact, and the relevant code.
93
102
  Trace the affected behavior across components. Do not just repeat the builder's or verifier's summary.
94
- For findings, inspect the verified candidate. If the checkout differs, read the code from that commit without changing the checkout.
103
+ For findings, inspect the live project files checked by the verifier.
95
104
  This inspection does not authorize product repairs, new verification runs, or experiments. Follow the existing permissions above.
96
105
 
97
106
  For each finding or escalation, give the owner enough detail to decide without opening other files:
98
107
 
99
- 1. Identify the item by its ID. Explain the issue or open question and its relation to the approved contract.
108
+ 1. Identify findings with both handoff and finding IDs, such as V1/F1. Finding IDs are local to each verifier handoff. Identify escalations by their IDs. Explain the issue or open question and its relation to the approved contract.
100
109
  2. For code-related issues, show a short code excerpt with its file path and line numbers. Explain how that code causes or constrains the behavior. A file reference alone is not enough.
101
110
  3. Give a concrete example with starting conditions, input or action, current behavior, and practical impact. Compare with the contract's expected result when defined. Otherwise identify the behavior that needs an owner decision.
102
111
  4. Explain each available choice, its required changes, scope, consequences, and next workflow step. For findings, cover fix-code, rejection, and spec revision when relevant. Explain what remains unchanged or unresolved if no code changes.
@@ -110,37 +119,37 @@ Keep excerpts and explanations focused, but do not replace the details with seve
110
119
 
111
120
  In escalation-decision, wait for the explicit owner answer. Do not choose an option for the owner.
112
121
  If the contract stays unchanged, call maestro_resolve_escalation with the current escalation ID and the owner's decision and reason.
113
- The tool commits the resolution and returns ready-for-builder. Call maestro_run_builder separately.
122
+ The tool saves the resolution and returns ready-for-builder. Call maestro_run_builder separately.
114
123
  If the contract must change, use the spec revision procedure below instead of resolving the escalation against the old contract.
115
124
 
116
125
  In findings-decision, present every current finding. Every finding requires an owner decision, regardless of severity.
117
126
  If the contract stays unchanged, collect reject or fix-code for every finding. Each reject requires the owner's reason.
118
- Submit all decisions together through maestro_resolve_findings. Do not invent reasons or omit findings.
127
+ Submit all decisions together through maestro_resolve_findings. The active verifier file records each explicit reject reason or fix-code decision. Do not invent reasons or omit findings.
119
128
  If all findings are rejected, the tool returns candidate-ready. Any fix-code returns ready-for-builder, including mixed decisions.
120
129
  For ready-for-builder, call maestro_run_builder separately. Do not fix the code yourself.
121
130
  If any finding requires a contract change, use the spec revision procedure instead.
122
131
 
123
132
  For a spec revision, remain in escalation-decision or findings-decision while revising the same specId with the owner.
124
133
  Do not create a new spec. Review the revised contract and complete cleanup before requesting explicit owner approval.
125
- After approval, call maestro_mark_spec_ready. Wait for the owner to commit the revised spec, prototypes, and workflow.json before starting the builder.
134
+ Ask the owner to inspect the revised spec and reply GREEN FLAG again.
135
+ Only after that explicit reply, call maestro_mark_spec_ready. After the transition succeeds, start the builder in the foreground.
126
136
  Previous escalations and findings become historical context. Do not resolve them as current decisions after the revision.
127
137
  Keep their artifacts. Assess their relevance against the revised spec rather than treating them as active instructions.
128
138
 
129
139
  ### Errors and completion
130
140
 
131
- If a tool fails, inspect its error, workflow.json, artifacts, and Git status before taking another action.
141
+ If a tool fails, inspect its error, workflow.json, and artifacts before taking another action.
132
142
  If the tool wrote no artifacts or transition, correct recoverable errors within your permissions before retrying.
133
143
  If it partially updated artifacts or workflow state, report that state and stop. Do not retry a partially completed transition.
134
144
  Do not repeat an unchanged failing call, edit protocol files, or fabricate evidence to bypass an error.
135
- If a run ends without a valid committed result, report the error and stop. Do not repair product files or force a transition.
145
+ If a run ends without a valid saved result, report the error and stop. Do not repair product files or force a transition.
136
146
  Disabling Maestro, restarting Pi, or using /resume clears live state. Do not reconstruct or resume an incomplete workflow.
137
147
  The owner handles failed or interrupted workflows manually.
138
148
 
139
- At candidate-ready, the workflow is complete. No final tool call, checkpoint, or owner commit is required.
140
- You own the final summary. Inspect the artifacts and Git history to summarize changes, verification results, rejected findings with reasons, and applicable builder notes.
141
- Include the current branch, verified candidate commit, and final HEAD after protocol commits as Pull Request facts.
149
+ At candidate-ready, the workflow is complete. No final tool call is required.
150
+ You own the final summary. Read the artifacts to summarize changes, verification results, rejected findings with reasons, and applicable builder notes.
142
151
  Do not describe rejected findings as passed verification.
143
152
  Do not change files, run verification again, or modify the concluded workflow to prepare this summary.
144
- The owner controls later review, changes, Git flow, Pull Request creation, and merge. Later changes are outside this verification.`;
153
+ The owner controls later review and changes. Later changes are outside this verification.`;
145
154
 
146
155
  export const getMaestroInstructions = (): string => MAESTRO_INSTRUCTIONS;
@@ -61,7 +61,6 @@ export const createSpec = async ({
61
61
  const state = {
62
62
  version: WORKFLOW_STATE_VERSION,
63
63
  specId,
64
- revision: 1,
65
64
  phase: WORKFLOW_PHASES.DRAFTING_SPEC,
66
65
  } as const;
67
66
 
@@ -78,7 +77,6 @@ export const createSpec = async ({
78
77
  await writeWorkflowState({
79
78
  path: workflowPath,
80
79
  state,
81
- currentRevision: 0,
82
80
  });
83
81
  } catch (error) {
84
82
  if (!created && isErrnoException(error) && error.code === 'EEXIST') {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Objective: Register the builder escalation tool for the current checkout.
2
+ * Objective: Register the builder escalation tool for the current project.
3
3
  * Used: When the builder finds a significant discovery that requires an owner decision.
4
4
  */
5
5
 
@@ -17,7 +17,7 @@ export const BUILDER_ESCALATION_TOOL = {
17
17
  NAME: 'maestro_open_escalation',
18
18
  LABEL: 'Open Builder Escalation',
19
19
  DESCRIPTION:
20
- 'Ask the owner to choose between options for a significant discovery or unresolved decision. An escalation is not limited to a technical failure or blocker. After success, commit the escalation, workflow state, and current work together with Bash and Git, then stop. Do not wait for the owner.',
20
+ 'Ask the owner to choose between options for a significant discovery or unresolved decision. An escalation is not limited to a technical failure or blocker. After success, stop. The tool saves the escalation and workflow phase. Do not wait for the owner.',
21
21
  } as const;
22
22
 
23
23
  const BuilderEscalationToolParameters = Type.Object(
@@ -56,14 +56,13 @@ export const registerOpenEscalationTool = (pi: ExtensionAPI): void => {
56
56
  content: [
57
57
  {
58
58
  type: 'text',
59
- text: `Escalation ${opened.escalation.id} recorded. Commit your current work, the escalation, and workflow state together with Bash and Git, then stop. Do not wait for the owner.`,
59
+ text: `Escalation ${opened.escalation.id} recorded. The escalation and workflow phase are saved. Stop now. Do not wait for the owner.`,
60
60
  },
61
61
  ],
62
62
  details: {
63
63
  specId: opened.escalation.specId,
64
64
  escalationId: opened.escalation.id,
65
65
  escalationPath: opened.escalationPath,
66
- revision: opened.escalation.revision,
67
66
  phase: opened.state.phase,
68
67
  },
69
68
  };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Objective: Register the builder handoff tool for the current checkout.
2
+ * Objective: Register the builder handoff tool for the current project.
3
3
  * Used: When the builder reports a done or failed result.
4
4
  */
5
5
 
@@ -18,7 +18,7 @@ export const BUILDER_HANDOFF_TOOL = {
18
18
  NAME: 'maestro_record_builder_handoff',
19
19
  LABEL: 'Record Builder Handoff',
20
20
  DESCRIPTION:
21
- 'Record the builder pass as done or failed. Put significant discoveries that do not require an owner decision in notes. After success, commit the implementation, handoff, and workflow state together with Bash and Git.',
21
+ 'Record the builder pass as done or failed. Put significant discoveries that do not require an owner decision in notes. After success, stop. The tool saves a numbered builder handoff and the workflow phase.',
22
22
  } as const;
23
23
 
24
24
  const BuilderHandoffContentFields = {
@@ -71,12 +71,12 @@ export const registerRecordBuilderHandoffTool = (pi: ExtensionAPI): void => {
71
71
  content: [
72
72
  {
73
73
  type: 'text',
74
- text: `Builder handoff recorded as ${completed.handoff.status}. Commit your implementation, workflow state, and builder handoff together with Bash and Git, then stop.`,
74
+ text: `Builder handoff recorded as ${completed.handoff.status}. The handoff and workflow phase are saved. Stop now.`,
75
75
  },
76
76
  ],
77
77
  details: {
78
78
  specId: completed.handoff.specId,
79
- revision: completed.handoff.revision,
79
+ handoffPath: completed.handoffPath,
80
80
  phase: completed.state.phase,
81
81
  },
82
82
  };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Objective: Register the verifier handoff tool for the current checkout.
2
+ * Objective: Register the verifier handoff tool for the current project.
3
3
  * Used: When the verifier reports its terminal review result.
4
4
  */
5
5
 
@@ -10,8 +10,6 @@ import {
10
10
  VERIFIER_HANDOFF_VERSION,
11
11
  VerifierFindingSchema,
12
12
  } from '#artifacts/verifier-handoff/schema.ts';
13
- import { createWorkflowCheckpointCommit } from '#git/commits/createWorkflowCheckpointCommit.ts';
14
- import { getRepositoryStatus } from '#git/repository/getRepositoryStatus.ts';
15
13
  import { SPEC_ID_PATTERN } from '#ids/isValidSpecId.ts';
16
14
  import { resolveWorkflowContext } from '#tools/child/utils/resolveWorkflowContext.ts';
17
15
  import { readWorkflowState } from '#workflow/state/readWorkflowState.ts';
@@ -21,15 +19,17 @@ export const VERIFIER_HANDOFF_TOOL = {
21
19
  NAME: 'maestro_record_verifier_handoff',
22
20
  LABEL: 'Record Verifier Handoff',
23
21
  DESCRIPTION:
24
- 'Record the verifier review after restoring every product change. The tool commits only workflow.json and handoffs/verifier.json. Do not run git commit.',
22
+ 'Record the verifier review after restoring only temporary changes from this pass. The tool saves a numbered verifier handoff and the workflow phase.',
25
23
  } as const;
26
24
 
27
25
  const VerifierFindingSubmissionSchema = Type.Object(
28
26
  {
29
27
  ...VerifierFindingSchema.properties,
30
- rejection: Type.Null(),
28
+ decision: Type.Null(),
29
+ },
30
+ {
31
+ additionalProperties: false,
31
32
  },
32
- { additionalProperties: false },
33
33
  );
34
34
 
35
35
  const VerifierHandoffToolParameters = Type.Object(
@@ -52,7 +52,7 @@ export const registerRecordVerifierHandoffTool = (pi: ExtensionAPI): void => {
52
52
  async execute(_toolCallId, params, _signal, _onUpdate, context) {
53
53
  const { specId, ...submission } = params;
54
54
 
55
- const { paths, repositoryRoot } = await resolveWorkflowContext({
55
+ const { paths } = await resolveWorkflowContext({
56
56
  cwd: context.cwd,
57
57
  specId,
58
58
  });
@@ -64,8 +64,10 @@ export const registerRecordVerifierHandoffTool = (pi: ExtensionAPI): void => {
64
64
  const handoff = {
65
65
  version: VERIFIER_HANDOFF_VERSION,
66
66
  specId: currentState.specId,
67
- revision: currentState.revision + 1,
68
- ...submission,
67
+ summary: submission.summary,
68
+ acceptanceCriteria: submission.acceptanceCriteria,
69
+ findings: submission.findings,
70
+ notes: submission.notes,
69
71
  };
70
72
 
71
73
  const completed = await completeVerifierPass({
@@ -74,31 +76,16 @@ export const registerRecordVerifierHandoffTool = (pi: ExtensionAPI): void => {
74
76
  handoff,
75
77
  });
76
78
 
77
- const workflowCheckpointCommit = await createWorkflowCheckpointCommit({
78
- repositoryRoot,
79
- expectedPaths: [
80
- paths.getWorkflowPath(specId),
81
- paths.getVerifierHandoffPath(specId),
82
- ],
83
- });
84
-
85
- if (!(await getRepositoryStatus(repositoryRoot)).clean) {
86
- throw new Error(
87
- 'Verifier handoff requires a clean checkout after its commit.',
88
- );
89
- }
90
-
91
79
  return {
92
80
  content: [
93
81
  {
94
82
  type: 'text',
95
- text: `Verifier handoff recorded as ${completed.state.phase}. The tool committed only the verifier handoff and workflow state. Do not run git commit.`,
83
+ text: `Verifier handoff recorded as ${completed.state.phase}. The handoff and workflow phase are saved. Stop now.`,
96
84
  },
97
85
  ],
98
86
  details: {
87
+ handoffPath: completed.handoffPath,
99
88
  phase: completed.state.phase,
100
- workflowCheckpointCommit,
101
- revision: completed.state.revision,
102
89
  specId: completed.handoff.specId,
103
90
  },
104
91
  };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Objective: Resolve the current checkout and explicit workflow identity.
2
+ * Objective: Resolve the current project and explicit workflow identity.
3
3
  * Used: By tools that write workflow artifacts.
4
4
  */
5
5
 
@@ -19,7 +19,7 @@ export const resolveWorkflowContext = async ({
19
19
  throw new Error(`Invalid spec ID: "${specId}".`);
20
20
  }
21
21
 
22
- const { paths, repositoryRoot } = await resolveToolRunContext(cwd);
22
+ const { paths, projectRoot } = await resolveToolRunContext(cwd);
23
23
 
24
- return { paths, specId, repositoryRoot };
24
+ return { paths, specId, projectRoot };
25
25
  };
@@ -14,7 +14,7 @@ export const MARK_SPEC_READY_TOOL = {
14
14
  NAME: 'maestro_mark_spec_ready',
15
15
  LABEL: 'Mark Spec Ready',
16
16
  DESCRIPTION:
17
- 'Approve the current spec.md after explicit owner approval and move the workflow to ready-for-builder. The owner must commit spec.md and workflow.json before running the builder.',
17
+ 'Approve the current spec.md after the owner replies GREEN FLAG and move the workflow to ready-for-builder. Only the owner reply GREEN FLAG authorizes approval. After this transition succeeds, call maestro_run_builder in the foreground.',
18
18
  } as const;
19
19
 
20
20
  const MarkSpecReadyToolParameters = Type.Object(
@@ -43,7 +43,7 @@ export const registerMarkSpecReadyTool = (pi: ExtensionAPI): void => {
43
43
  content: [
44
44
  {
45
45
  type: 'text',
46
- text: `Spec ${state.specId} is approved at workflow revision ${state.revision} and ready-for-builder. Commit spec.md and workflow.json before running the builder.`,
46
+ text: `Spec ${state.specId} is approved and ready-for-builder. Call maestro_run_builder now. No separate owner start request is needed.`,
47
47
  },
48
48
  ],
49
49
  details: state,
@@ -17,7 +17,7 @@ export const RESOLVE_ESCALATION_TOOL = {
17
17
  NAME: 'maestro_resolve_escalation',
18
18
  LABEL: 'Resolve Escalation',
19
19
  DESCRIPTION:
20
- 'Record the explicit owner decision for the current builder escalation when the approved contract remains valid. Commit the resolution and workflow transition on the current branch, then return ready-for-builder without running the builder. If the contract must change, edit spec.md and use maestro_mark_spec_ready instead.',
20
+ 'Record the explicit owner decision for the current builder escalation when the approved contract remains valid. Save the resolution and workflow transition, then return ready-for-builder without running the builder. If the contract must change, edit spec.md and use maestro_mark_spec_ready instead.',
21
21
  } as const;
22
22
 
23
23
  const ResolveEscalationToolParameters = Type.Object(
@@ -56,10 +56,8 @@ export const registerResolveEscalationTool = (pi: ExtensionAPI): void => {
56
56
  details: {
57
57
  specId: resolved.state.specId,
58
58
  escalationId: resolved.escalation.id,
59
- revision: resolved.state.revision,
60
59
  phase: resolved.state.phase,
61
- repositoryRoot: resolved.repositoryRoot,
62
- checkpointCommit: resolved.checkpointCommit,
60
+ projectRoot: resolved.projectRoot,
63
61
  },
64
62
  };
65
63
  },