Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/readme-prose-to-code.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@operatorstack/yield": patch
---

Show a tested prose-to-code workflow in the README and point npm packages to the Yield website.
313 changes: 147 additions & 166 deletions README.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions evals/results/latest.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"schema_version": 2,
"methodology_version": "1.1",
"generated_at": "2026-08-07T09:37:20.395Z",
"source_digest": "88346db6f97443ded683c99283a07f2695805bf2628e113acab5fbc8a041e268",
"generated_at": "2026-08-07T11:37:55.058Z",
"source_digest": "d75c9a27b4782ff37a16c76b472327ecb6c8ab1b014dcf8e01626870340a82ac",
"status": "passed",
"workflow_conformance": {
"passed": 40,
Expand Down
10 changes: 5 additions & 5 deletions examples/release-checklist/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: release-checklist
description: Deploy with an explicit human gate, build verification, and evidence-bound completion.
description: Test, review, approve, publish, and verify a package in a fixed order.
---

Run:
Expand All @@ -9,14 +9,14 @@ Run:

Follow each returned operation exactly.

- `ask_user`: ask the user using the host's normal interface.
- `agent_task`: perform the task and return schema-valid JSON.
- `ask_user`: ask the user through the host's normal interface.
- `run_command`: yskill executes it itself; you will not see this kind.

Resume the run after each operation:

yskill resume <run-id> --response response.json --skill .

Do not skip an operation or invent its response. The program enforces the
order: approval before build, build before notes, notes before deploy —
and completion requires both commands' observed exit codes.
Do not skip an operation or invent its response. The program enforces this
order: test, review, approval, publish, then registry verification. Critical
review findings and failed commands stop completion.
9 changes: 5 additions & 4 deletions examples/release-checklist/fixtures/responses.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"approve-deploy": { "value": "yes" },
"release-notes": {
"notes": "Ships the resumable-run supervisor with evidence-bound completion; no schema changes; rollback is redeploy of the previous tag."
}
"review-release": {
"critical": 0,
"summary": "Tests passed and the release has no critical findings."
},
"approve-publish": { "value": "yes" }
}
50 changes: 30 additions & 20 deletions examples/release-checklist/main.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,41 @@
// Example skill (TypeScript): a release runbook where the model cannot
// skip step four. Order, the human gate, and the verification requirement
// are code; judgment (the release notes) stays with the model.
// Example skill (TypeScript): a release checklist where tests, review,
// approval, publishing, and registry verification cannot be skipped.
import { defineSkill } from "../../sdk/typescript/src/index.ts";

