@lchase/kiln 0.0.0-stage → 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.
@@ -0,0 +1,239 @@
1
+ # One Kiln job, run by yak (@lchase/yak).
2
+ #
3
+ # Faithful to Lawrence Chase's factory plugin v0.7.0 (MIT):
4
+ # https://github.com/lchase/coding-agent-plugins/tree/4c84a2ce7fbde5ac298c0de9f0b90141eac4ed98/plugins/factory
5
+ # skills/factory/SKILL.md (the loop: spec, build, 4 reviews, approver)
6
+ # agents/spec-writer.md model opus
7
+ # agents/builder.md model opus
8
+ # agents/review-security.md model opus
9
+ # agents/review-ux.md model sonnet
10
+ # agents/review-ui.md model sonnet
11
+ # agents/review-code.md model sonnet
12
+ # agents/approver.md model opus
13
+ # The prompt bodies are copied verbatim into prompts/factory/. Each step's
14
+ # prompt file is a Kiln preamble (prompts/kiln/) that maps the factory's
15
+ # job-folder files onto yak artifacts and tells the agent to return JSON
16
+ # instead of writing a file. `kiln tick` appends the factory body and rewrites
17
+ # prompt.file to an absolute path under the kiln directory before launching,
18
+ # because yak resolves prompt.file from the checkout cwd
19
+ # (yak src/steps/agent.ts, path.resolve(cwd, file)).
20
+ #
21
+ # yak 0.6.1 limits this file still works inside:
22
+ # - command.run is not templated. verify runs $KILN_TEST through
23
+ # dist/truncate-output.js ($KILN_VERIFY_WRAPPER). `kiln tick` sets
24
+ # KILN_TEST from repos.<repo>.test. An empty value fails the step. The
25
+ # wrapper keeps the test's exit code and cuts stdout/stderr to the last
26
+ # 200 lines or 20KB, with a leading `[truncated:` line when it cuts.
27
+ # land commits with `git commit -m "kiln: $KILN_TASK_TITLE"`. verify and
28
+ # land need `input` (it carries a per-launch runNonce) so one job cannot
29
+ # cache-hit another. land runs only when approval.decision is approve,
30
+ # and it does not fail when the index is empty. `git add -A` stages every
31
+ # uncommitted path in the worktree.
32
+ # - input.baseRef is the commit the worktree was branched from (full SHA).
33
+ # deliver=local uses checkout HEAD. deliver=pr uses origin/<base>, or the
34
+ # upstream yak/<run-id> tip when the job is stacked. Every preamble maps
35
+ # `<main branch>` to that SHA. The worktree branch is yak/<run-id>.
36
+ # - A loop body does not evaluate skipIf, so the UI reviewer is a real step.
37
+ # review-ui.md itself returns PASS when no UI changed.
38
+ # - A loop-body artifact is not a top-level producer. The approver reads the
39
+ # last verify on rounds.verify; needs: [verify] on the approver is rejected.
40
+ # Reviewers run inside the loop, so they need verify directly. They inherit
41
+ # input (for baseRef) instead of listing it in needs, and the loop's
42
+ # concurrency is 4 so the four reviewers start together.
43
+ name: kiln-feature
44
+ version: "1"
45
+ inputSchema:
46
+ inline:
47
+ type: object
48
+ additionalProperties: false
49
+ properties:
50
+ title: { type: string }
51
+ description: { type: string }
52
+ acceptance: { type: string }
53
+ runNonce: { type: string }
54
+ baseRef: { type: string }
55
+ required: [title, description, acceptance, runNonce, baseRef]
56
+ steps:
57
+ - id: spec
58
+ needs: [input]
59
+ agent:
60
+ model: opus
61
+ prompt:
62
+ file: prompts/kiln/spec.md
63
+ schema:
64
+ inline:
65
+ type: object
66
+ additionalProperties: false
67
+ properties:
68
+ goal: { type: string }
69
+ design: { type: string }
70
+ acceptance: { type: string }
71
+ required: [goal, design, acceptance]
72
+ tools: [Read, Grep, Glob, Bash, Write, Skill]
73
+ produces: spec
74
+
75
+ - id: revise
76
+ needs: [spec]
77
+ loop:
78
+ # A BLOCKED build, a red verify (exitCode != 0), or any CHANGES verdict
79
+ # sends the builder around again. failOn: never on verify is what keeps
80
+ # a red test from failing the run before that can happen. max 2 rounds,
81
+ # then the approver still runs (factory step 5: round 2 done goes to
82
+ # the approver).
83
+ until: 'build.status == "READY" && security.verdict == "PASS" && ux.verdict == "PASS" && ui.verdict == "PASS" && code.verdict == "PASS" && verify.exitCode == 0'
84
+ budget:
85
+ maxIterations: 2
86
+ onExhausted: continue
87
+ concurrency: 4
88
+ body:
89
+ # security, ux, ui, code, and verify are later in this body, so on
90
+ # build they are the previous round. Round 1 leaves them undefined;
91
+ # the prompt's `.field ||` defaults cover findings and verify text.
92
+ # Round 1 leaves verify undefined. A verify that ran with exitCode
93
+ # null was signal-killed, so `verify.exitCode == null` is not labeled
94
+ # round 1. Exit code 0 still renders as 0.
95
+ # `{{ security || "x" }}` does not validate.
96
+ - id: build
97
+ needs: [input, spec, security, ux, ui, code, verify]
98
+ agent:
99
+ model: opus
100
+ prompt:
101
+ file: prompts/kiln/build.md
102
+ schema:
103
+ inline:
104
+ type: object
105
+ additionalProperties: false
106
+ properties:
107
+ summary: { type: string }
108
+ status: { type: string, enum: [READY, BLOCKED] }
109
+ required: [summary, status]
110
+ tools: [Read, Grep, Glob, Bash, Write, Edit, Skill]
111
+ produces: build
112
+
113
+ - id: verify
114
+ needs: [input, build]
115
+ command:
116
+ run: 'node "${KILN_VERIFY_WRAPPER:?KILN_VERIFY_WRAPPER is empty}"'
117
+ failOn: never
118
+ capture: [stdout, stderr, exitCode]
119
+ produces: verify
120
+
121
+ # Build and verify stay in order. These four do not need each other,
122
+ # so concurrency 4 starts them together. They have no Write or Edit.
123
+ # Bash stays, because the factory prompts diff with git. Yak warns
124
+ # that concurrent Bash steps share one cwd. The preambles forbid
125
+ # re-running tests, builds, and any other write; git and file reads
126
+ # stay. input is inherited for baseRef; it is not in needs.
127
+ - id: security
128
+ needs: [spec, build, verify]
129
+ agent:
130
+ model: opus
131
+ context:
132
+ inherit: [input]
133
+ prompt:
134
+ file: prompts/kiln/security.md
135
+ schema:
136
+ inline:
137
+ type: object
138
+ additionalProperties: false
139
+ properties:
140
+ verdict: { type: string, enum: [PASS, CHANGES] }
141
+ findings: { type: string }
142
+ required: [verdict, findings]
143
+ tools: [Read, Grep, Glob, Bash, Skill]
144
+ produces: security
145
+
146
+ - id: ux
147
+ needs: [spec, build, verify]
148
+ agent:
149
+ model: sonnet
150
+ context:
151
+ inherit: [input]
152
+ prompt:
153
+ file: prompts/kiln/ux.md
154
+ schema:
155
+ inline:
156
+ type: object
157
+ additionalProperties: false
158
+ properties:
159
+ verdict: { type: string, enum: [PASS, CHANGES] }
160
+ findings: { type: string }
161
+ required: [verdict, findings]
162
+ tools: [Read, Grep, Glob, Bash, Skill]
163
+ produces: ux
164
+
165
+ - id: ui
166
+ needs: [spec, build, verify]
167
+ agent:
168
+ model: sonnet
169
+ context:
170
+ inherit: [input]
171
+ prompt:
172
+ file: prompts/kiln/ui.md
173
+ schema:
174
+ inline:
175
+ type: object
176
+ additionalProperties: false
177
+ properties:
178
+ verdict: { type: string, enum: [PASS, CHANGES] }
179
+ findings: { type: string }
180
+ required: [verdict, findings]
181
+ tools: [Read, Grep, Glob, Bash, Skill]
182
+ produces: ui
183
+
184
+ - id: code
185
+ needs: [spec, build, verify]
186
+ agent:
187
+ model: sonnet
188
+ context:
189
+ inherit: [input]
190
+ prompt:
191
+ file: prompts/kiln/code.md
192
+ schema:
193
+ inline:
194
+ type: object
195
+ additionalProperties: false
196
+ properties:
197
+ verdict: { type: string, enum: [PASS, CHANGES] }
198
+ findings: { type: string }
199
+ required: [verdict, findings]
200
+ tools: [Read, Grep, Glob, Bash, Skill]
201
+ produces: code
202
+ produces: rounds
203
+
204
+ - id: approver
205
+ needs: [input, spec, rounds]
206
+ agent:
207
+ model: opus
208
+ prompt:
209
+ file: prompts/kiln/approver.md
210
+ schema:
211
+ inline:
212
+ type: object
213
+ additionalProperties: false
214
+ properties:
215
+ decision: { type: string, enum: [APPROVE, ESCALATE] }
216
+ reason: { type: string }
217
+ required: [decision, reason]
218
+ tools: [Read, Grep, Glob, Bash, Write, Skill]
219
+ produces: decision
220
+
221
+ - id: approve
222
+ needs: [input, decision]
223
+ gate:
224
+ schema:
225
+ inline:
226
+ type: object
227
+ additionalProperties: false
228
+ properties:
229
+ decision: { type: string, enum: [approve, reject] }
230
+ required: [decision]
231
+ render:
232
+ inline: 'Approve "{{input.title}}"? Agent decision: {{decision.decision}}. {{decision.reason}}'
233
+ produces: approval
234
+
235
+ - id: land
236
+ needs: [input, approval]
237
+ skipIf: 'approval.decision != "approve"'
238
+ command:
239
+ run: 'git add -A && git diff --cached --quiet || git commit -m "kiln: $KILN_TASK_TITLE"'