@operatorstack/yield 0.1.38 → 0.2.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 CHANGED
@@ -33,6 +33,37 @@ discover it.
33
33
  Verified with Cursor, Codex, and Claude Code. Registry-backed project paths are
34
34
  available for 73 more coding agents.
35
35
 
36
+ ## Start with your coding agent
37
+
38
+ Run the command for your project:
39
+
40
+ | Language | Command |
41
+ | ---------- | -------------------------------------------------------------------------------------------------------------- |
42
+ | TypeScript | `npm create @operatorstack/yield@latest` |
43
+ | Python | `uvx --from yieldskill yskill bootstrap --language python` |
44
+ | Rust | `cargo install yieldskill --root .yield --locked`, then `.yield/bin/yskill bootstrap --root . --language rust` |
45
+ | Go | `go run github.com/operatorstack/yield/cmd/yskill@latest bootstrap --root . --language go` |
46
+
47
+ Yield detects the repository, language, and installed coding agents. It shows
48
+ every proposed file and dependency change. It asks before it writes. It then
49
+ installs, tests, and registers the `yield-workflow-builder` skill workflow.
50
+
51
+ Restart your coding agent. To create a new skill workflow, ask:
52
+
53
+ ```text
54
+ Use Yield to create a tested skill workflow for releasing my package.
55
+ ```
56
+
57
+ To convert an existing `SKILL.md`, ask:
58
+
59
+ ```text
60
+ Use Yield to convert my existing release SKILL.md into a tested skill workflow.
61
+ ```
62
+
63
+ The builder can create a skill workflow from a description. It can also
64
+ convert an existing `SKILL.md`. Yield does not use install hooks to change the
65
+ repository.
66
+
36
67
  ## Move repeated instructions into code
37
68
 
38
69
  A release skill often starts as prose:
@@ -43,17 +74,18 @@ A release skill often starts as prose:
43
74
  Yield makes the order and stopping rules executable:
44
75
 
45
76
  <!-- release-example:start -->
77
+
46
78
  ```typescript
47
- import { defineSkill } from "@operatorstack/yield";
79
+ import { defineSkill } from "@operatorstack/yield"
48
80
 
49
- type Review = { critical: number; summary: string };
81
+ type Review = { critical: number; summary: string }
50
82
 
51
83
  defineSkill((ctx) => {
52
84
  // Yield runs commands itself and records their output and exit status.
53
- const tests = ctx.runCommand("test", "echo tests-ok", 300);
85
+ const tests = ctx.runCommand("test", "echo tests-ok", 300)
54
86
 
55
87
  // A failed requirement stops the workflow and keeps its evidence.
56
- ctx.require(tests.exit_code === 0, "the test command succeeds", tests);
88
+ ctx.require(tests.exit_code === 0, "the test command succeeds", tests)
57
89
 
58
90
  // Review gives TypeScript its compile-time type. The JSON schema checks the
59
91
  // coding agent's response at runtime before this workflow can continue.
@@ -69,28 +101,29 @@ defineSkill((ctx) => {
69
101
  summary: { type: "string", minLength: 1 },
70
102
  },
71
103
  },
72
- );
73
- ctx.require(review.critical === 0, "the review has no critical findings", review);
104
+ )
105
+ ctx.require(review.critical === 0, "the review has no critical findings", review)
74
106
 
75
107
  // Yield emits these fixed choices. A supported host may show native controls;
76
108
  // otherwise the coding agent asks through its normal interface.
77
109
  const approval = ctx.askUser("approve-publish", "Publish this package?", [
78
110
  { value: "yes", label: "Publish" },
79
111
  { value: "no", label: "Stop" },
80
- ]);
81
- if (approval !== "yes") ctx.refused("the operator declined publication");
112
+ ])
113
+ if (approval !== "yes") ctx.refused("the operator declined publication")
82
114
 
83
115
  // Publishing cannot start before approval. Verification is a separate step,
84
116
  // so completion requires evidence that the registry contains the release.
85
- const publish = ctx.runCommand("publish", "echo publish-ok", 600);
86
- ctx.require(publish.exit_code === 0, "the publish command succeeds", publish);
117
+ const publish = ctx.runCommand("publish", "echo publish-ok", 600)
118
+ ctx.require(publish.exit_code === 0, "the publish command succeeds", publish)
87
119
 
88
- const registry = ctx.runCommand("verify-registry", "echo registry-ok", 300);
89
- ctx.require(registry.exit_code === 0, "the registry contains the release", registry);
120
+ const registry = ctx.runCommand("verify-registry", "echo registry-ok", 300)
121
+ ctx.require(registry.exit_code === 0, "the registry contains the release", registry)
90
122
 
91
- return { published: true, summary: review.summary };
92
- });
123
+ return { published: true, summary: review.summary }
124
+ })
93
125
  ```
