From d13fab9fa5df639442a0e9cc25acb20c265a0c9c Mon Sep 17 00:00:00 2001 From: bigboateng Date: Sat, 8 Aug 2026 02:16:03 +0100 Subject: [PATCH 1/2] Add public Go onboarding and release proof --- .changeset/go-public-onboarding.md | 5 + .github/workflows/release-finalize.yml | 9 + README.md | 4 +- examples/investigate/main.go | 3 + packaging/go-release.mjs | 100 ++++++++ packaging/go-release.test.mjs | 65 ++++++ scripts/check-release-control.mjs | 2 + scripts/readme.test.mjs | 56 ++++- sdk/yield/README.md | 309 +++++++++++++++++++++++++ 9 files changed, 551 insertions(+), 2 deletions(-) create mode 100644 .changeset/go-public-onboarding.md create mode 100644 packaging/go-release.mjs create mode 100644 packaging/go-release.test.mjs create mode 100644 sdk/yield/README.md diff --git a/.changeset/go-public-onboarding.md b/.changeset/go-public-onboarding.md new file mode 100644 index 0000000..f5f168b --- /dev/null +++ b/.changeset/go-public-onboarding.md @@ -0,0 +1,5 @@ +--- +"@operatorstack/yield": patch +--- + +Add a Go-first onboarding guide, pkg.go.dev discovery links, and release-time verification through the public Go module proxy. diff --git a/.github/workflows/release-finalize.yml b/.github/workflows/release-finalize.yml index f62d4f5..09da042 100644 --- a/.github/workflows/release-finalize.yml +++ b/.github/workflows/release-finalize.yml @@ -78,6 +78,10 @@ jobs: node-version: "24" registry-url: https://registry.npmjs.org package-manager-cache: false + - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7 + with: + go-version-file: go.mod + cache: false - name: Require matching successful publisher receipts env: GH_TOKEN: ${{ github.token }} @@ -113,5 +117,10 @@ jobs: --archives "$RUNNER_TEMP/crates-receipt" \ --attempts 3 \ --delay-ms 10000 + node packaging/go-release.mjs \ + --version "$version" \ + --source-sha "$SOURCE_SHA" \ + --attempts 3 \ + --delay-ms 10000 test "$(git rev-list -n 1 "$TAG")" = "$SOURCE_SHA" gh release edit "$TAG" --repo "$GITHUB_REPOSITORY" --draft=false diff --git a/README.md b/README.md index a48e6bb..15a9bb6 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ PyPI version crates.io version + Go reference Build status MIT license @@ -29,6 +30,7 @@ PyPI · crates.io · + pkg.go.dev · GitHub

