From 6556f2f0b80b68d4d8c8f9dbb47de14559732ceb Mon Sep 17 00:00:00 2001 From: bigboateng Date: Sat, 1 Aug 2026 15:45:31 +0100 Subject: [PATCH 1/3] feat(yield): add multi-language example library MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Disclosure-Reviewed: reviewed — public-safe only, private facet kept out of this commit --- .github/workflows/yield-lab.yml | 2 + labs/22-yield/README.md | 3 + .../2026-08-01-example-library.md | 8 + labs/22-yield/public-readme/README.md | 27 +- labs/22-yield/yield/docs/examples.md | 34 ++ .../22-yield/yield/examples/library/README.md | 48 ++ .../yield/examples/library/catalog.json | 112 ++++ .../library/go/audit-security/SKILL.md | 13 + .../go/audit-security/fixtures/responses.json | 7 + .../library/go/audit-security/skill.json | 7 + .../library/go/investigate-failure/SKILL.md | 13 + .../fixtures/responses.json | 7 + .../library/go/investigate-failure/skill.json | 7 + .../library/go/migrate-database/SKILL.md | 13 + .../migrate-database/fixtures/responses.json | 10 + .../library/go/migrate-database/skill.json | 7 + .../examples/library/go/publish-ios/SKILL.md | 13 + .../go/publish-ios/fixtures/responses.json | 10 + .../library/go/publish-ios/skill.json | 7 + .../library/go/qa-web-change/SKILL.md | 13 + .../go/qa-web-change/fixtures/responses.json | 7 + .../library/go/qa-web-change/skill.json | 7 + .../library/go/release-package/SKILL.md | 13 + .../release-package/fixtures/responses.json | 10 + .../library/go/release-package/skill.json | 7 + .../examples/library/go/repair-ci/SKILL.md | 13 + .../go/repair-ci/fixtures/responses.json | 7 + .../examples/library/go/repair-ci/skill.json | 7 + .../library/go/review-branch/SKILL.md | 13 + .../go/review-branch/fixtures/responses.json | 7 + .../library/go/review-branch/skill.json | 7 + .../library/go/src/audit-security/main.go | 37 ++ .../go/src/investigate-failure/main.go | 37 ++ .../library/go/src/migrate-database/main.go | 54 ++ .../library/go/src/publish-ios/main.go | 54 ++ .../library/go/src/qa-web-change/main.go | 37 ++ .../library/go/src/release-package/main.go | 54 ++ .../examples/library/go/src/repair-ci/main.go | 43 ++ .../library/go/src/review-branch/main.go | 37 ++ .../library/go/src/triage-issue/main.go | 37 ++ .../library/go/src/upgrade-dependency/main.go | 54 ++ .../examples/library/go/triage-issue/SKILL.md | 13 + .../go/triage-issue/fixtures/responses.json | 7 + .../library/go/triage-issue/skill.json | 7 + .../library/go/upgrade-dependency/SKILL.md | 13 + .../fixtures/responses.json | 10 + .../library/go/upgrade-dependency/skill.json | 7 + .../library/python/audit-security/SKILL.md | 13 + .../audit-security/fixtures/responses.json | 7 + .../library/python/audit-security/skill.json | 6 + .../python/investigate-failure/SKILL.md | 13 + .../fixtures/responses.json | 7 + .../python/investigate-failure/skill.json | 6 + .../library/python/migrate-database/SKILL.md | 13 + .../migrate-database/fixtures/responses.json | 10 + .../python/migrate-database/skill.json | 6 + .../library/python/publish-ios/SKILL.md | 13 + .../publish-ios/fixtures/responses.json | 10 + .../library/python/publish-ios/skill.json | 6 + .../library/python/qa-web-change/SKILL.md | 13 + .../qa-web-change/fixtures/responses.json | 7 + .../library/python/qa-web-change/skill.json | 6 + .../library/python/release-package/SKILL.md | 13 + .../release-package/fixtures/responses.json | 10 + .../library/python/release-package/skill.json | 6 + .../library/python/repair-ci/SKILL.md | 13 + .../python/repair-ci/fixtures/responses.json | 7 + .../library/python/repair-ci/skill.json | 6 + .../library/python/review-branch/SKILL.md | 13 + .../review-branch/fixtures/responses.json | 7 + .../library/python/review-branch/skill.json | 6 + .../library/python/src/audit-security.py | 47 ++ .../library/python/src/investigate-failure.py | 47 ++ .../library/python/src/migrate-database.py | 61 ++ .../library/python/src/publish-ios.py | 61 ++ .../library/python/src/qa-web-change.py | 47 ++ .../library/python/src/release-package.py | 61 ++ .../examples/library/python/src/repair-ci.py | 53 ++ .../library/python/src/review-branch.py | 47 ++ .../library/python/src/triage-issue.py | 47 ++ .../library/python/src/upgrade-dependency.py | 61 ++ .../library/python/triage-issue/SKILL.md | 13 + .../triage-issue/fixtures/responses.json | 7 + .../library/python/triage-issue/skill.json | 6 + .../python/upgrade-dependency/SKILL.md | 13 + .../fixtures/responses.json | 10 + .../python/upgrade-dependency/skill.json | 6 + .../yield/examples/library/rust/Cargo.lock | 206 +++++++ .../yield/examples/library/rust/Cargo.toml | 9 + .../library/rust/audit-security/SKILL.md | 13 + .../audit-security/fixtures/responses.json | 7 + .../library/rust/audit-security/skill.json | 11 + .../library/rust/investigate-failure/SKILL.md | 13 + .../fixtures/responses.json | 7 + .../rust/investigate-failure/skill.json | 11 + .../library/rust/migrate-database/SKILL.md | 13 + .../migrate-database/fixtures/responses.json | 10 + .../library/rust/migrate-database/skill.json | 11 + .../library/rust/publish-ios/SKILL.md | 13 + .../rust/publish-ios/fixtures/responses.json | 10 + .../library/rust/publish-ios/skill.json | 11 + .../library/rust/qa-web-change/SKILL.md | 13 + .../qa-web-change/fixtures/responses.json | 7 + .../library/rust/qa-web-change/skill.json | 11 + .../library/rust/release-package/SKILL.md | 13 + .../release-package/fixtures/responses.json | 10 + .../library/rust/release-package/skill.json | 11 + .../examples/library/rust/repair-ci/SKILL.md | 13 + .../rust/repair-ci/fixtures/responses.json | 7 + .../library/rust/repair-ci/skill.json | 11 + .../library/rust/review-branch/SKILL.md | 13 + .../review-branch/fixtures/responses.json | 7 + .../library/rust/review-branch/skill.json | 11 + .../library/rust/src/bin/audit-security.rs | 38 ++ .../rust/src/bin/investigate-failure.rs | 38 ++ .../library/rust/src/bin/migrate-database.rs | 65 ++ .../library/rust/src/bin/publish-ios.rs | 65 ++ .../library/rust/src/bin/qa-web-change.rs | 38 ++ .../library/rust/src/bin/release-package.rs | 61 ++ .../library/rust/src/bin/repair-ci.rs | 56 ++ .../library/rust/src/bin/review-branch.rs | 38 ++ .../library/rust/src/bin/triage-issue.rs | 38 ++ .../rust/src/bin/upgrade-dependency.rs | 61 ++ .../library/rust/triage-issue/SKILL.md | 13 + .../rust/triage-issue/fixtures/responses.json | 7 + .../library/rust/triage-issue/skill.json | 11 + .../library/rust/upgrade-dependency/SKILL.md | 13 + .../fixtures/responses.json | 10 + .../rust/upgrade-dependency/skill.json | 11 + .../examples/library/scripts/generate.mjs | 558 ++++++++++++++++++ .../yield/examples/library/test-all.sh | 22 + .../typescript/audit-security/SKILL.md | 13 + .../audit-security/fixtures/responses.json | 7 + .../typescript/audit-security/skill.json | 6 + .../typescript/investigate-failure/SKILL.md | 13 + .../fixtures/responses.json | 7 + .../typescript/investigate-failure/skill.json | 6 + .../typescript/migrate-database/SKILL.md | 13 + .../migrate-database/fixtures/responses.json | 10 + .../typescript/migrate-database/skill.json | 6 + .../library/typescript/publish-ios/SKILL.md | 13 + .../publish-ios/fixtures/responses.json | 10 + .../library/typescript/publish-ios/skill.json | 6 + .../library/typescript/qa-web-change/SKILL.md | 13 + .../qa-web-change/fixtures/responses.json | 7 + .../typescript/qa-web-change/skill.json | 6 + .../typescript/release-package/SKILL.md | 13 + .../release-package/fixtures/responses.json | 10 + .../typescript/release-package/skill.json | 6 + .../library/typescript/repair-ci/SKILL.md | 13 + .../repair-ci/fixtures/responses.json | 7 + .../library/typescript/repair-ci/skill.json | 6 + .../library/typescript/review-branch/SKILL.md | 13 + .../review-branch/fixtures/responses.json | 7 + .../typescript/review-branch/skill.json | 6 + .../library/typescript/src/audit-security.ts | 43 ++ .../typescript/src/investigate-failure.ts | 43 ++ .../typescript/src/migrate-database.ts | 55 ++ .../library/typescript/src/publish-ios.ts | 55 ++ .../library/typescript/src/qa-web-change.ts | 43 ++ .../library/typescript/src/release-package.ts | 55 ++ .../library/typescript/src/repair-ci.ts | 49 ++ .../library/typescript/src/review-branch.ts | 43 ++ .../library/typescript/src/triage-issue.ts | 43 ++ .../typescript/src/upgrade-dependency.ts | 55 ++ .../library/typescript/triage-issue/SKILL.md | 13 + .../triage-issue/fixtures/responses.json | 7 + .../typescript/triage-issue/skill.json | 6 + .../typescript/upgrade-dependency/SKILL.md | 13 + .../fixtures/responses.json | 10 + .../typescript/upgrade-dependency/skill.json | 6 + 171 files changed, 4127 insertions(+), 8 deletions(-) create mode 100644 labs/22-yield/distribution/release-notes/2026-08-01-example-library.md create mode 100644 labs/22-yield/yield/docs/examples.md create mode 100644 labs/22-yield/yield/examples/library/README.md create mode 100644 labs/22-yield/yield/examples/library/catalog.json create mode 100644 labs/22-yield/yield/examples/library/go/audit-security/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/go/audit-security/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/go/audit-security/skill.json create mode 100644 labs/22-yield/yield/examples/library/go/investigate-failure/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/go/investigate-failure/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/go/investigate-failure/skill.json create mode 100644 labs/22-yield/yield/examples/library/go/migrate-database/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/go/migrate-database/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/go/migrate-database/skill.json create mode 100644 labs/22-yield/yield/examples/library/go/publish-ios/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/go/publish-ios/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/go/publish-ios/skill.json create mode 100644 labs/22-yield/yield/examples/library/go/qa-web-change/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/go/qa-web-change/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/go/qa-web-change/skill.json create mode 100644 labs/22-yield/yield/examples/library/go/release-package/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/go/release-package/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/go/release-package/skill.json create mode 100644 labs/22-yield/yield/examples/library/go/repair-ci/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/go/repair-ci/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/go/repair-ci/skill.json create mode 100644 labs/22-yield/yield/examples/library/go/review-branch/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/go/review-branch/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/go/review-branch/skill.json create mode 100644 labs/22-yield/yield/examples/library/go/src/audit-security/main.go create mode 100644 labs/22-yield/yield/examples/library/go/src/investigate-failure/main.go create mode 100644 labs/22-yield/yield/examples/library/go/src/migrate-database/main.go create mode 100644 labs/22-yield/yield/examples/library/go/src/publish-ios/main.go create mode 100644 labs/22-yield/yield/examples/library/go/src/qa-web-change/main.go create mode 100644 labs/22-yield/yield/examples/library/go/src/release-package/main.go create mode 100644 labs/22-yield/yield/examples/library/go/src/repair-ci/main.go create mode 100644 labs/22-yield/yield/examples/library/go/src/review-branch/main.go create mode 100644 labs/22-yield/yield/examples/library/go/src/triage-issue/main.go create mode 100644 labs/22-yield/yield/examples/library/go/src/upgrade-dependency/main.go create mode 100644 labs/22-yield/yield/examples/library/go/triage-issue/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/go/triage-issue/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/go/triage-issue/skill.json create mode 100644 labs/22-yield/yield/examples/library/go/upgrade-dependency/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/go/upgrade-dependency/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/go/upgrade-dependency/skill.json create mode 100644 labs/22-yield/yield/examples/library/python/audit-security/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/python/audit-security/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/python/audit-security/skill.json create mode 100644 labs/22-yield/yield/examples/library/python/investigate-failure/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/python/investigate-failure/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/python/investigate-failure/skill.json create mode 100644 labs/22-yield/yield/examples/library/python/migrate-database/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/python/migrate-database/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/python/migrate-database/skill.json create mode 100644 labs/22-yield/yield/examples/library/python/publish-ios/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/python/publish-ios/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/python/publish-ios/skill.json create mode 100644 labs/22-yield/yield/examples/library/python/qa-web-change/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/python/qa-web-change/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/python/qa-web-change/skill.json create mode 100644 labs/22-yield/yield/examples/library/python/release-package/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/python/release-package/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/python/release-package/skill.json create mode 100644 labs/22-yield/yield/examples/library/python/repair-ci/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/python/repair-ci/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/python/repair-ci/skill.json create mode 100644 labs/22-yield/yield/examples/library/python/review-branch/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/python/review-branch/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/python/review-branch/skill.json create mode 100644 labs/22-yield/yield/examples/library/python/src/audit-security.py create mode 100644 labs/22-yield/yield/examples/library/python/src/investigate-failure.py create mode 100644 labs/22-yield/yield/examples/library/python/src/migrate-database.py create mode 100644 labs/22-yield/yield/examples/library/python/src/publish-ios.py create mode 100644 labs/22-yield/yield/examples/library/python/src/qa-web-change.py create mode 100644 labs/22-yield/yield/examples/library/python/src/release-package.py create mode 100644 labs/22-yield/yield/examples/library/python/src/repair-ci.py create mode 100644 labs/22-yield/yield/examples/library/python/src/review-branch.py create mode 100644 labs/22-yield/yield/examples/library/python/src/triage-issue.py create mode 100644 labs/22-yield/yield/examples/library/python/src/upgrade-dependency.py create mode 100644 labs/22-yield/yield/examples/library/python/triage-issue/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/python/triage-issue/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/python/triage-issue/skill.json create mode 100644 labs/22-yield/yield/examples/library/python/upgrade-dependency/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/python/upgrade-dependency/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/python/upgrade-dependency/skill.json create mode 100644 labs/22-yield/yield/examples/library/rust/Cargo.lock create mode 100644 labs/22-yield/yield/examples/library/rust/Cargo.toml create mode 100644 labs/22-yield/yield/examples/library/rust/audit-security/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/rust/audit-security/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/rust/audit-security/skill.json create mode 100644 labs/22-yield/yield/examples/library/rust/investigate-failure/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/rust/investigate-failure/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/rust/investigate-failure/skill.json create mode 100644 labs/22-yield/yield/examples/library/rust/migrate-database/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/rust/migrate-database/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/rust/migrate-database/skill.json create mode 100644 labs/22-yield/yield/examples/library/rust/publish-ios/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/rust/publish-ios/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/rust/publish-ios/skill.json create mode 100644 labs/22-yield/yield/examples/library/rust/qa-web-change/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/rust/qa-web-change/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/rust/qa-web-change/skill.json create mode 100644 labs/22-yield/yield/examples/library/rust/release-package/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/rust/release-package/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/rust/release-package/skill.json create mode 100644 labs/22-yield/yield/examples/library/rust/repair-ci/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/rust/repair-ci/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/rust/repair-ci/skill.json create mode 100644 labs/22-yield/yield/examples/library/rust/review-branch/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/rust/review-branch/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/rust/review-branch/skill.json create mode 100644 labs/22-yield/yield/examples/library/rust/src/bin/audit-security.rs create mode 100644 labs/22-yield/yield/examples/library/rust/src/bin/investigate-failure.rs create mode 100644 labs/22-yield/yield/examples/library/rust/src/bin/migrate-database.rs create mode 100644 labs/22-yield/yield/examples/library/rust/src/bin/publish-ios.rs create mode 100644 labs/22-yield/yield/examples/library/rust/src/bin/qa-web-change.rs create mode 100644 labs/22-yield/yield/examples/library/rust/src/bin/release-package.rs create mode 100644 labs/22-yield/yield/examples/library/rust/src/bin/repair-ci.rs create mode 100644 labs/22-yield/yield/examples/library/rust/src/bin/review-branch.rs create mode 100644 labs/22-yield/yield/examples/library/rust/src/bin/triage-issue.rs create mode 100644 labs/22-yield/yield/examples/library/rust/src/bin/upgrade-dependency.rs create mode 100644 labs/22-yield/yield/examples/library/rust/triage-issue/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/rust/triage-issue/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/rust/triage-issue/skill.json create mode 100644 labs/22-yield/yield/examples/library/rust/upgrade-dependency/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/rust/upgrade-dependency/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/rust/upgrade-dependency/skill.json create mode 100644 labs/22-yield/yield/examples/library/scripts/generate.mjs create mode 100755 labs/22-yield/yield/examples/library/test-all.sh create mode 100644 labs/22-yield/yield/examples/library/typescript/audit-security/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/typescript/audit-security/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/typescript/audit-security/skill.json create mode 100644 labs/22-yield/yield/examples/library/typescript/investigate-failure/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/typescript/investigate-failure/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/typescript/investigate-failure/skill.json create mode 100644 labs/22-yield/yield/examples/library/typescript/migrate-database/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/typescript/migrate-database/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/typescript/migrate-database/skill.json create mode 100644 labs/22-yield/yield/examples/library/typescript/publish-ios/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/typescript/publish-ios/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/typescript/publish-ios/skill.json create mode 100644 labs/22-yield/yield/examples/library/typescript/qa-web-change/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/typescript/qa-web-change/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/typescript/qa-web-change/skill.json create mode 100644 labs/22-yield/yield/examples/library/typescript/release-package/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/typescript/release-package/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/typescript/release-package/skill.json create mode 100644 labs/22-yield/yield/examples/library/typescript/repair-ci/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/typescript/repair-ci/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/typescript/repair-ci/skill.json create mode 100644 labs/22-yield/yield/examples/library/typescript/review-branch/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/typescript/review-branch/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/typescript/review-branch/skill.json create mode 100644 labs/22-yield/yield/examples/library/typescript/src/audit-security.ts create mode 100644 labs/22-yield/yield/examples/library/typescript/src/investigate-failure.ts create mode 100644 labs/22-yield/yield/examples/library/typescript/src/migrate-database.ts create mode 100644 labs/22-yield/yield/examples/library/typescript/src/publish-ios.ts create mode 100644 labs/22-yield/yield/examples/library/typescript/src/qa-web-change.ts create mode 100644 labs/22-yield/yield/examples/library/typescript/src/release-package.ts create mode 100644 labs/22-yield/yield/examples/library/typescript/src/repair-ci.ts create mode 100644 labs/22-yield/yield/examples/library/typescript/src/review-branch.ts create mode 100644 labs/22-yield/yield/examples/library/typescript/src/triage-issue.ts create mode 100644 labs/22-yield/yield/examples/library/typescript/src/upgrade-dependency.ts create mode 100644 labs/22-yield/yield/examples/library/typescript/triage-issue/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/typescript/triage-issue/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/typescript/triage-issue/skill.json create mode 100644 labs/22-yield/yield/examples/library/typescript/upgrade-dependency/SKILL.md create mode 100644 labs/22-yield/yield/examples/library/typescript/upgrade-dependency/fixtures/responses.json create mode 100644 labs/22-yield/yield/examples/library/typescript/upgrade-dependency/skill.json diff --git a/.github/workflows/yield-lab.yml b/.github/workflows/yield-lab.yml index 5b42565c..29dd423c 100644 --- a/.github/workflows/yield-lab.yml +++ b/.github/workflows/yield-lab.yml @@ -27,6 +27,7 @@ jobs: workspaces: | labs/22-yield/yield/sdk/rust labs/22-yield/yield/examples/data-migration + labs/22-yield/yield/examples/library/rust labs/22-yield/yield/internal/conformance/testdata/skill-rs - name: Vet and test (includes subprocess e2e + 4-language conformance) working-directory: labs/22-yield/yield @@ -42,6 +43,7 @@ jobs: /tmp/yskill test examples/env-doctor /tmp/yskill test examples/data-migration YSKILL=/tmp/yskill /tmp/yskill test examples/convert-skill + YSKILL=/tmp/yskill bash ./examples/library/test-all.sh # Shift-left projection gate: materialize the public surface exactly as # operatorstack/yield would receive it and compile+test it, so a broken diff --git a/labs/22-yield/README.md b/labs/22-yield/README.md index 703fb9ab..ca10436d 100644 --- a/labs/22-yield/README.md +++ b/labs/22-yield/README.md @@ -48,6 +48,7 @@ yield/ ├── sdk/typescript/ TypeScript SDK — examples/release-checklist (node main.ts) ├── sdk/python/ Python SDK — examples/env-doctor (import yieldskill) ├── sdk/rust/ Rust SDK — examples/data-migration (crate yieldskill) +├── examples/library/ 10 workflows × 4 languages, all fixture-tested └── docs/locus* certified lifecycle + SDK-contract models, verdicts, discharge ``` @@ -63,6 +64,8 @@ divergence check is a *decided* design comparison, not a convention ``` go build -o /tmp/yskill ./yield/cmd/yskill /tmp/yskill test yield/examples/investigate # scripted fixture run to completion +/tmp/yskill test yield/examples/library/typescript/review-branch +YSKILL=/tmp/yskill bash yield/examples/library/test-all.sh # all 40 language/workflow pairs /tmp/yskill run yield/examples/investigate # prints the first operation envelope ``` diff --git a/labs/22-yield/distribution/release-notes/2026-08-01-example-library.md b/labs/22-yield/distribution/release-notes/2026-08-01-example-library.md new file mode 100644 index 00000000..d39bc30c --- /dev/null +++ b/labs/22-yield/distribution/release-notes/2026-08-01-example-library.md @@ -0,0 +1,8 @@ +# Yield example library + +- Add ten common coding-agent workflow examples in TypeScript, Python, Go, + and Rust. +- Add fixture-backed validation for all forty language/workflow pairs. +- Add a generated catalog so documentation can route visitors to their + preferred language without maintaining four separate lists. +- Reframe the public entry point around starting from useful workflows. diff --git a/labs/22-yield/public-readme/README.md b/labs/22-yield/public-readme/README.md index 72963f4b..f03ba26a 100644 --- a/labs/22-yield/public-readme/README.md +++ b/labs/22-yield/public-readme/README.md @@ -6,9 +6,10 @@ resumable programs.** > The skill yields the next typed operation. The coding agent performs it > and resumes the skill. -Write control flow in Go. Yield user questions, agent tasks, and commands -to the coding agent. Resume from the result. No custom agent runtime -required — the agent only runs a CLI and follows envelopes. +Write control flow in TypeScript, Python, Go, or Rust. Yield user +questions, agent tasks, and commands to the coding agent. Resume from the +result. No custom agent runtime required — the agent only runs a CLI and +follows envelopes. A skill keeps its thin `SKILL.md` (so it works wherever skills work today) and moves the part prose loses under context pressure — order, branching, @@ -59,16 +60,26 @@ four languages and asserts identical observable protocol behavior. Non-Go skills declare their runner in `skill.json`: `{"run": ["node", "main.ts"]}`. -Already have prose skills? `examples/convert-skill` is a converter — -itself a Yield skill — that extracts the implicit flow from an existing -`SKILL.md`, asks you which language you want, has the model write the -program, and completes only when the generated skill passes its own -fixture run. A conversion that was never executed is never "done". +## Ten workflows, every language + +The [example library](examples/library/) recreates ten common coding-agent +workflows independently in all four SDKs: branch review, failure +investigation, web QA, package release, issue triage, CI repair, dependency +upgrade, database migration, security audit, and iOS publishing. + +Each language has the same workflow, a thin `SKILL.md`, and a scripted +fixture. Start from the work you already do instead of starting from a +framework tutorial. ## Try it ``` go build -o yskill ./cmd/yskill +./yskill test examples/library/typescript/review-branch +./yskill test examples/library/python/review-branch +./yskill test examples/library/go/review-branch +./yskill test examples/library/rust/review-branch +YSKILL="$PWD/yskill" bash ./examples/library/test-all.sh ./yskill test examples/investigate # Go: scripted fixture run to completion ./yskill test examples/release-checklist # TypeScript (Node >= 23.6) ./yskill test examples/env-doctor # Python 3.10+ diff --git a/labs/22-yield/yield/docs/examples.md b/labs/22-yield/yield/docs/examples.md new file mode 100644 index 00000000..de03369a --- /dev/null +++ b/labs/22-yield/yield/docs/examples.md @@ -0,0 +1,34 @@ +# Example library + +The library contains ten common coding-agent workflows. Every workflow is +implemented in TypeScript, Python, Go, and Rust, so the first choice is your +repository's language—not which example happens to exist. + +| Workflow | Control flow moved into code | +|---|---| +| [Review a branch](../examples/library/typescript/review-branch/) | checks, review, zero-critical gate | +| [Investigate a failure](../examples/library/typescript/investigate-failure/) | evidence, diagnosis, supported cause | +| [QA a web change](../examples/library/typescript/qa-web-change/) | build, changed-route QA, no-blocker gate | +| [Release a package](../examples/library/typescript/release-package/) | tests, review, approval, publish, verify | +| [Triage an issue](../examples/library/typescript/triage-issue/) | read, classify, one next action | +| [Repair CI](../examples/library/typescript/repair-ci/) | failed log, supported repair, rerun | +| [Upgrade a dependency](../examples/library/typescript/upgrade-dependency/) | baseline, compatibility review, approval, update, tests | +| [Run a database migration](../examples/library/typescript/migrate-database/) | dry-run, risk review, approval, apply, verify | +| [Audit security](../examples/library/typescript/audit-security/) | mechanical scans, trust-boundary review, zero-critical gate | +| [Publish an iOS build](../examples/library/typescript/publish-ios/) | archive, metadata review, approval, upload, processing check | + +Change the language segment in any link to python, go, or rust. Source files +are grouped separately for fast browsing: + +- [TypeScript](../examples/library/typescript/src/) +- [Python](../examples/library/python/src/) +- [Go](../examples/library/go/src/) +- [Rust](../examples/library/rust/src/bin/) + +Run all forty fixtures: + + go build -o /tmp/yskill ./cmd/yskill + YSKILL=/tmp/yskill bash ./examples/library/test-all.sh + +The included commands produce harmless evidence so the examples run in this +repository. Replace them with project commands before adopting a workflow. diff --git a/labs/22-yield/yield/examples/library/README.md b/labs/22-yield/yield/examples/library/README.md new file mode 100644 index 00000000..a34a9ac0 --- /dev/null +++ b/labs/22-yield/yield/examples/library/README.md @@ -0,0 +1,48 @@ +# Example library + +Ten common coding-agent workflows, each implemented in TypeScript, Python, +Go, and Rust. Choose the language already used by your repository; the +workflow and fixture are otherwise the same. + +| Workflow | What the code keeps in order | +|---|---| +| review-branch | checks -> review -> zero-critical gate | +| investigate-failure | evidence -> diagnosis -> supported cause | +| qa-web-change | build -> changed-route QA -> no blockers | +| release-package | tests -> review -> approval -> publish -> verify | +| triage-issue | read -> classify -> one next action | +| repair-ci | failed log -> supported repair -> rerun | +| upgrade-dependency | baseline -> compatibility review -> approval -> update -> tests | +| migrate-database | dry-run -> risk review -> approval -> apply -> verify | +| audit-security | mechanical scans -> trust-boundary review -> zero-critical gate | +| publish-ios | archive -> metadata review -> approval -> upload -> processing check | + +The source files live under: + + typescript/src/.ts + python/src/.py + go/src//main.go + rust/src/bin/.rs + +Each language also has a runnable skill directory at +language/workflow/ containing a thin SKILL.md, runner manifest, and +scripted fixture. From the repository root: + + go build -o /tmp/yskill ./cmd/yskill + YSKILL=/tmp/yskill bash ./examples/library/test-all.sh + +Or run one: + + /tmp/yskill test examples/library/typescript/review-branch + /tmp/yskill test examples/library/python/review-branch + /tmp/yskill test examples/library/go/review-branch + /tmp/yskill test examples/library/rust/review-branch + +The shell commands deliberately produce harmless fixture evidence. Replace +them with the real commands from your repository before adopting a workflow. +The examples are independent implementations of recurring skill categories; +they do not copy another project's prompts or claim compatibility with them. + +Regenerate the checked-in matrix after editing the catalog: + + node examples/library/scripts/generate.mjs diff --git a/labs/22-yield/yield/examples/library/catalog.json b/labs/22-yield/yield/examples/library/catalog.json new file mode 100644 index 00000000..6e1ad4b5 --- /dev/null +++ b/labs/22-yield/yield/examples/library/catalog.json @@ -0,0 +1,112 @@ +[ + { + "slug": "review-branch", + "title": "Review a branch", + "summary": "Run mechanical checks, inspect the diff, and stop on critical findings.", + "languages": [ + "typescript", + "python", + "go", + "rust" + ] + }, + { + "slug": "investigate-failure", + "title": "Investigate a failure", + "summary": "Capture evidence, test the likely cause, and finish only with a causal explanation.", + "languages": [ + "typescript", + "python", + "go", + "rust" + ] + }, + { + "slug": "qa-web-change", + "title": "QA a web change", + "summary": "Build first, exercise changed routes, and finish only with no blocking regressions.", + "languages": [ + "typescript", + "python", + "go", + "rust" + ] + }, + { + "slug": "release-package", + "title": "Release a package", + "summary": "Test, review the release, ask for approval, publish, and verify.", + "languages": [ + "typescript", + "python", + "go", + "rust" + ] + }, + { + "slug": "triage-issue", + "title": "Triage an issue", + "summary": "Read the report, classify impact, and return one evidence-backed next action.", + "languages": [ + "typescript", + "python", + "go", + "rust" + ] + }, + { + "slug": "repair-ci", + "title": "Repair a CI failure", + "summary": "Read the failed job, apply one supported repair, and rerun the failing check.", + "languages": [ + "typescript", + "python", + "go", + "rust" + ] + }, + { + "slug": "upgrade-dependency", + "title": "Upgrade a dependency", + "summary": "Establish a baseline, review compatibility, approve the change, and rerun tests.", + "languages": [ + "typescript", + "python", + "go", + "rust" + ] + }, + { + "slug": "migrate-database", + "title": "Run a database migration", + "summary": "Dry-run, inspect risk, approve, apply, and verify the real result.", + "languages": [ + "typescript", + "python", + "go", + "rust" + ] + }, + { + "slug": "audit-security", + "title": "Audit a change for security", + "summary": "Collect mechanical audit output, inspect trust boundaries, and reject critical risk.", + "languages": [ + "typescript", + "python", + "go", + "rust" + ] + }, + { + "slug": "publish-ios", + "title": "Publish an iOS build", + "summary": "Archive, review release metadata, approve upload, publish, and verify processing.", + "languages": [ + "typescript", + "python", + "go", + "rust" + ] + } +] diff --git a/labs/22-yield/yield/examples/library/go/audit-security/SKILL.md b/labs/22-yield/yield/examples/library/go/audit-security/SKILL.md new file mode 100644 index 00000000..f83b8e72 --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/audit-security/SKILL.md @@ -0,0 +1,13 @@ +--- +name: audit-security +description: Collect mechanical audit output, inspect trust boundaries, and reject critical risk. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/go/audit-security/fixtures/responses.json b/labs/22-yield/yield/examples/library/go/audit-security/fixtures/responses.json new file mode 100644 index 00000000..f690e022 --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/audit-security/fixtures/responses.json @@ -0,0 +1,7 @@ +{ + "review-trust-boundaries": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Collect mechanical audit output, inspect trust boundaries, and reject critical risk." + } +} diff --git a/labs/22-yield/yield/examples/library/go/audit-security/skill.json b/labs/22-yield/yield/examples/library/go/audit-security/skill.json new file mode 100644 index 00000000..8e95b8a5 --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/audit-security/skill.json @@ -0,0 +1,7 @@ +{ + "run": [ + "go", + "run", + "../src/audit-security/main.go" + ] +} diff --git a/labs/22-yield/yield/examples/library/go/investigate-failure/SKILL.md b/labs/22-yield/yield/examples/library/go/investigate-failure/SKILL.md new file mode 100644 index 00000000..62fa2c91 --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/investigate-failure/SKILL.md @@ -0,0 +1,13 @@ +--- +name: investigate-failure +description: Capture evidence, test the likely cause, and finish only with a causal explanation. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/go/investigate-failure/fixtures/responses.json b/labs/22-yield/yield/examples/library/go/investigate-failure/fixtures/responses.json new file mode 100644 index 00000000..fa01815e --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/investigate-failure/fixtures/responses.json @@ -0,0 +1,7 @@ +{ + "diagnose-cause": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Capture evidence, test the likely cause, and finish only with a causal explanation." + } +} diff --git a/labs/22-yield/yield/examples/library/go/investigate-failure/skill.json b/labs/22-yield/yield/examples/library/go/investigate-failure/skill.json new file mode 100644 index 00000000..3eec0b06 --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/investigate-failure/skill.json @@ -0,0 +1,7 @@ +{ + "run": [ + "go", + "run", + "../src/investigate-failure/main.go" + ] +} diff --git a/labs/22-yield/yield/examples/library/go/migrate-database/SKILL.md b/labs/22-yield/yield/examples/library/go/migrate-database/SKILL.md new file mode 100644 index 00000000..6acca087 --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/migrate-database/SKILL.md @@ -0,0 +1,13 @@ +--- +name: migrate-database +description: Dry-run, inspect risk, approve, apply, and verify the real result. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/go/migrate-database/fixtures/responses.json b/labs/22-yield/yield/examples/library/go/migrate-database/fixtures/responses.json new file mode 100644 index 00000000..ae5f3c7a --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/migrate-database/fixtures/responses.json @@ -0,0 +1,10 @@ +{ + "review-migration": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Dry-run, inspect risk, approve, apply, and verify the real result." + }, + "approve-migration": { + "value": "continue" + } +} diff --git a/labs/22-yield/yield/examples/library/go/migrate-database/skill.json b/labs/22-yield/yield/examples/library/go/migrate-database/skill.json new file mode 100644 index 00000000..752dae24 --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/migrate-database/skill.json @@ -0,0 +1,7 @@ +{ + "run": [ + "go", + "run", + "../src/migrate-database/main.go" + ] +} diff --git a/labs/22-yield/yield/examples/library/go/publish-ios/SKILL.md b/labs/22-yield/yield/examples/library/go/publish-ios/SKILL.md new file mode 100644 index 00000000..88e7449d --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/publish-ios/SKILL.md @@ -0,0 +1,13 @@ +--- +name: publish-ios +description: Archive, review release metadata, approve upload, publish, and verify processing. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/go/publish-ios/fixtures/responses.json b/labs/22-yield/yield/examples/library/go/publish-ios/fixtures/responses.json new file mode 100644 index 00000000..9f0d5d6e --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/publish-ios/fixtures/responses.json @@ -0,0 +1,10 @@ +{ + "review-ios-release": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Archive, review release metadata, approve upload, publish, and verify processing." + }, + "approve-ios-upload": { + "value": "continue" + } +} diff --git a/labs/22-yield/yield/examples/library/go/publish-ios/skill.json b/labs/22-yield/yield/examples/library/go/publish-ios/skill.json new file mode 100644 index 00000000..1ab9b9d0 --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/publish-ios/skill.json @@ -0,0 +1,7 @@ +{ + "run": [ + "go", + "run", + "../src/publish-ios/main.go" + ] +} diff --git a/labs/22-yield/yield/examples/library/go/qa-web-change/SKILL.md b/labs/22-yield/yield/examples/library/go/qa-web-change/SKILL.md new file mode 100644 index 00000000..533bbdf7 --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/qa-web-change/SKILL.md @@ -0,0 +1,13 @@ +--- +name: qa-web-change +description: Build first, exercise changed routes, and finish only with no blocking regressions. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/go/qa-web-change/fixtures/responses.json b/labs/22-yield/yield/examples/library/go/qa-web-change/fixtures/responses.json new file mode 100644 index 00000000..1ed3c70b --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/qa-web-change/fixtures/responses.json @@ -0,0 +1,7 @@ +{ + "test-changed-routes": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Build first, exercise changed routes, and finish only with no blocking regressions." + } +} diff --git a/labs/22-yield/yield/examples/library/go/qa-web-change/skill.json b/labs/22-yield/yield/examples/library/go/qa-web-change/skill.json new file mode 100644 index 00000000..b5fc4704 --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/qa-web-change/skill.json @@ -0,0 +1,7 @@ +{ + "run": [ + "go", + "run", + "../src/qa-web-change/main.go" + ] +} diff --git a/labs/22-yield/yield/examples/library/go/release-package/SKILL.md b/labs/22-yield/yield/examples/library/go/release-package/SKILL.md new file mode 100644 index 00000000..7429d9eb --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/release-package/SKILL.md @@ -0,0 +1,13 @@ +--- +name: release-package +description: Test, review the release, ask for approval, publish, and verify. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/go/release-package/fixtures/responses.json b/labs/22-yield/yield/examples/library/go/release-package/fixtures/responses.json new file mode 100644 index 00000000..575d24a1 --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/release-package/fixtures/responses.json @@ -0,0 +1,10 @@ +{ + "review-release": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Test, review the release, ask for approval, publish, and verify." + }, + "approve-publish": { + "value": "continue" + } +} diff --git a/labs/22-yield/yield/examples/library/go/release-package/skill.json b/labs/22-yield/yield/examples/library/go/release-package/skill.json new file mode 100644 index 00000000..14c49d95 --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/release-package/skill.json @@ -0,0 +1,7 @@ +{ + "run": [ + "go", + "run", + "../src/release-package/main.go" + ] +} diff --git a/labs/22-yield/yield/examples/library/go/repair-ci/SKILL.md b/labs/22-yield/yield/examples/library/go/repair-ci/SKILL.md new file mode 100644 index 00000000..159ee45d --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/repair-ci/SKILL.md @@ -0,0 +1,13 @@ +--- +name: repair-ci +description: Read the failed job, apply one supported repair, and rerun the failing check. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/go/repair-ci/fixtures/responses.json b/labs/22-yield/yield/examples/library/go/repair-ci/fixtures/responses.json new file mode 100644 index 00000000..f73e7fc1 --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/repair-ci/fixtures/responses.json @@ -0,0 +1,7 @@ +{ + "plan-ci-repair": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Read the failed job, apply one supported repair, and rerun the failing check." + } +} diff --git a/labs/22-yield/yield/examples/library/go/repair-ci/skill.json b/labs/22-yield/yield/examples/library/go/repair-ci/skill.json new file mode 100644 index 00000000..e2b15eed --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/repair-ci/skill.json @@ -0,0 +1,7 @@ +{ + "run": [ + "go", + "run", + "../src/repair-ci/main.go" + ] +} diff --git a/labs/22-yield/yield/examples/library/go/review-branch/SKILL.md b/labs/22-yield/yield/examples/library/go/review-branch/SKILL.md new file mode 100644 index 00000000..24b513ac --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/review-branch/SKILL.md @@ -0,0 +1,13 @@ +--- +name: review-branch +description: Run mechanical checks, inspect the diff, and stop on critical findings. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/go/review-branch/fixtures/responses.json b/labs/22-yield/yield/examples/library/go/review-branch/fixtures/responses.json new file mode 100644 index 00000000..b891fae1 --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/review-branch/fixtures/responses.json @@ -0,0 +1,7 @@ +{ + "review-diff": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Run mechanical checks, inspect the diff, and stop on critical findings." + } +} diff --git a/labs/22-yield/yield/examples/library/go/review-branch/skill.json b/labs/22-yield/yield/examples/library/go/review-branch/skill.json new file mode 100644 index 00000000..5ce6c004 --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/review-branch/skill.json @@ -0,0 +1,7 @@ +{ + "run": [ + "go", + "run", + "../src/review-branch/main.go" + ] +} diff --git a/labs/22-yield/yield/examples/library/go/src/audit-security/main.go b/labs/22-yield/yield/examples/library/go/src/audit-security/main.go new file mode 100644 index 00000000..43f75437 --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/src/audit-security/main.go @@ -0,0 +1,37 @@ +// Audit a change for security. Replace the illustrative commands with your project commands. +package main + +import ( + "encoding/json" + + "github.com/operatorstack/yield/sdk/yield" +) + +type decision struct { + Status string `json:"status"` + Critical int `json:"critical"` + Summary string `json:"summary"` +} + +const decisionSchema = `{"type":"object","required":["status","critical","summary"],"properties":{"status":{"enum":["pass","needs_work"]},"critical":{"type":"integer","minimum":0},"summary":{"type":"string","minLength":1}}}` + +func main() { + yield.Main(func(ctx *yield.Context) (yield.Outcome, error) { + preflight := ctx.RunCommand("run-security-checks", "printf 'dependency and secret scans completed\\n'", 300) + ctx.Require(preflight.ExitCode == 0, "the mechanical security checks complete", preflight) + + raw := ctx.AgentTask( + "review-trust-boundaries", + "Review authentication, authorization, input handling, secrets, and trust-boundary changes. Return pass only when no critical risk remains.", + map[string]any{"stdout": preflight.Stdout, "stderr": preflight.Stderr}, + json.RawMessage(decisionSchema), + ) + var decision decision + if err := json.Unmarshal(raw, &decision); err != nil { + return yield.Outcome{}, err + } + ctx.Require(decision.Status == "pass" && decision.Critical == 0, "the change has no critical security finding", decision) + + return ctx.Complete(map[string]any{"workflow": "audit-security", "summary": decision.Summary}) + }) +} diff --git a/labs/22-yield/yield/examples/library/go/src/investigate-failure/main.go b/labs/22-yield/yield/examples/library/go/src/investigate-failure/main.go new file mode 100644 index 00000000..3eb1b730 --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/src/investigate-failure/main.go @@ -0,0 +1,37 @@ +// Investigate a failure. Replace the illustrative commands with your project commands. +package main + +import ( + "encoding/json" + + "github.com/operatorstack/yield/sdk/yield" +) + +type decision struct { + Status string `json:"status"` + Critical int `json:"critical"` + Summary string `json:"summary"` +} + +const decisionSchema = `{"type":"object","required":["status","critical","summary"],"properties":{"status":{"enum":["pass","needs_work"]},"critical":{"type":"integer","minimum":0},"summary":{"type":"string","minLength":1}}}` + +func main() { + yield.Main(func(ctx *yield.Context) (yield.Outcome, error) { + preflight := ctx.RunCommand("capture-failure", "printf 'failing test captured with recent diff\\n'", 300) + ctx.Require(preflight.ExitCode == 0, "the failure evidence is captured", preflight) + + raw := ctx.AgentTask( + "diagnose-cause", + "Use the failure output and recent change to identify the most likely root cause. Return pass only when the summary states a causal chain.", + map[string]any{"stdout": preflight.Stdout, "stderr": preflight.Stderr}, + json.RawMessage(decisionSchema), + ) + var decision decision + if err := json.Unmarshal(raw, &decision); err != nil { + return yield.Outcome{}, err + } + ctx.Require(decision.Status == "pass" && decision.Critical == 0, "the diagnosis states a supported cause", decision) + + return ctx.Complete(map[string]any{"workflow": "investigate-failure", "summary": decision.Summary}) + }) +} diff --git a/labs/22-yield/yield/examples/library/go/src/migrate-database/main.go b/labs/22-yield/yield/examples/library/go/src/migrate-database/main.go new file mode 100644 index 00000000..ee14012b --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/src/migrate-database/main.go @@ -0,0 +1,54 @@ +// Run a database migration. Replace the illustrative commands with your project commands. +package main + +import ( + "encoding/json" + + "github.com/operatorstack/yield/internal/protocol" + "github.com/operatorstack/yield/sdk/yield" +) + +type decision struct { + Status string `json:"status"` + Critical int `json:"critical"` + Summary string `json:"summary"` +} + +const decisionSchema = `{"type":"object","required":["status","critical","summary"],"properties":{"status":{"enum":["pass","needs_work"]},"critical":{"type":"integer","minimum":0},"summary":{"type":"string","minLength":1}}}` + +func main() { + yield.Main(func(ctx *yield.Context) (yield.Outcome, error) { + preflight := ctx.RunCommand("dry-run-migration", "printf 'dry run: add users_email_idx concurrently\\n'", 300) + ctx.Require(preflight.ExitCode == 0, "the migration dry-run succeeds", preflight) + + raw := ctx.AgentTask( + "review-migration", + "Review the migration plan for lock risk, irreversible work, and rollback. Return pass only when the plan is safe to apply.", + map[string]any{"stdout": preflight.Stdout, "stderr": preflight.Stderr}, + json.RawMessage(decisionSchema), + ) + var decision decision + if err := json.Unmarshal(raw, &decision); err != nil { + return yield.Outcome{}, err + } + ctx.Require(decision.Status == "pass" && decision.Critical == 0, "the migration plan has acceptable risk", decision) + + approval := ctx.AskUser( + "approve-migration", + "Apply the reviewed database migration?", + protocol.Option{Value: "continue", Label: "Continue"}, + protocol.Option{Value: "stop", Label: "Stop"}, + ) + if approval != "continue" { + return yield.Outcome{}, ctx.Refused("the operator declined to continue") + } + + action := ctx.RunCommand("apply-migration", "printf 'migration applied\\n'", 600) + ctx.Require(action.ExitCode == 0, "the migration applies cleanly", action) + + verify := ctx.RunCommand("verify-migration", "printf 'migration verification passed\\n'", 300) + ctx.Require(verify.ExitCode == 0, "the migrated database passes verification", verify) + + return ctx.Complete(map[string]any{"workflow": "migrate-database", "summary": decision.Summary}) + }) +} diff --git a/labs/22-yield/yield/examples/library/go/src/publish-ios/main.go b/labs/22-yield/yield/examples/library/go/src/publish-ios/main.go new file mode 100644 index 00000000..321410a4 --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/src/publish-ios/main.go @@ -0,0 +1,54 @@ +// Publish an iOS build. Replace the illustrative commands with your project commands. +package main + +import ( + "encoding/json" + + "github.com/operatorstack/yield/internal/protocol" + "github.com/operatorstack/yield/sdk/yield" +) + +type decision struct { + Status string `json:"status"` + Critical int `json:"critical"` + Summary string `json:"summary"` +} + +const decisionSchema = `{"type":"object","required":["status","critical","summary"],"properties":{"status":{"enum":["pass","needs_work"]},"critical":{"type":"integer","minimum":0},"summary":{"type":"string","minLength":1}}}` + +func main() { + yield.Main(func(ctx *yield.Context) (yield.Outcome, error) { + preflight := ctx.RunCommand("archive-ios", "printf 'iOS archive and tests passed\\n'", 300) + ctx.Require(preflight.ExitCode == 0, "the iOS archive and tests pass", preflight) + + raw := ctx.AgentTask( + "review-ios-release", + "Review the iOS release metadata, versioning, privacy notes, and rollout risk. Return pass only when the build is ready for upload.", + map[string]any{"stdout": preflight.Stdout, "stderr": preflight.Stderr}, + json.RawMessage(decisionSchema), + ) + var decision decision + if err := json.Unmarshal(raw, &decision); err != nil { + return yield.Outcome{}, err + } + ctx.Require(decision.Status == "pass" && decision.Critical == 0, "the iOS build is ready for upload", decision) + + approval := ctx.AskUser( + "approve-ios-upload", + "Upload this iOS build to App Store Connect?", + protocol.Option{Value: "continue", Label: "Continue"}, + protocol.Option{Value: "stop", Label: "Stop"}, + ) + if approval != "continue" { + return yield.Outcome{}, ctx.Refused("the operator declined to continue") + } + + action := ctx.RunCommand("upload-ios", "printf 'iOS build uploaded\\n'", 600) + ctx.Require(action.ExitCode == 0, "the iOS upload command succeeds", action) + + verify := ctx.RunCommand("verify-ios-processing", "printf 'uploaded build entered processing\\n'", 300) + ctx.Require(verify.ExitCode == 0, "the uploaded iOS build entered processing", verify) + + return ctx.Complete(map[string]any{"workflow": "publish-ios", "summary": decision.Summary}) + }) +} diff --git a/labs/22-yield/yield/examples/library/go/src/qa-web-change/main.go b/labs/22-yield/yield/examples/library/go/src/qa-web-change/main.go new file mode 100644 index 00000000..b5b22edc --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/src/qa-web-change/main.go @@ -0,0 +1,37 @@ +// QA a web change. Replace the illustrative commands with your project commands. +package main + +import ( + "encoding/json" + + "github.com/operatorstack/yield/sdk/yield" +) + +type decision struct { + Status string `json:"status"` + Critical int `json:"critical"` + Summary string `json:"summary"` +} + +const decisionSchema = `{"type":"object","required":["status","critical","summary"],"properties":{"status":{"enum":["pass","needs_work"]},"critical":{"type":"integer","minimum":0},"summary":{"type":"string","minLength":1}}}` + +func main() { + yield.Main(func(ctx *yield.Context) (yield.Outcome, error) { + preflight := ctx.RunCommand("build-web", "printf 'build passed; changed routes: / and /settings\\n'", 300) + ctx.Require(preflight.ExitCode == 0, "the web application builds", preflight) + + raw := ctx.AgentTask( + "test-changed-routes", + "Test the changed routes at desktop and mobile sizes, including keyboard navigation and form errors. Return pass only when no blocking regression remains.", + map[string]any{"stdout": preflight.Stdout, "stderr": preflight.Stderr}, + json.RawMessage(decisionSchema), + ) + var decision decision + if err := json.Unmarshal(raw, &decision); err != nil { + return yield.Outcome{}, err + } + ctx.Require(decision.Status == "pass" && decision.Critical == 0, "the changed routes have no blocking regression", decision) + + return ctx.Complete(map[string]any{"workflow": "qa-web-change", "summary": decision.Summary}) + }) +} diff --git a/labs/22-yield/yield/examples/library/go/src/release-package/main.go b/labs/22-yield/yield/examples/library/go/src/release-package/main.go new file mode 100644 index 00000000..b433da87 --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/src/release-package/main.go @@ -0,0 +1,54 @@ +// Release a package. Replace the illustrative commands with your project commands. +package main + +import ( + "encoding/json" + + "github.com/operatorstack/yield/internal/protocol" + "github.com/operatorstack/yield/sdk/yield" +) + +type decision struct { + Status string `json:"status"` + Critical int `json:"critical"` + Summary string `json:"summary"` +} + +const decisionSchema = `{"type":"object","required":["status","critical","summary"],"properties":{"status":{"enum":["pass","needs_work"]},"critical":{"type":"integer","minimum":0},"summary":{"type":"string","minLength":1}}}` + +func main() { + yield.Main(func(ctx *yield.Context) (yield.Outcome, error) { + preflight := ctx.RunCommand("test-package", "printf 'package tests passed\\n'", 300) + ctx.Require(preflight.ExitCode == 0, "the package tests pass", preflight) + + raw := ctx.AgentTask( + "review-release", + "Review the pending package release for breaking changes, missing notes, and rollback risk. Return pass only when it is ready to publish.", + map[string]any{"stdout": preflight.Stdout, "stderr": preflight.Stderr}, + json.RawMessage(decisionSchema), + ) + var decision decision + if err := json.Unmarshal(raw, &decision); err != nil { + return yield.Outcome{}, err + } + ctx.Require(decision.Status == "pass" && decision.Critical == 0, "the package is ready to publish", decision) + + approval := ctx.AskUser( + "approve-publish", + "Publish this package release?", + protocol.Option{Value: "continue", Label: "Continue"}, + protocol.Option{Value: "stop", Label: "Stop"}, + ) + if approval != "continue" { + return yield.Outcome{}, ctx.Refused("the operator declined to continue") + } + + action := ctx.RunCommand("publish-package", "printf 'package published\\n'", 600) + ctx.Require(action.ExitCode == 0, "the package publish command succeeds", action) + + verify := ctx.RunCommand("verify-package", "printf 'published package resolved from registry\\n'", 300) + ctx.Require(verify.ExitCode == 0, "the published package resolves from the registry", verify) + + return ctx.Complete(map[string]any{"workflow": "release-package", "summary": decision.Summary}) + }) +} diff --git a/labs/22-yield/yield/examples/library/go/src/repair-ci/main.go b/labs/22-yield/yield/examples/library/go/src/repair-ci/main.go new file mode 100644 index 00000000..8e93f825 --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/src/repair-ci/main.go @@ -0,0 +1,43 @@ +// Repair a CI failure. Replace the illustrative commands with your project commands. +package main + +import ( + "encoding/json" + + "github.com/operatorstack/yield/sdk/yield" +) + +type decision struct { + Status string `json:"status"` + Critical int `json:"critical"` + Summary string `json:"summary"` +} + +const decisionSchema = `{"type":"object","required":["status","critical","summary"],"properties":{"status":{"enum":["pass","needs_work"]},"critical":{"type":"integer","minimum":0},"summary":{"type":"string","minLength":1}}}` + +func main() { + yield.Main(func(ctx *yield.Context) (yield.Outcome, error) { + preflight := ctx.RunCommand("capture-ci-log", "printf 'ci log: test shard 2 failed after cache restore\\n'", 300) + ctx.Require(preflight.ExitCode == 0, "the failing CI evidence is captured", preflight) + + raw := ctx.AgentTask( + "plan-ci-repair", + "Diagnose the CI failure and describe the smallest supported repair. Return pass only when the repair is tied to the observed log.", + map[string]any{"stdout": preflight.Stdout, "stderr": preflight.Stderr}, + json.RawMessage(decisionSchema), + ) + var decision decision + if err := json.Unmarshal(raw, &decision); err != nil { + return yield.Outcome{}, err + } + ctx.Require(decision.Status == "pass" && decision.Critical == 0, "the CI repair is supported by the failure evidence", decision) + + action := ctx.RunCommand("apply-ci-repair", "printf 'ci repair applied\\n'", 600) + ctx.Require(action.ExitCode == 0, "the CI repair command succeeds", action) + + verify := ctx.RunCommand("rerun-ci-check", "printf 'failing CI check now passes\\n'", 300) + ctx.Require(verify.ExitCode == 0, "the previously failing CI check passes", verify) + + return ctx.Complete(map[string]any{"workflow": "repair-ci", "summary": decision.Summary}) + }) +} diff --git a/labs/22-yield/yield/examples/library/go/src/review-branch/main.go b/labs/22-yield/yield/examples/library/go/src/review-branch/main.go new file mode 100644 index 00000000..7d274784 --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/src/review-branch/main.go @@ -0,0 +1,37 @@ +// Review a branch. Replace the illustrative commands with your project commands. +package main + +import ( + "encoding/json" + + "github.com/operatorstack/yield/sdk/yield" +) + +type decision struct { + Status string `json:"status"` + Critical int `json:"critical"` + Summary string `json:"summary"` +} + +const decisionSchema = `{"type":"object","required":["status","critical","summary"],"properties":{"status":{"enum":["pass","needs_work"]},"critical":{"type":"integer","minimum":0},"summary":{"type":"string","minLength":1}}}` + +func main() { + yield.Main(func(ctx *yield.Context) (yield.Outcome, error) { + preflight := ctx.RunCommand("check-branch", "printf 'typecheck and tests passed\\n'", 300) + ctx.Require(preflight.ExitCode == 0, "the branch passes mechanical checks", preflight) + + raw := ctx.AgentTask( + "review-diff", + "Review the branch for correctness, security, data-loss risks, and missing tests. Return pass only when no critical finding remains.", + map[string]any{"stdout": preflight.Stdout, "stderr": preflight.Stderr}, + json.RawMessage(decisionSchema), + ) + var decision decision + if err := json.Unmarshal(raw, &decision); err != nil { + return yield.Outcome{}, err + } + ctx.Require(decision.Status == "pass" && decision.Critical == 0, "the review has no critical findings", decision) + + return ctx.Complete(map[string]any{"workflow": "review-branch", "summary": decision.Summary}) + }) +} diff --git a/labs/22-yield/yield/examples/library/go/src/triage-issue/main.go b/labs/22-yield/yield/examples/library/go/src/triage-issue/main.go new file mode 100644 index 00000000..c54913e6 --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/src/triage-issue/main.go @@ -0,0 +1,37 @@ +// Triage an issue. Replace the illustrative commands with your project commands. +package main + +import ( + "encoding/json" + + "github.com/operatorstack/yield/sdk/yield" +) + +type decision struct { + Status string `json:"status"` + Critical int `json:"critical"` + Summary string `json:"summary"` +} + +const decisionSchema = `{"type":"object","required":["status","critical","summary"],"properties":{"status":{"enum":["pass","needs_work"]},"critical":{"type":"integer","minimum":0},"summary":{"type":"string","minLength":1}}}` + +func main() { + yield.Main(func(ctx *yield.Context) (yield.Outcome, error) { + preflight := ctx.RunCommand("read-issue", "printf 'issue: intermittent timeout after retry change\\n'", 300) + ctx.Require(preflight.ExitCode == 0, "the issue report is available", preflight) + + raw := ctx.AgentTask( + "classify-issue", + "Classify severity, identify missing evidence, and propose exactly one next action. Return pass only when the summary is actionable.", + map[string]any{"stdout": preflight.Stdout, "stderr": preflight.Stderr}, + json.RawMessage(decisionSchema), + ) + var decision decision + if err := json.Unmarshal(raw, &decision); err != nil { + return yield.Outcome{}, err + } + ctx.Require(decision.Status == "pass" && decision.Critical == 0, "the issue has one actionable next step", decision) + + return ctx.Complete(map[string]any{"workflow": "triage-issue", "summary": decision.Summary}) + }) +} diff --git a/labs/22-yield/yield/examples/library/go/src/upgrade-dependency/main.go b/labs/22-yield/yield/examples/library/go/src/upgrade-dependency/main.go new file mode 100644 index 00000000..06a43f76 --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/src/upgrade-dependency/main.go @@ -0,0 +1,54 @@ +// Upgrade a dependency. Replace the illustrative commands with your project commands. +package main + +import ( + "encoding/json" + + "github.com/operatorstack/yield/internal/protocol" + "github.com/operatorstack/yield/sdk/yield" +) + +type decision struct { + Status string `json:"status"` + Critical int `json:"critical"` + Summary string `json:"summary"` +} + +const decisionSchema = `{"type":"object","required":["status","critical","summary"],"properties":{"status":{"enum":["pass","needs_work"]},"critical":{"type":"integer","minimum":0},"summary":{"type":"string","minLength":1}}}` + +func main() { + yield.Main(func(ctx *yield.Context) (yield.Outcome, error) { + preflight := ctx.RunCommand("baseline-tests", "printf 'baseline tests passed\\n'", 300) + ctx.Require(preflight.ExitCode == 0, "the baseline tests pass", preflight) + + raw := ctx.AgentTask( + "review-upgrade", + "Review the dependency upgrade for API changes, migration work, and rollback risk. Return pass only when the change is bounded.", + map[string]any{"stdout": preflight.Stdout, "stderr": preflight.Stderr}, + json.RawMessage(decisionSchema), + ) + var decision decision + if err := json.Unmarshal(raw, &decision); err != nil { + return yield.Outcome{}, err + } + ctx.Require(decision.Status == "pass" && decision.Critical == 0, "the dependency upgrade has a bounded plan", decision) + + approval := ctx.AskUser( + "approve-upgrade", + "Apply the reviewed dependency upgrade?", + protocol.Option{Value: "continue", Label: "Continue"}, + protocol.Option{Value: "stop", Label: "Stop"}, + ) + if approval != "continue" { + return yield.Outcome{}, ctx.Refused("the operator declined to continue") + } + + action := ctx.RunCommand("apply-upgrade", "printf 'dependency upgraded\\n'", 600) + ctx.Require(action.ExitCode == 0, "the dependency upgrade command succeeds", action) + + verify := ctx.RunCommand("post-upgrade-tests", "printf 'post-upgrade tests passed\\n'", 300) + ctx.Require(verify.ExitCode == 0, "the tests pass after the dependency upgrade", verify) + + return ctx.Complete(map[string]any{"workflow": "upgrade-dependency", "summary": decision.Summary}) + }) +} diff --git a/labs/22-yield/yield/examples/library/go/triage-issue/SKILL.md b/labs/22-yield/yield/examples/library/go/triage-issue/SKILL.md new file mode 100644 index 00000000..82dee14e --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/triage-issue/SKILL.md @@ -0,0 +1,13 @@ +--- +name: triage-issue +description: Read the report, classify impact, and return one evidence-backed next action. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/go/triage-issue/fixtures/responses.json b/labs/22-yield/yield/examples/library/go/triage-issue/fixtures/responses.json new file mode 100644 index 00000000..3462c970 --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/triage-issue/fixtures/responses.json @@ -0,0 +1,7 @@ +{ + "classify-issue": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Read the report, classify impact, and return one evidence-backed next action." + } +} diff --git a/labs/22-yield/yield/examples/library/go/triage-issue/skill.json b/labs/22-yield/yield/examples/library/go/triage-issue/skill.json new file mode 100644 index 00000000..748427d8 --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/triage-issue/skill.json @@ -0,0 +1,7 @@ +{ + "run": [ + "go", + "run", + "../src/triage-issue/main.go" + ] +} diff --git a/labs/22-yield/yield/examples/library/go/upgrade-dependency/SKILL.md b/labs/22-yield/yield/examples/library/go/upgrade-dependency/SKILL.md new file mode 100644 index 00000000..c40615fb --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/upgrade-dependency/SKILL.md @@ -0,0 +1,13 @@ +--- +name: upgrade-dependency +description: Establish a baseline, review compatibility, approve the change, and rerun tests. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/go/upgrade-dependency/fixtures/responses.json b/labs/22-yield/yield/examples/library/go/upgrade-dependency/fixtures/responses.json new file mode 100644 index 00000000..2f311f80 --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/upgrade-dependency/fixtures/responses.json @@ -0,0 +1,10 @@ +{ + "review-upgrade": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Establish a baseline, review compatibility, approve the change, and rerun tests." + }, + "approve-upgrade": { + "value": "continue" + } +} diff --git a/labs/22-yield/yield/examples/library/go/upgrade-dependency/skill.json b/labs/22-yield/yield/examples/library/go/upgrade-dependency/skill.json new file mode 100644 index 00000000..9e25f22f --- /dev/null +++ b/labs/22-yield/yield/examples/library/go/upgrade-dependency/skill.json @@ -0,0 +1,7 @@ +{ + "run": [ + "go", + "run", + "../src/upgrade-dependency/main.go" + ] +} diff --git a/labs/22-yield/yield/examples/library/python/audit-security/SKILL.md b/labs/22-yield/yield/examples/library/python/audit-security/SKILL.md new file mode 100644 index 00000000..f83b8e72 --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/audit-security/SKILL.md @@ -0,0 +1,13 @@ +--- +name: audit-security +description: Collect mechanical audit output, inspect trust boundaries, and reject critical risk. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/python/audit-security/fixtures/responses.json b/labs/22-yield/yield/examples/library/python/audit-security/fixtures/responses.json new file mode 100644 index 00000000..f690e022 --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/audit-security/fixtures/responses.json @@ -0,0 +1,7 @@ +{ + "review-trust-boundaries": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Collect mechanical audit output, inspect trust boundaries, and reject critical risk." + } +} diff --git a/labs/22-yield/yield/examples/library/python/audit-security/skill.json b/labs/22-yield/yield/examples/library/python/audit-security/skill.json new file mode 100644 index 00000000..e5e59ab7 --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/audit-security/skill.json @@ -0,0 +1,6 @@ +{ + "run": [ + "python3", + "../src/audit-security.py" + ] +} diff --git a/labs/22-yield/yield/examples/library/python/investigate-failure/SKILL.md b/labs/22-yield/yield/examples/library/python/investigate-failure/SKILL.md new file mode 100644 index 00000000..62fa2c91 --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/investigate-failure/SKILL.md @@ -0,0 +1,13 @@ +--- +name: investigate-failure +description: Capture evidence, test the likely cause, and finish only with a causal explanation. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/python/investigate-failure/fixtures/responses.json b/labs/22-yield/yield/examples/library/python/investigate-failure/fixtures/responses.json new file mode 100644 index 00000000..fa01815e --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/investigate-failure/fixtures/responses.json @@ -0,0 +1,7 @@ +{ + "diagnose-cause": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Capture evidence, test the likely cause, and finish only with a causal explanation." + } +} diff --git a/labs/22-yield/yield/examples/library/python/investigate-failure/skill.json b/labs/22-yield/yield/examples/library/python/investigate-failure/skill.json new file mode 100644 index 00000000..c1c33c35 --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/investigate-failure/skill.json @@ -0,0 +1,6 @@ +{ + "run": [ + "python3", + "../src/investigate-failure.py" + ] +} diff --git a/labs/22-yield/yield/examples/library/python/migrate-database/SKILL.md b/labs/22-yield/yield/examples/library/python/migrate-database/SKILL.md new file mode 100644 index 00000000..6acca087 --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/migrate-database/SKILL.md @@ -0,0 +1,13 @@ +--- +name: migrate-database +description: Dry-run, inspect risk, approve, apply, and verify the real result. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/python/migrate-database/fixtures/responses.json b/labs/22-yield/yield/examples/library/python/migrate-database/fixtures/responses.json new file mode 100644 index 00000000..ae5f3c7a --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/migrate-database/fixtures/responses.json @@ -0,0 +1,10 @@ +{ + "review-migration": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Dry-run, inspect risk, approve, apply, and verify the real result." + }, + "approve-migration": { + "value": "continue" + } +} diff --git a/labs/22-yield/yield/examples/library/python/migrate-database/skill.json b/labs/22-yield/yield/examples/library/python/migrate-database/skill.json new file mode 100644 index 00000000..db517239 --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/migrate-database/skill.json @@ -0,0 +1,6 @@ +{ + "run": [ + "python3", + "../src/migrate-database.py" + ] +} diff --git a/labs/22-yield/yield/examples/library/python/publish-ios/SKILL.md b/labs/22-yield/yield/examples/library/python/publish-ios/SKILL.md new file mode 100644 index 00000000..88e7449d --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/publish-ios/SKILL.md @@ -0,0 +1,13 @@ +--- +name: publish-ios +description: Archive, review release metadata, approve upload, publish, and verify processing. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/python/publish-ios/fixtures/responses.json b/labs/22-yield/yield/examples/library/python/publish-ios/fixtures/responses.json new file mode 100644 index 00000000..9f0d5d6e --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/publish-ios/fixtures/responses.json @@ -0,0 +1,10 @@ +{ + "review-ios-release": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Archive, review release metadata, approve upload, publish, and verify processing." + }, + "approve-ios-upload": { + "value": "continue" + } +} diff --git a/labs/22-yield/yield/examples/library/python/publish-ios/skill.json b/labs/22-yield/yield/examples/library/python/publish-ios/skill.json new file mode 100644 index 00000000..efad712d --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/publish-ios/skill.json @@ -0,0 +1,6 @@ +{ + "run": [ + "python3", + "../src/publish-ios.py" + ] +} diff --git a/labs/22-yield/yield/examples/library/python/qa-web-change/SKILL.md b/labs/22-yield/yield/examples/library/python/qa-web-change/SKILL.md new file mode 100644 index 00000000..533bbdf7 --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/qa-web-change/SKILL.md @@ -0,0 +1,13 @@ +--- +name: qa-web-change +description: Build first, exercise changed routes, and finish only with no blocking regressions. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/python/qa-web-change/fixtures/responses.json b/labs/22-yield/yield/examples/library/python/qa-web-change/fixtures/responses.json new file mode 100644 index 00000000..1ed3c70b --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/qa-web-change/fixtures/responses.json @@ -0,0 +1,7 @@ +{ + "test-changed-routes": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Build first, exercise changed routes, and finish only with no blocking regressions." + } +} diff --git a/labs/22-yield/yield/examples/library/python/qa-web-change/skill.json b/labs/22-yield/yield/examples/library/python/qa-web-change/skill.json new file mode 100644 index 00000000..8f2774d4 --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/qa-web-change/skill.json @@ -0,0 +1,6 @@ +{ + "run": [ + "python3", + "../src/qa-web-change.py" + ] +} diff --git a/labs/22-yield/yield/examples/library/python/release-package/SKILL.md b/labs/22-yield/yield/examples/library/python/release-package/SKILL.md new file mode 100644 index 00000000..7429d9eb --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/release-package/SKILL.md @@ -0,0 +1,13 @@ +--- +name: release-package +description: Test, review the release, ask for approval, publish, and verify. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/python/release-package/fixtures/responses.json b/labs/22-yield/yield/examples/library/python/release-package/fixtures/responses.json new file mode 100644 index 00000000..575d24a1 --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/release-package/fixtures/responses.json @@ -0,0 +1,10 @@ +{ + "review-release": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Test, review the release, ask for approval, publish, and verify." + }, + "approve-publish": { + "value": "continue" + } +} diff --git a/labs/22-yield/yield/examples/library/python/release-package/skill.json b/labs/22-yield/yield/examples/library/python/release-package/skill.json new file mode 100644 index 00000000..a5942f58 --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/release-package/skill.json @@ -0,0 +1,6 @@ +{ + "run": [ + "python3", + "../src/release-package.py" + ] +} diff --git a/labs/22-yield/yield/examples/library/python/repair-ci/SKILL.md b/labs/22-yield/yield/examples/library/python/repair-ci/SKILL.md new file mode 100644 index 00000000..159ee45d --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/repair-ci/SKILL.md @@ -0,0 +1,13 @@ +--- +name: repair-ci +description: Read the failed job, apply one supported repair, and rerun the failing check. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/python/repair-ci/fixtures/responses.json b/labs/22-yield/yield/examples/library/python/repair-ci/fixtures/responses.json new file mode 100644 index 00000000..f73e7fc1 --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/repair-ci/fixtures/responses.json @@ -0,0 +1,7 @@ +{ + "plan-ci-repair": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Read the failed job, apply one supported repair, and rerun the failing check." + } +} diff --git a/labs/22-yield/yield/examples/library/python/repair-ci/skill.json b/labs/22-yield/yield/examples/library/python/repair-ci/skill.json new file mode 100644 index 00000000..eba3c652 --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/repair-ci/skill.json @@ -0,0 +1,6 @@ +{ + "run": [ + "python3", + "../src/repair-ci.py" + ] +} diff --git a/labs/22-yield/yield/examples/library/python/review-branch/SKILL.md b/labs/22-yield/yield/examples/library/python/review-branch/SKILL.md new file mode 100644 index 00000000..24b513ac --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/review-branch/SKILL.md @@ -0,0 +1,13 @@ +--- +name: review-branch +description: Run mechanical checks, inspect the diff, and stop on critical findings. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/python/review-branch/fixtures/responses.json b/labs/22-yield/yield/examples/library/python/review-branch/fixtures/responses.json new file mode 100644 index 00000000..b891fae1 --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/review-branch/fixtures/responses.json @@ -0,0 +1,7 @@ +{ + "review-diff": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Run mechanical checks, inspect the diff, and stop on critical findings." + } +} diff --git a/labs/22-yield/yield/examples/library/python/review-branch/skill.json b/labs/22-yield/yield/examples/library/python/review-branch/skill.json new file mode 100644 index 00000000..8400ee25 --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/review-branch/skill.json @@ -0,0 +1,6 @@ +{ + "run": [ + "python3", + "../src/review-branch.py" + ] +} diff --git a/labs/22-yield/yield/examples/library/python/src/audit-security.py b/labs/22-yield/yield/examples/library/python/src/audit-security.py new file mode 100644 index 00000000..f88ed09d --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/src/audit-security.py @@ -0,0 +1,47 @@ +# Audit a change for security. Replace the illustrative commands with your project commands. +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parents[4] / "sdk" / "python")) +from yieldskill import define_skill # noqa: E402 + +DECISION_SCHEMA = { + "type": "object", + "required": [ + "status", + "critical", + "summary" + ], + "properties": { + "status": { + "enum": [ + "pass", + "needs_work" + ] + }, + "critical": { + "type": "integer", + "minimum": 0 + }, + "summary": { + "type": "string", + "minLength": 1 + } + } +} + +def program(ctx): + preflight = ctx.run_command("run-security-checks", "printf 'dependency and secret scans completed\\n'", 300) + ctx.require(preflight.exit_code == 0, "the mechanical security checks complete", preflight) + + decision = ctx.agent_task( + "review-trust-boundaries", + "Review authentication, authorization, input handling, secrets, and trust-boundary changes. Return pass only when no critical risk remains.", + context={"stdout": preflight.stdout, "stderr": preflight.stderr}, + schema=DECISION_SCHEMA, + ) + ctx.require(decision["status"] == "pass" and decision["critical"] == 0, "the change has no critical security finding", decision) + + return {"workflow": "audit-security", "summary": decision["summary"]} + +define_skill(program) diff --git a/labs/22-yield/yield/examples/library/python/src/investigate-failure.py b/labs/22-yield/yield/examples/library/python/src/investigate-failure.py new file mode 100644 index 00000000..b482ee3b --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/src/investigate-failure.py @@ -0,0 +1,47 @@ +# Investigate a failure. Replace the illustrative commands with your project commands. +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parents[4] / "sdk" / "python")) +from yieldskill import define_skill # noqa: E402 + +DECISION_SCHEMA = { + "type": "object", + "required": [ + "status", + "critical", + "summary" + ], + "properties": { + "status": { + "enum": [ + "pass", + "needs_work" + ] + }, + "critical": { + "type": "integer", + "minimum": 0 + }, + "summary": { + "type": "string", + "minLength": 1 + } + } +} + +def program(ctx): + preflight = ctx.run_command("capture-failure", "printf 'failing test captured with recent diff\\n'", 300) + ctx.require(preflight.exit_code == 0, "the failure evidence is captured", preflight) + + decision = ctx.agent_task( + "diagnose-cause", + "Use the failure output and recent change to identify the most likely root cause. Return pass only when the summary states a causal chain.", + context={"stdout": preflight.stdout, "stderr": preflight.stderr}, + schema=DECISION_SCHEMA, + ) + ctx.require(decision["status"] == "pass" and decision["critical"] == 0, "the diagnosis states a supported cause", decision) + + return {"workflow": "investigate-failure", "summary": decision["summary"]} + +define_skill(program) diff --git a/labs/22-yield/yield/examples/library/python/src/migrate-database.py b/labs/22-yield/yield/examples/library/python/src/migrate-database.py new file mode 100644 index 00000000..d07254db --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/src/migrate-database.py @@ -0,0 +1,61 @@ +# Run a database migration. Replace the illustrative commands with your project commands. +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parents[4] / "sdk" / "python")) +from yieldskill import define_skill # noqa: E402 + +DECISION_SCHEMA = { + "type": "object", + "required": [ + "status", + "critical", + "summary" + ], + "properties": { + "status": { + "enum": [ + "pass", + "needs_work" + ] + }, + "critical": { + "type": "integer", + "minimum": 0 + }, + "summary": { + "type": "string", + "minLength": 1 + } + } +} + +def program(ctx): + preflight = ctx.run_command("dry-run-migration", "printf 'dry run: add users_email_idx concurrently\\n'", 300) + ctx.require(preflight.exit_code == 0, "the migration dry-run succeeds", preflight) + + decision = ctx.agent_task( + "review-migration", + "Review the migration plan for lock risk, irreversible work, and rollback. Return pass only when the plan is safe to apply.", + context={"stdout": preflight.stdout, "stderr": preflight.stderr}, + schema=DECISION_SCHEMA, + ) + ctx.require(decision["status"] == "pass" and decision["critical"] == 0, "the migration plan has acceptable risk", decision) + + approval = ctx.ask_user( + "approve-migration", + "Apply the reviewed database migration?", + options=[{"value": "continue", "label": "Continue"}, {"value": "stop", "label": "Stop"}], + ) + if approval != "continue": + ctx.refused("the operator declined to continue") + + action = ctx.run_command("apply-migration", "printf 'migration applied\\n'", 600) + ctx.require(action.exit_code == 0, "the migration applies cleanly", action) + + verify = ctx.run_command("verify-migration", "printf 'migration verification passed\\n'", 300) + ctx.require(verify.exit_code == 0, "the migrated database passes verification", verify) + + return {"workflow": "migrate-database", "summary": decision["summary"]} + +define_skill(program) diff --git a/labs/22-yield/yield/examples/library/python/src/publish-ios.py b/labs/22-yield/yield/examples/library/python/src/publish-ios.py new file mode 100644 index 00000000..5e281dca --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/src/publish-ios.py @@ -0,0 +1,61 @@ +# Publish an iOS build. Replace the illustrative commands with your project commands. +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parents[4] / "sdk" / "python")) +from yieldskill import define_skill # noqa: E402 + +DECISION_SCHEMA = { + "type": "object", + "required": [ + "status", + "critical", + "summary" + ], + "properties": { + "status": { + "enum": [ + "pass", + "needs_work" + ] + }, + "critical": { + "type": "integer", + "minimum": 0 + }, + "summary": { + "type": "string", + "minLength": 1 + } + } +} + +def program(ctx): + preflight = ctx.run_command("archive-ios", "printf 'iOS archive and tests passed\\n'", 300) + ctx.require(preflight.exit_code == 0, "the iOS archive and tests pass", preflight) + + decision = ctx.agent_task( + "review-ios-release", + "Review the iOS release metadata, versioning, privacy notes, and rollout risk. Return pass only when the build is ready for upload.", + context={"stdout": preflight.stdout, "stderr": preflight.stderr}, + schema=DECISION_SCHEMA, + ) + ctx.require(decision["status"] == "pass" and decision["critical"] == 0, "the iOS build is ready for upload", decision) + + approval = ctx.ask_user( + "approve-ios-upload", + "Upload this iOS build to App Store Connect?", + options=[{"value": "continue", "label": "Continue"}, {"value": "stop", "label": "Stop"}], + ) + if approval != "continue": + ctx.refused("the operator declined to continue") + + action = ctx.run_command("upload-ios", "printf 'iOS build uploaded\\n'", 600) + ctx.require(action.exit_code == 0, "the iOS upload command succeeds", action) + + verify = ctx.run_command("verify-ios-processing", "printf 'uploaded build entered processing\\n'", 300) + ctx.require(verify.exit_code == 0, "the uploaded iOS build entered processing", verify) + + return {"workflow": "publish-ios", "summary": decision["summary"]} + +define_skill(program) diff --git a/labs/22-yield/yield/examples/library/python/src/qa-web-change.py b/labs/22-yield/yield/examples/library/python/src/qa-web-change.py new file mode 100644 index 00000000..28de733f --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/src/qa-web-change.py @@ -0,0 +1,47 @@ +# QA a web change. Replace the illustrative commands with your project commands. +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parents[4] / "sdk" / "python")) +from yieldskill import define_skill # noqa: E402 + +DECISION_SCHEMA = { + "type": "object", + "required": [ + "status", + "critical", + "summary" + ], + "properties": { + "status": { + "enum": [ + "pass", + "needs_work" + ] + }, + "critical": { + "type": "integer", + "minimum": 0 + }, + "summary": { + "type": "string", + "minLength": 1 + } + } +} + +def program(ctx): + preflight = ctx.run_command("build-web", "printf 'build passed; changed routes: / and /settings\\n'", 300) + ctx.require(preflight.exit_code == 0, "the web application builds", preflight) + + decision = ctx.agent_task( + "test-changed-routes", + "Test the changed routes at desktop and mobile sizes, including keyboard navigation and form errors. Return pass only when no blocking regression remains.", + context={"stdout": preflight.stdout, "stderr": preflight.stderr}, + schema=DECISION_SCHEMA, + ) + ctx.require(decision["status"] == "pass" and decision["critical"] == 0, "the changed routes have no blocking regression", decision) + + return {"workflow": "qa-web-change", "summary": decision["summary"]} + +define_skill(program) diff --git a/labs/22-yield/yield/examples/library/python/src/release-package.py b/labs/22-yield/yield/examples/library/python/src/release-package.py new file mode 100644 index 00000000..bcf63187 --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/src/release-package.py @@ -0,0 +1,61 @@ +# Release a package. Replace the illustrative commands with your project commands. +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parents[4] / "sdk" / "python")) +from yieldskill import define_skill # noqa: E402 + +DECISION_SCHEMA = { + "type": "object", + "required": [ + "status", + "critical", + "summary" + ], + "properties": { + "status": { + "enum": [ + "pass", + "needs_work" + ] + }, + "critical": { + "type": "integer", + "minimum": 0 + }, + "summary": { + "type": "string", + "minLength": 1 + } + } +} + +def program(ctx): + preflight = ctx.run_command("test-package", "printf 'package tests passed\\n'", 300) + ctx.require(preflight.exit_code == 0, "the package tests pass", preflight) + + decision = ctx.agent_task( + "review-release", + "Review the pending package release for breaking changes, missing notes, and rollback risk. Return pass only when it is ready to publish.", + context={"stdout": preflight.stdout, "stderr": preflight.stderr}, + schema=DECISION_SCHEMA, + ) + ctx.require(decision["status"] == "pass" and decision["critical"] == 0, "the package is ready to publish", decision) + + approval = ctx.ask_user( + "approve-publish", + "Publish this package release?", + options=[{"value": "continue", "label": "Continue"}, {"value": "stop", "label": "Stop"}], + ) + if approval != "continue": + ctx.refused("the operator declined to continue") + + action = ctx.run_command("publish-package", "printf 'package published\\n'", 600) + ctx.require(action.exit_code == 0, "the package publish command succeeds", action) + + verify = ctx.run_command("verify-package", "printf 'published package resolved from registry\\n'", 300) + ctx.require(verify.exit_code == 0, "the published package resolves from the registry", verify) + + return {"workflow": "release-package", "summary": decision["summary"]} + +define_skill(program) diff --git a/labs/22-yield/yield/examples/library/python/src/repair-ci.py b/labs/22-yield/yield/examples/library/python/src/repair-ci.py new file mode 100644 index 00000000..a3a1d73c --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/src/repair-ci.py @@ -0,0 +1,53 @@ +# Repair a CI failure. Replace the illustrative commands with your project commands. +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parents[4] / "sdk" / "python")) +from yieldskill import define_skill # noqa: E402 + +DECISION_SCHEMA = { + "type": "object", + "required": [ + "status", + "critical", + "summary" + ], + "properties": { + "status": { + "enum": [ + "pass", + "needs_work" + ] + }, + "critical": { + "type": "integer", + "minimum": 0 + }, + "summary": { + "type": "string", + "minLength": 1 + } + } +} + +def program(ctx): + preflight = ctx.run_command("capture-ci-log", "printf 'ci log: test shard 2 failed after cache restore\\n'", 300) + ctx.require(preflight.exit_code == 0, "the failing CI evidence is captured", preflight) + + decision = ctx.agent_task( + "plan-ci-repair", + "Diagnose the CI failure and describe the smallest supported repair. Return pass only when the repair is tied to the observed log.", + context={"stdout": preflight.stdout, "stderr": preflight.stderr}, + schema=DECISION_SCHEMA, + ) + ctx.require(decision["status"] == "pass" and decision["critical"] == 0, "the CI repair is supported by the failure evidence", decision) + + action = ctx.run_command("apply-ci-repair", "printf 'ci repair applied\\n'", 600) + ctx.require(action.exit_code == 0, "the CI repair command succeeds", action) + + verify = ctx.run_command("rerun-ci-check", "printf 'failing CI check now passes\\n'", 300) + ctx.require(verify.exit_code == 0, "the previously failing CI check passes", verify) + + return {"workflow": "repair-ci", "summary": decision["summary"]} + +define_skill(program) diff --git a/labs/22-yield/yield/examples/library/python/src/review-branch.py b/labs/22-yield/yield/examples/library/python/src/review-branch.py new file mode 100644 index 00000000..f3dac1e1 --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/src/review-branch.py @@ -0,0 +1,47 @@ +# Review a branch. Replace the illustrative commands with your project commands. +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parents[4] / "sdk" / "python")) +from yieldskill import define_skill # noqa: E402 + +DECISION_SCHEMA = { + "type": "object", + "required": [ + "status", + "critical", + "summary" + ], + "properties": { + "status": { + "enum": [ + "pass", + "needs_work" + ] + }, + "critical": { + "type": "integer", + "minimum": 0 + }, + "summary": { + "type": "string", + "minLength": 1 + } + } +} + +def program(ctx): + preflight = ctx.run_command("check-branch", "printf 'typecheck and tests passed\\n'", 300) + ctx.require(preflight.exit_code == 0, "the branch passes mechanical checks", preflight) + + decision = ctx.agent_task( + "review-diff", + "Review the branch for correctness, security, data-loss risks, and missing tests. Return pass only when no critical finding remains.", + context={"stdout": preflight.stdout, "stderr": preflight.stderr}, + schema=DECISION_SCHEMA, + ) + ctx.require(decision["status"] == "pass" and decision["critical"] == 0, "the review has no critical findings", decision) + + return {"workflow": "review-branch", "summary": decision["summary"]} + +define_skill(program) diff --git a/labs/22-yield/yield/examples/library/python/src/triage-issue.py b/labs/22-yield/yield/examples/library/python/src/triage-issue.py new file mode 100644 index 00000000..3f8fd9ae --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/src/triage-issue.py @@ -0,0 +1,47 @@ +# Triage an issue. Replace the illustrative commands with your project commands. +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parents[4] / "sdk" / "python")) +from yieldskill import define_skill # noqa: E402 + +DECISION_SCHEMA = { + "type": "object", + "required": [ + "status", + "critical", + "summary" + ], + "properties": { + "status": { + "enum": [ + "pass", + "needs_work" + ] + }, + "critical": { + "type": "integer", + "minimum": 0 + }, + "summary": { + "type": "string", + "minLength": 1 + } + } +} + +def program(ctx): + preflight = ctx.run_command("read-issue", "printf 'issue: intermittent timeout after retry change\\n'", 300) + ctx.require(preflight.exit_code == 0, "the issue report is available", preflight) + + decision = ctx.agent_task( + "classify-issue", + "Classify severity, identify missing evidence, and propose exactly one next action. Return pass only when the summary is actionable.", + context={"stdout": preflight.stdout, "stderr": preflight.stderr}, + schema=DECISION_SCHEMA, + ) + ctx.require(decision["status"] == "pass" and decision["critical"] == 0, "the issue has one actionable next step", decision) + + return {"workflow": "triage-issue", "summary": decision["summary"]} + +define_skill(program) diff --git a/labs/22-yield/yield/examples/library/python/src/upgrade-dependency.py b/labs/22-yield/yield/examples/library/python/src/upgrade-dependency.py new file mode 100644 index 00000000..6aab6e7a --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/src/upgrade-dependency.py @@ -0,0 +1,61 @@ +# Upgrade a dependency. Replace the illustrative commands with your project commands. +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parents[4] / "sdk" / "python")) +from yieldskill import define_skill # noqa: E402 + +DECISION_SCHEMA = { + "type": "object", + "required": [ + "status", + "critical", + "summary" + ], + "properties": { + "status": { + "enum": [ + "pass", + "needs_work" + ] + }, + "critical": { + "type": "integer", + "minimum": 0 + }, + "summary": { + "type": "string", + "minLength": 1 + } + } +} + +def program(ctx): + preflight = ctx.run_command("baseline-tests", "printf 'baseline tests passed\\n'", 300) + ctx.require(preflight.exit_code == 0, "the baseline tests pass", preflight) + + decision = ctx.agent_task( + "review-upgrade", + "Review the dependency upgrade for API changes, migration work, and rollback risk. Return pass only when the change is bounded.", + context={"stdout": preflight.stdout, "stderr": preflight.stderr}, + schema=DECISION_SCHEMA, + ) + ctx.require(decision["status"] == "pass" and decision["critical"] == 0, "the dependency upgrade has a bounded plan", decision) + + approval = ctx.ask_user( + "approve-upgrade", + "Apply the reviewed dependency upgrade?", + options=[{"value": "continue", "label": "Continue"}, {"value": "stop", "label": "Stop"}], + ) + if approval != "continue": + ctx.refused("the operator declined to continue") + + action = ctx.run_command("apply-upgrade", "printf 'dependency upgraded\\n'", 600) + ctx.require(action.exit_code == 0, "the dependency upgrade command succeeds", action) + + verify = ctx.run_command("post-upgrade-tests", "printf 'post-upgrade tests passed\\n'", 300) + ctx.require(verify.exit_code == 0, "the tests pass after the dependency upgrade", verify) + + return {"workflow": "upgrade-dependency", "summary": decision["summary"]} + +define_skill(program) diff --git a/labs/22-yield/yield/examples/library/python/triage-issue/SKILL.md b/labs/22-yield/yield/examples/library/python/triage-issue/SKILL.md new file mode 100644 index 00000000..82dee14e --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/triage-issue/SKILL.md @@ -0,0 +1,13 @@ +--- +name: triage-issue +description: Read the report, classify impact, and return one evidence-backed next action. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/python/triage-issue/fixtures/responses.json b/labs/22-yield/yield/examples/library/python/triage-issue/fixtures/responses.json new file mode 100644 index 00000000..3462c970 --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/triage-issue/fixtures/responses.json @@ -0,0 +1,7 @@ +{ + "classify-issue": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Read the report, classify impact, and return one evidence-backed next action." + } +} diff --git a/labs/22-yield/yield/examples/library/python/triage-issue/skill.json b/labs/22-yield/yield/examples/library/python/triage-issue/skill.json new file mode 100644 index 00000000..38d476f6 --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/triage-issue/skill.json @@ -0,0 +1,6 @@ +{ + "run": [ + "python3", + "../src/triage-issue.py" + ] +} diff --git a/labs/22-yield/yield/examples/library/python/upgrade-dependency/SKILL.md b/labs/22-yield/yield/examples/library/python/upgrade-dependency/SKILL.md new file mode 100644 index 00000000..c40615fb --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/upgrade-dependency/SKILL.md @@ -0,0 +1,13 @@ +--- +name: upgrade-dependency +description: Establish a baseline, review compatibility, approve the change, and rerun tests. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/python/upgrade-dependency/fixtures/responses.json b/labs/22-yield/yield/examples/library/python/upgrade-dependency/fixtures/responses.json new file mode 100644 index 00000000..2f311f80 --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/upgrade-dependency/fixtures/responses.json @@ -0,0 +1,10 @@ +{ + "review-upgrade": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Establish a baseline, review compatibility, approve the change, and rerun tests." + }, + "approve-upgrade": { + "value": "continue" + } +} diff --git a/labs/22-yield/yield/examples/library/python/upgrade-dependency/skill.json b/labs/22-yield/yield/examples/library/python/upgrade-dependency/skill.json new file mode 100644 index 00000000..50fd9b5a --- /dev/null +++ b/labs/22-yield/yield/examples/library/python/upgrade-dependency/skill.json @@ -0,0 +1,6 @@ +{ + "run": [ + "python3", + "../src/upgrade-dependency.py" + ] +} diff --git a/labs/22-yield/yield/examples/library/rust/Cargo.lock b/labs/22-yield/yield/examples/library/rust/Cargo.lock new file mode 100644 index 00000000..f5b999cf --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/Cargo.lock @@ -0,0 +1,206 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "syn" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "yield-example-library" +version = "0.1.0" +dependencies = [ + "serde_json", + "yieldskill", +] + +[[package]] +name = "yieldskill" +version = "0.1.0" +dependencies = [ + "hex", + "serde", + "serde_json", + "sha2", +] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/labs/22-yield/yield/examples/library/rust/Cargo.toml b/labs/22-yield/yield/examples/library/rust/Cargo.toml new file mode 100644 index 00000000..d35d3567 --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "yield-example-library" +version = "0.1.0" +edition = "2021" +publish = false + +[dependencies] +yieldskill = { path = "../../../sdk/rust" } +serde_json = "1" diff --git a/labs/22-yield/yield/examples/library/rust/audit-security/SKILL.md b/labs/22-yield/yield/examples/library/rust/audit-security/SKILL.md new file mode 100644 index 00000000..f83b8e72 --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/audit-security/SKILL.md @@ -0,0 +1,13 @@ +--- +name: audit-security +description: Collect mechanical audit output, inspect trust boundaries, and reject critical risk. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/rust/audit-security/fixtures/responses.json b/labs/22-yield/yield/examples/library/rust/audit-security/fixtures/responses.json new file mode 100644 index 00000000..f690e022 --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/audit-security/fixtures/responses.json @@ -0,0 +1,7 @@ +{ + "review-trust-boundaries": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Collect mechanical audit output, inspect trust boundaries, and reject critical risk." + } +} diff --git a/labs/22-yield/yield/examples/library/rust/audit-security/skill.json b/labs/22-yield/yield/examples/library/rust/audit-security/skill.json new file mode 100644 index 00000000..d69c8273 --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/audit-security/skill.json @@ -0,0 +1,11 @@ +{ + "run": [ + "cargo", + "run", + "--quiet", + "--manifest-path", + "../Cargo.toml", + "--bin", + "audit-security" + ] +} diff --git a/labs/22-yield/yield/examples/library/rust/investigate-failure/SKILL.md b/labs/22-yield/yield/examples/library/rust/investigate-failure/SKILL.md new file mode 100644 index 00000000..62fa2c91 --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/investigate-failure/SKILL.md @@ -0,0 +1,13 @@ +--- +name: investigate-failure +description: Capture evidence, test the likely cause, and finish only with a causal explanation. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/rust/investigate-failure/fixtures/responses.json b/labs/22-yield/yield/examples/library/rust/investigate-failure/fixtures/responses.json new file mode 100644 index 00000000..fa01815e --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/investigate-failure/fixtures/responses.json @@ -0,0 +1,7 @@ +{ + "diagnose-cause": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Capture evidence, test the likely cause, and finish only with a causal explanation." + } +} diff --git a/labs/22-yield/yield/examples/library/rust/investigate-failure/skill.json b/labs/22-yield/yield/examples/library/rust/investigate-failure/skill.json new file mode 100644 index 00000000..bb2ddc8e --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/investigate-failure/skill.json @@ -0,0 +1,11 @@ +{ + "run": [ + "cargo", + "run", + "--quiet", + "--manifest-path", + "../Cargo.toml", + "--bin", + "investigate-failure" + ] +} diff --git a/labs/22-yield/yield/examples/library/rust/migrate-database/SKILL.md b/labs/22-yield/yield/examples/library/rust/migrate-database/SKILL.md new file mode 100644 index 00000000..6acca087 --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/migrate-database/SKILL.md @@ -0,0 +1,13 @@ +--- +name: migrate-database +description: Dry-run, inspect risk, approve, apply, and verify the real result. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/rust/migrate-database/fixtures/responses.json b/labs/22-yield/yield/examples/library/rust/migrate-database/fixtures/responses.json new file mode 100644 index 00000000..ae5f3c7a --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/migrate-database/fixtures/responses.json @@ -0,0 +1,10 @@ +{ + "review-migration": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Dry-run, inspect risk, approve, apply, and verify the real result." + }, + "approve-migration": { + "value": "continue" + } +} diff --git a/labs/22-yield/yield/examples/library/rust/migrate-database/skill.json b/labs/22-yield/yield/examples/library/rust/migrate-database/skill.json new file mode 100644 index 00000000..ca11a48b --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/migrate-database/skill.json @@ -0,0 +1,11 @@ +{ + "run": [ + "cargo", + "run", + "--quiet", + "--manifest-path", + "../Cargo.toml", + "--bin", + "migrate-database" + ] +} diff --git a/labs/22-yield/yield/examples/library/rust/publish-ios/SKILL.md b/labs/22-yield/yield/examples/library/rust/publish-ios/SKILL.md new file mode 100644 index 00000000..88e7449d --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/publish-ios/SKILL.md @@ -0,0 +1,13 @@ +--- +name: publish-ios +description: Archive, review release metadata, approve upload, publish, and verify processing. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/rust/publish-ios/fixtures/responses.json b/labs/22-yield/yield/examples/library/rust/publish-ios/fixtures/responses.json new file mode 100644 index 00000000..9f0d5d6e --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/publish-ios/fixtures/responses.json @@ -0,0 +1,10 @@ +{ + "review-ios-release": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Archive, review release metadata, approve upload, publish, and verify processing." + }, + "approve-ios-upload": { + "value": "continue" + } +} diff --git a/labs/22-yield/yield/examples/library/rust/publish-ios/skill.json b/labs/22-yield/yield/examples/library/rust/publish-ios/skill.json new file mode 100644 index 00000000..25f60730 --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/publish-ios/skill.json @@ -0,0 +1,11 @@ +{ + "run": [ + "cargo", + "run", + "--quiet", + "--manifest-path", + "../Cargo.toml", + "--bin", + "publish-ios" + ] +} diff --git a/labs/22-yield/yield/examples/library/rust/qa-web-change/SKILL.md b/labs/22-yield/yield/examples/library/rust/qa-web-change/SKILL.md new file mode 100644 index 00000000..533bbdf7 --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/qa-web-change/SKILL.md @@ -0,0 +1,13 @@ +--- +name: qa-web-change +description: Build first, exercise changed routes, and finish only with no blocking regressions. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/rust/qa-web-change/fixtures/responses.json b/labs/22-yield/yield/examples/library/rust/qa-web-change/fixtures/responses.json new file mode 100644 index 00000000..1ed3c70b --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/qa-web-change/fixtures/responses.json @@ -0,0 +1,7 @@ +{ + "test-changed-routes": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Build first, exercise changed routes, and finish only with no blocking regressions." + } +} diff --git a/labs/22-yield/yield/examples/library/rust/qa-web-change/skill.json b/labs/22-yield/yield/examples/library/rust/qa-web-change/skill.json new file mode 100644 index 00000000..8f940f3f --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/qa-web-change/skill.json @@ -0,0 +1,11 @@ +{ + "run": [ + "cargo", + "run", + "--quiet", + "--manifest-path", + "../Cargo.toml", + "--bin", + "qa-web-change" + ] +} diff --git a/labs/22-yield/yield/examples/library/rust/release-package/SKILL.md b/labs/22-yield/yield/examples/library/rust/release-package/SKILL.md new file mode 100644 index 00000000..7429d9eb --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/release-package/SKILL.md @@ -0,0 +1,13 @@ +--- +name: release-package +description: Test, review the release, ask for approval, publish, and verify. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/rust/release-package/fixtures/responses.json b/labs/22-yield/yield/examples/library/rust/release-package/fixtures/responses.json new file mode 100644 index 00000000..575d24a1 --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/release-package/fixtures/responses.json @@ -0,0 +1,10 @@ +{ + "review-release": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Test, review the release, ask for approval, publish, and verify." + }, + "approve-publish": { + "value": "continue" + } +} diff --git a/labs/22-yield/yield/examples/library/rust/release-package/skill.json b/labs/22-yield/yield/examples/library/rust/release-package/skill.json new file mode 100644 index 00000000..6bebf4d4 --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/release-package/skill.json @@ -0,0 +1,11 @@ +{ + "run": [ + "cargo", + "run", + "--quiet", + "--manifest-path", + "../Cargo.toml", + "--bin", + "release-package" + ] +} diff --git a/labs/22-yield/yield/examples/library/rust/repair-ci/SKILL.md b/labs/22-yield/yield/examples/library/rust/repair-ci/SKILL.md new file mode 100644 index 00000000..159ee45d --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/repair-ci/SKILL.md @@ -0,0 +1,13 @@ +--- +name: repair-ci +description: Read the failed job, apply one supported repair, and rerun the failing check. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/rust/repair-ci/fixtures/responses.json b/labs/22-yield/yield/examples/library/rust/repair-ci/fixtures/responses.json new file mode 100644 index 00000000..f73e7fc1 --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/repair-ci/fixtures/responses.json @@ -0,0 +1,7 @@ +{ + "plan-ci-repair": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Read the failed job, apply one supported repair, and rerun the failing check." + } +} diff --git a/labs/22-yield/yield/examples/library/rust/repair-ci/skill.json b/labs/22-yield/yield/examples/library/rust/repair-ci/skill.json new file mode 100644 index 00000000..0a034f10 --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/repair-ci/skill.json @@ -0,0 +1,11 @@ +{ + "run": [ + "cargo", + "run", + "--quiet", + "--manifest-path", + "../Cargo.toml", + "--bin", + "repair-ci" + ] +} diff --git a/labs/22-yield/yield/examples/library/rust/review-branch/SKILL.md b/labs/22-yield/yield/examples/library/rust/review-branch/SKILL.md new file mode 100644 index 00000000..24b513ac --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/review-branch/SKILL.md @@ -0,0 +1,13 @@ +--- +name: review-branch +description: Run mechanical checks, inspect the diff, and stop on critical findings. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/rust/review-branch/fixtures/responses.json b/labs/22-yield/yield/examples/library/rust/review-branch/fixtures/responses.json new file mode 100644 index 00000000..b891fae1 --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/review-branch/fixtures/responses.json @@ -0,0 +1,7 @@ +{ + "review-diff": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Run mechanical checks, inspect the diff, and stop on critical findings." + } +} diff --git a/labs/22-yield/yield/examples/library/rust/review-branch/skill.json b/labs/22-yield/yield/examples/library/rust/review-branch/skill.json new file mode 100644 index 00000000..ca6384b7 --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/review-branch/skill.json @@ -0,0 +1,11 @@ +{ + "run": [ + "cargo", + "run", + "--quiet", + "--manifest-path", + "../Cargo.toml", + "--bin", + "review-branch" + ] +} diff --git a/labs/22-yield/yield/examples/library/rust/src/bin/audit-security.rs b/labs/22-yield/yield/examples/library/rust/src/bin/audit-security.rs new file mode 100644 index 00000000..92ca0e6f --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/src/bin/audit-security.rs @@ -0,0 +1,38 @@ +// Audit a change for security. Replace the illustrative commands with your project commands. +use serde_json::{json, Value}; +use yieldskill::{define_skill, Context, SkillResult}; + +fn decision_schema() -> Value { + json!({"type":"object","required":["status","critical","summary"],"properties":{"status":{"enum":["pass","needs_work"]},"critical":{"type":"integer","minimum":0},"summary":{"type":"string","minLength":1}}}) +} + +fn program(ctx: &mut Context) -> SkillResult { + let preflight = ctx.run_command( + "run-security-checks", + "printf 'dependency and secret scans completed\\n'", + 300, + ); + ctx.require( + preflight.exit_code == 0, + "the mechanical security checks complete", + Some(&json!({"exit_code": preflight.exit_code})), + ); + + let decision = ctx.agent_task( + "review-trust-boundaries", + "Review authentication, authorization, input handling, secrets, and trust-boundary changes. Return pass only when no critical risk remains.", + Some(json!({"stdout": preflight.stdout, "stderr": preflight.stderr})), + Some(decision_schema()), + ); + ctx.require( + decision["status"] == "pass" && decision["critical"] == 0, + "the change has no critical security finding", + Some(&decision), + ); + + Ok(json!({"workflow": "audit-security", "summary": decision["summary"]})) +} + +fn main() { + define_skill(program); +} diff --git a/labs/22-yield/yield/examples/library/rust/src/bin/investigate-failure.rs b/labs/22-yield/yield/examples/library/rust/src/bin/investigate-failure.rs new file mode 100644 index 00000000..55c4df6a --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/src/bin/investigate-failure.rs @@ -0,0 +1,38 @@ +// Investigate a failure. Replace the illustrative commands with your project commands. +use serde_json::{json, Value}; +use yieldskill::{define_skill, Context, SkillResult}; + +fn decision_schema() -> Value { + json!({"type":"object","required":["status","critical","summary"],"properties":{"status":{"enum":["pass","needs_work"]},"critical":{"type":"integer","minimum":0},"summary":{"type":"string","minLength":1}}}) +} + +fn program(ctx: &mut Context) -> SkillResult { + let preflight = ctx.run_command( + "capture-failure", + "printf 'failing test captured with recent diff\\n'", + 300, + ); + ctx.require( + preflight.exit_code == 0, + "the failure evidence is captured", + Some(&json!({"exit_code": preflight.exit_code})), + ); + + let decision = ctx.agent_task( + "diagnose-cause", + "Use the failure output and recent change to identify the most likely root cause. Return pass only when the summary states a causal chain.", + Some(json!({"stdout": preflight.stdout, "stderr": preflight.stderr})), + Some(decision_schema()), + ); + ctx.require( + decision["status"] == "pass" && decision["critical"] == 0, + "the diagnosis states a supported cause", + Some(&decision), + ); + + Ok(json!({"workflow": "investigate-failure", "summary": decision["summary"]})) +} + +fn main() { + define_skill(program); +} diff --git a/labs/22-yield/yield/examples/library/rust/src/bin/migrate-database.rs b/labs/22-yield/yield/examples/library/rust/src/bin/migrate-database.rs new file mode 100644 index 00000000..58ab1a90 --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/src/bin/migrate-database.rs @@ -0,0 +1,65 @@ +// Run a database migration. Replace the illustrative commands with your project commands. +use serde_json::{json, Value}; +use yieldskill::{define_skill, Context, SkillResult}; + +fn decision_schema() -> Value { + json!({"type":"object","required":["status","critical","summary"],"properties":{"status":{"enum":["pass","needs_work"]},"critical":{"type":"integer","minimum":0},"summary":{"type":"string","minLength":1}}}) +} + +fn program(ctx: &mut Context) -> SkillResult { + let preflight = ctx.run_command( + "dry-run-migration", + "printf 'dry run: add users_email_idx concurrently\\n'", + 300, + ); + ctx.require( + preflight.exit_code == 0, + "the migration dry-run succeeds", + Some(&json!({"exit_code": preflight.exit_code})), + ); + + let decision = ctx.agent_task( + "review-migration", + "Review the migration plan for lock risk, irreversible work, and rollback. Return pass only when the plan is safe to apply.", + Some(json!({"stdout": preflight.stdout, "stderr": preflight.stderr})), + Some(decision_schema()), + ); + ctx.require( + decision["status"] == "pass" && decision["critical"] == 0, + "the migration plan has acceptable risk", + Some(&decision), + ); + + let approval = ctx.ask_user( + "approve-migration", + "Apply the reviewed database migration?", + &[("continue", "Continue"), ("stop", "Stop")], + ); + if approval != "continue" { + return Err(ctx.refused("the operator declined to continue")); + } + + let action = ctx.run_command("apply-migration", "printf 'migration applied\\n'", 600); + ctx.require( + action.exit_code == 0, + "the migration applies cleanly", + Some(&json!({"exit_code": action.exit_code})), + ); + + let verify = ctx.run_command( + "verify-migration", + "printf 'migration verification passed\\n'", + 300, + ); + ctx.require( + verify.exit_code == 0, + "the migrated database passes verification", + Some(&json!({"exit_code": verify.exit_code})), + ); + + Ok(json!({"workflow": "migrate-database", "summary": decision["summary"]})) +} + +fn main() { + define_skill(program); +} diff --git a/labs/22-yield/yield/examples/library/rust/src/bin/publish-ios.rs b/labs/22-yield/yield/examples/library/rust/src/bin/publish-ios.rs new file mode 100644 index 00000000..32c2f2db --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/src/bin/publish-ios.rs @@ -0,0 +1,65 @@ +// Publish an iOS build. Replace the illustrative commands with your project commands. +use serde_json::{json, Value}; +use yieldskill::{define_skill, Context, SkillResult}; + +fn decision_schema() -> Value { + json!({"type":"object","required":["status","critical","summary"],"properties":{"status":{"enum":["pass","needs_work"]},"critical":{"type":"integer","minimum":0},"summary":{"type":"string","minLength":1}}}) +} + +fn program(ctx: &mut Context) -> SkillResult { + let preflight = ctx.run_command( + "archive-ios", + "printf 'iOS archive and tests passed\\n'", + 300, + ); + ctx.require( + preflight.exit_code == 0, + "the iOS archive and tests pass", + Some(&json!({"exit_code": preflight.exit_code})), + ); + + let decision = ctx.agent_task( + "review-ios-release", + "Review the iOS release metadata, versioning, privacy notes, and rollout risk. Return pass only when the build is ready for upload.", + Some(json!({"stdout": preflight.stdout, "stderr": preflight.stderr})), + Some(decision_schema()), + ); + ctx.require( + decision["status"] == "pass" && decision["critical"] == 0, + "the iOS build is ready for upload", + Some(&decision), + ); + + let approval = ctx.ask_user( + "approve-ios-upload", + "Upload this iOS build to App Store Connect?", + &[("continue", "Continue"), ("stop", "Stop")], + ); + if approval != "continue" { + return Err(ctx.refused("the operator declined to continue")); + } + + let action = ctx.run_command("upload-ios", "printf 'iOS build uploaded\\n'", 600); + ctx.require( + action.exit_code == 0, + "the iOS upload command succeeds", + Some(&json!({"exit_code": action.exit_code})), + ); + + let verify = ctx.run_command( + "verify-ios-processing", + "printf 'uploaded build entered processing\\n'", + 300, + ); + ctx.require( + verify.exit_code == 0, + "the uploaded iOS build entered processing", + Some(&json!({"exit_code": verify.exit_code})), + ); + + Ok(json!({"workflow": "publish-ios", "summary": decision["summary"]})) +} + +fn main() { + define_skill(program); +} diff --git a/labs/22-yield/yield/examples/library/rust/src/bin/qa-web-change.rs b/labs/22-yield/yield/examples/library/rust/src/bin/qa-web-change.rs new file mode 100644 index 00000000..9bf51553 --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/src/bin/qa-web-change.rs @@ -0,0 +1,38 @@ +// QA a web change. Replace the illustrative commands with your project commands. +use serde_json::{json, Value}; +use yieldskill::{define_skill, Context, SkillResult}; + +fn decision_schema() -> Value { + json!({"type":"object","required":["status","critical","summary"],"properties":{"status":{"enum":["pass","needs_work"]},"critical":{"type":"integer","minimum":0},"summary":{"type":"string","minLength":1}}}) +} + +fn program(ctx: &mut Context) -> SkillResult { + let preflight = ctx.run_command( + "build-web", + "printf 'build passed; changed routes: / and /settings\\n'", + 300, + ); + ctx.require( + preflight.exit_code == 0, + "the web application builds", + Some(&json!({"exit_code": preflight.exit_code})), + ); + + let decision = ctx.agent_task( + "test-changed-routes", + "Test the changed routes at desktop and mobile sizes, including keyboard navigation and form errors. Return pass only when no blocking regression remains.", + Some(json!({"stdout": preflight.stdout, "stderr": preflight.stderr})), + Some(decision_schema()), + ); + ctx.require( + decision["status"] == "pass" && decision["critical"] == 0, + "the changed routes have no blocking regression", + Some(&decision), + ); + + Ok(json!({"workflow": "qa-web-change", "summary": decision["summary"]})) +} + +fn main() { + define_skill(program); +} diff --git a/labs/22-yield/yield/examples/library/rust/src/bin/release-package.rs b/labs/22-yield/yield/examples/library/rust/src/bin/release-package.rs new file mode 100644 index 00000000..fc73057e --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/src/bin/release-package.rs @@ -0,0 +1,61 @@ +// Release a package. Replace the illustrative commands with your project commands. +use serde_json::{json, Value}; +use yieldskill::{define_skill, Context, SkillResult}; + +fn decision_schema() -> Value { + json!({"type":"object","required":["status","critical","summary"],"properties":{"status":{"enum":["pass","needs_work"]},"critical":{"type":"integer","minimum":0},"summary":{"type":"string","minLength":1}}}) +} + +fn program(ctx: &mut Context) -> SkillResult { + let preflight = ctx.run_command("test-package", "printf 'package tests passed\\n'", 300); + ctx.require( + preflight.exit_code == 0, + "the package tests pass", + Some(&json!({"exit_code": preflight.exit_code})), + ); + + let decision = ctx.agent_task( + "review-release", + "Review the pending package release for breaking changes, missing notes, and rollback risk. Return pass only when it is ready to publish.", + Some(json!({"stdout": preflight.stdout, "stderr": preflight.stderr})), + Some(decision_schema()), + ); + ctx.require( + decision["status"] == "pass" && decision["critical"] == 0, + "the package is ready to publish", + Some(&decision), + ); + + let approval = ctx.ask_user( + "approve-publish", + "Publish this package release?", + &[("continue", "Continue"), ("stop", "Stop")], + ); + if approval != "continue" { + return Err(ctx.refused("the operator declined to continue")); + } + + let action = ctx.run_command("publish-package", "printf 'package published\\n'", 600); + ctx.require( + action.exit_code == 0, + "the package publish command succeeds", + Some(&json!({"exit_code": action.exit_code})), + ); + + let verify = ctx.run_command( + "verify-package", + "printf 'published package resolved from registry\\n'", + 300, + ); + ctx.require( + verify.exit_code == 0, + "the published package resolves from the registry", + Some(&json!({"exit_code": verify.exit_code})), + ); + + Ok(json!({"workflow": "release-package", "summary": decision["summary"]})) +} + +fn main() { + define_skill(program); +} diff --git a/labs/22-yield/yield/examples/library/rust/src/bin/repair-ci.rs b/labs/22-yield/yield/examples/library/rust/src/bin/repair-ci.rs new file mode 100644 index 00000000..01adfc45 --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/src/bin/repair-ci.rs @@ -0,0 +1,56 @@ +// Repair a CI failure. Replace the illustrative commands with your project commands. +use serde_json::{json, Value}; +use yieldskill::{define_skill, Context, SkillResult}; + +fn decision_schema() -> Value { + json!({"type":"object","required":["status","critical","summary"],"properties":{"status":{"enum":["pass","needs_work"]},"critical":{"type":"integer","minimum":0},"summary":{"type":"string","minLength":1}}}) +} + +fn program(ctx: &mut Context) -> SkillResult { + let preflight = ctx.run_command( + "capture-ci-log", + "printf 'ci log: test shard 2 failed after cache restore\\n'", + 300, + ); + ctx.require( + preflight.exit_code == 0, + "the failing CI evidence is captured", + Some(&json!({"exit_code": preflight.exit_code})), + ); + + let decision = ctx.agent_task( + "plan-ci-repair", + "Diagnose the CI failure and describe the smallest supported repair. Return pass only when the repair is tied to the observed log.", + Some(json!({"stdout": preflight.stdout, "stderr": preflight.stderr})), + Some(decision_schema()), + ); + ctx.require( + decision["status"] == "pass" && decision["critical"] == 0, + "the CI repair is supported by the failure evidence", + Some(&decision), + ); + + let action = ctx.run_command("apply-ci-repair", "printf 'ci repair applied\\n'", 600); + ctx.require( + action.exit_code == 0, + "the CI repair command succeeds", + Some(&json!({"exit_code": action.exit_code})), + ); + + let verify = ctx.run_command( + "rerun-ci-check", + "printf 'failing CI check now passes\\n'", + 300, + ); + ctx.require( + verify.exit_code == 0, + "the previously failing CI check passes", + Some(&json!({"exit_code": verify.exit_code})), + ); + + Ok(json!({"workflow": "repair-ci", "summary": decision["summary"]})) +} + +fn main() { + define_skill(program); +} diff --git a/labs/22-yield/yield/examples/library/rust/src/bin/review-branch.rs b/labs/22-yield/yield/examples/library/rust/src/bin/review-branch.rs new file mode 100644 index 00000000..22b6f006 --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/src/bin/review-branch.rs @@ -0,0 +1,38 @@ +// Review a branch. Replace the illustrative commands with your project commands. +use serde_json::{json, Value}; +use yieldskill::{define_skill, Context, SkillResult}; + +fn decision_schema() -> Value { + json!({"type":"object","required":["status","critical","summary"],"properties":{"status":{"enum":["pass","needs_work"]},"critical":{"type":"integer","minimum":0},"summary":{"type":"string","minLength":1}}}) +} + +fn program(ctx: &mut Context) -> SkillResult { + let preflight = ctx.run_command( + "check-branch", + "printf 'typecheck and tests passed\\n'", + 300, + ); + ctx.require( + preflight.exit_code == 0, + "the branch passes mechanical checks", + Some(&json!({"exit_code": preflight.exit_code})), + ); + + let decision = ctx.agent_task( + "review-diff", + "Review the branch for correctness, security, data-loss risks, and missing tests. Return pass only when no critical finding remains.", + Some(json!({"stdout": preflight.stdout, "stderr": preflight.stderr})), + Some(decision_schema()), + ); + ctx.require( + decision["status"] == "pass" && decision["critical"] == 0, + "the review has no critical findings", + Some(&decision), + ); + + Ok(json!({"workflow": "review-branch", "summary": decision["summary"]})) +} + +fn main() { + define_skill(program); +} diff --git a/labs/22-yield/yield/examples/library/rust/src/bin/triage-issue.rs b/labs/22-yield/yield/examples/library/rust/src/bin/triage-issue.rs new file mode 100644 index 00000000..36d05224 --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/src/bin/triage-issue.rs @@ -0,0 +1,38 @@ +// Triage an issue. Replace the illustrative commands with your project commands. +use serde_json::{json, Value}; +use yieldskill::{define_skill, Context, SkillResult}; + +fn decision_schema() -> Value { + json!({"type":"object","required":["status","critical","summary"],"properties":{"status":{"enum":["pass","needs_work"]},"critical":{"type":"integer","minimum":0},"summary":{"type":"string","minLength":1}}}) +} + +fn program(ctx: &mut Context) -> SkillResult { + let preflight = ctx.run_command( + "read-issue", + "printf 'issue: intermittent timeout after retry change\\n'", + 300, + ); + ctx.require( + preflight.exit_code == 0, + "the issue report is available", + Some(&json!({"exit_code": preflight.exit_code})), + ); + + let decision = ctx.agent_task( + "classify-issue", + "Classify severity, identify missing evidence, and propose exactly one next action. Return pass only when the summary is actionable.", + Some(json!({"stdout": preflight.stdout, "stderr": preflight.stderr})), + Some(decision_schema()), + ); + ctx.require( + decision["status"] == "pass" && decision["critical"] == 0, + "the issue has one actionable next step", + Some(&decision), + ); + + Ok(json!({"workflow": "triage-issue", "summary": decision["summary"]})) +} + +fn main() { + define_skill(program); +} diff --git a/labs/22-yield/yield/examples/library/rust/src/bin/upgrade-dependency.rs b/labs/22-yield/yield/examples/library/rust/src/bin/upgrade-dependency.rs new file mode 100644 index 00000000..cf6ac9b4 --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/src/bin/upgrade-dependency.rs @@ -0,0 +1,61 @@ +// Upgrade a dependency. Replace the illustrative commands with your project commands. +use serde_json::{json, Value}; +use yieldskill::{define_skill, Context, SkillResult}; + +fn decision_schema() -> Value { + json!({"type":"object","required":["status","critical","summary"],"properties":{"status":{"enum":["pass","needs_work"]},"critical":{"type":"integer","minimum":0},"summary":{"type":"string","minLength":1}}}) +} + +fn program(ctx: &mut Context) -> SkillResult { + let preflight = ctx.run_command("baseline-tests", "printf 'baseline tests passed\\n'", 300); + ctx.require( + preflight.exit_code == 0, + "the baseline tests pass", + Some(&json!({"exit_code": preflight.exit_code})), + ); + + let decision = ctx.agent_task( + "review-upgrade", + "Review the dependency upgrade for API changes, migration work, and rollback risk. Return pass only when the change is bounded.", + Some(json!({"stdout": preflight.stdout, "stderr": preflight.stderr})), + Some(decision_schema()), + ); + ctx.require( + decision["status"] == "pass" && decision["critical"] == 0, + "the dependency upgrade has a bounded plan", + Some(&decision), + ); + + let approval = ctx.ask_user( + "approve-upgrade", + "Apply the reviewed dependency upgrade?", + &[("continue", "Continue"), ("stop", "Stop")], + ); + if approval != "continue" { + return Err(ctx.refused("the operator declined to continue")); + } + + let action = ctx.run_command("apply-upgrade", "printf 'dependency upgraded\\n'", 600); + ctx.require( + action.exit_code == 0, + "the dependency upgrade command succeeds", + Some(&json!({"exit_code": action.exit_code})), + ); + + let verify = ctx.run_command( + "post-upgrade-tests", + "printf 'post-upgrade tests passed\\n'", + 300, + ); + ctx.require( + verify.exit_code == 0, + "the tests pass after the dependency upgrade", + Some(&json!({"exit_code": verify.exit_code})), + ); + + Ok(json!({"workflow": "upgrade-dependency", "summary": decision["summary"]})) +} + +fn main() { + define_skill(program); +} diff --git a/labs/22-yield/yield/examples/library/rust/triage-issue/SKILL.md b/labs/22-yield/yield/examples/library/rust/triage-issue/SKILL.md new file mode 100644 index 00000000..82dee14e --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/triage-issue/SKILL.md @@ -0,0 +1,13 @@ +--- +name: triage-issue +description: Read the report, classify impact, and return one evidence-backed next action. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/rust/triage-issue/fixtures/responses.json b/labs/22-yield/yield/examples/library/rust/triage-issue/fixtures/responses.json new file mode 100644 index 00000000..3462c970 --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/triage-issue/fixtures/responses.json @@ -0,0 +1,7 @@ +{ + "classify-issue": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Read the report, classify impact, and return one evidence-backed next action." + } +} diff --git a/labs/22-yield/yield/examples/library/rust/triage-issue/skill.json b/labs/22-yield/yield/examples/library/rust/triage-issue/skill.json new file mode 100644 index 00000000..a2994fbe --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/triage-issue/skill.json @@ -0,0 +1,11 @@ +{ + "run": [ + "cargo", + "run", + "--quiet", + "--manifest-path", + "../Cargo.toml", + "--bin", + "triage-issue" + ] +} diff --git a/labs/22-yield/yield/examples/library/rust/upgrade-dependency/SKILL.md b/labs/22-yield/yield/examples/library/rust/upgrade-dependency/SKILL.md new file mode 100644 index 00000000..c40615fb --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/upgrade-dependency/SKILL.md @@ -0,0 +1,13 @@ +--- +name: upgrade-dependency +description: Establish a baseline, review compatibility, approve the change, and rerun tests. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/rust/upgrade-dependency/fixtures/responses.json b/labs/22-yield/yield/examples/library/rust/upgrade-dependency/fixtures/responses.json new file mode 100644 index 00000000..2f311f80 --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/upgrade-dependency/fixtures/responses.json @@ -0,0 +1,10 @@ +{ + "review-upgrade": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Establish a baseline, review compatibility, approve the change, and rerun tests." + }, + "approve-upgrade": { + "value": "continue" + } +} diff --git a/labs/22-yield/yield/examples/library/rust/upgrade-dependency/skill.json b/labs/22-yield/yield/examples/library/rust/upgrade-dependency/skill.json new file mode 100644 index 00000000..5d80d023 --- /dev/null +++ b/labs/22-yield/yield/examples/library/rust/upgrade-dependency/skill.json @@ -0,0 +1,11 @@ +{ + "run": [ + "cargo", + "run", + "--quiet", + "--manifest-path", + "../Cargo.toml", + "--bin", + "upgrade-dependency" + ] +} diff --git a/labs/22-yield/yield/examples/library/scripts/generate.mjs b/labs/22-yield/yield/examples/library/scripts/generate.mjs new file mode 100644 index 00000000..c5ff7e9e --- /dev/null +++ b/labs/22-yield/yield/examples/library/scripts/generate.mjs @@ -0,0 +1,558 @@ +import { mkdir, writeFile } from "node:fs/promises"; +import { execFile as execFileCallback } from "node:child_process"; +import { dirname, join, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; +import { promisify } from "node:util"; + +const libraryDir = resolve(dirname(fileURLToPath(import.meta.url)), ".."); +const languages = ["typescript", "python", "go", "rust"]; +const execFile = promisify(execFileCallback); + +const patterns = [ + { + slug: "review-branch", + title: "Review a branch", + summary: "Run mechanical checks, inspect the diff, and stop on critical findings.", + preflightId: "check-branch", + preflightCommand: "printf 'typecheck and tests passed\\n'", + preflightClaim: "the branch passes mechanical checks", + decisionId: "review-diff", + instruction: "Review the branch for correctness, security, data-loss risks, and missing tests. Return pass only when no critical finding remains.", + decisionClaim: "the review has no critical findings" + }, + { + slug: "investigate-failure", + title: "Investigate a failure", + summary: "Capture evidence, test the likely cause, and finish only with a causal explanation.", + preflightId: "capture-failure", + preflightCommand: "printf 'failing test captured with recent diff\\n'", + preflightClaim: "the failure evidence is captured", + decisionId: "diagnose-cause", + instruction: "Use the failure output and recent change to identify the most likely root cause. Return pass only when the summary states a causal chain.", + decisionClaim: "the diagnosis states a supported cause" + }, + { + slug: "qa-web-change", + title: "QA a web change", + summary: "Build first, exercise changed routes, and finish only with no blocking regressions.", + preflightId: "build-web", + preflightCommand: "printf 'build passed; changed routes: / and /settings\\n'", + preflightClaim: "the web application builds", + decisionId: "test-changed-routes", + instruction: "Test the changed routes at desktop and mobile sizes, including keyboard navigation and form errors. Return pass only when no blocking regression remains.", + decisionClaim: "the changed routes have no blocking regression" + }, + { + slug: "release-package", + title: "Release a package", + summary: "Test, review the release, ask for approval, publish, and verify.", + preflightId: "test-package", + preflightCommand: "printf 'package tests passed\\n'", + preflightClaim: "the package tests pass", + decisionId: "review-release", + instruction: "Review the pending package release for breaking changes, missing notes, and rollback risk. Return pass only when it is ready to publish.", + decisionClaim: "the package is ready to publish", + approvalId: "approve-publish", + approvalQuestion: "Publish this package release?", + actionId: "publish-package", + actionCommand: "printf 'package published\\n'", + actionClaim: "the package publish command succeeds", + verifyId: "verify-package", + verifyCommand: "printf 'published package resolved from registry\\n'", + verifyClaim: "the published package resolves from the registry" + }, + { + slug: "triage-issue", + title: "Triage an issue", + summary: "Read the report, classify impact, and return one evidence-backed next action.", + preflightId: "read-issue", + preflightCommand: "printf 'issue: intermittent timeout after retry change\\n'", + preflightClaim: "the issue report is available", + decisionId: "classify-issue", + instruction: "Classify severity, identify missing evidence, and propose exactly one next action. Return pass only when the summary is actionable.", + decisionClaim: "the issue has one actionable next step" + }, + { + slug: "repair-ci", + title: "Repair a CI failure", + summary: "Read the failed job, apply one supported repair, and rerun the failing check.", + preflightId: "capture-ci-log", + preflightCommand: "printf 'ci log: test shard 2 failed after cache restore\\n'", + preflightClaim: "the failing CI evidence is captured", + decisionId: "plan-ci-repair", + instruction: "Diagnose the CI failure and describe the smallest supported repair. Return pass only when the repair is tied to the observed log.", + decisionClaim: "the CI repair is supported by the failure evidence", + actionId: "apply-ci-repair", + actionCommand: "printf 'ci repair applied\\n'", + actionClaim: "the CI repair command succeeds", + verifyId: "rerun-ci-check", + verifyCommand: "printf 'failing CI check now passes\\n'", + verifyClaim: "the previously failing CI check passes" + }, + { + slug: "upgrade-dependency", + title: "Upgrade a dependency", + summary: "Establish a baseline, review compatibility, approve the change, and rerun tests.", + preflightId: "baseline-tests", + preflightCommand: "printf 'baseline tests passed\\n'", + preflightClaim: "the baseline tests pass", + decisionId: "review-upgrade", + instruction: "Review the dependency upgrade for API changes, migration work, and rollback risk. Return pass only when the change is bounded.", + decisionClaim: "the dependency upgrade has a bounded plan", + approvalId: "approve-upgrade", + approvalQuestion: "Apply the reviewed dependency upgrade?", + actionId: "apply-upgrade", + actionCommand: "printf 'dependency upgraded\\n'", + actionClaim: "the dependency upgrade command succeeds", + verifyId: "post-upgrade-tests", + verifyCommand: "printf 'post-upgrade tests passed\\n'", + verifyClaim: "the tests pass after the dependency upgrade" + }, + { + slug: "migrate-database", + title: "Run a database migration", + summary: "Dry-run, inspect risk, approve, apply, and verify the real result.", + preflightId: "dry-run-migration", + preflightCommand: "printf 'dry run: add users_email_idx concurrently\\n'", + preflightClaim: "the migration dry-run succeeds", + decisionId: "review-migration", + instruction: "Review the migration plan for lock risk, irreversible work, and rollback. Return pass only when the plan is safe to apply.", + decisionClaim: "the migration plan has acceptable risk", + approvalId: "approve-migration", + approvalQuestion: "Apply the reviewed database migration?", + actionId: "apply-migration", + actionCommand: "printf 'migration applied\\n'", + actionClaim: "the migration applies cleanly", + verifyId: "verify-migration", + verifyCommand: "printf 'migration verification passed\\n'", + verifyClaim: "the migrated database passes verification" + }, + { + slug: "audit-security", + title: "Audit a change for security", + summary: "Collect mechanical audit output, inspect trust boundaries, and reject critical risk.", + preflightId: "run-security-checks", + preflightCommand: "printf 'dependency and secret scans completed\\n'", + preflightClaim: "the mechanical security checks complete", + decisionId: "review-trust-boundaries", + instruction: "Review authentication, authorization, input handling, secrets, and trust-boundary changes. Return pass only when no critical risk remains.", + decisionClaim: "the change has no critical security finding" + }, + { + slug: "publish-ios", + title: "Publish an iOS build", + summary: "Archive, review release metadata, approve upload, publish, and verify processing.", + preflightId: "archive-ios", + preflightCommand: "printf 'iOS archive and tests passed\\n'", + preflightClaim: "the iOS archive and tests pass", + decisionId: "review-ios-release", + instruction: "Review the iOS release metadata, versioning, privacy notes, and rollout risk. Return pass only when the build is ready for upload.", + decisionClaim: "the iOS build is ready for upload", + approvalId: "approve-ios-upload", + approvalQuestion: "Upload this iOS build to App Store Connect?", + actionId: "upload-ios", + actionCommand: "printf 'iOS build uploaded\\n'", + actionClaim: "the iOS upload command succeeds", + verifyId: "verify-ios-processing", + verifyCommand: "printf 'uploaded build entered processing\\n'", + verifyClaim: "the uploaded iOS build entered processing" + } +]; + +const decisionSchema = { + type: "object", + required: ["status", "critical", "summary"], + properties: { + status: { enum: ["pass", "needs_work"] }, + critical: { type: "integer", minimum: 0 }, + summary: { type: "string", minLength: 1 } + } +}; + +function quoted(value) { + return JSON.stringify(value); +} + +function indent(lines, spaces) { + const prefix = " ".repeat(spaces); + return lines.map((line) => line ? prefix + line : line); +} + +function resultLines(pattern, language) { + if (language === "typescript") return ["return { workflow: " + quoted(pattern.slug) + ", summary: decision.summary }"]; + if (language === "python") return ["return {\"workflow\": " + quoted(pattern.slug) + ", \"summary\": decision[\"summary\"]}"]; + if (language === "go") return ["return ctx.Complete(map[string]any{\"workflow\": " + quoted(pattern.slug) + ", \"summary\": decision.Summary})"]; + return ["Ok(json!({\"workflow\": " + quoted(pattern.slug) + ", \"summary\": decision[\"summary\"]}))"]; +} + +function addOptionalTypeScriptSteps(body, pattern) { + if (pattern.approvalId) { + body.push( + "", + "const approval = ctx.askUser(" + quoted(pattern.approvalId) + ", " + quoted(pattern.approvalQuestion) + ", [", + " { value: \"continue\", label: \"Continue\" },", + " { value: \"stop\", label: \"Stop\" },", + "])", + "if (approval !== \"continue\") ctx.refused(\"the operator declined to continue\")" + ); + } + if (pattern.actionId) { + body.push( + "", + "const action = ctx.runCommand(" + quoted(pattern.actionId) + ", " + quoted(pattern.actionCommand) + ", 600)", + "ctx.require(action.exit_code === 0, " + quoted(pattern.actionClaim) + ", action)" + ); + } + if (pattern.verifyId) { + body.push( + "", + "const verify = ctx.runCommand(" + quoted(pattern.verifyId) + ", " + quoted(pattern.verifyCommand) + ", 300)", + "ctx.require(verify.exit_code === 0, " + quoted(pattern.verifyClaim) + ", verify)" + ); + } +} + +function renderTypeScript(pattern) { + const body = [ + "const preflight = ctx.runCommand(" + quoted(pattern.preflightId) + ", " + quoted(pattern.preflightCommand) + ", 300)", + "ctx.require(preflight.exit_code === 0, " + quoted(pattern.preflightClaim) + ", preflight)", + "", + "const decision = ctx.agentTask(", + " " + quoted(pattern.decisionId) + ",", + " " + quoted(pattern.instruction) + ",", + " { stdout: preflight.stdout, stderr: preflight.stderr },", + " decisionSchema,", + ")", + "ctx.require(decision.status === \"pass\" && decision.critical === 0, " + quoted(pattern.decisionClaim) + ", decision)" + ]; + addOptionalTypeScriptSteps(body, pattern); + body.push("", ...resultLines(pattern, "typescript")); + return [ + "// " + pattern.title + ". Replace the illustrative commands with your project commands.", + "import { defineSkill } from \"../../../../sdk/typescript/src/index.ts\";", + "", + "type Decision = { status: \"pass\" | \"needs_work\"; critical: number; summary: string };", + "const decisionSchema = " + JSON.stringify(decisionSchema, null, 2) + ";", + "", + "defineSkill((ctx) => {", + ...indent(body, 2), + "});", + "" + ].join("\n"); +} + +function addOptionalPythonSteps(body, pattern) { + if (pattern.approvalId) { + body.push( + "", + "approval = ctx.ask_user(", + " " + quoted(pattern.approvalId) + ",", + " " + quoted(pattern.approvalQuestion) + ",", + " options=[{\"value\": \"continue\", \"label\": \"Continue\"}, {\"value\": \"stop\", \"label\": \"Stop\"}],", + ")", + "if approval != \"continue\":", + " ctx.refused(\"the operator declined to continue\")" + ); + } + if (pattern.actionId) { + body.push( + "", + "action = ctx.run_command(" + quoted(pattern.actionId) + ", " + quoted(pattern.actionCommand) + ", 600)", + "ctx.require(action.exit_code == 0, " + quoted(pattern.actionClaim) + ", action)" + ); + } + if (pattern.verifyId) { + body.push( + "", + "verify = ctx.run_command(" + quoted(pattern.verifyId) + ", " + quoted(pattern.verifyCommand) + ", 300)", + "ctx.require(verify.exit_code == 0, " + quoted(pattern.verifyClaim) + ", verify)" + ); + } +} + +function renderPython(pattern) { + const body = [ + "preflight = ctx.run_command(" + quoted(pattern.preflightId) + ", " + quoted(pattern.preflightCommand) + ", 300)", + "ctx.require(preflight.exit_code == 0, " + quoted(pattern.preflightClaim) + ", preflight)", + "", + "decision = ctx.agent_task(", + " " + quoted(pattern.decisionId) + ",", + " " + quoted(pattern.instruction) + ",", + " context={\"stdout\": preflight.stdout, \"stderr\": preflight.stderr},", + " schema=DECISION_SCHEMA,", + ")", + "ctx.require(decision[\"status\"] == \"pass\" and decision[\"critical\"] == 0, " + quoted(pattern.decisionClaim) + ", decision)" + ]; + addOptionalPythonSteps(body, pattern); + body.push("", ...resultLines(pattern, "python")); + return [ + "# " + pattern.title + ". Replace the illustrative commands with your project commands.", + "import sys", + "from pathlib import Path", + "", + "sys.path.insert(0, str(Path(__file__).resolve().parents[4] / \"sdk\" / \"python\"))", + "from yieldskill import define_skill # noqa: E402", + "", + "DECISION_SCHEMA = " + JSON.stringify(decisionSchema, null, 2), + "", + "def program(ctx):", + ...indent(body, 4), + "", + "define_skill(program)", + "" + ].join("\n"); +} + +function addOptionalGoSteps(body, pattern) { + if (pattern.approvalId) { + body.push( + "", + "approval := ctx.AskUser(", + " " + quoted(pattern.approvalId) + ",", + " " + quoted(pattern.approvalQuestion) + ",", + " protocol.Option{Value: \"continue\", Label: \"Continue\"},", + " protocol.Option{Value: \"stop\", Label: \"Stop\"},", + ")", + "if approval != \"continue\" {", + " return yield.Outcome{}, ctx.Refused(\"the operator declined to continue\")", + "}" + ); + } + if (pattern.actionId) { + body.push( + "", + "action := ctx.RunCommand(" + quoted(pattern.actionId) + ", " + quoted(pattern.actionCommand) + ", 600)", + "ctx.Require(action.ExitCode == 0, " + quoted(pattern.actionClaim) + ", action)" + ); + } + if (pattern.verifyId) { + body.push( + "", + "verify := ctx.RunCommand(" + quoted(pattern.verifyId) + ", " + quoted(pattern.verifyCommand) + ", 300)", + "ctx.Require(verify.ExitCode == 0, " + quoted(pattern.verifyClaim) + ", verify)" + ); + } +} + +function renderGo(pattern) { + const goTick = String.fromCharCode(96); + const body = [ + "preflight := ctx.RunCommand(" + quoted(pattern.preflightId) + ", " + quoted(pattern.preflightCommand) + ", 300)", + "ctx.Require(preflight.ExitCode == 0, " + quoted(pattern.preflightClaim) + ", preflight)", + "", + "raw := ctx.AgentTask(", + " " + quoted(pattern.decisionId) + ",", + " " + quoted(pattern.instruction) + ",", + " map[string]any{\"stdout\": preflight.Stdout, \"stderr\": preflight.Stderr},", + " json.RawMessage(decisionSchema),", + ")", + "var decision decision", + "if err := json.Unmarshal(raw, &decision); err != nil {", + " return yield.Outcome{}, err", + "}", + "ctx.Require(decision.Status == \"pass\" && decision.Critical == 0, " + quoted(pattern.decisionClaim) + ", decision)" + ]; + addOptionalGoSteps(body, pattern); + body.push("", ...resultLines(pattern, "go")); + return [ + "// " + pattern.title + ". Replace the illustrative commands with your project commands.", + "package main", + "", + "import (", + " \"encoding/json\"", + "", + ...(pattern.approvalId ? [" \"github.com/operatorstack/yield/internal/protocol\""] : []), + " \"github.com/operatorstack/yield/sdk/yield\"", + ")", + "", + "type decision struct {", + " Status string " + goTick + "json:\"status\"" + goTick, + " Critical int " + goTick + "json:\"critical\"" + goTick, + " Summary string " + goTick + "json:\"summary\"" + goTick, + "}", + "", + "const decisionSchema = " + goTick + JSON.stringify(decisionSchema) + goTick, + "", + "func main() {", + " yield.Main(func(ctx *yield.Context) (yield.Outcome, error) {", + ...indent(body, 4), + " })", + "}", + "" + ].join("\n"); +} + +function addOptionalRustSteps(body, pattern) { + if (pattern.approvalId) { + body.push( + "", + "let approval = ctx.ask_user(", + " " + quoted(pattern.approvalId) + ",", + " " + quoted(pattern.approvalQuestion) + ",", + " &[(\"continue\", \"Continue\"), (\"stop\", \"Stop\")],", + ");", + "if approval != \"continue\" {", + " return Err(ctx.refused(\"the operator declined to continue\"));", + "}" + ); + } + if (pattern.actionId) { + body.push( + "", + "let action = ctx.run_command(" + quoted(pattern.actionId) + ", " + quoted(pattern.actionCommand) + ", 600);", + "ctx.require(", + " action.exit_code == 0,", + " " + quoted(pattern.actionClaim) + ",", + " Some(&json!({\"exit_code\": action.exit_code})),", + ");" + ); + } + if (pattern.verifyId) { + body.push( + "", + "let verify = ctx.run_command(" + quoted(pattern.verifyId) + ", " + quoted(pattern.verifyCommand) + ", 300);", + "ctx.require(", + " verify.exit_code == 0,", + " " + quoted(pattern.verifyClaim) + ",", + " Some(&json!({\"exit_code\": verify.exit_code})),", + ");" + ); + } +} + +function renderRust(pattern) { + const body = [ + "let preflight = ctx.run_command(" + quoted(pattern.preflightId) + ", " + quoted(pattern.preflightCommand) + ", 300);", + "ctx.require(", + " preflight.exit_code == 0,", + " " + quoted(pattern.preflightClaim) + ",", + " Some(&json!({\"exit_code\": preflight.exit_code})),", + ");", + "", + "let decision = ctx.agent_task(", + " " + quoted(pattern.decisionId) + ",", + " " + quoted(pattern.instruction) + ",", + " Some(json!({\"stdout\": preflight.stdout, \"stderr\": preflight.stderr})),", + " Some(decision_schema()),", + ");", + "ctx.require(", + " decision[\"status\"] == \"pass\" && decision[\"critical\"] == 0,", + " " + quoted(pattern.decisionClaim) + ",", + " Some(&decision),", + ");" + ]; + addOptionalRustSteps(body, pattern); + body.push("", ...resultLines(pattern, "rust")); + return [ + "// " + pattern.title + ". Replace the illustrative commands with your project commands.", + "use serde_json::{json, Value};", + "use yieldskill::{define_skill, Context, SkillResult};", + "", + "fn decision_schema() -> Value {", + " json!(" + JSON.stringify(decisionSchema) + ")", + "}", + "", + "fn program(ctx: &mut Context) -> SkillResult {", + ...indent(body, 4), + "}", + "", + "fn main() {", + " define_skill(program);", + "}", + "" + ].join("\n"); +} + +function renderSkill(pattern) { + return [ + "---", + "name: " + pattern.slug, + "description: " + pattern.summary, + "---", + "", + "Run:", + "", + " yskill run .", + "", + "Follow each returned operation exactly and resume the run with the result.", + "The program owns order, approval, commands, and finish rules. The agent", + "owns judgment inside each agent task. Replace the illustrative commands", + "with the real commands from your repository before using this workflow.", + "" + ].join("\n"); +} + +function renderFixture(pattern) { + const fixture = { + [pattern.decisionId]: { + status: "pass", + critical: 0, + summary: "Fixture result: " + pattern.summary + } + }; + if (pattern.approvalId) fixture[pattern.approvalId] = { value: "continue" }; + return JSON.stringify(fixture, null, 2) + "\n"; +} + +function manifestFor(language, slug) { + if (language === "typescript") return { run: ["node", "../src/" + slug + ".ts"] }; + if (language === "python") return { run: ["python3", "../src/" + slug + ".py"] }; + if (language === "go") return { run: ["go", "run", "../src/" + slug + "/main.go"] }; + return { run: ["cargo", "run", "--quiet", "--manifest-path", "../Cargo.toml", "--bin", slug] }; +} + +async function write(path, content) { + await mkdir(dirname(path), { recursive: true }); + await writeFile(path, content); +} + +await write(join(libraryDir, "catalog.json"), JSON.stringify(patterns.map((pattern) => ({ + slug: pattern.slug, + title: pattern.title, + summary: pattern.summary, + languages +})), null, 2) + "\n"); + +await write(join(libraryDir, "rust", "Cargo.toml"), [ + "[package]", + "name = \"yield-example-library\"", + "version = \"0.1.0\"", + "edition = \"2021\"", + "publish = false", + "", + "[dependencies]", + "yieldskill = { path = \"../../../sdk/rust\" }", + "serde_json = \"1\"", + "" +].join("\n")); + +const goSources = []; +for (const pattern of patterns) { + const sources = { + typescript: renderTypeScript(pattern), + python: renderPython(pattern), + go: renderGo(pattern), + rust: renderRust(pattern) + }; + const extensions = { typescript: "ts", python: "py", go: "go", rust: "rs" }; + for (const language of languages) { + const sourceDir = language === "rust" + ? join(libraryDir, language, "src", "bin") + : language === "go" + ? join(libraryDir, language, "src", pattern.slug) + : join(libraryDir, language, "src"); + const sourceName = language === "go" ? "main.go" : pattern.slug + "." + extensions[language]; + const sourcePath = join(sourceDir, sourceName); + await write(sourcePath, sources[language]); + if (language === "go") goSources.push(sourcePath); + const skillDir = join(libraryDir, language, pattern.slug); + await write(join(skillDir, "SKILL.md"), renderSkill(pattern)); + await write(join(skillDir, "skill.json"), JSON.stringify(manifestFor(language, pattern.slug), null, 2) + "\n"); + await write(join(skillDir, "fixtures", "responses.json"), renderFixture(pattern)); + } +} + +await execFile("gofmt", ["-w", ...goSources]); +await execFile("cargo", ["fmt", "--manifest-path", join(libraryDir, "rust", "Cargo.toml")]); + +console.log("generated " + patterns.length + " patterns in " + languages.length + " languages"); diff --git a/labs/22-yield/yield/examples/library/test-all.sh b/labs/22-yield/yield/examples/library/test-all.sh new file mode 100755 index 00000000..157c41b9 --- /dev/null +++ b/labs/22-yield/yield/examples/library/test-all.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail + +library_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +yskill="${YSKILL:-yskill}" +count=0 + +for language in typescript python go rust; do + for skill_dir in "$library_dir/$language"/*; do + [[ -f "$skill_dir/fixtures/responses.json" ]] || continue + echo "==> ${language}/$(basename "$skill_dir")" + "$yskill" test "$skill_dir" + count=$((count + 1)) + done +done + +if [[ "$count" -ne 40 ]]; then + echo "expected 40 fixture runs, found $count" >&2 + exit 1 +fi + +echo "validated $count example workflows" diff --git a/labs/22-yield/yield/examples/library/typescript/audit-security/SKILL.md b/labs/22-yield/yield/examples/library/typescript/audit-security/SKILL.md new file mode 100644 index 00000000..f83b8e72 --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/audit-security/SKILL.md @@ -0,0 +1,13 @@ +--- +name: audit-security +description: Collect mechanical audit output, inspect trust boundaries, and reject critical risk. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/typescript/audit-security/fixtures/responses.json b/labs/22-yield/yield/examples/library/typescript/audit-security/fixtures/responses.json new file mode 100644 index 00000000..f690e022 --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/audit-security/fixtures/responses.json @@ -0,0 +1,7 @@ +{ + "review-trust-boundaries": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Collect mechanical audit output, inspect trust boundaries, and reject critical risk." + } +} diff --git a/labs/22-yield/yield/examples/library/typescript/audit-security/skill.json b/labs/22-yield/yield/examples/library/typescript/audit-security/skill.json new file mode 100644 index 00000000..86e81d90 --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/audit-security/skill.json @@ -0,0 +1,6 @@ +{ + "run": [ + "node", + "../src/audit-security.ts" + ] +} diff --git a/labs/22-yield/yield/examples/library/typescript/investigate-failure/SKILL.md b/labs/22-yield/yield/examples/library/typescript/investigate-failure/SKILL.md new file mode 100644 index 00000000..62fa2c91 --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/investigate-failure/SKILL.md @@ -0,0 +1,13 @@ +--- +name: investigate-failure +description: Capture evidence, test the likely cause, and finish only with a causal explanation. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/typescript/investigate-failure/fixtures/responses.json b/labs/22-yield/yield/examples/library/typescript/investigate-failure/fixtures/responses.json new file mode 100644 index 00000000..fa01815e --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/investigate-failure/fixtures/responses.json @@ -0,0 +1,7 @@ +{ + "diagnose-cause": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Capture evidence, test the likely cause, and finish only with a causal explanation." + } +} diff --git a/labs/22-yield/yield/examples/library/typescript/investigate-failure/skill.json b/labs/22-yield/yield/examples/library/typescript/investigate-failure/skill.json new file mode 100644 index 00000000..291e572e --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/investigate-failure/skill.json @@ -0,0 +1,6 @@ +{ + "run": [ + "node", + "../src/investigate-failure.ts" + ] +} diff --git a/labs/22-yield/yield/examples/library/typescript/migrate-database/SKILL.md b/labs/22-yield/yield/examples/library/typescript/migrate-database/SKILL.md new file mode 100644 index 00000000..6acca087 --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/migrate-database/SKILL.md @@ -0,0 +1,13 @@ +--- +name: migrate-database +description: Dry-run, inspect risk, approve, apply, and verify the real result. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/typescript/migrate-database/fixtures/responses.json b/labs/22-yield/yield/examples/library/typescript/migrate-database/fixtures/responses.json new file mode 100644 index 00000000..ae5f3c7a --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/migrate-database/fixtures/responses.json @@ -0,0 +1,10 @@ +{ + "review-migration": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Dry-run, inspect risk, approve, apply, and verify the real result." + }, + "approve-migration": { + "value": "continue" + } +} diff --git a/labs/22-yield/yield/examples/library/typescript/migrate-database/skill.json b/labs/22-yield/yield/examples/library/typescript/migrate-database/skill.json new file mode 100644 index 00000000..e436e406 --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/migrate-database/skill.json @@ -0,0 +1,6 @@ +{ + "run": [ + "node", + "../src/migrate-database.ts" + ] +} diff --git a/labs/22-yield/yield/examples/library/typescript/publish-ios/SKILL.md b/labs/22-yield/yield/examples/library/typescript/publish-ios/SKILL.md new file mode 100644 index 00000000..88e7449d --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/publish-ios/SKILL.md @@ -0,0 +1,13 @@ +--- +name: publish-ios +description: Archive, review release metadata, approve upload, publish, and verify processing. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/typescript/publish-ios/fixtures/responses.json b/labs/22-yield/yield/examples/library/typescript/publish-ios/fixtures/responses.json new file mode 100644 index 00000000..9f0d5d6e --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/publish-ios/fixtures/responses.json @@ -0,0 +1,10 @@ +{ + "review-ios-release": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Archive, review release metadata, approve upload, publish, and verify processing." + }, + "approve-ios-upload": { + "value": "continue" + } +} diff --git a/labs/22-yield/yield/examples/library/typescript/publish-ios/skill.json b/labs/22-yield/yield/examples/library/typescript/publish-ios/skill.json new file mode 100644 index 00000000..0ec603d0 --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/publish-ios/skill.json @@ -0,0 +1,6 @@ +{ + "run": [ + "node", + "../src/publish-ios.ts" + ] +} diff --git a/labs/22-yield/yield/examples/library/typescript/qa-web-change/SKILL.md b/labs/22-yield/yield/examples/library/typescript/qa-web-change/SKILL.md new file mode 100644 index 00000000..533bbdf7 --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/qa-web-change/SKILL.md @@ -0,0 +1,13 @@ +--- +name: qa-web-change +description: Build first, exercise changed routes, and finish only with no blocking regressions. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/typescript/qa-web-change/fixtures/responses.json b/labs/22-yield/yield/examples/library/typescript/qa-web-change/fixtures/responses.json new file mode 100644 index 00000000..1ed3c70b --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/qa-web-change/fixtures/responses.json @@ -0,0 +1,7 @@ +{ + "test-changed-routes": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Build first, exercise changed routes, and finish only with no blocking regressions." + } +} diff --git a/labs/22-yield/yield/examples/library/typescript/qa-web-change/skill.json b/labs/22-yield/yield/examples/library/typescript/qa-web-change/skill.json new file mode 100644 index 00000000..47999973 --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/qa-web-change/skill.json @@ -0,0 +1,6 @@ +{ + "run": [ + "node", + "../src/qa-web-change.ts" + ] +} diff --git a/labs/22-yield/yield/examples/library/typescript/release-package/SKILL.md b/labs/22-yield/yield/examples/library/typescript/release-package/SKILL.md new file mode 100644 index 00000000..7429d9eb --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/release-package/SKILL.md @@ -0,0 +1,13 @@ +--- +name: release-package +description: Test, review the release, ask for approval, publish, and verify. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/typescript/release-package/fixtures/responses.json b/labs/22-yield/yield/examples/library/typescript/release-package/fixtures/responses.json new file mode 100644 index 00000000..575d24a1 --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/release-package/fixtures/responses.json @@ -0,0 +1,10 @@ +{ + "review-release": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Test, review the release, ask for approval, publish, and verify." + }, + "approve-publish": { + "value": "continue" + } +} diff --git a/labs/22-yield/yield/examples/library/typescript/release-package/skill.json b/labs/22-yield/yield/examples/library/typescript/release-package/skill.json new file mode 100644 index 00000000..290467b2 --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/release-package/skill.json @@ -0,0 +1,6 @@ +{ + "run": [ + "node", + "../src/release-package.ts" + ] +} diff --git a/labs/22-yield/yield/examples/library/typescript/repair-ci/SKILL.md b/labs/22-yield/yield/examples/library/typescript/repair-ci/SKILL.md new file mode 100644 index 00000000..159ee45d --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/repair-ci/SKILL.md @@ -0,0 +1,13 @@ +--- +name: repair-ci +description: Read the failed job, apply one supported repair, and rerun the failing check. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/typescript/repair-ci/fixtures/responses.json b/labs/22-yield/yield/examples/library/typescript/repair-ci/fixtures/responses.json new file mode 100644 index 00000000..f73e7fc1 --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/repair-ci/fixtures/responses.json @@ -0,0 +1,7 @@ +{ + "plan-ci-repair": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Read the failed job, apply one supported repair, and rerun the failing check." + } +} diff --git a/labs/22-yield/yield/examples/library/typescript/repair-ci/skill.json b/labs/22-yield/yield/examples/library/typescript/repair-ci/skill.json new file mode 100644 index 00000000..7324bf8f --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/repair-ci/skill.json @@ -0,0 +1,6 @@ +{ + "run": [ + "node", + "../src/repair-ci.ts" + ] +} diff --git a/labs/22-yield/yield/examples/library/typescript/review-branch/SKILL.md b/labs/22-yield/yield/examples/library/typescript/review-branch/SKILL.md new file mode 100644 index 00000000..24b513ac --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/review-branch/SKILL.md @@ -0,0 +1,13 @@ +--- +name: review-branch +description: Run mechanical checks, inspect the diff, and stop on critical findings. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/typescript/review-branch/fixtures/responses.json b/labs/22-yield/yield/examples/library/typescript/review-branch/fixtures/responses.json new file mode 100644 index 00000000..b891fae1 --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/review-branch/fixtures/responses.json @@ -0,0 +1,7 @@ +{ + "review-diff": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Run mechanical checks, inspect the diff, and stop on critical findings." + } +} diff --git a/labs/22-yield/yield/examples/library/typescript/review-branch/skill.json b/labs/22-yield/yield/examples/library/typescript/review-branch/skill.json new file mode 100644 index 00000000..84488ecf --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/review-branch/skill.json @@ -0,0 +1,6 @@ +{ + "run": [ + "node", + "../src/review-branch.ts" + ] +} diff --git a/labs/22-yield/yield/examples/library/typescript/src/audit-security.ts b/labs/22-yield/yield/examples/library/typescript/src/audit-security.ts new file mode 100644 index 00000000..ab9e7ba4 --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/src/audit-security.ts @@ -0,0 +1,43 @@ +// Audit a change for security. Replace the illustrative commands with your project commands. +import { defineSkill } from "../../../../sdk/typescript/src/index.ts"; + +type Decision = { status: "pass" | "needs_work"; critical: number; summary: string }; +const decisionSchema = { + "type": "object", + "required": [ + "status", + "critical", + "summary" + ], + "properties": { + "status": { + "enum": [ + "pass", + "needs_work" + ] + }, + "critical": { + "type": "integer", + "minimum": 0 + }, + "summary": { + "type": "string", + "minLength": 1 + } + } +}; + +defineSkill((ctx) => { + const preflight = ctx.runCommand("run-security-checks", "printf 'dependency and secret scans completed\\n'", 300) + ctx.require(preflight.exit_code === 0, "the mechanical security checks complete", preflight) + + const decision = ctx.agentTask( + "review-trust-boundaries", + "Review authentication, authorization, input handling, secrets, and trust-boundary changes. Return pass only when no critical risk remains.", + { stdout: preflight.stdout, stderr: preflight.stderr }, + decisionSchema, + ) + ctx.require(decision.status === "pass" && decision.critical === 0, "the change has no critical security finding", decision) + + return { workflow: "audit-security", summary: decision.summary } +}); diff --git a/labs/22-yield/yield/examples/library/typescript/src/investigate-failure.ts b/labs/22-yield/yield/examples/library/typescript/src/investigate-failure.ts new file mode 100644 index 00000000..2987c3e5 --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/src/investigate-failure.ts @@ -0,0 +1,43 @@ +// Investigate a failure. Replace the illustrative commands with your project commands. +import { defineSkill } from "../../../../sdk/typescript/src/index.ts"; + +type Decision = { status: "pass" | "needs_work"; critical: number; summary: string }; +const decisionSchema = { + "type": "object", + "required": [ + "status", + "critical", + "summary" + ], + "properties": { + "status": { + "enum": [ + "pass", + "needs_work" + ] + }, + "critical": { + "type": "integer", + "minimum": 0 + }, + "summary": { + "type": "string", + "minLength": 1 + } + } +}; + +defineSkill((ctx) => { + const preflight = ctx.runCommand("capture-failure", "printf 'failing test captured with recent diff\\n'", 300) + ctx.require(preflight.exit_code === 0, "the failure evidence is captured", preflight) + + const decision = ctx.agentTask( + "diagnose-cause", + "Use the failure output and recent change to identify the most likely root cause. Return pass only when the summary states a causal chain.", + { stdout: preflight.stdout, stderr: preflight.stderr }, + decisionSchema, + ) + ctx.require(decision.status === "pass" && decision.critical === 0, "the diagnosis states a supported cause", decision) + + return { workflow: "investigate-failure", summary: decision.summary } +}); diff --git a/labs/22-yield/yield/examples/library/typescript/src/migrate-database.ts b/labs/22-yield/yield/examples/library/typescript/src/migrate-database.ts new file mode 100644 index 00000000..0cbfcdd0 --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/src/migrate-database.ts @@ -0,0 +1,55 @@ +// Run a database migration. Replace the illustrative commands with your project commands. +import { defineSkill } from "../../../../sdk/typescript/src/index.ts"; + +type Decision = { status: "pass" | "needs_work"; critical: number; summary: string }; +const decisionSchema = { + "type": "object", + "required": [ + "status", + "critical", + "summary" + ], + "properties": { + "status": { + "enum": [ + "pass", + "needs_work" + ] + }, + "critical": { + "type": "integer", + "minimum": 0 + }, + "summary": { + "type": "string", + "minLength": 1 + } + } +}; + +defineSkill((ctx) => { + const preflight = ctx.runCommand("dry-run-migration", "printf 'dry run: add users_email_idx concurrently\\n'", 300) + ctx.require(preflight.exit_code === 0, "the migration dry-run succeeds", preflight) + + const decision = ctx.agentTask( + "review-migration", + "Review the migration plan for lock risk, irreversible work, and rollback. Return pass only when the plan is safe to apply.", + { stdout: preflight.stdout, stderr: preflight.stderr }, + decisionSchema, + ) + ctx.require(decision.status === "pass" && decision.critical === 0, "the migration plan has acceptable risk", decision) + + const approval = ctx.askUser("approve-migration", "Apply the reviewed database migration?", [ + { value: "continue", label: "Continue" }, + { value: "stop", label: "Stop" }, + ]) + if (approval !== "continue") ctx.refused("the operator declined to continue") + + const action = ctx.runCommand("apply-migration", "printf 'migration applied\\n'", 600) + ctx.require(action.exit_code === 0, "the migration applies cleanly", action) + + const verify = ctx.runCommand("verify-migration", "printf 'migration verification passed\\n'", 300) + ctx.require(verify.exit_code === 0, "the migrated database passes verification", verify) + + return { workflow: "migrate-database", summary: decision.summary } +}); diff --git a/labs/22-yield/yield/examples/library/typescript/src/publish-ios.ts b/labs/22-yield/yield/examples/library/typescript/src/publish-ios.ts new file mode 100644 index 00000000..1d85a266 --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/src/publish-ios.ts @@ -0,0 +1,55 @@ +// Publish an iOS build. Replace the illustrative commands with your project commands. +import { defineSkill } from "../../../../sdk/typescript/src/index.ts"; + +type Decision = { status: "pass" | "needs_work"; critical: number; summary: string }; +const decisionSchema = { + "type": "object", + "required": [ + "status", + "critical", + "summary" + ], + "properties": { + "status": { + "enum": [ + "pass", + "needs_work" + ] + }, + "critical": { + "type": "integer", + "minimum": 0 + }, + "summary": { + "type": "string", + "minLength": 1 + } + } +}; + +defineSkill((ctx) => { + const preflight = ctx.runCommand("archive-ios", "printf 'iOS archive and tests passed\\n'", 300) + ctx.require(preflight.exit_code === 0, "the iOS archive and tests pass", preflight) + + const decision = ctx.agentTask( + "review-ios-release", + "Review the iOS release metadata, versioning, privacy notes, and rollout risk. Return pass only when the build is ready for upload.", + { stdout: preflight.stdout, stderr: preflight.stderr }, + decisionSchema, + ) + ctx.require(decision.status === "pass" && decision.critical === 0, "the iOS build is ready for upload", decision) + + const approval = ctx.askUser("approve-ios-upload", "Upload this iOS build to App Store Connect?", [ + { value: "continue", label: "Continue" }, + { value: "stop", label: "Stop" }, + ]) + if (approval !== "continue") ctx.refused("the operator declined to continue") + + const action = ctx.runCommand("upload-ios", "printf 'iOS build uploaded\\n'", 600) + ctx.require(action.exit_code === 0, "the iOS upload command succeeds", action) + + const verify = ctx.runCommand("verify-ios-processing", "printf 'uploaded build entered processing\\n'", 300) + ctx.require(verify.exit_code === 0, "the uploaded iOS build entered processing", verify) + + return { workflow: "publish-ios", summary: decision.summary } +}); diff --git a/labs/22-yield/yield/examples/library/typescript/src/qa-web-change.ts b/labs/22-yield/yield/examples/library/typescript/src/qa-web-change.ts new file mode 100644 index 00000000..ec84f885 --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/src/qa-web-change.ts @@ -0,0 +1,43 @@ +// QA a web change. Replace the illustrative commands with your project commands. +import { defineSkill } from "../../../../sdk/typescript/src/index.ts"; + +type Decision = { status: "pass" | "needs_work"; critical: number; summary: string }; +const decisionSchema = { + "type": "object", + "required": [ + "status", + "critical", + "summary" + ], + "properties": { + "status": { + "enum": [ + "pass", + "needs_work" + ] + }, + "critical": { + "type": "integer", + "minimum": 0 + }, + "summary": { + "type": "string", + "minLength": 1 + } + } +}; + +defineSkill((ctx) => { + const preflight = ctx.runCommand("build-web", "printf 'build passed; changed routes: / and /settings\\n'", 300) + ctx.require(preflight.exit_code === 0, "the web application builds", preflight) + + const decision = ctx.agentTask( + "test-changed-routes", + "Test the changed routes at desktop and mobile sizes, including keyboard navigation and form errors. Return pass only when no blocking regression remains.", + { stdout: preflight.stdout, stderr: preflight.stderr }, + decisionSchema, + ) + ctx.require(decision.status === "pass" && decision.critical === 0, "the changed routes have no blocking regression", decision) + + return { workflow: "qa-web-change", summary: decision.summary } +}); diff --git a/labs/22-yield/yield/examples/library/typescript/src/release-package.ts b/labs/22-yield/yield/examples/library/typescript/src/release-package.ts new file mode 100644 index 00000000..b03e62fb --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/src/release-package.ts @@ -0,0 +1,55 @@ +// Release a package. Replace the illustrative commands with your project commands. +import { defineSkill } from "../../../../sdk/typescript/src/index.ts"; + +type Decision = { status: "pass" | "needs_work"; critical: number; summary: string }; +const decisionSchema = { + "type": "object", + "required": [ + "status", + "critical", + "summary" + ], + "properties": { + "status": { + "enum": [ + "pass", + "needs_work" + ] + }, + "critical": { + "type": "integer", + "minimum": 0 + }, + "summary": { + "type": "string", + "minLength": 1 + } + } +}; + +defineSkill((ctx) => { + const preflight = ctx.runCommand("test-package", "printf 'package tests passed\\n'", 300) + ctx.require(preflight.exit_code === 0, "the package tests pass", preflight) + + const decision = ctx.agentTask( + "review-release", + "Review the pending package release for breaking changes, missing notes, and rollback risk. Return pass only when it is ready to publish.", + { stdout: preflight.stdout, stderr: preflight.stderr }, + decisionSchema, + ) + ctx.require(decision.status === "pass" && decision.critical === 0, "the package is ready to publish", decision) + + const approval = ctx.askUser("approve-publish", "Publish this package release?", [ + { value: "continue", label: "Continue" }, + { value: "stop", label: "Stop" }, + ]) + if (approval !== "continue") ctx.refused("the operator declined to continue") + + const action = ctx.runCommand("publish-package", "printf 'package published\\n'", 600) + ctx.require(action.exit_code === 0, "the package publish command succeeds", action) + + const verify = ctx.runCommand("verify-package", "printf 'published package resolved from registry\\n'", 300) + ctx.require(verify.exit_code === 0, "the published package resolves from the registry", verify) + + return { workflow: "release-package", summary: decision.summary } +}); diff --git a/labs/22-yield/yield/examples/library/typescript/src/repair-ci.ts b/labs/22-yield/yield/examples/library/typescript/src/repair-ci.ts new file mode 100644 index 00000000..933869d8 --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/src/repair-ci.ts @@ -0,0 +1,49 @@ +// Repair a CI failure. Replace the illustrative commands with your project commands. +import { defineSkill } from "../../../../sdk/typescript/src/index.ts"; + +type Decision = { status: "pass" | "needs_work"; critical: number; summary: string }; +const decisionSchema = { + "type": "object", + "required": [ + "status", + "critical", + "summary" + ], + "properties": { + "status": { + "enum": [ + "pass", + "needs_work" + ] + }, + "critical": { + "type": "integer", + "minimum": 0 + }, + "summary": { + "type": "string", + "minLength": 1 + } + } +}; + +defineSkill((ctx) => { + const preflight = ctx.runCommand("capture-ci-log", "printf 'ci log: test shard 2 failed after cache restore\\n'", 300) + ctx.require(preflight.exit_code === 0, "the failing CI evidence is captured", preflight) + + const decision = ctx.agentTask( + "plan-ci-repair", + "Diagnose the CI failure and describe the smallest supported repair. Return pass only when the repair is tied to the observed log.", + { stdout: preflight.stdout, stderr: preflight.stderr }, + decisionSchema, + ) + ctx.require(decision.status === "pass" && decision.critical === 0, "the CI repair is supported by the failure evidence", decision) + + const action = ctx.runCommand("apply-ci-repair", "printf 'ci repair applied\\n'", 600) + ctx.require(action.exit_code === 0, "the CI repair command succeeds", action) + + const verify = ctx.runCommand("rerun-ci-check", "printf 'failing CI check now passes\\n'", 300) + ctx.require(verify.exit_code === 0, "the previously failing CI check passes", verify) + + return { workflow: "repair-ci", summary: decision.summary } +}); diff --git a/labs/22-yield/yield/examples/library/typescript/src/review-branch.ts b/labs/22-yield/yield/examples/library/typescript/src/review-branch.ts new file mode 100644 index 00000000..86048e1d --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/src/review-branch.ts @@ -0,0 +1,43 @@ +// Review a branch. Replace the illustrative commands with your project commands. +import { defineSkill } from "../../../../sdk/typescript/src/index.ts"; + +type Decision = { status: "pass" | "needs_work"; critical: number; summary: string }; +const decisionSchema = { + "type": "object", + "required": [ + "status", + "critical", + "summary" + ], + "properties": { + "status": { + "enum": [ + "pass", + "needs_work" + ] + }, + "critical": { + "type": "integer", + "minimum": 0 + }, + "summary": { + "type": "string", + "minLength": 1 + } + } +}; + +defineSkill((ctx) => { + const preflight = ctx.runCommand("check-branch", "printf 'typecheck and tests passed\\n'", 300) + ctx.require(preflight.exit_code === 0, "the branch passes mechanical checks", preflight) + + const decision = ctx.agentTask( + "review-diff", + "Review the branch for correctness, security, data-loss risks, and missing tests. Return pass only when no critical finding remains.", + { stdout: preflight.stdout, stderr: preflight.stderr }, + decisionSchema, + ) + ctx.require(decision.status === "pass" && decision.critical === 0, "the review has no critical findings", decision) + + return { workflow: "review-branch", summary: decision.summary } +}); diff --git a/labs/22-yield/yield/examples/library/typescript/src/triage-issue.ts b/labs/22-yield/yield/examples/library/typescript/src/triage-issue.ts new file mode 100644 index 00000000..b466881f --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/src/triage-issue.ts @@ -0,0 +1,43 @@ +// Triage an issue. Replace the illustrative commands with your project commands. +import { defineSkill } from "../../../../sdk/typescript/src/index.ts"; + +type Decision = { status: "pass" | "needs_work"; critical: number; summary: string }; +const decisionSchema = { + "type": "object", + "required": [ + "status", + "critical", + "summary" + ], + "properties": { + "status": { + "enum": [ + "pass", + "needs_work" + ] + }, + "critical": { + "type": "integer", + "minimum": 0 + }, + "summary": { + "type": "string", + "minLength": 1 + } + } +}; + +defineSkill((ctx) => { + const preflight = ctx.runCommand("read-issue", "printf 'issue: intermittent timeout after retry change\\n'", 300) + ctx.require(preflight.exit_code === 0, "the issue report is available", preflight) + + const decision = ctx.agentTask( + "classify-issue", + "Classify severity, identify missing evidence, and propose exactly one next action. Return pass only when the summary is actionable.", + { stdout: preflight.stdout, stderr: preflight.stderr }, + decisionSchema, + ) + ctx.require(decision.status === "pass" && decision.critical === 0, "the issue has one actionable next step", decision) + + return { workflow: "triage-issue", summary: decision.summary } +}); diff --git a/labs/22-yield/yield/examples/library/typescript/src/upgrade-dependency.ts b/labs/22-yield/yield/examples/library/typescript/src/upgrade-dependency.ts new file mode 100644 index 00000000..917bc434 --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/src/upgrade-dependency.ts @@ -0,0 +1,55 @@ +// Upgrade a dependency. Replace the illustrative commands with your project commands. +import { defineSkill } from "../../../../sdk/typescript/src/index.ts"; + +type Decision = { status: "pass" | "needs_work"; critical: number; summary: string }; +const decisionSchema = { + "type": "object", + "required": [ + "status", + "critical", + "summary" + ], + "properties": { + "status": { + "enum": [ + "pass", + "needs_work" + ] + }, + "critical": { + "type": "integer", + "minimum": 0 + }, + "summary": { + "type": "string", + "minLength": 1 + } + } +}; + +defineSkill((ctx) => { + const preflight = ctx.runCommand("baseline-tests", "printf 'baseline tests passed\\n'", 300) + ctx.require(preflight.exit_code === 0, "the baseline tests pass", preflight) + + const decision = ctx.agentTask( + "review-upgrade", + "Review the dependency upgrade for API changes, migration work, and rollback risk. Return pass only when the change is bounded.", + { stdout: preflight.stdout, stderr: preflight.stderr }, + decisionSchema, + ) + ctx.require(decision.status === "pass" && decision.critical === 0, "the dependency upgrade has a bounded plan", decision) + + const approval = ctx.askUser("approve-upgrade", "Apply the reviewed dependency upgrade?", [ + { value: "continue", label: "Continue" }, + { value: "stop", label: "Stop" }, + ]) + if (approval !== "continue") ctx.refused("the operator declined to continue") + + const action = ctx.runCommand("apply-upgrade", "printf 'dependency upgraded\\n'", 600) + ctx.require(action.exit_code === 0, "the dependency upgrade command succeeds", action) + + const verify = ctx.runCommand("post-upgrade-tests", "printf 'post-upgrade tests passed\\n'", 300) + ctx.require(verify.exit_code === 0, "the tests pass after the dependency upgrade", verify) + + return { workflow: "upgrade-dependency", summary: decision.summary } +}); diff --git a/labs/22-yield/yield/examples/library/typescript/triage-issue/SKILL.md b/labs/22-yield/yield/examples/library/typescript/triage-issue/SKILL.md new file mode 100644 index 00000000..82dee14e --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/triage-issue/SKILL.md @@ -0,0 +1,13 @@ +--- +name: triage-issue +description: Read the report, classify impact, and return one evidence-backed next action. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/typescript/triage-issue/fixtures/responses.json b/labs/22-yield/yield/examples/library/typescript/triage-issue/fixtures/responses.json new file mode 100644 index 00000000..3462c970 --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/triage-issue/fixtures/responses.json @@ -0,0 +1,7 @@ +{ + "classify-issue": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Read the report, classify impact, and return one evidence-backed next action." + } +} diff --git a/labs/22-yield/yield/examples/library/typescript/triage-issue/skill.json b/labs/22-yield/yield/examples/library/typescript/triage-issue/skill.json new file mode 100644 index 00000000..67bb078d --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/triage-issue/skill.json @@ -0,0 +1,6 @@ +{ + "run": [ + "node", + "../src/triage-issue.ts" + ] +} diff --git a/labs/22-yield/yield/examples/library/typescript/upgrade-dependency/SKILL.md b/labs/22-yield/yield/examples/library/typescript/upgrade-dependency/SKILL.md new file mode 100644 index 00000000..c40615fb --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/upgrade-dependency/SKILL.md @@ -0,0 +1,13 @@ +--- +name: upgrade-dependency +description: Establish a baseline, review compatibility, approve the change, and rerun tests. +--- + +Run: + + yskill run . + +Follow each returned operation exactly and resume the run with the result. +The program owns order, approval, commands, and finish rules. The agent +owns judgment inside each agent task. Replace the illustrative commands +with the real commands from your repository before using this workflow. diff --git a/labs/22-yield/yield/examples/library/typescript/upgrade-dependency/fixtures/responses.json b/labs/22-yield/yield/examples/library/typescript/upgrade-dependency/fixtures/responses.json new file mode 100644 index 00000000..2f311f80 --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/upgrade-dependency/fixtures/responses.json @@ -0,0 +1,10 @@ +{ + "review-upgrade": { + "status": "pass", + "critical": 0, + "summary": "Fixture result: Establish a baseline, review compatibility, approve the change, and rerun tests." + }, + "approve-upgrade": { + "value": "continue" + } +} diff --git a/labs/22-yield/yield/examples/library/typescript/upgrade-dependency/skill.json b/labs/22-yield/yield/examples/library/typescript/upgrade-dependency/skill.json new file mode 100644 index 00000000..c35ca5c2 --- /dev/null +++ b/labs/22-yield/yield/examples/library/typescript/upgrade-dependency/skill.json @@ -0,0 +1,6 @@ +{ + "run": [ + "node", + "../src/upgrade-dependency.ts" + ] +} From 8da9ee3640f8f09a51258ca22d73387e20e14062 Mon Sep 17 00:00:00 2001 From: bigboateng Date: Sat, 1 Aug 2026 15:59:52 +0100 Subject: [PATCH 2/3] feat(yield): harden program output boundary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Disclosure-Reviewed: reviewed — public-safe only, private facet kept out of this commit --- labs/22-yield/yield/docs/locus-conformance.md | 13 ++ .../yield/docs/locus/sdk-contract.json | 6 +- .../internal/conformance/conformance_test.go | 2 +- labs/22-yield/yield/internal/engine/engine.go | 6 +- .../yield/internal/engine/engine_test.go | 23 +++ .../yield/internal/protocol/ir_test.go | 49 ++++++ .../yield/internal/protocol/protocol.go | 143 +++++++++++++++-- .../ir/yield.v1/program-output.schema.json | 145 ++++++------------ labs/22-yield/yield/sdk/rust/src/lib.rs | 41 +++-- .../yield/sdk/typescript/src/index.ts | 33 ++-- 10 files changed, 322 insertions(+), 139 deletions(-) diff --git a/labs/22-yield/yield/docs/locus-conformance.md b/labs/22-yield/yield/docs/locus-conformance.md index 5d8c5826..597bdaa7 100644 --- a/labs/22-yield/yield/docs/locus-conformance.md +++ b/labs/22-yield/yield/docs/locus-conformance.md @@ -13,6 +13,14 @@ discharges the whole program's obligations. Models and derivations live in | `sdk-contract.json` | control.nonblockingness | **nonblocking** — every SDK execution reaches an emit | | `divergence-in-sdk.json` vs `divergence-supervisor-only.json` | verification.safety-reachability (rival designs, `drv-ad50b13e…`) | **decided** — in-SDK per-step checking satisfies `forbidden-unreachable`; supervisor-only is rejected with the verbatim trace `op_drifts → consume_unchecked → CONSUMED_MISMATCHED` | +The feature-extension boundary also passed +`practice.boundary-conformance`. Its control law is deliberately small: +SDK stdout becomes engine authority only after the protocol package admits +exactly one complete `request`, `terminal`, or `diverged` variant. Unknown +fields and malformed, missing, or ambiguous variants fail before dispatch. +The canonical IR uses the same exact-one shape, while TypeScript and Rust +encode it with closed surface types. + The decided comparison is why per-step digest comparison is a MANDATORY part of the SDK contract in every language, not an optional nicety: without it, a drifted operation silently consumes a recorded response meant for a @@ -42,6 +50,11 @@ scenario matrix and what each observes: | `TestGuardRefusals` | schema-invalid, duplicate-rewrite, wrong-run refusals through the live engine | | `TestDivergenceFailsLoudlyEverywhere` | the decided design: a tampered recorded operation is detected by every SDK at replay | +`internal/protocol/ir_test.go` adds the feature-upgrade gate: positive and +negative outputs must receive the same decision from protocol admission and +the canonical schema. `internal/engine/engine_test.go` proves ambiguous SDK +output is refused at the real subprocess boundary. + Languages whose toolchain is missing are skipped locally; CI provides all four (`.github/workflows/yield-lab.yml`). diff --git a/labs/22-yield/yield/docs/locus/sdk-contract.json b/labs/22-yield/yield/docs/locus/sdk-contract.json index 8c94b130..0fa6646a 100644 --- a/labs/22-yield/yield/docs/locus/sdk-contract.json +++ b/labs/22-yield/yield/docs/locus/sdk-contract.json @@ -5,7 +5,7 @@ "evidence": [ { "path": "labs/22-yield/yield/sdk/yield/yield.go", - "note": "Go SDK: step() replay/compare/emit, Main() terminal emission \u2014 the behavior TS/Python SDKs must refine" + "note": "Go SDK: step() replay/compare/emit and Main() terminal emission \u2014 the reference behavior all four SDKs refine" }, { "path": "labs/22-yield/yield/internal/engine/engine.go", @@ -225,7 +225,7 @@ "selector": "marked" }, "unknowns": [ - "The TS and Python SDKs are not yet implemented; this contract is what they must exhibit, discharged by running each example skill through yskill test.", + "A future output variant must be added coherently to every SDK surface, the canonical IR, protocol admission, engine dispatch, and conformance fixtures.", "Determinism between yields is the program author's obligation in every language; the contract detects divergence, it cannot prevent nondeterminism." ] -} \ No newline at end of file +} diff --git a/labs/22-yield/yield/internal/conformance/conformance_test.go b/labs/22-yield/yield/internal/conformance/conformance_test.go index 24f2f42f..4926a038 100644 --- a/labs/22-yield/yield/internal/conformance/conformance_test.go +++ b/labs/22-yield/yield/internal/conformance/conformance_test.go @@ -149,7 +149,7 @@ func runComplete(t *testing.T, lang language) trace { if p.Terminal == nil || p.Terminal.Status != protocol.StatusCompleted { t.Fatalf("[%s] must complete, got %+v", lang.name, p) } - tr.Terminal = p.Terminal.Status + tr.Terminal = string(p.Terminal.Status) l, err := e.Log(p.RunID) if err != nil { diff --git a/labs/22-yield/yield/internal/engine/engine.go b/labs/22-yield/yield/internal/engine/engine.go index e86489bc..cbd77358 100644 --- a/labs/22-yield/yield/internal/engine/engine.go +++ b/labs/22-yield/yield/internal/engine/engine.go @@ -283,11 +283,11 @@ func (e *Engine) execute(l *runlog.Log, runID string) (*protocol.ProgramOutput, if err != nil { return nil, fmt.Errorf("skill program failed: %w", err) } - var out protocol.ProgramOutput - if err := json.Unmarshal(outBytes, &out); err != nil { + out, err := protocol.DecodeProgramOutput(outBytes) + if err != nil { return nil, fmt.Errorf("skill program emitted invalid output: %w", err) } - return &out, nil + return out, nil } // runnerCommand decides how to execute the skill program. A skill.json diff --git a/labs/22-yield/yield/internal/engine/engine_test.go b/labs/22-yield/yield/internal/engine/engine_test.go index 9df4815d..d5e2e09f 100644 --- a/labs/22-yield/yield/internal/engine/engine_test.go +++ b/labs/22-yield/yield/internal/engine/engine_test.go @@ -180,6 +180,29 @@ func TestReplayDivergenceFailsLoudly(t *testing.T) { } } +func TestExecuteRejectsAmbiguousProgramOutput(t *testing.T) { + dir := t.TempDir() + manifest := `{"run":["sh","-c","printf '%s\\n' '{\"type\":\"request\",\"envelope\":{},\"terminal\":{\"status\":\"completed\"}}'"]}` + if err := os.WriteFile(filepath.Join(dir, "skill.json"), []byte(manifest), 0o600); err != nil { + t.Fatal(err) + } + e := &Engine{SkillDir: dir, RunsDir: t.TempDir(), Stderr: os.Stderr} + l, err := runlog.Create(e.RunsDir, "run_1") + if err != nil { + t.Fatal(err) + } + if _, err := l.Append(runlog.RunStarted, map[string]any{ + "run_id": "run_1", + "skill": protocol.SkillRef{Name: "invalid", Digest: protocol.DigestBytes([]byte("invalid"))}, + }); err != nil { + t.Fatal(err) + } + _, err = e.execute(l, "run_1") + if err == nil || !strings.Contains(err.Error(), "exactly one variant") { + t.Fatalf("engine must reject ambiguous output before dispatch, got %v", err) + } +} + func TestFailedRequirementBlocksRun(t *testing.T) { e := testEngine(t, "skill-reqfail") p, err := e.StartRun(nil) diff --git a/labs/22-yield/yield/internal/protocol/ir_test.go b/labs/22-yield/yield/internal/protocol/ir_test.go index b5a87bf5..bd1d581a 100644 --- a/labs/22-yield/yield/internal/protocol/ir_test.go +++ b/labs/22-yield/yield/internal/protocol/ir_test.go @@ -61,6 +61,21 @@ func validateIR(t *testing.T, c *jsonschema.Compiler, schemaFile string, v any) } } +func rejectIR(t *testing.T, c *jsonschema.Compiler, schemaFile string, raw []byte) { + t.Helper() + compiled, err := c.Compile(schemaFile) + if err != nil { + t.Fatal(err) + } + doc, err := jsonschema.UnmarshalJSON(bytes.NewReader(raw)) + if err != nil { + t.Fatal(err) + } + if err := compiled.Validate(doc); err == nil { + t.Fatalf("IR must reject %s", raw) + } +} + const irDigest = "sha256:9f2c9f2c9f2c9f2c9f2c9f2c9f2c9f2c9f2c9f2c9f2c9f2c9f2c9f2c9f2c9f2c" func sampleEnvelope() RequestEnvelope { @@ -132,3 +147,37 @@ func TestIRRejectsUnknownKind(t *testing.T) { t.Fatal("the IR must reject operation kinds outside the closed set") } } + +func TestProgramOutputAdmissionMatchesIR(t *testing.T) { + c := irCompiler(t) + valid := [][]byte{ + []byte(`{"type":"request","envelope":{"protocol":"yield.v1","run_id":"run_1","skill":{"name":"safe-change","digest":"` + irDigest + `"},"sequence":1,"request":{"id":"confirm-scope","kind":"ask_user","payload":{"question":"Continue?"}}}}`), + []byte(`{"type":"terminal","terminal":{"status":"completed","result":{"ok":true}}}`), + []byte(`{"type":"diverged","divergence":{"sequence":1,"expected_digest":"` + irDigest + `","got_digest":"` + irDigest + `"}}`), + } + for _, raw := range valid { + if _, err := DecodeProgramOutput(raw); err != nil { + t.Fatalf("decoder rejected valid output %s: %v", raw, err) + } + var value any + if err := json.Unmarshal(raw, &value); err != nil { + t.Fatal(err) + } + validateIR(t, c, "program-output.schema.json", value) + } + + invalid := [][]byte{ + []byte(`{"type":"future","terminal":{"status":"completed"}}`), + []byte(`{"type":"request"}`), + []byte(`{"type":"request","envelope":{"protocol":"yield.v1"},"terminal":{"status":"completed"}}`), + []byte(`{"type":"terminal","terminal":{"status":"future"}}`), + []byte(`{"type":"diverged","divergence":{"sequence":0,"expected_digest":"bad","got_digest":"bad"}}`), + []byte(`{"type":"terminal","terminal":{"status":"completed"},"future_field":true}`), + } + for _, raw := range invalid { + if _, err := DecodeProgramOutput(raw); err == nil { + t.Fatalf("decoder must reject %s", raw) + } + rejectIR(t, c, "program-output.schema.json", raw) + } +} diff --git a/labs/22-yield/yield/internal/protocol/protocol.go b/labs/22-yield/yield/internal/protocol/protocol.go index fffe59d9..cecfc32b 100644 --- a/labs/22-yield/yield/internal/protocol/protocol.go +++ b/labs/22-yield/yield/internal/protocol/protocol.go @@ -10,6 +10,7 @@ import ( "encoding/hex" "encoding/json" "fmt" + "io" "io/fs" "os" "path/filepath" @@ -115,22 +116,26 @@ type Requirement struct { // Program output types: a skill subprocess emits exactly one ProgramOutput // per execution — the next yielded request, a terminal outcome, or a // replay divergence report. +type OutputKind string + const ( - OutputRequest = "request" - OutputTerminal = "terminal" - OutputDiverged = "diverged" + OutputRequest OutputKind = "request" + OutputTerminal OutputKind = "terminal" + OutputDiverged OutputKind = "diverged" ) // Terminal statuses. +type TerminalStatus string + const ( - StatusCompleted = "completed" - StatusBlocked = "blocked" - StatusRefused = "refused" - StatusRequirementFailed = "requirement_failed" + StatusCompleted TerminalStatus = "completed" + StatusBlocked TerminalStatus = "blocked" + StatusRefused TerminalStatus = "refused" + StatusRequirementFailed TerminalStatus = "requirement_failed" ) type ProgramOutput struct { - Type string `json:"type"` + Type OutputKind `json:"type"` Envelope *RequestEnvelope `json:"envelope,omitempty"` Terminal *TerminalOutcome `json:"terminal,omitempty"` Divergence *Divergence `json:"divergence,omitempty"` @@ -138,7 +143,7 @@ type ProgramOutput struct { } type TerminalOutcome struct { - Status string `json:"status"` + Status TerminalStatus `json:"status"` Result json.RawMessage `json:"result,omitempty"` Reason string `json:"reason,omitempty"` } @@ -153,6 +158,126 @@ type Divergence struct { Detail string `json:"detail,omitempty"` } +// InvalidProgramOutputError means a skill emitted bytes that are not one +// complete yield.v1 output variant. The engine must not dispatch such output. +type InvalidProgramOutputError struct { + Reason string +} + +func (e *InvalidProgramOutputError) Error() string { + return "invalid program output: " + e.Reason +} + +// DecodeProgramOutput is the single admission boundary between an SDK +// subprocess and engine authority. It accepts exactly one complete variant +// and rejects unknown fields so future protocol changes fail closed until the +// IR, decoder, and dispatch logic are upgraded together. +func DecodeProgramOutput(raw []byte) (*ProgramOutput, error) { + dec := json.NewDecoder(bytes.NewReader(raw)) + dec.DisallowUnknownFields() + var out ProgramOutput + if err := dec.Decode(&out); err != nil { + return nil, &InvalidProgramOutputError{Reason: err.Error()} + } + if err := dec.Decode(&struct{}{}); err != io.EOF { + if err == nil { + err = fmt.Errorf("multiple JSON values") + } + return nil, &InvalidProgramOutputError{Reason: err.Error()} + } + if err := out.validate(); err != nil { + return nil, &InvalidProgramOutputError{Reason: err.Error()} + } + return &out, nil +} + +func (out ProgramOutput) validate() error { + active := 0 + if out.Envelope != nil { + active++ + } + if out.Terminal != nil { + active++ + } + if out.Divergence != nil { + active++ + } + if active != 1 { + return fmt.Errorf("expected exactly one variant payload, got %d", active) + } + switch out.Type { + case OutputRequest: + if out.Envelope == nil { + return fmt.Errorf("request output requires envelope") + } + if err := out.Envelope.validate(); err != nil { + return err + } + case OutputTerminal: + if out.Terminal == nil { + return fmt.Errorf("terminal output requires terminal") + } + switch out.Terminal.Status { + case StatusCompleted, StatusBlocked, StatusRefused, StatusRequirementFailed: + default: + return fmt.Errorf("unknown terminal status %q", out.Terminal.Status) + } + case OutputDiverged: + if out.Divergence == nil { + return fmt.Errorf("diverged output requires divergence") + } + if out.Divergence.Sequence < 1 { + return fmt.Errorf("divergence sequence must be positive") + } + if !validDigest(out.Divergence.Expected) || !validDigest(out.Divergence.Got) { + return fmt.Errorf("divergence digests must be sha256 digests") + } + default: + return fmt.Errorf("unknown output type %q", out.Type) + } + for _, requirement := range out.Requirements { + if requirement.Claim == "" { + return fmt.Errorf("requirement claim must not be empty") + } + if requirement.EvidenceDigest != "" && !validDigest(requirement.EvidenceDigest) { + return fmt.Errorf("requirement evidence must be a sha256 digest") + } + } + return nil +} + +func (env RequestEnvelope) validate() error { + if env.Protocol != Version { + return fmt.Errorf("request protocol must be %q", Version) + } + if env.RunID == "" || env.Skill.Name == "" || !validDigest(env.Skill.Digest) { + return fmt.Errorf("request run and skill identity are incomplete") + } + if env.Sequence < 1 || env.Request.ID == "" { + return fmt.Errorf("request sequence and id are required") + } + switch env.Request.Kind { + case OpAskUser, OpAgentTask, OpRunCommand: + default: + return fmt.Errorf("unknown operation kind %q", env.Request.Kind) + } + if !json.Valid(env.Request.Payload) { + return fmt.Errorf("request payload must be valid JSON") + } + if len(env.Request.OutputSchema) > 0 && !json.Valid(env.Request.OutputSchema) { + return fmt.Errorf("request output schema must be valid JSON") + } + return nil +} + +func validDigest(value string) bool { + if len(value) != len("sha256:")+sha256.Size*2 || !strings.HasPrefix(value, "sha256:") { + return false + } + _, err := hex.DecodeString(strings.TrimPrefix(value, "sha256:")) + return err == nil +} + // JournalEntry is one recorded request/response pair handed to the skill // subprocess for replay. type JournalEntry struct { diff --git a/labs/22-yield/yield/ir/yield.v1/program-output.schema.json b/labs/22-yield/yield/ir/yield.v1/program-output.schema.json index 01f2db8d..7744f808 100644 --- a/labs/22-yield/yield/ir/yield.v1/program-output.schema.json +++ b/labs/22-yield/yield/ir/yield.v1/program-output.schema.json @@ -1,54 +1,40 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "yield.v1 program output \u2014 the single output of one skill-program execution", - "type": "object", - "required": [ - "type" - ], - "properties": { - "type": { - "enum": [ - "request", - "terminal", - "diverged" - ] - }, - "envelope": { - "$ref": "request-envelope.schema.json" + "title": "yield.v1 program output — the single output of one skill-program execution", + "$defs": { + "requirements": { + "type": "array", + "items": { + "type": "object", + "required": ["claim", "passed"], + "properties": { + "claim": { "type": "string", "minLength": 1 }, + "passed": { "type": "boolean" }, + "evidence_digest": { + "type": "string", + "pattern": "^sha256:[0-9a-f]{64}$" + } + }, + "additionalProperties": false + } }, "terminal": { "type": "object", - "required": [ - "status" - ], + "required": ["status"], "properties": { "status": { - "enum": [ - "completed", - "blocked", - "refused", - "requirement_failed" - ] + "enum": ["completed", "blocked", "refused", "requirement_failed"] }, "result": {}, - "reason": { - "type": "string" - } + "reason": { "type": "string" } }, "additionalProperties": false }, "divergence": { "type": "object", - "required": [ - "sequence", - "expected_digest", - "got_digest" - ], + "required": ["sequence", "expected_digest", "got_digest"], "properties": { - "sequence": { - "type": "integer", - "minimum": 1 - }, + "sequence": { "type": "integer", "minimum": 1 }, "expected_digest": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" @@ -57,80 +43,41 @@ "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" }, - "detail": { - "type": "string" - } + "detail": { "type": "string" } }, "additionalProperties": false - }, - "requirements": { - "type": "array", - "items": { - "type": "object", - "required": [ - "claim", - "passed" - ], - "properties": { - "claim": { - "type": "string", - "minLength": 1 - }, - "passed": { - "type": "boolean" - }, - "evidence_digest": { - "type": "string", - "pattern": "^sha256:[0-9a-f]{64}$" - } - }, - "additionalProperties": false - } } }, - "allOf": [ + "oneOf": [ { - "if": { - "properties": { - "type": { - "const": "request" - } - } + "type": "object", + "required": ["type", "envelope"], + "properties": { + "type": { "const": "request" }, + "envelope": { "$ref": "request-envelope.schema.json" }, + "requirements": { "$ref": "#/$defs/requirements" } }, - "then": { - "required": [ - "envelope" - ] - } + "additionalProperties": false }, { - "if": { - "properties": { - "type": { - "const": "terminal" - } - } + "type": "object", + "required": ["type", "terminal"], + "properties": { + "type": { "const": "terminal" }, + "terminal": { "$ref": "#/$defs/terminal" }, + "requirements": { "$ref": "#/$defs/requirements" } }, - "then": { - "required": [ - "terminal" - ] - } + "additionalProperties": false }, { - "if": { - "properties": { - "type": { - "const": "diverged" - } - } + "type": "object", + "required": ["type", "divergence"], + "properties": { + "type": { "const": "diverged" }, + "divergence": { "$ref": "#/$defs/divergence" }, + "requirements": { "$ref": "#/$defs/requirements" } }, - "then": { - "required": [ - "divergence" - ] - } + "additionalProperties": false } - ], - "additionalProperties": false + ] } diff --git a/labs/22-yield/yield/sdk/rust/src/lib.rs b/labs/22-yield/yield/sdk/rust/src/lib.rs index c2cac1e7..9a2a69b5 100644 --- a/labs/22-yield/yield/sdk/rust/src/lib.rs +++ b/labs/22-yield/yield/sdk/rust/src/lib.rs @@ -86,9 +86,18 @@ pub struct Requirement { pub evidence_digest: Option, } +#[derive(Debug, Serialize)] +#[serde(rename_all = "snake_case")] +enum TerminalStatus { + Completed, + Blocked, + Refused, + RequirementFailed, +} + #[derive(Debug, Serialize)] struct TerminalOutcome { - status: String, + status: TerminalStatus, #[serde(skip_serializing_if = "Option::is_none")] result: Option, #[serde(skip_serializing_if = "Option::is_none")] @@ -103,10 +112,18 @@ struct Divergence { detail: String, } +#[derive(Debug, Serialize)] +#[serde(rename_all = "snake_case")] +enum OutputKind { + Request, + Terminal, + Diverged, +} + #[derive(Debug, Serialize)] struct ProgramOutput { #[serde(rename = "type")] - kind: String, + kind: OutputKind, #[serde(skip_serializing_if = "Option::is_none")] envelope: Option, #[serde(skip_serializing_if = "Option::is_none")] @@ -252,10 +269,10 @@ impl Context { self.requirements.push(req); if !ok { emit(ProgramOutput { - kind: "terminal".to_string(), + kind: OutputKind::Terminal, envelope: None, terminal: Some(TerminalOutcome { - status: "requirement_failed".to_string(), + status: TerminalStatus::RequirementFailed, result: None, reason: Some(claim.to_string()), }), @@ -285,7 +302,7 @@ impl Context { let got = request_digest(&req); if want != got { emit(ProgramOutput { - kind: "diverged".to_string(), + kind: OutputKind::Diverged, envelope: None, terminal: None, divergence: Some(Divergence { @@ -305,7 +322,7 @@ impl Context { } self.idx += 1; emit(ProgramOutput { - kind: "request".to_string(), + kind: OutputKind::Request, envelope: Some(RequestEnvelope { protocol: PROTOCOL.to_string(), run_id: self.journal.run_id.clone(), @@ -352,10 +369,10 @@ pub fn define_skill(program: fn(&mut Context) -> SkillResult) -> ! { }; match program(&mut ctx) { Ok(result) => emit(ProgramOutput { - kind: "terminal".to_string(), + kind: OutputKind::Terminal, envelope: None, terminal: Some(TerminalOutcome { - status: "completed".to_string(), + status: TerminalStatus::Completed, result: Some(result), reason: None, }), @@ -363,10 +380,10 @@ pub fn define_skill(program: fn(&mut Context) -> SkillResult) -> ! { requirements: ctx.requirements, }), Err(Exit::Blocked(reason)) => emit(ProgramOutput { - kind: "terminal".to_string(), + kind: OutputKind::Terminal, envelope: None, terminal: Some(TerminalOutcome { - status: "blocked".to_string(), + status: TerminalStatus::Blocked, result: None, reason: Some(reason), }), @@ -374,10 +391,10 @@ pub fn define_skill(program: fn(&mut Context) -> SkillResult) -> ! { requirements: ctx.requirements, }), Err(Exit::Refused(reason)) => emit(ProgramOutput { - kind: "terminal".to_string(), + kind: OutputKind::Terminal, envelope: None, terminal: Some(TerminalOutcome { - status: "refused".to_string(), + status: TerminalStatus::Refused, result: None, reason: Some(reason), }), diff --git a/labs/22-yield/yield/sdk/typescript/src/index.ts b/labs/22-yield/yield/sdk/typescript/src/index.ts index 3c7c0666..2aa89fd7 100644 --- a/labs/22-yield/yield/sdk/typescript/src/index.ts +++ b/labs/22-yield/yield/sdk/typescript/src/index.ts @@ -71,18 +71,27 @@ interface Journal { entries?: { request: Request; response: ResponseEnvelope }[]; } -interface ProgramOutput { - type: "request" | "terminal" | "diverged"; - envelope?: RequestEnvelope; - terminal?: { status: string; result?: unknown; reason?: string }; - divergence?: { - sequence: number; - expected_digest: string; - got_digest: string; - detail?: string; - }; - requirements?: Requirement[]; -} +type ProgramOutput = + | { type: "request"; envelope: RequestEnvelope; requirements?: Requirement[] } + | { + type: "terminal"; + terminal: { + status: "completed" | "blocked" | "refused" | "requirement_failed"; + result?: unknown; + reason?: string; + }; + requirements?: Requirement[]; + } + | { + type: "diverged"; + divergence: { + sequence: number; + expected_digest: string; + got_digest: string; + detail?: string; + }; + requirements?: Requirement[]; + }; /** Terminal exit: a true frontier was reached — say so explicitly. */ export class Blocked extends Error { From 435a7e3461de4f519c199372e7cf8074c11f6a8a Mon Sep 17 00:00:00 2001 From: bigboateng Date: Sat, 1 Aug 2026 16:43:53 +0100 Subject: [PATCH 3/3] docs(yield): add programmer-first guides MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Disclosure-Reviewed: reviewed — public-safe only, private facet kept out of this commit --- .github/workflows/yield-lab.yml | 19 +++ labs/22-yield/README.md | 4 + .../2026-08-01-docs-and-typescript-package.md | 8 + labs/22-yield/public-readme/README.md | 15 ++ labs/22-yield/yield/docs/README.md | 46 ++++++ .../yield/docs/convert-existing-skill.md | 66 ++++++++ labs/22-yield/yield/docs/examples.md | 28 ++++ labs/22-yield/yield/docs/primitives/README.md | 30 ++++ .../yield/docs/primitives/agent-task.md | 40 +++++ .../yield/docs/primitives/ask-user.md | 25 +++ .../yield/docs/primitives/outcomes.md | 37 +++++ .../22-yield/yield/docs/primitives/require.md | 24 +++ .../yield/docs/primitives/run-command.md | 37 +++++ labs/22-yield/yield/docs/quickstart.md | 143 ++++++++++++++++++ labs/22-yield/yield/docs/reference/cli.md | 59 ++++++++ .../yield/docs/reference/execution-model.md | 32 ++++ .../yield/docs/reference/guarantees.md | 29 ++++ .../yield/docs/reference/sdk-parity.md | 25 +++ labs/22-yield/yield/docs/tutorials/README.md | 17 +++ .../22-yield/yield/docs/tutorials/approval.md | 24 +++ .../yield/docs/tutorials/bounded-debugging.md | 35 +++++ .../yield/docs/tutorials/code-review.md | 34 +++++ .../yield/docs/tutorials/data-migration.md | 23 +++ .../docs/tutorials/environment-repair.md | 32 ++++ .../yield/sdk/typescript/package.json | 14 +- .../yield/sdk/typescript/scripts/build.mjs | 19 +++ 26 files changed, 864 insertions(+), 1 deletion(-) create mode 100644 labs/22-yield/distribution/release-notes/2026-08-01-docs-and-typescript-package.md create mode 100644 labs/22-yield/yield/docs/README.md create mode 100644 labs/22-yield/yield/docs/convert-existing-skill.md create mode 100644 labs/22-yield/yield/docs/primitives/README.md create mode 100644 labs/22-yield/yield/docs/primitives/agent-task.md create mode 100644 labs/22-yield/yield/docs/primitives/ask-user.md create mode 100644 labs/22-yield/yield/docs/primitives/outcomes.md create mode 100644 labs/22-yield/yield/docs/primitives/require.md create mode 100644 labs/22-yield/yield/docs/primitives/run-command.md create mode 100644 labs/22-yield/yield/docs/quickstart.md create mode 100644 labs/22-yield/yield/docs/reference/cli.md create mode 100644 labs/22-yield/yield/docs/reference/execution-model.md create mode 100644 labs/22-yield/yield/docs/reference/guarantees.md create mode 100644 labs/22-yield/yield/docs/reference/sdk-parity.md create mode 100644 labs/22-yield/yield/docs/tutorials/README.md create mode 100644 labs/22-yield/yield/docs/tutorials/approval.md create mode 100644 labs/22-yield/yield/docs/tutorials/bounded-debugging.md create mode 100644 labs/22-yield/yield/docs/tutorials/code-review.md create mode 100644 labs/22-yield/yield/docs/tutorials/data-migration.md create mode 100644 labs/22-yield/yield/docs/tutorials/environment-repair.md create mode 100644 labs/22-yield/yield/sdk/typescript/scripts/build.mjs diff --git a/.github/workflows/yield-lab.yml b/.github/workflows/yield-lab.yml index 29dd423c..27d10b87 100644 --- a/.github/workflows/yield-lab.yml +++ b/.github/workflows/yield-lab.yml @@ -22,6 +22,16 @@ jobs: - uses: actions/setup-node@v4 with: node-version: "24" + - name: Build and smoke-test the packed TypeScript SDK + working-directory: labs/22-yield/yield/sdk/typescript + run: | + npm run build + tarball="$RUNNER_TEMP/$(npm pack --silent --pack-destination "$RUNNER_TEMP")" + smoke_dir="$(mktemp -d)" + cd "$smoke_dir" + npm init -y >/dev/null + npm install "$tarball" >/dev/null + node --input-type=module -e 'import { defineSkill } from "@operatorstack/yield"; if (typeof defineSkill !== "function") process.exit(1)' - uses: Swatinem/rust-cache@v2 with: workspaces: | @@ -70,6 +80,15 @@ jobs: - uses: actions/setup-node@v4 with: node-version: "24" + - name: Build and smoke-test the projected TypeScript package + working-directory: ${{ runner.temp }}/yield-projected/sdk/typescript + run: | + tarball="$RUNNER_TEMP/$(npm pack --silent --pack-destination "$RUNNER_TEMP")" + smoke_dir="$(mktemp -d)" + cd "$smoke_dir" + npm init -y >/dev/null + npm install "$tarball" >/dev/null + node --input-type=module -e 'import { defineSkill } from "@operatorstack/yield"; if (typeof defineSkill !== "function") process.exit(1)' - name: Build and test the projected module (incl. 4-language conformance) working-directory: ${{ runner.temp }}/yield-projected env: diff --git a/labs/22-yield/README.md b/labs/22-yield/README.md index ca10436d..a1ada8c5 100644 --- a/labs/22-yield/README.md +++ b/labs/22-yield/README.md @@ -69,6 +69,10 @@ YSKILL=/tmp/yskill bash yield/examples/library/test-all.sh # all 40 language/wo /tmp/yskill run yield/examples/investigate # prints the first operation envelope ``` +The public documentation starts at [`yield/docs/README.md`](yield/docs/README.md). +It leads with a clean-install TypeScript quickstart, then separates primitive +guides, complete tutorials, executable examples, conversion, and reference. + ## Formal grounding The run lifecycle was designed against Locus verdicts diff --git a/labs/22-yield/distribution/release-notes/2026-08-01-docs-and-typescript-package.md b/labs/22-yield/distribution/release-notes/2026-08-01-docs-and-typescript-package.md new file mode 100644 index 00000000..e441bfd3 --- /dev/null +++ b/labs/22-yield/distribution/release-notes/2026-08-01-docs-and-typescript-package.md @@ -0,0 +1,8 @@ +# Yield documentation and runnable TypeScript package + +- Add a programmer-first documentation path: clean install, first workflow, + primitive guides, tutorials, examples, conversion, and runtime reference. +- Compile the TypeScript SDK before packing so Node loads JavaScript from + `node_modules` instead of refusing runtime type stripping there. +- Smoke-test both the source and projected npm tarballs in clean temporary + projects before publication. diff --git a/labs/22-yield/public-readme/README.md b/labs/22-yield/public-readme/README.md index f03ba26a..cab8eaf0 100644 --- a/labs/22-yield/public-readme/README.md +++ b/labs/22-yield/public-readme/README.md @@ -71,6 +71,21 @@ Each language has the same workflow, a thin `SKILL.md`, and a scripted fixture. Start from the work you already do instead of starting from a framework tutorial. +## Documentation + +Start with the [ten-minute TypeScript quickstart](docs/quickstart.md), then +use the documentation by job: + +- [primitive guides](docs/primitives/README.md) — commands, model work, + human input, evidence gates, and outcomes; +- [tutorials](docs/tutorials/README.md) — review, approval, environment + repair, bounded debugging, and migration; +- [examples](docs/examples.md) — working programs in all four languages; +- [convert an existing skill](docs/convert-existing-skill.md) — move + control flow into code without claiming that fixture execution proves + every reading of the original prose; +- [CLI and runtime reference](docs/reference/cli.md). + ## Try it ``` diff --git a/labs/22-yield/yield/docs/README.md b/labs/22-yield/yield/docs/README.md new file mode 100644 index 00000000..23d3b5f4 --- /dev/null +++ b/labs/22-yield/yield/docs/README.md @@ -0,0 +1,46 @@ +# Yield documentation + +You already know the workflow. You may be repeating it in a prompt: + +> Run the checks. Review the diff. Stop if anything critical remains. Ask me +> before publishing. If the session ends, start again without losing our place. + +Yield lets you keep the useful words and put the order in normal code. The +coding agent still investigates, reviews, edits, and explains. Your program +decides which operation comes next, what evidence must exist, and when the run +is finished. + +## Start here + +1. [Build and run your first skill](quickstart.md) — a TypeScript workflow you + can test in about ten minutes. +2. [Learn the primitives](primitives/README.md) — commands, model work, human + input, gates, and honest outcomes. +3. [Follow a complete tutorial](tutorials/README.md) — review, approval, + environment repair, bounded debugging, and migration. +4. [Browse the examples](examples.md) — working programs in Go, TypeScript, + Python, and Rust. +5. [Convert an existing prose skill](convert-existing-skill.md) — use Yield's + verified converter after you understand one ordinary workflow. + +## The split to remember + +| Put in code | Leave with the model | +|---|---| +| order and branching | investigation and judgment | +| retry limits | reading unfamiliar code | +| commands that must really run | proposing changes | +| approval points | writing explanations | +| evidence required to finish | interpreting evidence | + +This is not a new agent runtime. A thin `SKILL.md` starts the program, the +program emits one typed operation, and the coding agent performs that operation +through its normal interface. Yield records the response and resumes from the +next unanswered operation. + +## Reference + +- [CLI commands](reference/cli.md) +- [Run, pause, resume, and replay](reference/execution-model.md) +- [The four SDKs](reference/sdk-parity.md) +- [Guarantees and limits](reference/guarantees.md) diff --git a/labs/22-yield/yield/docs/convert-existing-skill.md b/labs/22-yield/yield/docs/convert-existing-skill.md new file mode 100644 index 00000000..70273513 --- /dev/null +++ b/labs/22-yield/yield/docs/convert-existing-skill.md @@ -0,0 +1,66 @@ +# Convert an existing prose skill + +Use conversion after you have run one ordinary Yield workflow. Conversion is a +separate job from the runtime itself: the converter helps extract and encode a +policy; Yield then executes and verifies the resulting program. + +The repository includes [`examples/convert-skill`](../examples/convert-skill/), +a converter that is itself a Yield skill. + +## What moves, and what stays + +Keep these in the thin `SKILL.md`: + +- the goal and when the skill should be used; +- domain context the model needs; +- judgment criteria and useful examples; +- the instruction to start and resume the Yield program. + +Move these into the program: + +- required order; +- branches and retry limits; +- commands whose output must be observed; +- approval points; +- claims required for completion; +- `Blocked` and `Refused` outcomes. + +## Run the converter + +From a checkout of the public repository: + +```bash +go build -o /tmp/yskill ./cmd/yskill +cd examples/convert-skill +YSKILL=/tmp/yskill /tmp/yskill run . +``` + +The workflow asks for: + +1. the source directory containing `SKILL.md`; +2. a target language; +3. a destination directory. + +The coding agent extracts the implicit flow and writes the generated files. The +converter then runs the generated skill's own fixtures under `yskill test`. It +allows two bounded repair attempts and returns `Blocked` if the fixture run +still fails. + +## What “verified” means here + +The converter verifies that the generated program executes its declared fixture +path. It does **not** prove that the extracted policy is behaviorally equivalent +to every reading of the original prose. + +Review the conversion as a policy change: + +- map every load-bearing source instruction to code, retained model judgment, + or an explicit exclusion; +- add a positive fixture and at least one negative or refusal path; +- test bypass attempts and failure states; +- replay a completed run to check determinism; +- keep performance or token-reduction claims separate from runtime correctness. + +The implemented safety comparison is documented in +[`locus-converter.md`](locus-converter.md). Its narrow conclusion is that the +converter cannot report success before the generated fixture run passes. diff --git a/labs/22-yield/yield/docs/examples.md b/labs/22-yield/yield/docs/examples.md index de03369a..cd14bdf2 100644 --- a/labs/22-yield/yield/docs/examples.md +++ b/labs/22-yield/yield/docs/examples.md @@ -32,3 +32,31 @@ Run all forty fixtures: The included commands produce harmless evidence so the examples run in this repository. Replace them with project commands before adopting a workflow. + +## Complete walkthroughs + +These examples show longer programs with a thin `SKILL.md` and scripted +responses under `fixtures/responses.json`. + +| Example | Language | Pattern | +|---|---|---| +| [`release-checklist`](../examples/release-checklist/) | TypeScript | approval, build, model-authored notes, publish, verify | +| [`env-doctor`](../examples/env-doctor/) | Python | probe, diagnose, wait for a person, recheck | +| [`investigate`](../examples/investigate/) | Go | structured hypotheses, real probes, bounded attempts | +| [`data-migration`](../examples/data-migration/) | Rust | dry-run, approval, apply, verify | +| [`convert-skill`](../examples/convert-skill/) | Go | extract a prose workflow, generate code, execute its fixtures | + +From the repository root: + +```bash +go build -o /tmp/yskill ./cmd/yskill +/tmp/yskill test examples/release-checklist +/tmp/yskill test examples/env-doctor +/tmp/yskill test examples/investigate +/tmp/yskill test examples/data-migration +YSKILL=/tmp/yskill /tmp/yskill test examples/convert-skill +``` + +When adapting an example, change the repository-specific commands and model +instructions. Keep stable operation IDs for existing steps so saved runs can +replay them. diff --git a/labs/22-yield/yield/docs/primitives/README.md b/labs/22-yield/yield/docs/primitives/README.md new file mode 100644 index 00000000..ff6ea711 --- /dev/null +++ b/labs/22-yield/yield/docs/primitives/README.md @@ -0,0 +1,30 @@ +# Yield primitives + +Yield has a deliberately small API. Each primitive has one clear owner. + +| Primitive | What it does | Who performs it | +|---|---|---| +| [`RunCommand`](run-command.md) | Runs a command and records its real output | `yskill` | +| [`AgentTask`](agent-task.md) | Requests model judgment with an optional JSON schema | coding agent | +| [`AskUser`](ask-user.md) | Pauses for a human answer | coding agent and user | +| [`Require`](require.md) | Prevents completion unless a claim passes | skill program | +| [Outcomes](outcomes.md) | Completes, blocks, or refuses with a recorded reason | skill program | + +Ordinary language features provide the rest. Use `if` for choices, `for` or +`while` for bounded retries, functions for reusable flows, and your language's +types for local data. + +## Names in each SDK + +| Meaning | TypeScript | Python | Go | Rust | +|---|---|---|---|---| +| ask a person | `ctx.askUser` | `ctx.ask_user` | `ctx.AskUser` | `ctx.ask_user` | +| ask the model | `ctx.agentTask` | `ctx.agent_task` | `ctx.AgentTask` | `ctx.agent_task` | +| run a command | `ctx.runCommand` | `ctx.run_command` | `ctx.RunCommand` | `ctx.run_command` | +| enforce a claim | `ctx.require` | `ctx.require` | `ctx.Require` | `ctx.require` | +| finish | `return value` | `return value` | `ctx.Complete` | `Ok(value)` | +| cannot continue | `ctx.blocked` | `ctx.blocked` | `ctx.Blocked` | `Err(ctx.blocked(...))` | +| decline to continue | `ctx.refused` | `ctx.refused` | `ctx.Refused` | `Err(ctx.refused(...))` | + +All four SDKs emit the same `yield.v1` protocol. Choose the language that best +fits the repository containing the skill. diff --git a/labs/22-yield/yield/docs/primitives/agent-task.md b/labs/22-yield/yield/docs/primitives/agent-task.md new file mode 100644 index 00000000..7da56dcd --- /dev/null +++ b/labs/22-yield/yield/docs/primitives/agent-task.md @@ -0,0 +1,40 @@ +# `AgentTask`: keep judgment with the model + +Use `AgentTask` for work that needs interpretation: reviewing a diff, +diagnosing a failure, comparing designs, extracting a policy, or proposing a +fix. + +```ts +type Diagnosis = { cause: string; confidence: number }; + +const diagnosis = ctx.agentTask( + "diagnose", + "Find the most likely cause of this test failure.", + { stdout: test.stdout, stderr: test.stderr }, + { + type: "object", + required: ["cause", "confidence"], + properties: { + cause: { type: "string" }, + confidence: { type: "number" }, + }, + }, +); +``` + +The arguments are: + +1. a stable operation ID; +2. the instruction; +3. optional structured context; +4. an optional JSON Schema for the response. + +The supervisor validates the response schema before accepting it. Schema-valid +does not mean true; use `RunCommand`, human approval, or another explicit check +when the workflow needs stronger evidence. + +## Common mistake + +Do not put retry order, approval rules, or completion policy inside the +instruction. Keep those rules in the surrounding program where they can be +replayed and tested. diff --git a/labs/22-yield/yield/docs/primitives/ask-user.md b/labs/22-yield/yield/docs/primitives/ask-user.md new file mode 100644 index 00000000..44c65342 --- /dev/null +++ b/labs/22-yield/yield/docs/primitives/ask-user.md @@ -0,0 +1,25 @@ +# `AskUser`: pause for a person + +Use `AskUser` when a person must choose, provide missing information, or approve +an irreversible action. + +```ts +const answer = ctx.askUser("approve", "Publish this release?", [ + { value: "yes", label: "Publish" }, + { value: "no", label: "Stop" }, +]); + +if (answer !== "yes") ctx.refused("the user declined publication"); +``` + +The coding agent asks through its normal interface. Yield records the answer +and replays it when the program starts again. The run can wait on disk between +the question and the answer. + +Use a closed list of options when only specific values are valid. Use a free +answer when the person needs to provide a path, identifier, or explanation. + +## Common mistake + +Do not ask for approval after the command has already changed the system. Put +the question before the effect, and use `Refused` when the person says no. diff --git a/labs/22-yield/yield/docs/primitives/outcomes.md b/labs/22-yield/yield/docs/primitives/outcomes.md new file mode 100644 index 00000000..e4c8ca87 --- /dev/null +++ b/labs/22-yield/yield/docs/primitives/outcomes.md @@ -0,0 +1,37 @@ +# Outcomes: complete, blocked, or refused + +Every run should end honestly. + +## Complete + +Return the useful result when the workflow has satisfied its requirements: + +```ts +return { published: true, version }; +``` + +TypeScript and Python complete by returning. Go uses `ctx.Complete(value)` and +Rust returns `Ok(value)`. + +## Blocked + +Use `Blocked` when the workflow cannot continue without new information or a +real-world change: + +```ts +ctx.blocked("three probes failed; new evidence is required"); +``` + +Blocked is not an error to hide. It records the frontier so another session can +understand why the work stopped. + +## Refused + +Use `Refused` when the workflow deliberately declines to perform an action: + +```ts +if (approval !== "yes") ctx.refused("release not approved"); +``` + +Refused is useful for rejected approvals, unsafe requests, or policy choices. +It is distinct from a missing dependency or exhausted investigation. diff --git a/labs/22-yield/yield/docs/primitives/require.md b/labs/22-yield/yield/docs/primitives/require.md new file mode 100644 index 00000000..e60fed17 --- /dev/null +++ b/labs/22-yield/yield/docs/primitives/require.md @@ -0,0 +1,24 @@ +# `Require`: make the finish rule executable + +Use `Require` when the workflow must not continue unless a claim is true. + +```ts +const dryRun = ctx.runCommand("dry-run", "npm run migrate -- --dry-run", 300); +ctx.require(dryRun.exit_code === 0, "the migration dry run succeeds", dryRun); +``` + +A failed requirement records `requirement_failed` and ends the program at that +point. Later commands are structurally unreachable. + +Pass the value supporting the claim as evidence. Yield stores its digest with +the requirement: + +```ts +ctx.require(review.critical === 0, "no critical findings remain", review); +``` + +## What `Require` does not do + +`Require` checks the Boolean expression you wrote. It cannot make a model result +true, and it cannot prove that an omitted check was unnecessary. Prefer facts +from `RunCommand` for mechanical checks and explicit human answers for approval. diff --git a/labs/22-yield/yield/docs/primitives/run-command.md b/labs/22-yield/yield/docs/primitives/run-command.md new file mode 100644 index 00000000..0435e53b --- /dev/null +++ b/labs/22-yield/yield/docs/primitives/run-command.md @@ -0,0 +1,37 @@ +# `RunCommand`: record what actually ran + +Use `RunCommand` when the workflow depends on a command's real exit code or +output. Typical uses are tests, type checks, builds, dry runs, deploy commands, +and verification probes. + +```ts +const test = ctx.runCommand("test", "npm test", 300); +ctx.require(test.exit_code === 0, "the tests pass", test); +``` + +The arguments are: + +1. a stable operation ID; +2. the shell command; +3. an optional timeout in seconds. + +`yskill` executes the command. The coding agent does not transcribe the result. +The saved response contains `exit_code`, `stdout`, `stderr`, and whether the +command timed out. + +## Use the result as evidence + +Pass the command result to `Require` when a later completion depends on it: + +```ts +const build = ctx.runCommand("build", "npm run build", 600); +ctx.require(build.exit_code === 0, "the production build succeeds", build); +``` + +This binds the claim to the recorded command result. A failed requirement ends +the run before later operations can execute. + +## Common mistake + +Do not use `AgentTask` to ask the model whether a command passed. Let Yield run +the command, then use the model only if its output needs interpretation. diff --git a/labs/22-yield/yield/docs/quickstart.md b/labs/22-yield/yield/docs/quickstart.md new file mode 100644 index 00000000..1ebfb704 --- /dev/null +++ b/labs/22-yield/yield/docs/quickstart.md @@ -0,0 +1,143 @@ +# Run your first Yield skill + +This tutorial turns a repeated review checklist into a small TypeScript +program: + +1. run a real check; +2. ask the coding agent to review the branch; +3. stop unless the result has zero critical findings; +4. save the structured review. + +You need Go 1.24 or newer and Node.js 24 or newer. + +## 1. Install the supervisor and SDK + +```bash +go install github.com/operatorstack/yield/cmd/yskill@latest + +mkdir review-skill +cd review-skill +mkdir -p fixtures +``` + +Make sure the Go bin directory is on your `PATH`. `go env GOPATH` prints its +parent directory; the binary normally lives in `$(go env GOPATH)/bin`. + +## 2. Create the package + +Create `package.json`: + +```json +{ + "private": true, + "type": "module", + "scripts": { + "check": "node --check main.ts" + } +} +``` + +Install the SDK: + +```bash +npm install @operatorstack/yield \ + --registry=https://get.operatorstack.systems/npm/ +``` + +## 3. Add the workflow + +Create `main.ts`: + +```ts +import { defineSkill } from "@operatorstack/yield"; + +type Review = { + critical: number; + summary: string; +}; + +defineSkill((ctx) => { + const check = ctx.runCommand("check", "npm run check", 60); + ctx.require(check.exit_code === 0, "the code check passes", check); + + const review = ctx.agentTask( + "review", + "Review the current branch. Find correctness, security, and data-loss risks.", + undefined, + { + type: "object", + required: ["critical", "summary"], + properties: { + critical: { type: "number" }, + summary: { type: "string" }, + }, + }, + ); + + ctx.require(review.critical === 0, "no critical findings remain", review); + return review; +}); +``` + +Add `skill.json` so Yield knows how to start the program: + +```json +{"run":["node","main.ts"]} +``` + +## 4. Add the thin skill file + +Create `SKILL.md`: + +```markdown +--- +name: review +description: Check and review the current branch before it is shipped. +--- + +Run `yskill run .` and follow each returned operation exactly. + +For `agent_task`, perform the task and return schema-valid JSON. Resume with +`yskill resume --response response.json --skill .`. + +Do not skip an operation or invent a response. The program owns the order and +the finish rule. +``` + +The file still tells the agent what the skill is for. It no longer has to +describe every branch and gate in prose. + +## 5. Prove the workflow locally + +Create `fixtures/responses.json`: + +```json +{ + "review": { + "critical": 0, + "summary": "No critical findings in the fixture run." + } +} +``` + +Run: + +```bash +yskill test . +``` + +`run_command` operations execute for real. The fixture supplies only the model +and user responses. A successful result ends with: + +```text +test: run reached completed +``` + +## 6. Use it from your coding agent + +Ask the agent to run the `review` skill in this directory. The agent reads +`SKILL.md`, starts `yskill`, performs the review operation, and resumes the +saved run. If the session closes, the run remains on disk. + +Next: [understand each primitive](primitives/README.md), or follow the +[complete review tutorial](tutorials/code-review.md). diff --git a/labs/22-yield/yield/docs/reference/cli.md b/labs/22-yield/yield/docs/reference/cli.md new file mode 100644 index 00000000..32d55ae5 --- /dev/null +++ b/labs/22-yield/yield/docs/reference/cli.md @@ -0,0 +1,59 @@ +# CLI reference + +`yskill` is the supervisor. It owns run logs, validates responses, executes +commands, and starts the skill program. + +## `init` + +```bash +yskill init +``` + +Scaffolds a new skill or adds a Yield program beside an existing prose skill. + +## `run` + +```bash +yskill run [--input input.json] +``` + +Starts a run and prints the first unanswered operation. The run is stored under +the skill's `.yield/runs/` directory. + +## `resume` + +```bash +yskill resume --response response.json [--skill directory] +``` + +Validates one response and prints the next operation or terminal outcome. +`--accept-new-digest` explicitly rebinds a saved run after intentional skill +source changes; do not use it to hide accidental drift. + +## `inspect` + +```bash +yskill inspect [run-id] [--skill directory] +``` + +Without a run ID, lists saved runs. With an ID, prints the append-only event +log. + +## `replay` + +```bash +yskill replay [--skill directory] +``` + +Re-executes the program from the log and verifies that recorded operations lead +to the same frontier. Operation drift fails loudly. + +## `test` + +```bash +yskill test +``` + +Uses `fixtures/responses.json` for `ask_user` and `agent_task` operations. +`run_command` operations still execute for real. The command succeeds only when +the program reaches `completed`. diff --git a/labs/22-yield/yield/docs/reference/execution-model.md b/labs/22-yield/yield/docs/reference/execution-model.md new file mode 100644 index 00000000..a4e665a5 --- /dev/null +++ b/labs/22-yield/yield/docs/reference/execution-model.md @@ -0,0 +1,32 @@ +# Run, pause, resume, and replay + +Yield does not keep a daemon or suspended coroutine alive. It uses deterministic +re-execution. + +1. `yskill` starts the skill program with its journal. +2. The program runs from the top. +3. Recorded operations receive their recorded responses in order. +4. Before consuming each response, the SDK checks that the operation digest + still matches. +5. At the first unanswered operation, the SDK emits a request and exits. +6. `yskill resume` records one validated response and starts the program again. + +This makes a saved run ordinary durable data. A new process or coding-agent +session can resume it. + +## Divergence + +If replay produces a different operation at an existing sequence, the SDK emits +`diverged` with the expected and actual digests. It never feeds an old response +to a changed operation. + +Changing source code during a run changes the skill digest. Resume refuses by +default. Use `--accept-new-digest` only for an intentional migration after +reviewing the change. + +## Filesystem effects + +Skill programs must remain deterministic between yielded operations. Do not +read clocks, randomness, changing environment variables, or mutable files +directly when they affect control flow. Cross observable system effects through +`RunCommand`, and pass stable input through the run input or recorded responses. diff --git a/labs/22-yield/yield/docs/reference/guarantees.md b/labs/22-yield/yield/docs/reference/guarantees.md new file mode 100644 index 00000000..e89a5f13 --- /dev/null +++ b/labs/22-yield/yield/docs/reference/guarantees.md @@ -0,0 +1,29 @@ +# Guarantees and limits + +## What Yield enforces + +- operation order expressed by the program; +- typed request and response envelopes; +- persistent append-only run state; +- per-step digest checks during replay; +- rejection of stale, duplicate, wrong-run, and schema-invalid responses; +- real command execution by the supervisor; +- requirements that prevent later completion after failure; +- recorded completed, blocked, and refused outcomes. + +## What remains outside the guarantee + +- A schema-valid model response may still be factually wrong. +- Portable mode cannot prove that an agent performed no work outside the + requested operation. +- Yield does not sandbox commands or supply deployment, migration, or publishing + logic. +- A fixture demonstrates declared paths; it is not automatically a complete + behavioral-equivalence proof for converted prose. +- Yield is not a hosted runtime, workflow marketplace, or multi-agent + orchestrator. + +Use `RunCommand` for facts the machine can observe, `AskUser` for human +authority, and explicit tests for the paths that matter. The formal scope is +documented in [`locus-yield.md`](../locus-yield.md) and +[`locus-conformance.md`](../locus-conformance.md). diff --git a/labs/22-yield/yield/docs/reference/sdk-parity.md b/labs/22-yield/yield/docs/reference/sdk-parity.md new file mode 100644 index 00000000..87e6102e --- /dev/null +++ b/labs/22-yield/yield/docs/reference/sdk-parity.md @@ -0,0 +1,25 @@ +# Four SDKs, one protocol + +Go, TypeScript, Python, and Rust implement the same observable `yield.v1` +contract. + +| Language | Package | Program entry | +|---|---|---| +| TypeScript | `@operatorstack/yield` | `defineSkill((ctx) => value)` | +| Python | `yieldskill` | `define_skill(program)` | +| Go | `github.com/operatorstack/yield/sdk/yield` | `yield.Main(program)` | +| Rust | `yieldskill` | `yieldskill::define_skill(program)` | + +Non-Go skills declare their runner in `skill.json`, for example: + +```json +{"run":["node","main.ts"]} +``` + +The conformance suite runs the same workflow in all four languages and compares +the observable protocol traces. Language-specific types and syntax differ; run +IDs, operation sequencing, digests, responses, requirements, divergence, and +terminal outcomes do not. + +Use the language already present in the repository. A mixed-language skill is +usually harder to install and maintain without changing what Yield can express. diff --git a/labs/22-yield/yield/docs/tutorials/README.md b/labs/22-yield/yield/docs/tutorials/README.md new file mode 100644 index 00000000..ab9bb543 --- /dev/null +++ b/labs/22-yield/yield/docs/tutorials/README.md @@ -0,0 +1,17 @@ +# Tutorials + +Each tutorial starts with an engineering job, not a protocol concept. + +1. [Check and review a branch](code-review.md) — combine deterministic checks + with model judgment. +2. [Pause for approval before publishing](approval.md) — put the human gate + before the effect. +3. [Resume after a person fixes the environment](environment-repair.md) — wait + on disk, then recheck. +4. [Bound a debugging loop](bounded-debugging.md) — stop guessing after a + declared number of attempts. +5. [Run a migration safely](data-migration.md) — dry-run, approve, apply, and + verify in order. + +The repository contains fixture-backed versions of these patterns. Run an +example with `yskill test examples/` before adapting it. diff --git a/labs/22-yield/yield/docs/tutorials/approval.md b/labs/22-yield/yield/docs/tutorials/approval.md new file mode 100644 index 00000000..3aa2f5fa --- /dev/null +++ b/labs/22-yield/yield/docs/tutorials/approval.md @@ -0,0 +1,24 @@ +# Tutorial: pause for approval before publishing + +An approval belongs before the command that changes the system. + +```ts +const approval = ctx.askUser("approve", "Publish this release?", [ + { value: "yes", label: "Publish" }, + { value: "no", label: "Stop" }, +]); + +if (approval !== "yes") ctx.refused("the user declined publication"); + +const publish = ctx.runCommand("publish", "npm run publish", 600); +ctx.require(publish.exit_code === 0, "the publish command succeeds", publish); +return { published: true }; +``` + +Yield does not provide publishing logic. `npm run publish` is your command and +your repository remains responsible for what it does. Yield records the +approval, runs the command, and prevents completion when the exit code fails. + +See [`examples/release-checklist`](../../examples/release-checklist/main.ts) for +a fixture-backed TypeScript program that also asks the model to draft release +notes. diff --git a/labs/22-yield/yield/docs/tutorials/bounded-debugging.md b/labs/22-yield/yield/docs/tutorials/bounded-debugging.md new file mode 100644 index 00000000..6a234b8a --- /dev/null +++ b/labs/22-yield/yield/docs/tutorials/bounded-debugging.md @@ -0,0 +1,35 @@ +# Tutorial: bound a debugging loop + +“Keep investigating until you find it” has no finish rule. A useful debugging +workflow should say when to stop guessing and ask for new evidence. + +The Go investigation example makes the boundary explicit: + +1. ask the model for observable evidence; +2. form at least three hypotheses, cheapest to disprove first; +3. run the proposed probe for each hypothesis; +4. allow at most three failed attempts; +5. complete only with a causal chain, otherwise return `Blocked`. + +```go +failures := 0 +for _, h := range hypotheses { + if failures >= 3 { + break + } + probe := ctx.RunCommand("probe-"+h.ID, h.DisproveCommand, 300) + assessment := assess(ctx, h, probe) + if assessment.Refuted { + failures++ + continue + } + ctx.Require(assessment.CausalChain != "", "a causal chain exists", assessment) + return ctx.Complete(assessment) +} +return yield.Outcome{}, ctx.Blocked("new evidence is required") +``` + +The model chooses and assesses hypotheses. Code owns the attempt bound and the +completion rule. + +Source: [`examples/investigate/main.go`](../../examples/investigate/main.go). diff --git a/labs/22-yield/yield/docs/tutorials/code-review.md b/labs/22-yield/yield/docs/tutorials/code-review.md new file mode 100644 index 00000000..46125e87 --- /dev/null +++ b/labs/22-yield/yield/docs/tutorials/code-review.md @@ -0,0 +1,34 @@ +# Tutorial: check and review a branch + +Many review skills mix two different jobs in prose: + +- mechanical checks that should really execute; +- judgment that needs a coding agent. + +Yield gives each job a clear owner. + +```ts +const check = ctx.runCommand("check", "npm run typecheck", 300); +ctx.require(check.exit_code === 0, "typecheck passes", check); + +const review = ctx.agentTask( + "review", + "Review the branch for correctness, security, and data-loss risks.", + undefined, + reviewSchema, +); + +ctx.require(review.critical === 0, "no critical findings remain", review); +return review; +``` + +## Why this split helps + +The agent still reads the diff and finds problems. It cannot skip the type +check, silently turn a failed check into success, or complete while the declared +critical count is non-zero. + +Use a schema containing the fields your later code actually reads. Avoid a huge +review schema when the gate only needs a small stable result. + +The [quickstart](../quickstart.md) builds this workflow from an empty directory. diff --git a/labs/22-yield/yield/docs/tutorials/data-migration.md b/labs/22-yield/yield/docs/tutorials/data-migration.md new file mode 100644 index 00000000..25548073 --- /dev/null +++ b/labs/22-yield/yield/docs/tutorials/data-migration.md @@ -0,0 +1,23 @@ +# Tutorial: run a migration safely + +A migration is a useful example because ordering matters: + +```text +dry-run → inspect plan → ask for approval → apply → verify → complete +``` + +The Rust example keeps every effect behind that order. If the dry run fails, +approval is never requested. If approval is declined, apply is never executed. +If verification fails, the run cannot complete successfully. + +Use your own commands for the dry run, apply, and verification. Yield provides +the execution and control primitives; it does not provide database migration +logic. + +Run the fixture-backed example: + +```bash +yskill test examples/data-migration +``` + +Source: [`examples/data-migration/src/main.rs`](../../examples/data-migration/src/main.rs). diff --git a/labs/22-yield/yield/docs/tutorials/environment-repair.md b/labs/22-yield/yield/docs/tutorials/environment-repair.md new file mode 100644 index 00000000..833dd032 --- /dev/null +++ b/labs/22-yield/yield/docs/tutorials/environment-repair.md @@ -0,0 +1,32 @@ +# Tutorial: resume after an environment repair + +Some workflows need a person to change something outside the agent session. +The run should wait without losing its earlier evidence. + +The Python environment-doctor example follows this path: + +1. `run_command` records the current probe. +2. `agent_task` interprets the output. +3. If unhealthy, `ask_user` explains the fix and waits. +4. A second `run_command` checks the environment again. +5. `require` prevents completion unless the recheck succeeds. + +```python +probe = ctx.run_command("probe-python", "python3 --version", timeout_seconds=60) +diagnosis = ctx.agent_task("diagnose", instruction, context=probe_context, schema=schema) + +if not diagnosis["healthy"]: + answer = ctx.ask_user("apply-fix", diagnosis["fix_hint"], options=options) + if answer != "done": + ctx.blocked("the environment fix was not applied") + recheck = ctx.run_command("recheck-python", "python3 --version", timeout_seconds=60) + ctx.require(recheck.exit_code == 0, "the environment probe passes", recheck) +``` + +Run the complete example: + +```bash +yskill test examples/env-doctor +``` + +Source: [`examples/env-doctor/main.py`](../../examples/env-doctor/main.py). diff --git a/labs/22-yield/yield/sdk/typescript/package.json b/labs/22-yield/yield/sdk/typescript/package.json index 11dad24e..803f7e93 100644 --- a/labs/22-yield/yield/sdk/typescript/package.json +++ b/labs/22-yield/yield/sdk/typescript/package.json @@ -4,8 +4,20 @@ "description": "Yield skill-program SDK for TypeScript: turn SKILL.md workflows into resumable programs.", "license": "MIT", "type": "module", + "files": [ + "dist", + "src" + ], "exports": { - ".": "./src/index.ts" + ".": { + "types": "./src/index.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" + } + }, + "scripts": { + "build": "node scripts/build.mjs", + "prepack": "npm run build" }, "engines": { "node": ">=23.6" diff --git a/labs/22-yield/yield/sdk/typescript/scripts/build.mjs b/labs/22-yield/yield/sdk/typescript/scripts/build.mjs new file mode 100644 index 00000000..a97e8f59 --- /dev/null +++ b/labs/22-yield/yield/sdk/typescript/scripts/build.mjs @@ -0,0 +1,19 @@ +import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; +import { stripTypeScriptTypes } from "node:module"; +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +const here = dirname(fileURLToPath(import.meta.url)); +const root = resolve(here, ".."); +const sourcePath = resolve(root, "src/index.ts"); +const distPath = resolve(root, "dist"); +const outputPath = resolve(distPath, "index.js"); +const source = readFileSync(sourcePath, "utf8"); +const runtime = stripTypeScriptTypes(source, { mode: "transform" }); + +rmSync(distPath, { recursive: true, force: true }); +mkdirSync(dirname(outputPath), { recursive: true }); +writeFileSync( + outputPath, + "// Generated from src/index.ts by scripts/build.mjs. Do not edit.\n" + runtime, +);