126
+
94
127
  <!-- release-example:end -->
95
128
 
96
129
  The example uses harmless commands so its fixture can run in any checkout.
@@ -98,7 +131,7 @@ Replace them with the test, publish, and registry commands for your project.
98
131
  The complete tested source is in
99
132
  [`examples/release-checklist`](https://github.com/operatorstack/yield/tree/main/examples/release-checklist/).
100
133
 
101
- ## Use Yield in five steps
134
+ ## Advanced: build manually
102
135
 
103
136
  ### 1. Install Yield
104
137
 
@@ -110,7 +143,7 @@ npm exec -- yskill --version
110
143
  ```
111
144
 
112
145
  [Public npm releases](https://www.npmjs.com/package/@operatorstack/yield)
113
- use trusted publishing. The SDK package and all six runtime packages include
146
+ use trusted publishing. The initializer, SDK, and six runtime packages include
114
147
  SLSA v1 provenance.
115
148
 
116
149
  ### 2. Create the workflow
@@ -203,13 +236,13 @@ The agent follows the generated adapter, runs the canonical workflow in
203
236
  If replay produces a different operation, the run fails instead of silently
204
237
  forking. Every side effect crosses one of these primitives:
205
238
 
206
- | Primitive | Purpose |
207
- |---|---|
208
- | `runCommand` | Execute a command and record its exit code and output. |
209
- | `agentTask` | Ask the coding agent for schema-valid JSON. |
210
- | `askUser` | Request an explicit human decision. |
211
- | `require` | Bind a required claim to recorded evidence. |
212
- | `blocked` / `refused` | Stop honestly when work cannot or must not continue. |
239
+ | Primitive | Purpose |
240
+ | --------------------- | ------------------------------------------------------ |
241
+ | `runCommand` | Execute a command and record its exit code and output. |
242
+ | `agentTask` | Ask the coding agent for schema-valid JSON. |
243
+ | `askUser` | Request an explicit human decision. |
244
+ | `require` | Bind a required claim to recorded evidence. |
245
+ | `blocked` / `refused` | Stop honestly when work cannot or must not continue. |
213
246
 
214
247
  See the [primitive guides](https://github.com/operatorstack/yield/blob/main/docs/primitives/README.md) and
215
248
  [runtime reference](https://github.com/operatorstack/yield/blob/main/docs/reference/cli.md) for the full contract.
@@ -219,12 +252,12 @@ See the [primitive guides](https://github.com/operatorstack/yield/blob/main/docs
219
252
  All four SDKs implement the same execution contract. The conformance suite runs
220
253
  the same program in every language and compares observable behavior.
221
254
 
222
- | Language | SDK | Example |
223
- |---|---|---|
224
- | TypeScript | [`@operatorstack/yield`](https://github.com/operatorstack/yield/tree/main/sdk/typescript/) | [`release-checklist`](https://github.com/operatorstack/yield/tree/main/examples/release-checklist/) |
225
- | Python | [`yieldskill`](https://github.com/operatorstack/yield/tree/main/sdk/python/) | [`env-doctor`](https://github.com/operatorstack/yield/tree/main/examples/env-doctor/) |
226
- | Go | [`github.com/operatorstack/yield/sdk/yield`](https://pkg.go.dev/github.com/operatorstack/yield/sdk/yield) | [`investigate`](https://github.com/operatorstack/yield/tree/main/examples/investigate/) |
227
- | Rust | [`yieldskill`](https://github.com/operatorstack/yield/tree/main/sdk/rust/) | [`data-migration`](https://github.com/operatorstack/yield/tree/main/examples/data-migration/) |
255
+ | Language | SDK | Example |
256
+ | ---------- | --------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
257
+ | TypeScript | [`@operatorstack/yield`](https://github.com/operatorstack/yield/tree/main/sdk/typescript/) | [`release-checklist`](https://github.com/operatorstack/yield/tree/main/examples/release-checklist/) |
258
+ | Python | [`yieldskill`](https://github.com/operatorstack/yield/tree/main/sdk/python/) | [`env-doctor`](https://github.com/operatorstack/yield/tree/main/examples/env-doctor/) |
259
+ | Go | [`github.com/operatorstack/yield/sdk/yield`](https://pkg.go.dev/github.com/operatorstack/yield/sdk/yield) | [`investigate`](https://github.com/operatorstack/yield/tree/main/examples/investigate/) |
260
+ | Rust | [`yieldskill`](https://github.com/operatorstack/yield/tree/main/sdk/rust/) | [`data-migration`](https://github.com/operatorstack/yield/tree/main/examples/data-migration/) |
228
261
 
229
262
  Cursor, Codex, and Claude Code are verified integrations. Yield also includes
230
263
  registry-backed project paths for 73 more coding agents. Those paths support
@@ -258,10 +291,16 @@ loop, multi-agent orchestrator, or security sandbox.
258
291
  Run the main checks from the repository root:
259
292
 
260
293
  ```bash
294
+ npm run format:check
261
295
  go test ./...
262
296
  npm run test:release
263
297
  ```
264
298
 
299
+ Run `npm run format` to format the supported source files. Install the repository
300
+ npm dependencies first. The command also needs Go, Rust, and `uvx`. Generated
301
+ files and evaluation sources with byte-bound receipts stay unchanged until their
302
+ generators or evaluations run.
303
+
265
304
  The [example library](https://github.com/operatorstack/yield/tree/main/examples/library/) contains ten common workflows in all
266
305
  four SDKs, including code review, failure investigation, CI repair, dependency
267
306
  updates, database migration, security audit, and package release.
package/bin/runtime.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { createRequire } from "node:module";
1
+ import { createRequire } from "node:module"
2
2
 
3
3
  const packages = new Map([
4
4
  ["darwin:x64", "@operatorstack/yield-darwin-amd64"],
@@ -7,14 +7,14 @@ const packages = new Map([
7
7
  ["linux:arm64", "@operatorstack/yield-linux-arm64"],
8
8
  ["win32:x64", "@operatorstack/yield-windows-amd64"],
9
9
  ["win32:arm64", "@operatorstack/yield-windows-arm64"],
10
- ]);
10
+ ])
11
11
 
12
12
  export function runtimePackage(platform = process.platform, arch = process.arch) {
13
- const name = packages.get(`${platform}:${arch}`);
13
+ const name = packages.get(`${platform}:${arch}`)
14
14
  if (!name) {
15
- throw new Error(`Yield does not provide a runtime for ${platform}/${arch}`);
15
+ throw new Error(`Yield does not provide a runtime for ${platform}/${arch}`)
16
16
  }
17
- return name;
17
+ return name
18
18
  }
19
19
 
20
20
  export function resolveRuntime({
@@ -22,13 +22,13 @@ export function resolveRuntime({
22
22
  arch = process.arch,
23
23
  resolve = createRequire(import.meta.url).resolve,
24
24
  } = {}) {
25
- const name = runtimePackage(platform, arch);
25
+ const name = runtimePackage(platform, arch)
26
26
  try {
27
- return resolve(name);
27
+ return resolve(name)
28
28
  } catch (error) {
29
29
  throw new Error(
30
30
  `The runtime package ${name} is missing. Reinstall @operatorstack/yield for ${platform}/${arch}.`,
31
31
  { cause: error },
32
- );
32
+ )
33
33
  }
34
34
  }
@@ -1,6 +1,6 @@
1
- import test from "node:test";
2
- import assert from "node:assert/strict";
3
- import { resolveRuntime, runtimePackage } from "./runtime.mjs";
1
+ import test from "node:test"
2
+ import assert from "node:assert/strict"
3
+ import { resolveRuntime, runtimePackage } from "./runtime.mjs"
4
4
 
5
5
  const cases = [
6
6
  ["darwin", "x64", "@operatorstack/yield-darwin-amd64"],
@@ -9,22 +9,32 @@ const cases = [
9
9
  ["linux", "arm64", "@operatorstack/yield-linux-arm64"],
10
10
  ["win32", "x64", "@operatorstack/yield-windows-amd64"],
11
11
  ["win32", "arm64", "@operatorstack/yield-windows-arm64"],
12
- ];
12
+ ]
13
13
 
14
14
  test("selects the exact runtime package for every supported target", () => {
15
15
  for (const [platform, arch, expected] of cases) {
16
- assert.equal(runtimePackage(platform, arch), expected);
17
- assert.equal(resolveRuntime({ platform, arch, resolve: (name) => `/packages/${name}` }), `/packages/${expected}`);
16
+ assert.equal(runtimePackage(platform, arch), expected)
17
+ assert.equal(
18
+ resolveRuntime({ platform, arch, resolve: (name) => `/packages/${name}` }),
19
+ `/packages/${expected}`,
20
+ )
18
21
  }
19
- });
22
+ })
20
23
 
21
24
  test("rejects unsupported targets", () => {
22
- assert.throws(() => runtimePackage("freebsd", "x64"), /does not provide a runtime/);
23
- });
25
+ assert.throws(() => runtimePackage("freebsd", "x64"), /does not provide a runtime/)
26
+ })
24
27
 
25
28
  test("does not fall back when the selected package is missing", () => {
26
29
  assert.throws(
27
- () => resolveRuntime({ platform: "linux", arch: "x64", resolve: () => { throw new Error("missing"); } }),
30
+ () =>
31
+ resolveRuntime({
32
+ platform: "linux",
33
+ arch: "x64",
34
+ resolve: () => {
35
+ throw new Error("missing")
36
+ },
37
+ }),
28
38
  /Reinstall @operatorstack\/yield/,
29
- );
30
- });
39
+ )
40
+ })
package/bin/yskill.mjs CHANGED
@@ -1,33 +1,33 @@
1
1
  #!/usr/bin/env node
2
- import { spawn } from "node:child_process";
3
- import process from "node:process";
4
- import { resolveRuntime } from "./runtime.mjs";
2
+ import { spawn } from "node:child_process"
3
+ import process from "node:process"
4
+ import { resolveRuntime } from "./runtime.mjs"
5
5
 
6
- let binary;
6
+ let binary
7
7
  try {
8
- binary = resolveRuntime();
8
+ binary = resolveRuntime()
9
9
  } catch (error) {
10
- console.error(`yskill: ${error.message}`);
11
- process.exit(1);
10
+ console.error(`yskill: ${error.message}`)
11
+ process.exit(1)
12
12
  }
13
13
 
14
14
  const child = spawn(binary, process.argv.slice(2), {
15
15
  stdio: "inherit",
16
16
  env: { ...process.env, YIELD_LANGUAGE: process.env.YIELD_LANGUAGE ?? "typescript" },
17
- });
17
+ })
18
18
  for (const signal of ["SIGINT", "SIGTERM", "SIGHUP"]) {
19
19
  process.on(signal, () => {
20
- if (!child.killed) child.kill(signal);
21
- });
20
+ if (!child.killed) child.kill(signal)
21
+ })
22
22
  }
23
23
  child.on("error", (error) => {
24
- console.error(`yskill: could not start the packaged runtime: ${error.message}`);
25
- process.exit(1);
26
- });
24
+ console.error(`yskill: could not start the packaged runtime: ${error.message}`)
25
+ process.exit(1)
26
+ })
27
27
  child.on("exit", (code, signal) => {
28
28
  if (signal && process.platform !== "win32") {
29
- process.kill(process.pid, signal);
30
- return;
29
+ process.kill(process.pid, signal)
30
+ return
31
31
  }
32
- process.exit(code ?? 1);
33
- });
32
+ process.exit(code ?? 1)
33
+ })
package/dist/index.js CHANGED
@@ -2,6 +2,19 @@
2
2
  import { createHash } from "node:crypto";
3
3
  import { readFileSync } from "node:fs";
4
4
  import { exit, env, stdout, stderr } from "node:process";
5
+ function verifySupervisorIdentity() {
6
+ let manifest;
7
+ try {
8
+ manifest = JSON.parse(readFileSync("skill.json", "utf8"));
9
+ } catch {
10
+ return;
11
+ }
12
+ if (manifest.version !== 1) return;
13
+ if (!manifest.yield_version || env.YIELD_SUPERVISOR_VERSION !== manifest.yield_version) {
14
+ stderr.write(`yield: supervisor version ${env.YIELD_SUPERVISOR_VERSION || "missing"} does not match workflow Yield version ${manifest.yield_version || "missing"}\n`);
15
+ exit(2);
16
+ }
17
+ }
5
18
  export class Blocked extends Error {
6
19
  reason;
7
20
  constructor(reason){
@@ -195,6 +208,7 @@ function emit(output) {
195
208
  exit(0);
196
209
  }
197
210
  export function defineSkill(program) {
211
+ verifySupervisorIdentity();
198
212
  const path = env.YIELD_JOURNAL;
199
213
  if (!path) {
200
214
  stderr.write("yield: YIELD_JOURNAL is not set; this program is run by yskill, not directly\n");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@operatorstack/yield",
3
- "version": "0.1.38",
3
+ "version": "0.2.0",
4
4
  "description": "Yield skill-program SDK for TypeScript: turn SKILL.md workflows into resumable programs.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -50,11 +50,11 @@
50
50
  "registry": "https://registry.npmjs.org/"
51
51
  },
52
52
  "optionalDependencies": {
53
- "@operatorstack/yield-darwin-amd64": "0.1.38",
54
- "@operatorstack/yield-darwin-arm64": "0.1.38",
55
- "@operatorstack/yield-linux-amd64": "0.1.38",
56
- "@operatorstack/yield-linux-arm64": "0.1.38",
57
- "@operatorstack/yield-windows-amd64": "0.1.38",
58
- "@operatorstack/yield-windows-arm64": "0.1.38"
53
+ "@operatorstack/yield-darwin-amd64": "0.2.0",
54
+ "@operatorstack/yield-darwin-arm64": "0.2.0",
55
+ "@operatorstack/yield-linux-amd64": "0.2.0",
56
+ "@operatorstack/yield-linux-arm64": "0.2.0",
57
+ "@operatorstack/yield-windows-amd64": "0.2.0",
58
+ "@operatorstack/yield-windows-arm64": "0.2.0"
59
59
  }
60
60
  }
package/src/index.ts CHANGED
@@ -71,6 +71,20 @@ interface Journal {
71
71
  entries?: { request: Request; response: ResponseEnvelope }[];
72
72
  }
73
73
 
74
+ function verifySupervisorIdentity(): void {
75
+ let manifest: { version?: number; yield_version?: string };
76
+ try {
77
+ manifest = JSON.parse(readFileSync("skill.json", "utf8")) as { version?: number; yield_version?: string };
78
+ } catch {
79
+ return;
80
+ }
81
+ if (manifest.version !== 1) return;
82
+ if (!manifest.yield_version || env.YIELD_SUPERVISOR_VERSION !== manifest.yield_version) {
83
+ stderr.write(`yield: supervisor version ${env.YIELD_SUPERVISOR_VERSION || "missing"} does not match workflow Yield version ${manifest.yield_version || "missing"}\n`);
84
+ exit(2);
85
+ }
86
+ }
87
+
74
88
  type ProgramOutput =
75
89
  | { type: "request"; envelope: RequestEnvelope; requirements?: Requirement[] }
76
90
  | {
@@ -302,6 +316,7 @@ function emit(output: ProgramOutput): never {
302
316
  * the honest terminals.
303
317
  */
304
318
  export function defineSkill(program: (ctx: Context) => unknown): void {
319
+ verifySupervisorIdentity();
305
320
  const path = env.YIELD_JOURNAL;
306
321
  if (!path) {
307
322
  stderr.write(