pipeline-sdk 0.1.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/LICENSE +21 -0
- package/README.md +146 -0
- package/package.json +63 -0
- package/schemas/pipeline.schema.json +158 -0
- package/src/adapters/claude-code.ts +112 -0
- package/src/adapters/detector.ts +26 -0
- package/src/adapters/generic.ts +30 -0
- package/src/adapters/interface.ts +7 -0
- package/src/cli/advance.ts +27 -0
- package/src/cli/cleanup.ts +55 -0
- package/src/cli/helpers.ts +52 -0
- package/src/cli/index.ts +92 -0
- package/src/cli/init.ts +248 -0
- package/src/cli/resume.ts +45 -0
- package/src/cli/signal.ts +21 -0
- package/src/cli/start.ts +33 -0
- package/src/cli/status.ts +24 -0
- package/src/cli/template.ts +28 -0
- package/src/cli/validate.ts +21 -0
- package/src/cli/verify.ts +33 -0
- package/src/cli/visualize.ts +36 -0
- package/src/core/cleanup.ts +75 -0
- package/src/core/evidence.ts +144 -0
- package/src/core/gate-runner.ts +109 -0
- package/src/core/loader.ts +125 -0
- package/src/core/state-machine.ts +119 -0
- package/src/daemon/ipc.ts +56 -0
- package/src/daemon/server.ts +144 -0
- package/src/daemon/state-file.ts +65 -0
- package/src/gates/async.ts +60 -0
- package/src/gates/builtin.ts +40 -0
- package/src/gates/custom.ts +71 -0
- package/src/index.ts +20 -0
- package/src/mcp/prompts.ts +40 -0
- package/src/mcp/resources.ts +71 -0
- package/src/mcp/server.ts +211 -0
- package/src/mcp/tools.ts +52 -0
- package/src/templates/infra-gitops.yaml +37 -0
- package/src/templates/sdlc-full.yaml +69 -0
- package/src/templates/static-site.yaml +45 -0
- package/src/templates/zship.yaml +224 -0
- package/src/types.ts +210 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import {
|
|
4
|
+
CallToolRequestSchema,
|
|
5
|
+
GetPromptRequestSchema,
|
|
6
|
+
ListPromptsRequestSchema,
|
|
7
|
+
ListResourcesRequestSchema,
|
|
8
|
+
ListToolsRequestSchema,
|
|
9
|
+
ReadResourceRequestSchema,
|
|
10
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
11
|
+
import type { EvidenceStore } from "../core/evidence";
|
|
12
|
+
import type { StateMachine } from "../core/state-machine";
|
|
13
|
+
import type { PipelineDefinition } from "../types";
|
|
14
|
+
import { createStagePrompt } from "./prompts";
|
|
15
|
+
import { createPipelineResources } from "./resources";
|
|
16
|
+
import { createPipelineTools } from "./tools";
|
|
17
|
+
|
|
18
|
+
export function createMcpServer(
|
|
19
|
+
machine: StateMachine,
|
|
20
|
+
pipeline: PipelineDefinition,
|
|
21
|
+
_evidenceStore: EvidenceStore,
|
|
22
|
+
) {
|
|
23
|
+
const server = new Server(
|
|
24
|
+
{ name: "pipeline-sdk", version: "1.0.0" },
|
|
25
|
+
{
|
|
26
|
+
capabilities: {
|
|
27
|
+
tools: {},
|
|
28
|
+
resources: {},
|
|
29
|
+
prompts: {},
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const tools = createPipelineTools(machine);
|
|
35
|
+
const resources = createPipelineResources(machine, pipeline);
|
|
36
|
+
|
|
37
|
+
// ─── Tools ────────────────────────────────────────────────
|
|
38
|
+
|
|
39
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
40
|
+
tools: [
|
|
41
|
+
{
|
|
42
|
+
name: "pipeline_check",
|
|
43
|
+
description: "Check whether a tool is allowed in the current pipeline stage.",
|
|
44
|
+
inputSchema: {
|
|
45
|
+
type: "object",
|
|
46
|
+
properties: {
|
|
47
|
+
tool: { type: "string", description: "Tool name to check" },
|
|
48
|
+
command: { type: "string", description: "Optional command string" },
|
|
49
|
+
},
|
|
50
|
+
required: ["tool"],
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: "pipeline_advance",
|
|
55
|
+
description: "Advance the pipeline by firing a transition event.",
|
|
56
|
+
inputSchema: {
|
|
57
|
+
type: "object",
|
|
58
|
+
properties: {
|
|
59
|
+
event: { type: "string", description: "Transition event name, e.g. STAGE_COMPLETE" },
|
|
60
|
+
},
|
|
61
|
+
required: ["event"],
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: "pipeline_signal",
|
|
66
|
+
description: "Deliver a signal to clear a named gate.",
|
|
67
|
+
inputSchema: {
|
|
68
|
+
type: "object",
|
|
69
|
+
properties: {
|
|
70
|
+
signal: { type: "string", description: "Signal name" },
|
|
71
|
+
gate_id: { type: "string", description: "Gate ID to clear" },
|
|
72
|
+
source: { type: "string", description: "Optional signal source" },
|
|
73
|
+
},
|
|
74
|
+
required: ["signal", "gate_id"],
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: "pipeline_status",
|
|
79
|
+
description: "Return the current pipeline stage and gate status.",
|
|
80
|
+
inputSchema: {
|
|
81
|
+
type: "object",
|
|
82
|
+
properties: {},
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
}));
|
|
87
|
+
|
|
88
|
+
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
89
|
+
const { name, arguments: args } = req.params;
|
|
90
|
+
const input = (args ?? {}) as Record<string, string>;
|
|
91
|
+
|
|
92
|
+
let result: unknown;
|
|
93
|
+
|
|
94
|
+
switch (name) {
|
|
95
|
+
case "pipeline_check":
|
|
96
|
+
result = tools.check({ tool: input.tool, command: input.command });
|
|
97
|
+
break;
|
|
98
|
+
case "pipeline_advance":
|
|
99
|
+
result = tools.advance({ event: input.event });
|
|
100
|
+
break;
|
|
101
|
+
case "pipeline_signal":
|
|
102
|
+
result = tools.signal({
|
|
103
|
+
signal: input.signal,
|
|
104
|
+
gate_id: input.gate_id,
|
|
105
|
+
source: input.source,
|
|
106
|
+
});
|
|
107
|
+
break;
|
|
108
|
+
case "pipeline_status":
|
|
109
|
+
result = tools.status();
|
|
110
|
+
break;
|
|
111
|
+
default:
|
|
112
|
+
return {
|
|
113
|
+
content: [{ type: "text" as const, text: `Unknown tool: ${name}` }],
|
|
114
|
+
isError: true,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }],
|
|
120
|
+
};
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// ─── Resources ────────────────────────────────────────────
|
|
124
|
+
|
|
125
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
|
|
126
|
+
resources: [
|
|
127
|
+
{
|
|
128
|
+
uri: "pipeline://state/current",
|
|
129
|
+
name: "Current Pipeline State",
|
|
130
|
+
mimeType: "application/json",
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
uri: "pipeline://instructions/current",
|
|
134
|
+
name: "Current Stage Instructions",
|
|
135
|
+
mimeType: "application/json",
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
uri: "pipeline://gates/available",
|
|
139
|
+
name: "Available Gates",
|
|
140
|
+
mimeType: "application/json",
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
}));
|
|
144
|
+
|
|
145
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (req) => {
|
|
146
|
+
const { uri } = req.params;
|
|
147
|
+
const handler = resources[uri as keyof typeof resources];
|
|
148
|
+
|
|
149
|
+
if (!handler) {
|
|
150
|
+
throw new Error(`Unknown resource: ${uri}`);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const content = handler();
|
|
154
|
+
return {
|
|
155
|
+
contents: [
|
|
156
|
+
{
|
|
157
|
+
uri: content.uri,
|
|
158
|
+
mimeType: content.mimeType,
|
|
159
|
+
text: content.text,
|
|
160
|
+
},
|
|
161
|
+
],
|
|
162
|
+
};
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// ─── Prompts ──────────────────────────────────────────────
|
|
166
|
+
|
|
167
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => ({
|
|
168
|
+
prompts: [
|
|
169
|
+
{
|
|
170
|
+
name: "pipeline_stage_prompt",
|
|
171
|
+
description: "System prompt for the current pipeline stage.",
|
|
172
|
+
arguments: [
|
|
173
|
+
{
|
|
174
|
+
name: "stage",
|
|
175
|
+
description: "Stage name (defaults to current stage)",
|
|
176
|
+
required: false,
|
|
177
|
+
},
|
|
178
|
+
],
|
|
179
|
+
},
|
|
180
|
+
],
|
|
181
|
+
}));
|
|
182
|
+
|
|
183
|
+
server.setRequestHandler(GetPromptRequestSchema, async (req) => {
|
|
184
|
+
const { name, arguments: args } = req.params;
|
|
185
|
+
|
|
186
|
+
if (name !== "pipeline_stage_prompt") {
|
|
187
|
+
throw new Error(`Unknown prompt: ${name}`);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const stageName = (args as Record<string, string> | undefined)?.stage ?? machine.currentStage;
|
|
191
|
+
const text = createStagePrompt(pipeline, stageName);
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
description: `Stage prompt for "${stageName}"`,
|
|
195
|
+
messages: [
|
|
196
|
+
{
|
|
197
|
+
role: "user" as const,
|
|
198
|
+
content: { type: "text" as const, text },
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
};
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
return {
|
|
205
|
+
server,
|
|
206
|
+
async startStdio(): Promise<void> {
|
|
207
|
+
const transport = new StdioServerTransport();
|
|
208
|
+
await server.connect(transport);
|
|
209
|
+
},
|
|
210
|
+
};
|
|
211
|
+
}
|
package/src/mcp/tools.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { StateMachine } from "../core/state-machine";
|
|
2
|
+
import type { IpcResponse } from "../types";
|
|
3
|
+
|
|
4
|
+
export function createPipelineTools(machine: StateMachine) {
|
|
5
|
+
return {
|
|
6
|
+
check(input: { tool: string; command?: string }): IpcResponse {
|
|
7
|
+
const allowedTools = machine.allowedTools;
|
|
8
|
+
if (allowedTools.length === 0) {
|
|
9
|
+
return {
|
|
10
|
+
allowed: true,
|
|
11
|
+
current_stage: machine.currentStage,
|
|
12
|
+
allowed_tools: [],
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
const allowed = allowedTools.includes(input.tool);
|
|
16
|
+
return {
|
|
17
|
+
allowed,
|
|
18
|
+
current_stage: machine.currentStage,
|
|
19
|
+
allowed_tools: allowedTools,
|
|
20
|
+
reason: allowed
|
|
21
|
+
? undefined
|
|
22
|
+
: `Tool "${input.tool}" not allowed in stage "${machine.currentStage}"`,
|
|
23
|
+
};
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
status(): IpcResponse {
|
|
27
|
+
const stage = machine.currentStageDefinition;
|
|
28
|
+
const state = machine.exportState();
|
|
29
|
+
return {
|
|
30
|
+
stage: machine.currentStage,
|
|
31
|
+
gates_remaining: stage?.gates?.exit ?? [],
|
|
32
|
+
elapsed: `${Math.round((Date.now() - new Date(state.started_at).getTime()) / 1000)}s`,
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
advance(input: { event: string }): IpcResponse {
|
|
37
|
+
const result = machine.transition(input.event);
|
|
38
|
+
return {
|
|
39
|
+
transitioned: result.success,
|
|
40
|
+
new_stage: result.newStage,
|
|
41
|
+
error: result.error,
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
signal(input: { signal: string; gate_id: string; source?: string }): IpcResponse {
|
|
46
|
+
return {
|
|
47
|
+
received: true,
|
|
48
|
+
gate_cleared: input.gate_id,
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
pipeline:
|
|
2
|
+
id: infra-gitops
|
|
3
|
+
version: 1
|
|
4
|
+
description: "Infrastructure changes with mandatory approval"
|
|
5
|
+
initial: validate
|
|
6
|
+
stages:
|
|
7
|
+
validate:
|
|
8
|
+
description: "Validate manifests and configs"
|
|
9
|
+
on:
|
|
10
|
+
STAGE_COMPLETE: { target: preview }
|
|
11
|
+
preview:
|
|
12
|
+
description: "Deploy to staging environment"
|
|
13
|
+
on:
|
|
14
|
+
STAGE_COMPLETE: { target: approve }
|
|
15
|
+
HEALTH_FAIL: { target: validate }
|
|
16
|
+
approve:
|
|
17
|
+
description: "Human approval required"
|
|
18
|
+
gates:
|
|
19
|
+
entry: [human-approval]
|
|
20
|
+
on:
|
|
21
|
+
APPROVED: { target: production }
|
|
22
|
+
REJECTED: { target: validate }
|
|
23
|
+
production:
|
|
24
|
+
description: "Deploy to production"
|
|
25
|
+
on:
|
|
26
|
+
STAGE_COMPLETE: { target: complete }
|
|
27
|
+
HEALTH_FAIL: { target: rollback }
|
|
28
|
+
rollback:
|
|
29
|
+
on:
|
|
30
|
+
ROLLBACK_COMPLETE: { target: complete }
|
|
31
|
+
complete:
|
|
32
|
+
type: terminal
|
|
33
|
+
|
|
34
|
+
gates:
|
|
35
|
+
human-approval:
|
|
36
|
+
type: async
|
|
37
|
+
signal: approval
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
pipeline:
|
|
2
|
+
id: sdlc-full
|
|
3
|
+
version: 1
|
|
4
|
+
description: "Full SDLC enforcement for production monorepos"
|
|
5
|
+
initial: planning
|
|
6
|
+
stages:
|
|
7
|
+
planning:
|
|
8
|
+
description: "Analyze requirements and create implementation plan"
|
|
9
|
+
agent:
|
|
10
|
+
instructions: "Create a detailed implementation plan with TDD"
|
|
11
|
+
tools: [Read, Grep, Glob, Write, WebSearch]
|
|
12
|
+
gates:
|
|
13
|
+
exit: [plan-document-exists]
|
|
14
|
+
on:
|
|
15
|
+
STAGE_COMPLETE: { target: implement }
|
|
16
|
+
implement:
|
|
17
|
+
description: "Write code following TDD red-green-refactor"
|
|
18
|
+
agent:
|
|
19
|
+
instructions: "Implement using TDD. Write failing test first."
|
|
20
|
+
tools: [Read, Write, Edit, Bash, Grep, Glob]
|
|
21
|
+
gates:
|
|
22
|
+
exit: [lint-pass, typecheck-pass, tests-pass]
|
|
23
|
+
on:
|
|
24
|
+
STAGE_COMPLETE: { target: review }
|
|
25
|
+
TESTS_FAIL: { target: fix }
|
|
26
|
+
fix:
|
|
27
|
+
description: "Fix failing tests or lint issues"
|
|
28
|
+
max_retries: 3
|
|
29
|
+
agent:
|
|
30
|
+
instructions: "Fix the failures. Do not change test expectations."
|
|
31
|
+
tools: [Read, Edit, Bash, Grep]
|
|
32
|
+
on:
|
|
33
|
+
FIX_COMPLETE: { target: implement }
|
|
34
|
+
MAX_RETRIES: { target: escalate }
|
|
35
|
+
review:
|
|
36
|
+
description: "Code review gate"
|
|
37
|
+
on:
|
|
38
|
+
APPROVED: { target: deploy }
|
|
39
|
+
CHANGES_REQUESTED: { target: implement }
|
|
40
|
+
deploy:
|
|
41
|
+
description: "Deploy to production"
|
|
42
|
+
gates:
|
|
43
|
+
exit: [build-succeeds]
|
|
44
|
+
on:
|
|
45
|
+
STAGE_COMPLETE: { target: complete }
|
|
46
|
+
escalate:
|
|
47
|
+
type: terminal
|
|
48
|
+
description: "Human intervention required"
|
|
49
|
+
complete:
|
|
50
|
+
type: terminal
|
|
51
|
+
description: "Pipeline succeeded"
|
|
52
|
+
|
|
53
|
+
gates:
|
|
54
|
+
plan-document-exists:
|
|
55
|
+
type: custom
|
|
56
|
+
script: "test -f docs/plan.md"
|
|
57
|
+
expect: { status: pass }
|
|
58
|
+
lint-pass:
|
|
59
|
+
type: builtin
|
|
60
|
+
command: "bun run lint"
|
|
61
|
+
typecheck-pass:
|
|
62
|
+
type: builtin
|
|
63
|
+
command: "bun run typecheck"
|
|
64
|
+
tests-pass:
|
|
65
|
+
type: builtin
|
|
66
|
+
command: "bun test"
|
|
67
|
+
build-succeeds:
|
|
68
|
+
type: builtin
|
|
69
|
+
command: "bun run build"
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
pipeline:
|
|
2
|
+
id: static-site
|
|
3
|
+
version: 1
|
|
4
|
+
description: "Pipeline for static sites and portfolios"
|
|
5
|
+
initial: quality
|
|
6
|
+
stages:
|
|
7
|
+
quality:
|
|
8
|
+
gates:
|
|
9
|
+
exit: [lint-pass, typecheck-pass, build-succeeds]
|
|
10
|
+
on:
|
|
11
|
+
STAGE_COMPLETE: { target: visual }
|
|
12
|
+
visual:
|
|
13
|
+
description: "Visual and accessibility checks"
|
|
14
|
+
on:
|
|
15
|
+
STAGE_COMPLETE: { target: deploy }
|
|
16
|
+
ANY_FAILED: { target: fix }
|
|
17
|
+
fix:
|
|
18
|
+
max_retries: 2
|
|
19
|
+
on:
|
|
20
|
+
FIX_COMPLETE: { target: quality }
|
|
21
|
+
deploy:
|
|
22
|
+
type: terminal
|
|
23
|
+
|
|
24
|
+
gates:
|
|
25
|
+
lint-pass:
|
|
26
|
+
type: builtin
|
|
27
|
+
command: "bun run lint"
|
|
28
|
+
typecheck-pass:
|
|
29
|
+
type: builtin
|
|
30
|
+
command: "bun run typecheck"
|
|
31
|
+
build-succeeds:
|
|
32
|
+
type: builtin
|
|
33
|
+
command: "bun run build"
|
|
34
|
+
a11y-audit:
|
|
35
|
+
type: custom
|
|
36
|
+
script: "bun run a11y"
|
|
37
|
+
expect: { status: pass }
|
|
38
|
+
lighthouse-pass:
|
|
39
|
+
type: custom
|
|
40
|
+
script: "bun run lighthouse"
|
|
41
|
+
expect: { status: pass }
|
|
42
|
+
responsive-check:
|
|
43
|
+
type: custom
|
|
44
|
+
script: "bun run responsive"
|
|
45
|
+
expect: { status: pass }
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# zship.yaml — Dual-Model Development Pipeline
|
|
2
|
+
# 6-stage pipeline with dual-phase gates (Claude + Codex)
|
|
3
|
+
# Converts the zship process into Pipeline SDK format
|
|
4
|
+
|
|
5
|
+
pipeline:
|
|
6
|
+
id: zship
|
|
7
|
+
version: 1
|
|
8
|
+
description: "Dual-model autonomous development pipeline (BRAINSTORM → PLAN → IMPLEMENT → TEST → REVIEW → SHIP)"
|
|
9
|
+
initial: brainstorm
|
|
10
|
+
|
|
11
|
+
stages:
|
|
12
|
+
brainstorm:
|
|
13
|
+
description: "Interrogate requirements via grill-me interrogation"
|
|
14
|
+
agent:
|
|
15
|
+
instructions: "Interrogate requirements relentlessly. Produce approved spec at docs/zship/spec.md."
|
|
16
|
+
tools: [Read, Grep, Glob, Write, WebSearch]
|
|
17
|
+
on:
|
|
18
|
+
SPEC_APPROVED: { target: plan }
|
|
19
|
+
ABORT: { target: aborted }
|
|
20
|
+
|
|
21
|
+
plan:
|
|
22
|
+
description: "Create TDD implementation plan with task breakdown"
|
|
23
|
+
agent:
|
|
24
|
+
instructions: "Produce TDD plan from spec. Each task: RED test → GREEN implement → REFACTOR."
|
|
25
|
+
tools: [Read, Grep, Glob, Write]
|
|
26
|
+
gates:
|
|
27
|
+
exit: [plan-document-exists]
|
|
28
|
+
on:
|
|
29
|
+
STAGE_COMPLETE: { target: implement }
|
|
30
|
+
SPEC_CHANGES: { target: brainstorm }
|
|
31
|
+
|
|
32
|
+
implement:
|
|
33
|
+
description: "Ralph Loop: TDD cycles per task with Gate 1 (test quality) and Gate 2 (impl review)"
|
|
34
|
+
agent:
|
|
35
|
+
instructions: "Execute TDD plan. RED → GREEN → Gate 1 review → REFACTOR. After all tasks: Gate 2 full review."
|
|
36
|
+
tools: [Read, Write, Edit, Bash, Grep, Glob]
|
|
37
|
+
gates:
|
|
38
|
+
exit: [lint-pass, typecheck-pass, tests-pass, tdd-quality-review, impl-review]
|
|
39
|
+
max_retries: 6
|
|
40
|
+
on:
|
|
41
|
+
STAGE_COMPLETE: { target: test }
|
|
42
|
+
TESTS_FAIL: { target: fix-implement }
|
|
43
|
+
GATE_FAIL: { target: fix-implement }
|
|
44
|
+
|
|
45
|
+
fix-implement:
|
|
46
|
+
description: "Fix test quality or implementation issues from Gates 1-2"
|
|
47
|
+
max_retries: 3
|
|
48
|
+
agent:
|
|
49
|
+
instructions: "Fix gate findings. Do not change test expectations unless finding specifically requires it."
|
|
50
|
+
tools: [Read, Edit, Bash, Grep]
|
|
51
|
+
on:
|
|
52
|
+
FIX_COMPLETE: { target: implement }
|
|
53
|
+
MAX_RETRIES: { target: escalate-implement }
|
|
54
|
+
|
|
55
|
+
test:
|
|
56
|
+
description: "E2E testing + smoke testing with Gate 3 (coverage) and Gate 4 (smoke gaps)"
|
|
57
|
+
agent:
|
|
58
|
+
instructions: "Create E2E tests covering spec requirements. Run smoke tests. Gates review coverage and gaps."
|
|
59
|
+
tools: [Read, Write, Edit, Bash, Grep, Glob]
|
|
60
|
+
gates:
|
|
61
|
+
exit: [e2e-tests-pass, coverage-review, smoke-gap-review]
|
|
62
|
+
max_retries: 6
|
|
63
|
+
on:
|
|
64
|
+
STAGE_COMPLETE: { target: review }
|
|
65
|
+
GATE_FAIL: { target: fix-test }
|
|
66
|
+
IMPLEMENT_CHANGES: { target: implement }
|
|
67
|
+
|
|
68
|
+
fix-test:
|
|
69
|
+
description: "Fix test coverage gaps or smoke testing issues from Gates 3-4"
|
|
70
|
+
max_retries: 3
|
|
71
|
+
agent:
|
|
72
|
+
instructions: "Fix coverage gaps and smoke test findings."
|
|
73
|
+
tools: [Read, Edit, Bash, Grep]
|
|
74
|
+
on:
|
|
75
|
+
FIX_COMPLETE: { target: test }
|
|
76
|
+
MAX_RETRIES: { target: escalate-test }
|
|
77
|
+
|
|
78
|
+
review:
|
|
79
|
+
description: "Gate 5: Adversarial code review (dual-phase Claude + Codex)"
|
|
80
|
+
agent:
|
|
81
|
+
instructions: "Process adversarial findings. Fix security, concurrency, performance issues."
|
|
82
|
+
tools: [Read, Edit, Bash, Grep]
|
|
83
|
+
gates:
|
|
84
|
+
exit: [adversarial-review]
|
|
85
|
+
max_retries: 6
|
|
86
|
+
on:
|
|
87
|
+
STAGE_COMPLETE: { target: ship }
|
|
88
|
+
GATE_FAIL: { target: fix-review }
|
|
89
|
+
TEST_CHANGES: { target: test }
|
|
90
|
+
|
|
91
|
+
fix-review:
|
|
92
|
+
description: "Fix adversarial review findings from Gate 5"
|
|
93
|
+
max_retries: 3
|
|
94
|
+
agent:
|
|
95
|
+
instructions: "Fix adversarial findings. Verify fixes via tests. Do not introduce regressions."
|
|
96
|
+
tools: [Read, Edit, Bash, Grep]
|
|
97
|
+
on:
|
|
98
|
+
FIX_COMPLETE: { target: review }
|
|
99
|
+
MAX_RETRIES: { target: escalate-review }
|
|
100
|
+
|
|
101
|
+
ship:
|
|
102
|
+
description: "Gate 6: Final quality gate then PR creation"
|
|
103
|
+
agent:
|
|
104
|
+
instructions: "Final quality check. If passes, create PR with full context and evidence links."
|
|
105
|
+
tools: [Read, Edit, Bash, Grep]
|
|
106
|
+
gates:
|
|
107
|
+
exit: [final-quality-gate]
|
|
108
|
+
on:
|
|
109
|
+
STAGE_COMPLETE: { target: complete }
|
|
110
|
+
GATE_FAIL: { target: fix-ship }
|
|
111
|
+
REVIEW_CHANGES: { target: review }
|
|
112
|
+
|
|
113
|
+
fix-ship:
|
|
114
|
+
description: "Fix regressions or unresolved issues from Gate 6"
|
|
115
|
+
max_retries: 3
|
|
116
|
+
agent:
|
|
117
|
+
instructions: "Fix final gate findings. This is the last chance before shipping."
|
|
118
|
+
tools: [Read, Edit, Bash, Grep]
|
|
119
|
+
on:
|
|
120
|
+
FIX_COMPLETE: { target: ship }
|
|
121
|
+
MAX_RETRIES: { target: escalate-ship }
|
|
122
|
+
|
|
123
|
+
complete:
|
|
124
|
+
type: terminal
|
|
125
|
+
description: "Pipeline succeeded — PR created and ready for human merge"
|
|
126
|
+
|
|
127
|
+
aborted:
|
|
128
|
+
type: terminal
|
|
129
|
+
description: "Pipeline aborted by user"
|
|
130
|
+
|
|
131
|
+
escalate-implement:
|
|
132
|
+
type: terminal
|
|
133
|
+
description: "Implementation gates failed after max retries"
|
|
134
|
+
on_enter:
|
|
135
|
+
- script: "./tools/pipeline/notify-escalation.sh"
|
|
136
|
+
- script: "./tools/pipeline/create-escalation-issue.sh"
|
|
137
|
+
|
|
138
|
+
escalate-test:
|
|
139
|
+
type: terminal
|
|
140
|
+
description: "Testing gates failed after max retries"
|
|
141
|
+
on_enter:
|
|
142
|
+
- script: "./tools/pipeline/notify-escalation.sh"
|
|
143
|
+
- script: "./tools/pipeline/create-escalation-issue.sh"
|
|
144
|
+
|
|
145
|
+
escalate-review:
|
|
146
|
+
type: terminal
|
|
147
|
+
description: "Review gate failed after max retries"
|
|
148
|
+
on_enter:
|
|
149
|
+
- script: "./tools/pipeline/notify-escalation.sh"
|
|
150
|
+
- script: "./tools/pipeline/create-escalation-issue.sh"
|
|
151
|
+
|
|
152
|
+
escalate-ship:
|
|
153
|
+
type: terminal
|
|
154
|
+
description: "Final gate failed after max retries"
|
|
155
|
+
on_enter:
|
|
156
|
+
- script: "./tools/pipeline/notify-escalation.sh"
|
|
157
|
+
- script: "./tools/pipeline/create-escalation-issue.sh"
|
|
158
|
+
|
|
159
|
+
gates:
|
|
160
|
+
plan-document-exists:
|
|
161
|
+
type: custom
|
|
162
|
+
script: "test -f docs/zship/spec.md"
|
|
163
|
+
expect: { status: pass }
|
|
164
|
+
lint-pass:
|
|
165
|
+
type: builtin
|
|
166
|
+
command: "bun run lint"
|
|
167
|
+
typecheck-pass:
|
|
168
|
+
type: builtin
|
|
169
|
+
command: "bun run typecheck"
|
|
170
|
+
tests-pass:
|
|
171
|
+
type: builtin
|
|
172
|
+
command: "bun test"
|
|
173
|
+
e2e-tests-pass:
|
|
174
|
+
type: builtin
|
|
175
|
+
command: "bun run test:e2e"
|
|
176
|
+
|
|
177
|
+
tdd-quality-review:
|
|
178
|
+
type: custom
|
|
179
|
+
script: "./tools/gates/tdd-quality-review.sh"
|
|
180
|
+
protocol: json-stdout
|
|
181
|
+
inputs:
|
|
182
|
+
mode: dual-phase
|
|
183
|
+
phase_a: claude
|
|
184
|
+
phase_b: codex
|
|
185
|
+
|
|
186
|
+
impl-review:
|
|
187
|
+
type: custom
|
|
188
|
+
script: "./tools/gates/impl-review.sh"
|
|
189
|
+
protocol: json-stdout
|
|
190
|
+
inputs:
|
|
191
|
+
mode: dual-phase
|
|
192
|
+
focus: architecture
|
|
193
|
+
|
|
194
|
+
coverage-review:
|
|
195
|
+
type: custom
|
|
196
|
+
script: "./tools/gates/coverage-review.sh"
|
|
197
|
+
protocol: json-stdout
|
|
198
|
+
inputs:
|
|
199
|
+
mode: dual-phase
|
|
200
|
+
focus: test_coverage
|
|
201
|
+
|
|
202
|
+
smoke-gap-review:
|
|
203
|
+
type: custom
|
|
204
|
+
script: "./tools/gates/smoke-gap-review.sh"
|
|
205
|
+
protocol: json-stdout
|
|
206
|
+
inputs:
|
|
207
|
+
mode: dual-phase
|
|
208
|
+
focus: smoke_analysis
|
|
209
|
+
|
|
210
|
+
adversarial-review:
|
|
211
|
+
type: custom
|
|
212
|
+
script: "./tools/gates/adversarial-review.sh"
|
|
213
|
+
protocol: json-stdout
|
|
214
|
+
inputs:
|
|
215
|
+
mode: dual-phase
|
|
216
|
+
focus: adversarial
|
|
217
|
+
|
|
218
|
+
final-quality-gate:
|
|
219
|
+
type: custom
|
|
220
|
+
script: "./tools/gates/final-quality-gate.sh"
|
|
221
|
+
protocol: json-stdout
|
|
222
|
+
inputs:
|
|
223
|
+
mode: dual-phase
|
|
224
|
+
focus: final_quality
|