defineSkill((ctx) => {
const approval = ctx.askUser("approve-deploy", "Deploy to production?", [
{ value: "yes", label: "Deploy" },
{ value: "no", label: "Abort" },
]);
if (approval !== "yes") ctx.refused("the operator declined the deploy");
// README_EXAMPLE_START
type Review = { critical: number; summary: string };

const build = ctx.runCommand("build", "echo build-ok", 300);
ctx.require(build.exit_code === 0, "the build succeeds", build);
defineSkill((ctx) => {
const tests = ctx.runCommand("test", "echo tests-ok", 300);
ctx.require(tests.exit_code === 0, "the test command succeeds", tests);

const notes = ctx.agentTask<{ notes: string }>(
"release-notes",
"Draft one-paragraph release notes for this deploy.",
{ approved: approval },
const review = ctx.agentTask<Review>(
"review-release",
"Review this release. Report critical findings and a short summary.",
{ stdout: tests.stdout, stderr: tests.stderr },
{
type: "object",
required: ["notes"],
properties: { notes: { type: "string", minLength: 1 } },
required: ["critical", "summary"],
properties: {
critical: { type: "integer", minimum: 0 },
summary: { type: "string", minLength: 1 },
},
},
);
ctx.require(review.critical === 0, "the review has no critical findings", review);

const approval = ctx.askUser("approve-publish", "Publish this package?", [
{ value: "yes", label: "Publish" },
{ value: "no", label: "Stop" },
]);
if (approval !== "yes") ctx.refused("the operator declined publication");

const publish = ctx.runCommand("publish", "echo publish-ok", 600);
ctx.require(publish.exit_code === 0, "the publish command succeeds", publish);

const deploy = ctx.runCommand("deploy", "echo deploy-ok", 600);
ctx.require(deploy.exit_code === 0, "the deploy command succeeds", deploy);
const registry = ctx.runCommand("verify-registry", "echo registry-ok", 300);
ctx.require(registry.exit_code === 0, "the registry contains the release", registry);

return { deployed: true, notes: notes.notes };
return { published: true, summary: review.summary };
});
// README_EXAMPLE_END
2 changes: 1 addition & 1 deletion packaging/assemble.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ async function assembleNpm({ version, binaries, output }) {
name: npmPackage(target), version, description: `Yield runtime for ${target.id}`,
license: "MIT", os: [target.nodeOs], cpu: [target.nodeCpu], main: `./${runtime}`,
files: [runtime, "LICENSE"], repository: { type: "git", url: "git+https://github.com/operatorstack/yield.git" },
homepage: "https://github.com/operatorstack/yield#readme",
homepage: "https://yield.operatorstack.systems/",
bugs: { url: "https://github.com/operatorstack/yield/issues" },
publishConfig: { access: "public", provenance: true, registry: "https://registry.npmjs.org/" },
}, null, 2)}\n`);
Expand Down
8 changes: 7 additions & 1 deletion packaging/assemble.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { tmpdir } from "node:os";
import { assemble, isPackageVersion } from "./assemble.mjs";
import { binaryName, npmPackage, targets } from "./targets.mjs";

const homepage = "https://yield.operatorstack.systems/";

test("accepts stable and exact Yield canary versions", () => {
assert.equal(isPackageVersion("1.2.3"), true);
assert.equal(isPackageVersion("0.0.0-canary.20260807104031.b081bae38282"), true);
Expand All @@ -31,6 +33,7 @@ test("assembles one public npm package and six matching runtimes", async (t) =>

assert.equal(main.name, "@operatorstack/yield");
assert.equal(main.version, "1.2.3");
assert.equal(main.homepage, homepage);
assert.deepEqual(main.publishConfig, {
access: "public",
provenance: true,
Expand All @@ -40,13 +43,16 @@ test("assembles one public npm package and six matching runtimes", async (t) =>
main.optionalDependencies,
Object.fromEntries(targets.map((target) => [npmPackage(target), "1.2.3"])),
);
assert.match(await readFile(join(output, "npm/yield/README.md"), "utf8"), /^# Yield/m);
const assembledReadme = await readFile(join(output, "npm/yield/README.md"), "utf8");
assert.equal(assembledReadme, await readFile(join(import.meta.dirname, "../README.md"), "utf8"));
assert.match(assembledReadme, /<h1 align="center">Yield<\/h1>/);
assert.match(await readFile(join(output, "npm/yield/LICENSE"), "utf8"), /MIT License/);

for (const target of targets) {
const runtime = await readJson(join(output, `npm/${target.id}/package.json`));
assert.equal(runtime.name, npmPackage(target));
assert.equal(runtime.version, "1.2.3");
assert.equal(runtime.homepage, homepage);
assert.deepEqual(runtime.os, [target.nodeOs]);
assert.deepEqual(runtime.cpu, [target.nodeCpu]);
assert.equal(runtime.publishConfig.provenance, true);
Expand Down
54 changes: 54 additions & 0 deletions scripts/readme.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import test from "node:test";
import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import { resolve } from "node:path";

const root = resolve(import.meta.dirname, "..");

async function text(path) {
return readFile(resolve(root, path), "utf8");
}

test("README release example matches the tested TypeScript source", async () => {
const [readme, source] = await Promise.all([
text("README.md"),
text("examples/release-checklist/main.ts"),
]);

const readmeMatch = readme.match(
/<!-- release-example:start -->\s*```typescript\n([\s\S]*?)\n```\s*<!-- release-example:end -->/,
);
assert.ok(readmeMatch, "README release example markers are missing");

const sourceMatch = source.match(
/\/\/ README_EXAMPLE_START\n([\s\S]*?)\n\/\/ README_EXAMPLE_END/,
);
assert.ok(sourceMatch, "TypeScript release example markers are missing");

const readmeProgram = readmeMatch[1]
.replace(/^import \{ defineSkill \} from "@operatorstack\/yield";\n+/, "")
.trim();
assert.equal(readmeProgram, sourceMatch[1].trim());
});

test("README agent claims match the pinned registry", async () => {
const [readme, registryText] = await Promise.all([
text("README.md"),
text("cmd/yskill/registry/agents.json"),
]);
const registry = JSON.parse(registryText);
const verified = registry.agents.filter((agent) => agent.tier === "verified");
const registryBacked = registry.agents.filter((agent) => agent.tier === "registry");
const normalized = readme.replace(/\s+/g, " ");

assert.deepEqual(
verified.map((agent) => agent.id).sort(),
["claude-code", "codex", "cursor"],
);
assert.match(normalized, /Verified with Cursor, Codex, and Claude Code\./);
assert.match(
normalized,
new RegExp(`Registry-backed project paths are available for ${registryBacked.length} more coding agents\\.`),
);
assert.doesNotMatch(readme, /Agent Plugins and Yield/);
});
2 changes: 1 addition & 1 deletion sdk/typescript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"url": "git+https://github.com/operatorstack/yield.git",
"directory": "sdk/typescript"
},
"homepage": "https://github.com/operatorstack/yield#readme",
"homepage": "https://yield.operatorstack.systems/",
"bugs": {
"url": "https://github.com/operatorstack/yield/issues"
},
Expand Down