@operatorstack/yield 0.1.38 → 0.3.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
@@ -30,9 +30,43 @@ programs. The canonical workflow stays inside your repository beside the code
30
30
  and dependencies it uses. Generated `SKILL.md` files only help coding agents
31
31
  discover it.
32
32
 
33
+ Write the workflow in code. Use `AgentTask` only where a bounded step needs
34
+ coding-agent judgment, then continue with structured data in normal code.
35
+
33
36
  Verified with Cursor, Codex, and Claude Code. Registry-backed project paths are
34
37
  available for 73 more coding agents.
35
38
 
39
+ ## Start with your coding agent
40
+
41
+ Run the command for your project:
42
+
43
+ | Language | Command |
44
+ | ---------- | -------------------------------------------------------------------------------------------------------------- |
45
+ | TypeScript | `npm create @operatorstack/yield@latest` |
46
+ | Python | `uvx --from yieldskill yskill bootstrap --language python` |
47
+ | Rust | `cargo install yieldskill --root .yield --locked`, then `.yield/bin/yskill bootstrap --root . --language rust` |
48
+ | Go | `go run github.com/operatorstack/yield/cmd/yskill@latest bootstrap --root . --language go` |
49
+
50
+ Yield detects the repository, language, and installed coding agents. It shows
51
+ every proposed file and dependency change. It asks before it writes. It then
52
+ installs, tests, and registers the `yield-workflow-builder` skill workflow.
53
+
54
+ Restart your coding agent. To create a new skill workflow, ask:
55
+
56
+ ```text
57
+ Use Yield to create a tested skill workflow for releasing my package.
58
+ ```
59
+
60
+ To convert an existing `SKILL.md`, ask:
61
+
62
+ ```text
63
+ Use Yield to convert my existing release SKILL.md into a tested skill workflow.
64
+ ```
65
+
66
+ The builder can create a skill workflow from a description. It can also
67
+ convert an existing `SKILL.md`. Yield does not use install hooks to change the
68
+ repository.
69
+
36
70
  ## Move repeated instructions into code
37
71
 
38
72
  A release skill often starts as prose:
@@ -40,26 +74,29 @@ A release skill often starts as prose:
40
74
  > Run the tests. Review the release. Stop if the review finds a critical issue.
41
75
  > Ask me before publishing. Publish the package, then verify the registry.
42
76
 
43
- Yield makes the order and stopping rules executable:
77
+ Yield makes the order and stopping rules executable. The coding agent reviews
78
+ what the deterministic check may miss; the program still owns the gate,
79
+ approval, publish, and verification steps:
44
80
 
45
81
  <!-- release-example:start -->
82
+
46
83
  ```typescript
47
- import { defineSkill } from "@operatorstack/yield";
84
+ import { defineSkill } from "@operatorstack/yield"
48
85
 
49
- type Review = { critical: number; summary: string };
86
+ type Review = { critical: number; summary: string }
50
87
 
51
88
  defineSkill((ctx) => {
52
89
  // Yield runs commands itself and records their output and exit status.
53
- const tests = ctx.runCommand("test", "echo tests-ok", 300);
90
+ const tests = ctx.runCommand("test", "echo tests-ok", 300)
54
91
 
55
92
  // A failed requirement stops the workflow and keeps its evidence.
56
- ctx.require(tests.exit_code === 0, "the test command succeeds", tests);
93
+ ctx.require(tests.exit_code === 0, "the test command succeeds", tests)
57
94
 
58
95
  // Review gives TypeScript its compile-time type. The JSON schema checks the
59
96
  // coding agent's response at runtime before this workflow can continue.
60
97
  const review = ctx.agentTask<Review>(
61
98
  "review-release",
62
- "Review this release. Report critical findings and a short summary.",
99
+ "Review this release for correctness problems that the test command may miss. Report critical findings and a short summary.",
63
100
  { stdout: tests.stdout, stderr: tests.stderr },
64
101
  {
65
102
  type: "object",
@@ -69,28 +106,29 @@ defineSkill((ctx) => {
69
106
  summary: { type: "string", minLength: 1 },
70
107
  },
71
108
  },
72
- );
73
- ctx.require(review.critical === 0, "the review has no critical findings", review);
109
+ )
110
+ ctx.require(review.critical === 0, "the review has no critical findings", review)
74
111
 
75
112
  // Yield emits these fixed choices. A supported host may show native controls;
76
113
  // otherwise the coding agent asks through its normal interface.
77
114
  const approval = ctx.askUser("approve-publish", "Publish this package?", [
78
115
  { value: "yes", label: "Publish" },
79
116
  { value: "no", label: "Stop" },
80
- ]);
81
- if (approval !== "yes") ctx.refused("the operator declined publication");
117
+ ])
118
+ if (approval !== "yes") ctx.refused("the operator declined publication")
82
119
 
83
120
  // Publishing cannot start before approval. Verification is a separate step,
84
121
  // 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);
122
+ const publish = ctx.runCommand("publish", "echo publish-ok", 600)
123
+ ctx.require(publish.exit_code === 0, "the publish command succeeds", publish)
87
124
 
88
- const registry = ctx.runCommand("verify-registry", "echo registry-ok", 300);
89
- ctx.require(registry.exit_code === 0, "the registry contains the release", registry);
125
+ const registry = ctx.runCommand("verify-registry", "echo registry-ok", 300)
126
+ ctx.require(registry.exit_code === 0, "the registry contains the release", registry)
90
127
 
91
- return { published: true, summary: review.summary };
92
- });
128
+ return { published: true, summary: review.summary }
129
+ })
93
130
  ```