@@ -231,7 +233,7 @@ the same program in every language and compares observable behavior. |---|---|---| | TypeScript | [`@operatorstack/yield`](https://github.com/operatorstack/yield/tree/main/sdk/typescript/) | [`release-checklist`](https://github.com/operatorstack/yield/tree/main/examples/release-checklist/) | | Python | [`yieldskill`](https://github.com/operatorstack/yield/tree/main/sdk/python/) | [`env-doctor`](https://github.com/operatorstack/yield/tree/main/examples/env-doctor/) | -| Go | [`sdk/yield`](https://github.com/operatorstack/yield/tree/main/sdk/yield/) | [`investigate`](https://github.com/operatorstack/yield/tree/main/examples/investigate/) | +| 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/) | | Rust | [`yieldskill`](https://github.com/operatorstack/yield/tree/main/sdk/rust/) | [`data-migration`](https://github.com/operatorstack/yield/tree/main/examples/data-migration/) | Cursor, Codex, and Claude Code are verified integrations. Yield also includes diff --git a/examples/investigate/main.go b/examples/investigate/main.go index 3abfabe..e970d69 100644 --- a/examples/investigate/main.go +++ b/examples/investigate/main.go @@ -5,6 +5,7 @@ // Judgment — forming and assessing hypotheses — stays with the model. package main +// README_EXAMPLE_START import ( "encoding/json" "fmt" @@ -97,3 +98,5 @@ func main() { fmt.Sprintf("frontier reached: %d hypotheses refuted with %d failed attempts and none surviving — new evidence is needed, not more guessing", len(hs.Hypotheses), failures)) }) } + +// README_EXAMPLE_END diff --git a/packaging/go-release.mjs b/packaging/go-release.mjs new file mode 100644 index 0000000..8b48d3f --- /dev/null +++ b/packaging/go-release.mjs @@ -0,0 +1,100 @@ +#!/usr/bin/env node +import { execFile as execFileCallback } from "node:child_process"; +import { mkdtemp, rm } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join, resolve } from "node:path"; +import process from "node:process"; +import { promisify } from "node:util"; +import { pathToFileURL } from "node:url"; + +export const modulePath = "github.com/operatorstack/yield"; +const stableVersion = /^\d+\.\d+\.\d+$/; +const commit = /^[0-9a-f]{40}$/; +const execFile = promisify(execFileCallback); + +function goPlatform() { + const operatingSystem = process.platform === "win32" ? "windows" : process.platform; + const architecture = process.arch === "x64" ? "amd64" : process.arch; + return `${operatingSystem}/${architecture}`; +} + +function expect(condition, message) { + if (!condition) throw new Error(message); +} + +export function validateModuleReceipt(receipt, { version, sourceSha }) { + expect(stableVersion.test(version), `invalid stable version ${version}`); + expect(commit.test(sourceSha), `invalid source SHA ${sourceSha}`); + expect(receipt?.Path === modulePath, `unexpected Go module ${receipt?.Path ?? "missing"}`); + expect(receipt?.Version === `v${version}`, `unexpected Go module version ${receipt?.Version ?? "missing"}`); + expect(receipt?.Origin?.VCS === "git", "Go module origin must use git"); + expect(receipt?.Origin?.URL === `https://${modulePath}`, `unexpected Go module origin ${receipt?.Origin?.URL ?? "missing"}`); + expect(receipt?.Origin?.Hash === sourceSha, "Go module source does not match the release tag"); + return receipt; +} + +export async function verifyGoRelease({ + version, + sourceSha, + attempts = 1, + delayMs = 0, + execImpl = execFile, + delay = (milliseconds) => new Promise((resolveDelay) => setTimeout(resolveDelay, milliseconds)), +}) { + expect(Number.isInteger(attempts) && attempts > 0, "attempts must be a positive integer"); + const bin = await mkdtemp(join(tmpdir(), "yield-go-release-")); + const environment = { + ...process.env, + GOBIN: bin, + GOSUMDB: "sum.golang.org", + GOPROXY: "https://proxy.golang.org", + GOWORK: "off", + }; + let lastError; + try { + for (let attempt = 1; attempt <= attempts; attempt += 1) { + try { + const listed = await execImpl("go", ["list", "-m", "-json", `${modulePath}@v${version}`], { env: environment }); + validateModuleReceipt(JSON.parse(listed.stdout), { version, sourceSha }); + await execImpl("go", ["install", `${modulePath}/cmd/yskill@v${version}`], { env: environment }); + const executable = join(bin, process.platform === "win32" ? "yskill.exe" : "yskill"); + const installed = await execImpl(executable, ["--version"], { env: environment }); + expect(installed.stdout.trim() === `yskill ${version} ${goPlatform()}`, `unexpected yskill version: ${installed.stdout.trim()}`); + return { module: modulePath, version, sourceSha }; + } catch (error) { + lastError = error; + if (attempt < attempts) await delay(delayMs); + } + } + } finally { + await rm(bin, { recursive: true, force: true }); + } + throw lastError; +} + +function parseArgs(argv) { + const values = {}; + for (let index = 0; index < argv.length; index += 2) { + const key = argv[index]; + if (!key?.startsWith("--") || argv[index + 1] === undefined) throw new Error(`invalid argument ${key ?? ""}`); + values[key.slice(2)] = argv[index + 1]; + } + expect(stableVersion.test(values.version ?? ""), "--version must be stable semver"); + expect(commit.test(values["source-sha"] ?? ""), "--source-sha must be a full commit SHA"); + return values; +} + +async function main() { + const values = parseArgs(process.argv.slice(2)); + const result = await verifyGoRelease({ + version: values.version, + sourceSha: values["source-sha"], + attempts: Number(values.attempts ?? "1"), + delayMs: Number(values["delay-ms"] ?? "0"), + }); + process.stdout.write(`${JSON.stringify({ ...result, verified: true })}\n`); +} + +if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) { + main().catch((error) => { console.error(`go-release: ${error.message}`); process.exit(1); }); +} diff --git a/packaging/go-release.test.mjs b/packaging/go-release.test.mjs new file mode 100644 index 0000000..4748321 --- /dev/null +++ b/packaging/go-release.test.mjs @@ -0,0 +1,65 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import { modulePath, validateModuleReceipt, verifyGoRelease } from "./go-release.mjs"; + +const sourceSha = "a".repeat(40); +const goPlatform = `${process.platform === "win32" ? "windows" : process.platform}/${process.arch === "x64" ? "amd64" : process.arch}`; + +function receipt(version = "1.2.3") { + return { + Path: modulePath, + Version: `v${version}`, + Origin: { VCS: "git", URL: `https://${modulePath}`, Hash: sourceSha }, + }; +} + +test("binds the public Go module to its immutable tag source", () => { + assert.equal(validateModuleReceipt(receipt(), { version: "1.2.3", sourceSha }).Version, "v1.2.3"); + assert.throws( + () => validateModuleReceipt({ ...receipt(), Origin: { ...receipt().Origin, Hash: "b".repeat(40) } }, { version: "1.2.3", sourceSha }), + /does not match the release tag/, + ); +}); + +test("verifies proxy discovery and a fresh command install", async () => { + const calls = []; + const result = await verifyGoRelease({ + version: "1.2.3", + sourceSha, + execImpl: async (file, args, options) => { + calls.push({ file, args, options }); + if (args[0] === "list") return { stdout: JSON.stringify(receipt()) }; + if (file === "go") return { stdout: "" }; + return { stdout: `yskill 1.2.3 ${goPlatform}\n` }; + }, + }); + assert.equal(result.module, modulePath); + assert.deepEqual(calls[0].args, ["list", "-m", "-json", `${modulePath}@v1.2.3`]); + assert.deepEqual(calls[1].args, ["install", `${modulePath}/cmd/yskill@v1.2.3`]); + assert.equal(calls[0].options.env.GOPROXY, "https://proxy.golang.org"); + assert.equal(calls[0].options.env.GOSUMDB, "sum.golang.org"); + assert.equal(calls[0].options.env.GOWORK, "off"); +}); + +test("retries a proxy miss without accepting a partial release", async () => { + let lists = 0; + let delays = 0; + await verifyGoRelease({ + version: "1.2.3", + sourceSha, + attempts: 2, + delayMs: 1, + delay: async () => { delays += 1; }, + execImpl: async (file, args) => { + if (args[0] === "list") { + lists += 1; + if (lists === 1) throw new Error("module not found"); + return { stdout: JSON.stringify(receipt()) }; + } + if (file === "go") return { stdout: "" }; + return { stdout: `yskill 1.2.3 ${goPlatform}\n` }; + }, + }); + assert.equal(lists, 2); + assert.equal(delays, 1); +}); diff --git a/scripts/check-release-control.mjs b/scripts/check-release-control.mjs index 29f73b0..21caf52 100644 --- a/scripts/check-release-control.mjs +++ b/scripts/check-release-control.mjs @@ -99,6 +99,8 @@ export async function checkReleaseControl(root = resolve(import.meta.dirname, ". expect(raw["release-finalize.yml"].includes("npm-publish.yml"), "finalization must bind the combined publisher receipt"); expect(raw["release-finalize.yml"].includes("pypi-release.mjs verify"), "finalization must verify the PyPI wheel hashes"); expect(raw["release-finalize.yml"].includes("crates-release.mjs verify"), "finalization must verify the crates.io package hashes"); + expect(raw["release-finalize.yml"].includes("go-release.mjs"), "finalization must verify the public Go module and command install"); + expect(raw["release-finalize.yml"].includes("--source-sha \"$SOURCE_SHA\""), "Go finalization must bind the module to the release source"); expect(raw["release-finalize.yml"].includes("--name \"crates-${version}-${SOURCE_SHA}\""), "finalization must consume the publisher-produced crates receipt"); expect(raw["release.yml"].includes("gh workflow run npm-publish.yml"), "the release controller must dispatch the trusted-publishing event after tagging"); expect(!Object.values(raw).some((text) => text.includes("CRATES_BOOTSTRAP_TOKEN")), "crates.io publishing must not use a bootstrap token"); diff --git a/scripts/readme.test.mjs b/scripts/readme.test.mjs index 33591cd..7dc0662 100644 --- a/scripts/readme.test.mjs +++ b/scripts/readme.test.mjs @@ -78,6 +78,57 @@ test("Rust README example matches the tested data migration", async () => { assert.deepEqual(JSON.parse(fixtureMatch[1]), JSON.parse(fixture)); }); +test("Go README example matches the tested investigation workflow", async () => { + const [readme, source, fixture] = await Promise.all([ + text("sdk/yield/README.md"), + text("examples/investigate/main.go"), + text("examples/investigate/fixtures/responses.json"), + ]); + + const readmeMatch = readme.match( + /\s*```go\n([\s\S]*?)\n```\s*/, + ); + assert.ok(readmeMatch, "Go README example markers are missing"); + const sourceMatch = source.match( + /\/\/ README_EXAMPLE_START\n([\s\S]*?)\n\/\/ README_EXAMPLE_END/, + ); + assert.ok(sourceMatch, "Go source example markers are missing"); + const readmeProgram = readmeMatch[1].replace(/^package main\n+/, "").trim(); + assert.equal(readmeProgram, sourceMatch[1].trim()); + + const fixtureMatch = readme.match( + /\s*```json\n([\s\S]*?)\n```\s*/, + ); + assert.ok(fixtureMatch, "Go README fixture markers are missing"); + assert.deepEqual(JSON.parse(fixtureMatch[1]), JSON.parse(fixture)); +}); + +test("Go README presents a public five-step workflow", async () => { + const readme = await text("sdk/yield/README.md"); + const headings = [ + "### 1. Install Yield", + "### 2. Create the workflow", + "### 3. Test the workflow", + "### 4. Register the skill", + "### 5. Run the skill", + ]; + let previous = -1; + for (const heading of headings) { + const current = readme.indexOf(heading); + assert.ok(current > previous, `${heading} is missing or out of order`); + previous = current; + } + assert.match(readme, /go install github\.com\/operatorstack\/yield\/cmd\/yskill@latest/); + assert.match(readme, /yskill init skills\/investigate/); + assert.match(readme, /yskill doctor skills\/investigate --test/); + assert.match(readme, /yskill register skills\/investigate/); + assert.match(readme, /^\/investigate$/m); + assert.match(readme, /https:\/\/pkg\.go\.dev\/github\.com\/operatorstack\/yield\/sdk\/yield/); + assert.match(readme, /https:\/\/proxy\.golang\.org/); + assert.doesNotMatch(readme, /npmjs\.com|pypi\.org|crates\.io/); + assert.doesNotMatch(readme, /(?:href|src)="(?!https:\/\/)/); +}); + test("Rust README presents a public five-step workflow", async () => { const readme = await text("sdk/rust/README.md"); const headings = [ @@ -215,10 +266,11 @@ test("README uses the borderless Yield mark", async () => { }); test("README and quickstart use the public documentation and package registries", async () => { - const [readme, pythonReadme, rustReadme, docsIndex, quickstart, agentSetup] = await Promise.all([ + const [readme, pythonReadme, rustReadme, goReadme, docsIndex, quickstart, agentSetup] = await Promise.all([ text("README.md"), text("sdk/python/README.md"), text("sdk/rust/README.md"), + text("sdk/yield/README.md"), text("docs/README.md"), text("docs/quickstart.md"), text("docs/agent-setup.md"), @@ -227,11 +279,13 @@ test("README and quickstart use the public documentation and package registries" assert.match(readme, /href="https:\/\/yield\.operatorstack\.systems\/docs\/">Documentation<\/a>/); assert.match(readme, /href="https:\/\/pypi\.org\/project\/yieldskill\/">PyPI<\/a>/); assert.match(readme, /href="https:\/\/crates\.io\/crates\/yieldskill">crates\.io<\/a>/); + assert.match(readme, /href="https:\/\/pkg\.go\.dev\/github\.com\/operatorstack\/yield\/sdk\/yield">pkg\.go\.dev<\/a>/); assert.match(pythonReadme, /python -m pip install yieldskill/); assert.match(pythonReadme, /https:\/\/pypi\.org\/project\/yieldskill\//); assert.doesNotMatch(pythonReadme, /get\.operatorstack\.systems\/pip/); assert.match(rustReadme, /cargo install yieldskill --locked/); assert.doesNotMatch(rustReadme, /get\.operatorstack\.systems\/cargo/); + assert.match(goReadme, /go install github\.com\/operatorstack\/yield\/cmd\/yskill@latest/); assert.match(docsIndex, /\[public documentation\]\(https:\/\/yield\.operatorstack\.systems\/docs\/\)/); assert.match(quickstart, /npm install --save-exact @operatorstack\/yield/); assert.doesNotMatch(quickstart, /get\.operatorstack\.systems\/npm|@operatorstack\/yield@0\./); diff --git a/sdk/yield/README.md b/sdk/yield/README.md new file mode 100644 index 0000000..3946705 --- /dev/null +++ b/sdk/yield/README.md @@ -0,0 +1,309 @@ +

+ + Yield + +

+ +

Yield for Go

+ +

Move repeatable coding-agent instructions from words into Go.

+ +

+ Build typed, resumable workflows that stay beside the code they operate on. +

+ +

+ Go reference + Go module version + Build status + MIT license +

+ +

+ Website · + Documentation · + pkg.go.dev · + GitHub +

+ +The Go module is `github.com/operatorstack/yield`. Import the SDK as +`github.com/operatorstack/yield/sdk/yield`. The installed command is `yskill`. + +## Build a Go skill in five steps + +### 1. Install Yield + +Yield supports Go on macOS, Linux, and Windows. Install the public command: + +```bash +go install github.com/operatorstack/yield/cmd/yskill@latest +yskill --version +``` + +Go downloads the tagged module through +[`proxy.golang.org`](https://proxy.golang.org/). You do not need a separate +registry account or private package source. + +### 2. Create the workflow + +Create a Go workflow inside your repository: + +```bash +yskill init skills/investigate \ + --language go \ + --description "Collect failure evidence, test hypotheses, and report the cause." +``` + +Replace `skills/investigate/main.go` with this tested workflow: + + +```go +package main + +import ( + "encoding/json" + "fmt" + + "github.com/operatorstack/yield/sdk/yield" +) + +type hypothesis struct { + ID string `json:"id"` + Statement string `json:"statement"` + DisproveCommand string `json:"disprove_command"` +} + +type assessment struct { + Refuted bool `json:"refuted"` + CausalChain string `json:"causal_chain"` +} + +const hypothesesSchema = `{ + "type": "object", + "required": ["hypotheses"], + "properties": { + "hypotheses": { + "type": "array", + "minItems": 3, + "items": { + "type": "object", + "required": ["id", "statement", "disprove_command"], + "properties": { + "id": {"type": "string"}, + "statement": {"type": "string"}, + "disprove_command": {"type": "string"} + } + } + } + } +}` + +const assessmentSchema = `{ + "type": "object", + "required": ["refuted"], + "properties": { + "refuted": {"type": "boolean"}, + "causal_chain": {"type": "string"} + } +}` + +func main() { + yield.Main(func(ctx *yield.Context) (yield.Outcome, error) { + evidence := ctx.AgentTask("collect-evidence", + "Collect the observable evidence for the failure under investigation: error output, logs, recent changes. Return {\"observations\": [string]}.", + nil, json.RawMessage(`{"type":"object","required":["observations"],"properties":{"observations":{"type":"array","items":{"type":"string"}}}}`)) + + raw := ctx.AgentTask("form-hypotheses", + "Produce at least three hypotheses explaining the evidence, ordered cheapest-to-disprove first. Each carries a shell command whose failure would disprove it.", + json.RawMessage(evidence), json.RawMessage(hypothesesSchema)) + var hs struct { + Hypotheses []hypothesis `json:"hypotheses"` + } + if err := json.Unmarshal(raw, &hs); err != nil { + return yield.Outcome{}, err + } + + failures := 0 + for _, h := range hs.Hypotheses { + if failures >= 3 { + break + } + result := ctx.RunCommand("probe-"+h.ID, h.DisproveCommand, 300) + assessRaw := ctx.AgentTask("assess-"+h.ID, + fmt.Sprintf("Hypothesis %q: %s. Given the probe result, is it refuted? If it survives, state the causal chain from root cause to observed failure.", h.ID, h.Statement), + map[string]any{"hypothesis": h, "probe": result}, + json.RawMessage(assessmentSchema)) + var a assessment + if err := json.Unmarshal(assessRaw, &a); err != nil { + return yield.Outcome{}, err + } + if a.Refuted { + failures++ + continue + } + ctx.Require(a.CausalChain != "", "the surviving hypothesis states a causal chain", a) + return ctx.Complete(map[string]any{ + "hypothesis": h, + "causal_chain": a.CausalChain, + "probe_exit": result.ExitCode, + }) + } + return yield.Outcome{}, ctx.Blocked( + fmt.Sprintf("frontier reached: %d hypotheses refuted with %d failed attempts and none surviving — new evidence is needed, not more guessing", len(hs.Hypotheses), failures)) + }) +} +``` + + +The generated `go.mod` pins the public Yield module to the installed CLI +version. The generated `skill.json` runs the Go program. + +### 3. Test the workflow + +Use deterministic responses during tests. Save this as +`skills/investigate/fixtures/responses.json`: + + +```json +{ + "collect-evidence": { + "observations": [ + "CI fails on ubuntu only with 'Text file busy' (exit 126)", + "failure started after the hydrate step became concurrent", + "macOS and windows runners are green" + ] + }, + "form-hypotheses": { + "hypotheses": [ + { + "id": "h1", + "statement": "The runner image is missing the binary entirely", + "disprove_command": "exit 1" + }, + { + "id": "h2", + "statement": "Concurrent hydrate writes the binary while another process execs it (ETXTBSY)", + "disprove_command": "true" + }, + { + "id": "h3", + "statement": "A permissions regression strips the execute bit", + "disprove_command": "true" + } + ] + }, + "assess-h1": { + "refuted": true + }, + "assess-h2": { + "refuted": false, + "causal_chain": "concurrent hydrate holds the binary open for write -> exec of the same inode returns ETXTBSY -> shell reports exit 126 -> job fails only where hydrate and exec overlap (ubuntu)" + } +} +``` + + +Then test the workflow: + +```bash +yskill doctor skills/investigate --test +``` + +Yield runs commands for real and supplies agent responses from the fixture. A +successful test reaches `completed` without leaving a run journal. + +### 4. Register the skill + +Registration lets installed coding agents discover the workflow: + +```bash +yskill register skills/investigate +``` + +Select the verified agents explicitly when you do not want automatic +detection: + +```bash +yskill register skills/investigate \ + --agent cursor,codex,claude-code +``` + +The generated adapters point back to `skills/investigate`. They do not copy the +workflow or install its dependencies again. + +### 5. Run the skill + +Start a new coding-agent session so it discovers the registered skill. Where +slash skills are supported, run: + +```text +/investigate +``` + +Otherwise, ask the agent in plain language: + +```text +Use the investigate skill to diagnose this failure. +``` + +The agent follows the adapter, starts the canonical Go workflow, and supplies +each required agent response. + +## How Yield runs and resumes + +1. Your Go function emits one typed operation. +2. Yield records the request and exits. It does not run a daemon. +3. The coding agent, user, or CLI supplies the result. +4. Yield replays the function from its journal until it reaches the next + operation. + +Replay must produce the same operation sequence. Yield reports divergence +instead of giving a recorded response to a different operation. + +| Go primitive | Purpose | +|---|---| +| `ctx.RunCommand()` | Execute a command and record its exit code and output. | +| `ctx.AgentTask()` | Ask the coding agent for schema-valid JSON. | +| `ctx.AskUser()` | Request an explicit human decision. | +| `ctx.Require()` | Bind a required claim to recorded evidence. | +| `ctx.Blocked()` / `ctx.Refused()` | Stop honestly when work cannot or must not continue. | + +See the [Go reference](https://pkg.go.dev/github.com/operatorstack/yield/sdk/yield), +[primitive guides](https://yield.operatorstack.systems/docs/primitives/), and +[CLI reference](https://github.com/operatorstack/yield/blob/main/docs/reference/cli.md) +for the complete contract. + +## Guarantees and limits + +Yield provides deterministic control flow, typed requests and responses, +persistent run state, replay with divergence detection, stale and duplicate +response rejection, and evidence-bound completion. + +Schema validity is not truth. Yield cannot prove that a coding agent performed +only the requested work. `RunCommand` is different: the Yield CLI executes the +command, so its recorded exit code and output are observed facts. + +Programs must remain deterministic between operations. Do not read clocks, +random values, environment variables, or changing files to choose the next +operation. Cross those boundaries through a Yield operation instead. + +Yield is not a daemon, hosted runtime, workflow DSL, marketplace, coding-agent +replacement, or permission sandbox. Your operating system, repository, and +coding-agent permissions remain the security boundary. + +## Coding-agent support + +Yield verifies adapters for Cursor, Codex, and Claude Code. Registry-backed +project paths are available for other coding agents. See the +[agent setup guide](https://yield.operatorstack.systems/docs/agent-setup/). + +## Source and support + +- [Go API reference](https://pkg.go.dev/github.com/operatorstack/yield/sdk/yield) +- [Public documentation](https://yield.operatorstack.systems/docs/) +- [Go source](https://github.com/operatorstack/yield/tree/main/sdk/yield) +- [Working examples](https://github.com/operatorstack/yield/tree/main/examples) +- [Issues](https://github.com/operatorstack/yield/issues) +- [Security policy](https://github.com/operatorstack/yield/blob/main/SECURITY.md) + +Yield is available under the [MIT License](https://github.com/operatorstack/yield/blob/main/LICENSE). From af22cd89ff8adcb54f6da2295bc44eb6969ad73c Mon Sep 17 00:00:00 2001 From: bigboateng Date: Sat, 8 Aug 2026 02:21:06 +0100 Subject: [PATCH 2/2] Keep Go example receipt synchronized --- evals/results/latest.json | 4 ++-- examples/investigate/main.go | 3 --- scripts/readme.test.mjs | 9 +++------ 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/evals/results/latest.json b/evals/results/latest.json index f0bf2f0..e03bef0 100644 --- a/evals/results/latest.json +++ b/evals/results/latest.json @@ -1,8 +1,8 @@ { "schema_version": 2, "methodology_version": "1.1", - "generated_at": "2026-08-07T22:52:34.977Z", - "source_digest": "b5c66a96530cc9d100c388a4df9bbbc8d0aea6e78ef0fe2cfa0009b8aa1da778", + "generated_at": "2026-08-08T01:20:38.016Z", + "source_digest": "eb20ae102ae5de056d91ad3a9b8cbfc77284185050c3e3639d93c111b78ed6db", "status": "passed", "workflow_conformance": { "passed": 40, diff --git a/examples/investigate/main.go b/examples/investigate/main.go index e970d69..3abfabe 100644 --- a/examples/investigate/main.go +++ b/examples/investigate/main.go @@ -5,7 +5,6 @@ // Judgment — forming and assessing hypotheses — stays with the model. package main -// README_EXAMPLE_START import ( "encoding/json" "fmt" @@ -98,5 +97,3 @@ func main() { fmt.Sprintf("frontier reached: %d hypotheses refuted with %d failed attempts and none surviving — new evidence is needed, not more guessing", len(hs.Hypotheses), failures)) }) } - -// README_EXAMPLE_END diff --git a/scripts/readme.test.mjs b/scripts/readme.test.mjs index 7dc0662..59f4552 100644 --- a/scripts/readme.test.mjs +++ b/scripts/readme.test.mjs @@ -89,12 +89,9 @@ test("Go README example matches the tested investigation workflow", async () => /\s*```go\n([\s\S]*?)\n```\s*/, ); assert.ok(readmeMatch, "Go README example markers are missing"); - const sourceMatch = source.match( - /\/\/ README_EXAMPLE_START\n([\s\S]*?)\n\/\/ README_EXAMPLE_END/, - ); - assert.ok(sourceMatch, "Go source example markers are missing"); - const readmeProgram = readmeMatch[1].replace(/^package main\n+/, "").trim(); - assert.equal(readmeProgram, sourceMatch[1].trim()); + const sourceMatch = source.match(/^(package main[\s\S]*)$/m); + assert.ok(sourceMatch, "Go source program is missing"); + assert.equal(readmeMatch[1].trim(), sourceMatch[1].trim()); const fixtureMatch = readme.match( /\s*```json\n([\s\S]*?)\n```\s*/,