@emiliosp/pi-maestro 0.5.1 → 0.6.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.
- package/README.md +38 -41
- package/agents/builder.md +16 -18
- package/agents/verifier.md +24 -21
- package/docs/configuration.md +16 -24
- package/docs/subagent-integration.md +18 -40
- package/docs/workflow.md +106 -169
- package/package.json +1 -2
- package/src/MaestroPaths.ts +111 -47
- package/src/artifacts/builder-handoff/assertBuilderHandoff.ts +2 -15
- package/src/artifacts/builder-handoff/readBuilderHandoff.ts +0 -3
- package/src/artifacts/builder-handoff/schema.ts +1 -1
- package/src/artifacts/builder-handoff/writeBuilderHandoff.ts +3 -5
- package/src/artifacts/escalation/createEscalation.ts +7 -7
- package/src/artifacts/escalation/getNextEscalationId.ts +0 -3
- package/src/artifacts/escalation/readEscalation.ts +1 -11
- package/src/artifacts/escalation/readEscalationHistory.ts +0 -3
- package/src/artifacts/escalation/resolveEscalation.ts +2 -12
- package/src/artifacts/escalation/schema.ts +0 -1
- package/src/artifacts/verifier-handoff/assertVerifierHandoff.ts +2 -9
- package/src/artifacts/verifier-handoff/readVerifierHandoff.ts +0 -3
- package/src/artifacts/verifier-handoff/schema.ts +20 -6
- package/src/artifacts/verifier-handoff/writeVerifierHandoff.ts +7 -7
- package/src/config/loadConfiguration.ts +18 -18
- package/src/maestro/checks/assertEnvironment.ts +13 -17
- package/src/maestro/instructions/getMaestroInstructions.ts +33 -33
- package/src/specs/create.ts +0 -2
- package/src/tools/child/open-escalation.ts +3 -4
- package/src/tools/child/record-builder-handoff.ts +4 -4
- package/src/tools/child/record-verifier-handoff.ts +13 -26
- package/src/tools/child/utils/resolveWorkflowContext.ts +3 -3
- package/src/tools/main/mark-spec-ready.ts +2 -2
- package/src/tools/main/resolve-escalation.ts +2 -4
- package/src/tools/main/resolve-findings.ts +17 -15
- package/src/tools/main/run-builder.ts +10 -38
- package/src/tools/main/run-verifier.ts +6 -33
- package/src/tools/utils/resolveToolRunContext.ts +8 -8
- package/src/utils/path-strictly-within.ts +4 -4
- package/src/utils/write-json.ts +24 -0
- package/src/workflow/builder/completeBuilderPass.ts +6 -15
- package/src/workflow/builder/prepareBuilderRun.ts +3 -34
- package/src/workflow/escalation/openBuilderEscalation.ts +2 -10
- package/src/workflow/escalation/resolveBuilderEscalation.ts +9 -14
- package/src/workflow/findings/resolveFindings.ts +25 -135
- package/src/workflow/spec/markSpecReady.ts +0 -1
- package/src/workflow/state/readWorkflowState.ts +2 -2
- package/src/workflow/state/schema.ts +0 -1
- package/src/workflow/state/writeWorkflowState.ts +7 -63
- package/src/workflow/transitions.ts +2 -2
- package/src/workflow/verifier/completeVerifierPass.ts +8 -14
- package/src/workflow/verifier/prepareVerifierRun.ts +4 -41
- package/src/artifacts/verifier-handoff/rejectVerifierFinding.ts +0 -54
- package/src/git/command.ts +0 -172
- package/src/git/commits/createCommit.ts +0 -76
- package/src/git/commits/createWorkflowCheckpointCommit.ts +0 -24
- package/src/git/commits/findCommitByMessage.ts +0 -39
- package/src/git/commits/getStagedPaths.ts +0 -23
- package/src/git/history/getParentCommit.ts +0 -25
- package/src/git/repository/assertRepositoryTrusted.ts +0 -16
- package/src/git/repository/findRepositoryRoot.ts +0 -19
- package/src/git/repository/getCurrentBranch.ts +0 -18
- package/src/git/repository/getHeadCommit.ts +0 -18
- package/src/git/repository/getRepositoryStatus.ts +0 -74
- package/src/git/utils/hasGitExitCode.ts +0 -19
- package/src/utils/write-atomically.ts +0 -41
- 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 {
|
|
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
|
|
20
|
+
const input = { handoff: draftHandoff, specId };
|
|
23
21
|
assertVerifierHandoff(input);
|
|
24
22
|
const { handoff } = input;
|
|
25
23
|
|
|
26
|
-
if (handoff.findings.some((finding) => finding.
|
|
27
|
-
throw new Error(
|
|
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
|
|
30
|
+
await writeJson({ path, data: handoff });
|
|
31
31
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Objective: Load and validate
|
|
3
|
-
* Used: When Maestro initializes for a
|
|
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
|
|
50
|
+
throw new Error(`${name} must be relative to the project root.`);
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
type ResolveSafeDirectoryInput = {
|
|
55
|
-
|
|
55
|
+
projectRoot: string;
|
|
56
56
|
directory: string;
|
|
57
57
|
name: string;
|
|
58
58
|
};
|
|
59
59
|
|
|
60
60
|
const resolveSafeDirectory = ({
|
|
61
|
-
|
|
61
|
+
projectRoot,
|
|
62
62
|
directory,
|
|
63
63
|
name,
|
|
64
64
|
}: ResolveSafeDirectoryInput): string => {
|
|
65
65
|
assertSafeDirectoryInput({ value: directory, name });
|
|
66
66
|
|
|
67
|
-
const requestedDirectory = resolve(
|
|
67
|
+
const requestedDirectory = resolve(projectRoot, directory);
|
|
68
68
|
|
|
69
|
-
if (requestedDirectory ===
|
|
70
|
-
throw new Error(`${name} must not be the
|
|
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:
|
|
76
|
-
|
|
75
|
+
parent: projectRoot,
|
|
76
|
+
path: requestedDirectory,
|
|
77
77
|
})
|
|
78
78
|
) {
|
|
79
|
-
throw new Error(`${name} must stay inside the
|
|
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
|
-
|
|
86
|
+
projectRoot: string;
|
|
87
87
|
config: MaestroConfig;
|
|
88
88
|
};
|
|
89
89
|
|
|
90
90
|
const resolveDirectories = ({
|
|
91
|
-
|
|
91
|
+
projectRoot,
|
|
92
92
|
config,
|
|
93
93
|
}: ResolveDirectoriesInput): MaestroConfig => {
|
|
94
94
|
const specDirectory = resolveSafeDirectory({
|
|
95
|
-
|
|
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
|
|
121
|
-
const targetPath = join(
|
|
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({
|
|
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({
|
|
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
|
|
17
|
-
context: ExtensionContext,
|
|
18
|
-
): Promise<string> => {
|
|
15
|
+
const getProjectRoot = async (context: ExtensionContext): Promise<string> => {
|
|
19
16
|
try {
|
|
20
|
-
const
|
|
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: "${
|
|
20
|
+
throw new Error(`Project is not trusted: "${projectRoot}".`);
|
|
25
21
|
}
|
|
26
22
|
|
|
27
|
-
return
|
|
23
|
+
return projectRoot;
|
|
28
24
|
} catch (error) {
|
|
29
|
-
throw new Error(`
|
|
25
|
+
throw new Error(`Project check failed: ${getErrorMessage(error)}`);
|
|
30
26
|
}
|
|
31
27
|
};
|
|
32
28
|
|
|
33
29
|
const getActivationConfiguration = async (
|
|
34
|
-
|
|
30
|
+
projectRoot: string,
|
|
35
31
|
): Promise<Awaited<ReturnType<typeof loadConfiguration>>> => {
|
|
36
32
|
try {
|
|
37
|
-
return await loadConfiguration(
|
|
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(
|
|
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:
|
|
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
|
|
82
|
+
const projectRoot = await getProjectRoot(context);
|
|
87
83
|
|
|
88
84
|
try {
|
|
89
|
-
await assertAgentsAvailable(
|
|
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(
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
Do not
|
|
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.
|
|
35
|
-
8.
|
|
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.
|
|
@@ -44,15 +48,6 @@ Every probe remains mandatory for builder and verifier.
|
|
|
44
48
|
The builder chooses test code, fixtures, mocks, and commands.
|
|
45
49
|
Do not copy agent procedures, repository rules, investigation logs, or workflow history into the spec.
|
|
46
50
|
|
|
47
|
-
During spec preparation and revisions, identify the decisions and unresolved facts that each open question depends on.
|
|
48
|
-
Ask a question only after its prerequisite decisions are settled and the relevant investigation is complete.
|
|
49
|
-
After each owner answer or investigation result, update the remaining questions and remove those that no longer apply.
|
|
50
|
-
If an earlier decision changes, review the decisions that depend on it.
|
|
51
|
-
|
|
52
|
-
Before requesting approval for an initial or revised spec, check that all decisions needed for the agreed scope are explicit.
|
|
53
|
-
Resolve open decisions with the owner before requesting approval. Do not leave necessary decisions as implicit assumptions.
|
|
54
|
-
Do not extend this check to routine implementation choices that belong to the builder.
|
|
55
|
-
|
|
56
51
|
During spec preparation and revisions, investigate each technical decision before presenting options or recommending an answer. Do not wait for the owner to request code analysis.
|
|
57
52
|
Trace the relevant code and data flow across affected components, including transformations that limit the available data.
|
|
58
53
|
Use repository evidence to explain each option's feasibility, required changes, scope, and effects on existing behavior.
|
|
@@ -64,6 +59,7 @@ In spec.md, keep only a brief reason, essential references, and unresolved limit
|
|
|
64
59
|
|
|
65
60
|
Edit the active spec.md and its prototypes/ directory only in drafting-spec or during owner-directed contract revisions in decision phases.
|
|
66
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.
|
|
67
63
|
Use any available tool for these permitted edits. Do not change other workflow artifacts.
|
|
68
64
|
|
|
69
65
|
Only in those same circumstances, run tests and checks to answer specification questions.
|
|
@@ -73,16 +69,16 @@ Remove temporary files created by checks. Preserve all pre-existing files and ch
|
|
|
73
69
|
|
|
74
70
|
Before an experiment, agree on its question and scope with the owner.
|
|
75
71
|
Use any available tool for temporary product changes and checks within that scope. Do not implement the feature.
|
|
76
|
-
Do not
|
|
72
|
+
Do not change workflow.json, handoffs, or other protected workflow artifacts.
|
|
77
73
|
Get explicit owner approval before installing packages or adding or updating dependencies.
|
|
78
74
|
Before requesting spec approval or continuing the workflow, restore only your experiment changes and remove your temporary files.
|
|
79
|
-
If cleanup fails, report the remaining changes and stop.
|
|
75
|
+
If cleanup fails, report the remaining changes and stop. Preserve all pre-existing files and content.
|
|
80
76
|
After cleanup, summarize only experiment conclusions and limits that affect the contract in spec.md. Experiments do not replace builder or verifier work.
|
|
81
77
|
|
|
82
78
|
### Run the workflow
|
|
83
79
|
|
|
84
|
-
In ready-for-builder, call maestro_run_builder with the active specId
|
|
85
|
-
The tool
|
|
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.
|
|
86
82
|
Read the returned artifact and follow its outcome:
|
|
87
83
|
|
|
88
84
|
1. done: The phase is ready-for-verifier. Call maestro_run_verifier with the active specId.
|
|
@@ -92,20 +88,24 @@ Read the returned artifact and follow its outcome:
|
|
|
92
88
|
A significant discovery needs an escalation when the owner must choose between meaningful alternatives, even without a technical blocker.
|
|
93
89
|
Do not invent an escalation for routine implementation details. Read significant discoveries without owner decisions from the builder handoff notes.
|
|
94
90
|
|
|
95
|
-
The verifier tool
|
|
96
|
-
|
|
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.
|
|
97
97
|
Read the returned verifier handoff. If there are findings, follow findings-decision. If there are none, follow candidate-ready.
|
|
98
98
|
|
|
99
99
|
### Explain findings and escalations
|
|
100
100
|
|
|
101
101
|
Before requesting a decision, read the active spec, the finding or escalation artifact, and the relevant code.
|
|
102
102
|
Trace the affected behavior across components. Do not just repeat the builder's or verifier's summary.
|
|
103
|
-
For findings, inspect the
|
|
103
|
+
For findings, inspect the live project files checked by the verifier.
|
|
104
104
|
This inspection does not authorize product repairs, new verification runs, or experiments. Follow the existing permissions above.
|
|
105
105
|
|
|
106
106
|
For each finding or escalation, give the owner enough detail to decide without opening other files:
|
|
107
107
|
|
|
108
|
-
1. Identify
|
|
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.
|
|
109
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.
|
|
110
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.
|
|
111
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.
|
|
@@ -119,37 +119,37 @@ Keep excerpts and explanations focused, but do not replace the details with seve
|
|
|
119
119
|
|
|
120
120
|
In escalation-decision, wait for the explicit owner answer. Do not choose an option for the owner.
|
|
121
121
|
If the contract stays unchanged, call maestro_resolve_escalation with the current escalation ID and the owner's decision and reason.
|
|
122
|
-
The tool
|
|
122
|
+
The tool saves the resolution and returns ready-for-builder. Call maestro_run_builder separately.
|
|
123
123
|
If the contract must change, use the spec revision procedure below instead of resolving the escalation against the old contract.
|
|
124
124
|
|
|
125
125
|
In findings-decision, present every current finding. Every finding requires an owner decision, regardless of severity.
|
|
126
126
|
If the contract stays unchanged, collect reject or fix-code for every finding. Each reject requires the owner's reason.
|
|
127
|
-
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.
|
|
128
128
|
If all findings are rejected, the tool returns candidate-ready. Any fix-code returns ready-for-builder, including mixed decisions.
|
|
129
129
|
For ready-for-builder, call maestro_run_builder separately. Do not fix the code yourself.
|
|
130
130
|
If any finding requires a contract change, use the spec revision procedure instead.
|
|
131
131
|
|
|
132
132
|
For a spec revision, remain in escalation-decision or findings-decision while revising the same specId with the owner.
|
|
133
133
|
Do not create a new spec. Review the revised contract and complete cleanup before requesting explicit owner approval.
|
|
134
|
-
|
|
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.
|
|
135
136
|
Previous escalations and findings become historical context. Do not resolve them as current decisions after the revision.
|
|
136
137
|
Keep their artifacts. Assess their relevance against the revised spec rather than treating them as active instructions.
|
|
137
138
|
|
|
138
139
|
### Errors and completion
|
|
139
140
|
|
|
140
|
-
If a tool fails, inspect its error, workflow.json,
|
|
141
|
+
If a tool fails, inspect its error, workflow.json, and artifacts before taking another action.
|
|
141
142
|
If the tool wrote no artifacts or transition, correct recoverable errors within your permissions before retrying.
|
|
142
143
|
If it partially updated artifacts or workflow state, report that state and stop. Do not retry a partially completed transition.
|
|
143
144
|
Do not repeat an unchanged failing call, edit protocol files, or fabricate evidence to bypass an error.
|
|
144
|
-
If a run ends without a valid
|
|
145
|
+
If a run ends without a valid saved result, report the error and stop. Do not repair product files or force a transition.
|
|
145
146
|
Disabling Maestro, restarting Pi, or using /resume clears live state. Do not reconstruct or resume an incomplete workflow.
|
|
146
147
|
The owner handles failed or interrupted workflows manually.
|
|
147
148
|
|
|
148
|
-
At candidate-ready, the workflow is complete. No final tool call
|
|
149
|
-
You own the final summary.
|
|
150
|
-
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.
|
|
151
151
|
Do not describe rejected findings as passed verification.
|
|
152
152
|
Do not change files, run verification again, or modify the concluded workflow to prepare this summary.
|
|
153
|
-
The owner controls later review
|
|
153
|
+
The owner controls later review and changes. Later changes are outside this verification.`;
|
|
154
154
|
|
|
155
155
|
export const getMaestroInstructions = (): string => MAESTRO_INSTRUCTIONS;
|
package/src/specs/create.ts
CHANGED
|
@@ -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
|
|
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,
|
|
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.
|
|
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
|
|
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,
|
|
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}.
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
68
|
-
|
|
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
|
|
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
|
|
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,
|
|
22
|
+
const { paths, projectRoot } = await resolveToolRunContext(cwd);
|
|
23
23
|
|
|
24
|
-
return { paths, specId,
|
|
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
|
|
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
|
|
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.
|
|
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
|
-
|
|
62
|
-
checkpointCommit: resolved.checkpointCommit,
|
|
60
|
+
projectRoot: resolved.projectRoot,
|
|
63
61
|
},
|
|
64
62
|
};
|
|
65
63
|
},
|