131
+
94
132
  <!-- release-example:end -->
95
133
 
96
134
  The example uses harmless commands so its fixture can run in any checkout.
@@ -98,7 +136,7 @@ Replace them with the test, publish, and registry commands for your project.
98
136
  The complete tested source is in
99
137
  [`examples/release-checklist`](https://github.com/operatorstack/yield/tree/main/examples/release-checklist/).
100
138
 
101
- ## Use Yield in five steps
139
+ ## Advanced: build manually
102
140
 
103
141
  ### 1. Install Yield
104
142
 
@@ -110,7 +148,7 @@ npm exec -- yskill --version
110
148
  ```
111
149
 
112
150
  [Public npm releases](https://www.npmjs.com/package/@operatorstack/yield)
113
- use trusted publishing. The SDK package and all six runtime packages include
151
+ use trusted publishing. The initializer, SDK, and six runtime packages include
114
152
  SLSA v1 provenance.
115
153
 
116
154
  ### 2. Create the workflow
@@ -203,13 +241,13 @@ The agent follows the generated adapter, runs the canonical workflow in
203
241
  If replay produces a different operation, the run fails instead of silently
204
242
  forking. Every side effect crosses one of these primitives:
205
243
 
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. |
244
+ | Primitive | Purpose |
245
+ | --------------------- | ----------------------------------------------------------------------- |
246
+ | `runCommand` | Execute a command and record its exit code and output. |
247
+ | `agentTask` | Delegate one bounded judgment; an optional schema validates the result. |
248
+ | `askUser` | Request an explicit human decision. |
249
+ | `require` | Bind a required claim to recorded evidence. |
250
+ | `blocked` / `refused` | Stop honestly when work cannot or must not continue. |
213
251
 
214
252
  See the [primitive guides](https://github.com/operatorstack/yield/blob/main/docs/primitives/README.md) and
215
253
  [runtime reference](https://github.com/operatorstack/yield/blob/main/docs/reference/cli.md) for the full contract.
@@ -219,12 +257,12 @@ See the [primitive guides](https://github.com/operatorstack/yield/blob/main/docs
219
257
  All four SDKs implement the same execution contract. The conformance suite runs
220
258
  the same program in every language and compares observable behavior.
221
259
 
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/) |
260
+ | Language | SDK | Example |
261
+ | ---------- | --------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
262
+ | TypeScript | [`@operatorstack/yield`](https://github.com/operatorstack/yield/tree/main/sdk/typescript/) | [`release-checklist`](https://github.com/operatorstack/yield/tree/main/examples/release-checklist/) |
263
+ | Python | [`yieldskill`](https://github.com/operatorstack/yield/tree/main/sdk/python/) | [`env-doctor`](https://github.com/operatorstack/yield/tree/main/examples/env-doctor/) |
264
+ | 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/) |
265
+ | Rust | [`yieldskill`](https://github.com/operatorstack/yield/tree/main/sdk/rust/) | [`data-migration`](https://github.com/operatorstack/yield/tree/main/examples/data-migration/) |
228
266
 
229
267
  Cursor, Codex, and Claude Code are verified integrations. Yield also includes
230
268
  registry-backed project paths for 73 more coding agents. Those paths support
@@ -258,10 +296,16 @@ loop, multi-agent orchestrator, or security sandbox.
258
296
  Run the main checks from the repository root:
259
297
 
260
298
  ```bash
299
+ npm run format:check
261
300
  go test ./...
262
301
  npm run test:release
263
302
  ```
264
303
 
304
+ Run `npm run format` to format the supported source files. Install the repository
305
+ npm dependencies first. The command also needs Go, Rust, and `uvx`. Generated
306
+ files and evaluation sources with byte-bound receipts stay unchanged until their
307
+ generators or evaluations run.
308
+
265
309
  The [example library](https://github.com/operatorstack/yield/tree/main/examples/library/) contains ten common workflows in all
266
310
  four SDKs, including code review, failure investigation, CI repair, dependency
267
311
  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.3.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.3.0",
54
+ "@operatorstack/yield-darwin-arm64": "0.3.0",
55
+ "@operatorstack/yield-linux-amd64": "0.3.0",
56
+ "@operatorstack/yield-linux-arm64": "0.3.0",
57
+ "@operatorstack/yield-windows-amd64": "0.3.0",
58
+ "@operatorstack/yield-windows-arm64": "0.3.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(