From d0cd6eb20cf5fb2d8e8654a7ec356117f67c9ab2 Mon Sep 17 00:00:00 2001 From: "operator-stack-publisher[bot]" Date: Sun, 2 Aug 2026 00:50:25 +0000 Subject: [PATCH] Sync Yield from Intelligence Flow @ 34cac6048389 --- README.md | 34 +- UPSTREAM.json | 124 ++-- cmd/yskill/agents.go | 538 ++++++++++++++++++ cmd/yskill/agents_test.go | 241 ++++++++ cmd/yskill/main.go | 20 +- cmd/yskill/main_test.go | 32 +- cmd/yskill/registry/README.md | 12 + cmd/yskill/registry/VERCEL_SKILLS_LICENSE | 21 + cmd/yskill/registry/agents.json | 466 +++++++++++++++ cmd/yskill/scaffold.go | 40 +- cmd/yskill/skillmeta.go | 86 +++ docs/README.md | 11 +- docs/agent-setup.md | 61 ++ docs/primitives/agent-task.md | 2 +- docs/quickstart.md | 111 ++-- docs/reference/cli.md | 41 +- docs/reference/guarantees.md | 2 +- docs/reference/sdk-parity.md | 4 +- evals/results/latest.json | 4 +- examples/convert-skill/skill.json | 5 + examples/data-migration/skill.json | 8 +- examples/env-doctor/skill.json | 7 +- examples/investigate/skill.json | 5 + examples/library/go/audit-security/skill.json | 2 + .../library/go/investigate-failure/skill.json | 2 + .../library/go/migrate-database/skill.json | 2 + examples/library/go/publish-ios/skill.json | 2 + examples/library/go/qa-web-change/skill.json | 2 + .../library/go/release-package/skill.json | 2 + examples/library/go/repair-ci/skill.json | 2 + examples/library/go/review-branch/skill.json | 2 + examples/library/go/triage-issue/skill.json | 2 + .../library/go/upgrade-dependency/skill.json | 2 + .../library/python/audit-security/skill.json | 2 + .../python/investigate-failure/skill.json | 2 + .../python/migrate-database/skill.json | 2 + .../library/python/publish-ios/skill.json | 2 + .../library/python/qa-web-change/skill.json | 2 + .../library/python/release-package/skill.json | 2 + examples/library/python/repair-ci/skill.json | 2 + .../library/python/review-branch/skill.json | 2 + .../library/python/triage-issue/skill.json | 2 + .../python/upgrade-dependency/skill.json | 2 + .../library/rust/audit-security/skill.json | 2 + .../rust/investigate-failure/skill.json | 2 + .../library/rust/migrate-database/skill.json | 2 + examples/library/rust/publish-ios/skill.json | 2 + .../library/rust/qa-web-change/skill.json | 2 + .../library/rust/release-package/skill.json | 2 + examples/library/rust/repair-ci/skill.json | 2 + .../library/rust/review-branch/skill.json | 2 + examples/library/rust/triage-issue/skill.json | 2 + .../rust/upgrade-dependency/skill.json | 2 + .../typescript/audit-security/skill.json | 2 + .../typescript/investigate-failure/skill.json | 2 + .../typescript/migrate-database/skill.json | 2 + .../library/typescript/publish-ios/skill.json | 2 + .../typescript/qa-web-change/skill.json | 2 + .../typescript/release-package/skill.json | 2 + .../library/typescript/repair-ci/skill.json | 2 + .../typescript/review-branch/skill.json | 2 + .../typescript/triage-issue/skill.json | 2 + .../typescript/upgrade-dependency/skill.json | 2 + examples/release-checklist/skill.json | 7 +- go.mod | 5 +- go.sum | 4 + .../2026-08-02-cross-agent-registration.md | 8 + 67 files changed, 1822 insertions(+), 157 deletions(-) create mode 100644 cmd/yskill/agents.go create mode 100644 cmd/yskill/agents_test.go create mode 100644 cmd/yskill/registry/README.md create mode 100644 cmd/yskill/registry/VERCEL_SKILLS_LICENSE create mode 100644 cmd/yskill/registry/agents.json create mode 100644 cmd/yskill/skillmeta.go create mode 100644 docs/agent-setup.md create mode 100644 examples/convert-skill/skill.json create mode 100644 examples/investigate/skill.json create mode 100644 release-notes/2026-08-02-cross-agent-registration.md diff --git a/README.md b/README.md index ae70c2a..163512a 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,28 @@ cargo install yieldskill \ yskill --version ``` +## Create and register a workflow + +Keep the real workflow beside the language dependencies it uses. Yield writes +small adapters into each coding agent's project skill directory; it does not +copy the workflow or install its dependencies again. + +```bash +# TypeScript example +npm exec -- yskill init skills/review \ + --language typescript \ + --description "Review changed code when the user wants a branch checked before shipping." + +# Detect installed agents, or pass --agent cursor,codex,claude-code +npm exec -- yskill register skills/review +npm exec -- yskill doctor skills/review --test +``` + +`yskill agents` lists the available agent IDs and project paths. Cursor, +Codex, and Claude Code are verified. Remaining entries support explicit path +registration from the pinned open registry; they are not presented as +end-to-end verified. + ## How it works Deterministic re-execution: on every run/resume, `yskill` re-executes the @@ -82,8 +104,8 @@ four languages and asserts identical observable protocol behavior. | Python | `sdk/python` (`yieldskill`) | `examples/env-doctor` — probe, branch, resume after the human | | Rust | `sdk/rust` (`yieldskill`) | `examples/data-migration` — dry-run → approve → apply → verify | -Non-Go skills declare their runner in `skill.json`: -`{"run": ["node", "main.ts"]}`. +Skills declare their language and runner in `skill.json`: +`{"version": 1, "language": "typescript", "run": ["node", "main.ts"]}`. ## Ten workflows, every language @@ -106,6 +128,8 @@ use the documentation by job: - [tutorials](docs/tutorials/README.md) — review, approval, environment repair, bounded debugging, and migration; - [examples](docs/examples.md) — working programs in all four languages; +- [coding-agent setup](docs/agent-setup.md) — register one workflow with the + agents used by the project; - [evaluations](evals/README.md) — first-party workflow conformance and runtime invariant results, including the exact claim boundary; - [convert an existing skill](docs/convert-existing-skill.md) — move @@ -127,7 +151,9 @@ YSKILL="$PWD/yskill" bash ./examples/library/test-all.sh ./yskill test examples/env-doctor # Python 3.10+ ./yskill test examples/data-migration # Rust (cargo) ./yskill run examples/investigate # prints the first operation envelope -./yskill init my-skill # scaffold, or wrap an existing prose skill +./yskill init my-skill --description "Run this workflow when ..." +./yskill register my-skill --agent codex # write a thin project adapter +./yskill doctor my-skill --agent codex # verify package + adapter wiring ``` The reference skill, `examples/investigate`, encodes an investigation @@ -144,7 +170,7 @@ rejection, evidence-bound completion. Not guaranteed: that the agent performed *only* the requested operation, or that a schema-valid `agent_task` result is true — schema validity is not truth. `RunCommand` is the exception by construction: commands are -executed by the supervisor, so exit codes and output enter the log as +executed by the Yield CLI, so exit codes and output enter the log as observed fact. The formal analysis behind this line is in `docs/locus-yield.md`. diff --git a/UPSTREAM.json b/UPSTREAM.json index eb9deb9..71cffa7 100644 --- a/UPSTREAM.json +++ b/UPSTREAM.json @@ -2,11 +2,18 @@ "files": { ".gitignore": "803c5f79d6da7f2c5a1dc0ce27c53b8e5c059309b165782831c4c472af058a4c", "LICENSE": "fff261ce507eabd57666c283a621f33e183a3aedebda04c4ecbc6309a62f5edf", - "README.md": "25414dfd686342b2153b63bab6c8a5c9fbab1e5fb80be368b8c43f5161b53b83", - "cmd/yskill/main.go": "391d388b1f5ad4eaebcd833d802eca0dcbcb669a876bc9fe6cd57f54e3689732", - "cmd/yskill/main_test.go": "629a5468f587d9ad69e8147601ab8983db0089fa6856378edb3ab14c1928bfd8", - "cmd/yskill/scaffold.go": "cc528eb8dabb2032ddaf5ac07a54ff5b95a7250c32d6603ec285cc7d8a20619c", - "docs/README.md": "cd8a4105f4f04143172661b39789e3c533d031ad46437aa2c078625a29a0a9db", + "README.md": "da05508b2bae74f3cea3b88945a0346b8f454739a134ba412603fab42530f099", + "cmd/yskill/agents.go": "850e443e0c8279bdc00d9ae39ae729b77db9f222e014e0c7d92f86a9e109eeeb", + "cmd/yskill/agents_test.go": "ea9b229ed35adaeacce59412058500db72ef598fbf0f1ff311fde117ccee6278", + "cmd/yskill/main.go": "fd1fa92a5c30444e6ef09ad8bffcd115c274b2789ed9247d3c2a3781aeefb5e8", + "cmd/yskill/main_test.go": "5da95687ce60f71600530444798c3d290ce033d55466cbcc2e7ec9429da4ec31", + "cmd/yskill/registry/README.md": "fab385921ee7972f76deb94a3b7ae41184735598ea4145c9d8ccdde2c2b876c4", + "cmd/yskill/registry/VERCEL_SKILLS_LICENSE": "779258e329008bdb9330e6c1daad644ff867f164d11c4cc4404350479f3e92ee", + "cmd/yskill/registry/agents.json": "6edfee31cdc0390516adbb107fc97fc3531eb02e1a28b9d62b5b86fdccaed7c1", + "cmd/yskill/scaffold.go": "648b772f6c4926d5052245cbd1dc84e713c99210f3436ef4488e83e8e233854b", + "cmd/yskill/skillmeta.go": "12b0c25689bf825d676404af7b3fb74fb92db3d9e222d4e553d8800d86aea45e", + "docs/README.md": "63bfd77584e84be09fe55bfcf2e1792d67d9690f9ebf302e6756a77c4c0cfbf5", + "docs/agent-setup.md": "40c5adacbb22fd8d58c37300c68225c1442f579c58614742cefb7da995e40f2d", "docs/convert-existing-skill.md": "0dd538e908a1f2d3a1958e4b2cc1efede2a8e7a73341e32c1a75fec69a9acb8a", "docs/examples.md": "3c19bacae7ec7b31bf93417e61d01cd1872f26228fedf0ed6decfce7c41ed274", "docs/locus-conformance.md": "a71fd5a72678dcad344afc71cd7a788090ef008a8e5e82d925da5a3db41af6a0", @@ -25,16 +32,16 @@ "docs/locus/yield-diag-portable.json": "71f2880721196f42c82cc152c49dff6d0fd4ac71a84586c468f66442bc305051", "docs/locus/yield-protocol.json": "82c3490000357d66bc1f35623176a9b0279800340684047d46696d2eb43677d2", "docs/primitives/README.md": "4181e5a4115fff00edef8b0266aa1ecb1bd3443acd0e0272246e650efd13acc9", - "docs/primitives/agent-task.md": "a135d7772f9a15221aa95140d2c66e0a6274bf24eae823b4cd1e18cb2f70c3e8", + "docs/primitives/agent-task.md": "89ec69ec7d83c4b78b8d71ee877dfc2b5cabb4fe5bee3f2ee1a524da40349b2d", "docs/primitives/ask-user.md": "6f12772749efb485b0479cdb17d6aa1dd3394e4a5500278bd80f653bb910e638", "docs/primitives/outcomes.md": "a584976fada6af3772894736e686f5deb466d3cc8fd1ecacf49f6b9042d6a232", "docs/primitives/require.md": "1ea8c3a9ea11aa61e2baee01cf83fca8c872e846a47d7ef230cf6b76d04c90d8", "docs/primitives/run-command.md": "af9bcc617f90fd2ee0086aeabb5c98854542efe81636a020699c2f688f8b3b8c", - "docs/quickstart.md": "2fc6a4780a6c47ea00b02b4f644a6a12c804491e455ca498ed3d5f294a013f59", - "docs/reference/cli.md": "d26f76f367c31b99c4cc44cb486834f0a581cda5f952c781de5f5ffc8b9bef59", + "docs/quickstart.md": "5bc7febcdb6493d34ac7c16f76f63e4ca3304fdeead256a2038d73f0fd906c7b", + "docs/reference/cli.md": "aa409436156bad1a7691bef47e191e09a083d533ff8893068d07df28ce68b30b", "docs/reference/execution-model.md": "b221051da602953ebd9e1cc5e7f848de8f59721b36a1793211e6374745f74507", - "docs/reference/guarantees.md": "e42dcdc1e6c4ed755d0a8156f0d58b2f552edf1cb8f910f0c2f872b1ac6907ff", - "docs/reference/sdk-parity.md": "f598cd9a19b76727f4ec27b6c029640fe2e4661d964db2938fda27bdc962b345", + "docs/reference/guarantees.md": "07df3251a34345c4673e826ca19ae8a8d2539432bbc7848d1f0e0eb8aa68c808", + "docs/reference/sdk-parity.md": "b8c3d6d6efad246b9212db760bb72cba7182b04da321cfd667783000ae75f733", "docs/tutorials/README.md": "d574e869782a1a5e39113b275744cb8cd74b7f63f69c8e30520559d32c21f8d1", "docs/tutorials/approval.md": "d0144288e12488627fce085d3053b1c9b79cc1dac2d45157c214062de3375a9c", "docs/tutorials/bounded-debugging.md": "903b876fb13fa5bff6789c500f56c1b97c5ae1bc0059147d845a8f327d553340", @@ -59,51 +66,53 @@ "evals/package.json": "84ac7bd7d1c0d1db2233dab54754296195b267e5e907d9f6c402d0d44d569adb", "evals/results/README.md": "65b74bfab83dfc51fc5b8a3a4824c37b722fb3a358a5dcfb217dc2af199f4801", "evals/results/latest-agent.json": "1484174819ae29bbcffeb615036fa165518669525e6d664123f6a38ca3614b69", - "evals/results/latest.json": "4fbd1a9322b138cfa0c8518c07daa71a58a8d4c1b590af8bd825a32890bd72cb", + "evals/results/latest.json": "fa1fc16ecd5983b5d78427a4854a8e2d27bb896df919f5dda502461237e63cd0", "evals/scripts/run.mjs": "119248cd4d383326d396f4459df28c51ce7c31088d97639851f2f5ab4c329892", "evals/scripts/validate.mjs": "7ac2a3239cd1b52a604c8a8a52a1af4ac55c4007ac2751d4fbfe20d0e1f568dc", "examples/convert-skill/SKILL.md": "e6376f34365d4ac030d316db55e91f0c606a501668099f4ecf1e27d43ec806a2", "examples/convert-skill/fixtures/responses.json": "5b5f27b0ae5962360ac7b0e779992f430c655f352a38da37debb3505c32cd60a", "examples/convert-skill/main.go": "eb987ed1ce9139e6d0d40a2fae20c532c2fba3b27357e31555db2f0f52db4e39", + "examples/convert-skill/skill.json": "cd9f5e46c623597dad1224735a03d1363b8a426f541bd00321752d1cf7d9b116", "examples/data-migration/Cargo.lock": "e1bd35afbfdf0119c4accc8de657241b027c12b029f5117147349063ccb0d6c7", "examples/data-migration/Cargo.toml": "f578e4084a0457c4027100bc99c7698c388356d8e893f9d12b8e49491fdb9705", "examples/data-migration/SKILL.md": "da864f02e985982cfd73b4ccf2b250d53c0166cdd71adba24fac565e1182b02d", "examples/data-migration/fixtures/responses.json": "9568d3cf9a7b0e25d562cdc77cf2b0d494dae342fcb60bb58c4dc7b502603200", - "examples/data-migration/skill.json": "4ae73a29cbaf4eab7561620b2e8e7d76e4f7d45e748f550e2b98c5198217af59", + "examples/data-migration/skill.json": "e688478483ffdbac242d1d51a901bfc07a1eef098b38d54f85af2f1cce75621f", "examples/data-migration/src/main.rs": "1cda13ca0eb9da954abbb82d1805a476d6d41d5bcf2d86cbee8ea0727c6b4295", "examples/env-doctor/SKILL.md": "d146f3055b9baa15972582ff753f1d7085f8a50ceba1a034897c99d303ef15bd", "examples/env-doctor/fixtures/responses.json": "1c4edc95d8c71966fe2e05b5ccfa39f73dbecef805a33a1cb60fdf60040d1691", "examples/env-doctor/main.py": "e996ee895f8c1a3bee800d11c896e0383596e8e48a171dcc1757c3ca218db2fa", - "examples/env-doctor/skill.json": "5207b98487b29a9914f3621d40daf8da3d1626a90a8fc0173ca0c7ee114b9764", + "examples/env-doctor/skill.json": "a03efd4fe141e598a1ba57cdd14a561cc99ec2dd6f6106738c14b2f8391ddcc1", "examples/investigate/SKILL.md": "401fc32bdfa594c8c2189723dbabf135365705281a3a75d6aee910d9126d297e", "examples/investigate/fixtures/responses.json": "b17bde7104427926d120d14e2f989186a1834b78a0a039384f34a2847cbd787e", "examples/investigate/main.go": "2e1a21e347791a0ecfc740f862631e7e6af6d518fb26fc4b0062d9170bcae44b", + "examples/investigate/skill.json": "cd9f5e46c623597dad1224735a03d1363b8a426f541bd00321752d1cf7d9b116", "examples/library/README.md": "aa8fbdd41179d866b18763784d9396516cc88f858d95f0de113e676a4dc33e9f", "examples/library/catalog.json": "1572538febe5f6cb610ac68df3fe5be5ee1aff1cf3e83398ab0d310d37088f82", "examples/library/go/audit-security/SKILL.md": "3ca2a8ffdb4504854cc45879e4c8bb795fc073560c1994eaf20f3d42d00d62f1", "examples/library/go/audit-security/fixtures/responses.json": "d738404c2e2912705de936c5948c4520ae4145bae0068d478f7689aae9aaedaa", - "examples/library/go/audit-security/skill.json": "d1edb87a0f0f3d1aa41cccd8429421b3ef39926cea5841c9d327430bbd1dc3cf", + "examples/library/go/audit-security/skill.json": "1b5cbb34a60cb84c7cdf064458792da8889931da751e84ee74bfee6514b94269", "examples/library/go/investigate-failure/SKILL.md": "73d7f356adee39ffac667659ff875c2e3632f1fe15a94a491e95e88d4a5ac110", "examples/library/go/investigate-failure/fixtures/responses.json": "cd9fd2b16d636ba2098884b011f66008056439a2e34d68b1777f48010653192e", - "examples/library/go/investigate-failure/skill.json": "21a2f73c843df1e64b722907e759fe06c20337693681c21f0ee534c43fd76b01", + "examples/library/go/investigate-failure/skill.json": "0ac20376f3d0bbb01b72b2f4b7d138c2098c08268553299d514c9527d99f948d", "examples/library/go/migrate-database/SKILL.md": "1328621f6b19da12f642c379456ba24ced1827bd676bf35df1c5f616ff791575", "examples/library/go/migrate-database/fixtures/responses.json": "e7114f5615a134e8afe151b6e9133cc601549392eae53b94a308fd3131b1d77a", - "examples/library/go/migrate-database/skill.json": "f3e8aa0a27247560d651b5aed997c9a078f9d9ee02a4b8e710ab3f9a1fdcc4d3", + "examples/library/go/migrate-database/skill.json": "911a807870b8fb80b552ec756afc190236be9825e64cfed1c07719f4c6c0ef71", "examples/library/go/publish-ios/SKILL.md": "1e2cd5e91ea0225793f15440b05e1cdd9f3582f7dfe6ea6346762ccd4ef73ad0", "examples/library/go/publish-ios/fixtures/responses.json": "76721fc014a01ce76a30c804743be83af2299469a3640e6df095971214d2c2a3", - "examples/library/go/publish-ios/skill.json": "64c3abfcca444274467d56bd4c4d954935f1fc37dbf8156358dafb2694e92077", + "examples/library/go/publish-ios/skill.json": "9220341bf4be4cca80c3a71ecc6da492ee4ee50011fd2351b768afa05e1b2c75", "examples/library/go/qa-web-change/SKILL.md": "c04d21e12b3f05ccf20493088d4546d135b38196c43832a4d75773b6b465e2a4", "examples/library/go/qa-web-change/fixtures/responses.json": "d12ea67b9fde2e179f7a1d4e64f3d341c64c230fbfb61b70bfbe9fc1c2ee2269", - "examples/library/go/qa-web-change/skill.json": "095685f33608374b27fdb735978699a61c390307e99def092f80f4440a91da3c", + "examples/library/go/qa-web-change/skill.json": "74b4a1490d997ee73d4b2fa3f4b7c38d531d9bb9f29ad566be819ecc7c2b8ea5", "examples/library/go/release-package/SKILL.md": "c4666ba653113ee812a965960f3b591f9b316a97afaf5a1f80e70218e2bfcf3a", "examples/library/go/release-package/fixtures/responses.json": "7aeb44594f14bd110dcfbe938d4efb0d71a4dc310646a7aaf03f5713574767da", - "examples/library/go/release-package/skill.json": "9c020dd0edaf7d93bed7b2fdbc2a9f9276547804b1a2591ebc0fc4e29c2d64ac", + "examples/library/go/release-package/skill.json": "a5ad7688e3a9d3760ba0eb4306e23c998748dd7c9224b00ef3cef56ecd4f0fd4", "examples/library/go/repair-ci/SKILL.md": "eb61f59ada1e1a4a591d87a4b80e921f274dea4fb8ff5657942e129f243f1820", "examples/library/go/repair-ci/fixtures/responses.json": "b9cae86c313eb64033c04082ec40c98d5888ebd996391728373d03856cc90b10", - "examples/library/go/repair-ci/skill.json": "5b801bcecd7ea0b15e076fe8fbfd76ec8d88429132b3c012321f23ee7bff733f", + "examples/library/go/repair-ci/skill.json": "1991c9926e13371e713c63d6dfce28f6c290d37b6cb2c9ede10bcb0376155120", "examples/library/go/review-branch/SKILL.md": "722716de93a060dde3453c05804a1c4d3b66af18e76c24f15fd0738510ee735b", "examples/library/go/review-branch/fixtures/responses.json": "9de268b5b0f8ed4bc88901d8bdbd14cc5ff61a93ef01e26f28fae815fda45fac", - "examples/library/go/review-branch/skill.json": "602950dfe48ae8e1cc43c11926843e76453b9d30565ed628cc6dcd7307d91d14", + "examples/library/go/review-branch/skill.json": "9208838fdc88dec59a3ea02deb8151ea24439e5a2d9950d6ca0bfdd7e92dcbb7", "examples/library/go/src/audit-security/main.go": "ebb7d56f941e7405c492e681027b198ce0d9f91ec8372ce9010ae2179ef2ced1", "examples/library/go/src/investigate-failure/main.go": "7dc17697a7e6fbc77534fcc71f33dd9ff05d16268eca2f92f46d6b8a7421c1cb", "examples/library/go/src/migrate-database/main.go": "5e5792a300a7ef5d32804add6fb14902840e05fcd59486fa1f196d43a1b0970d", @@ -116,34 +125,34 @@ "examples/library/go/src/upgrade-dependency/main.go": "6ef20ce2bccf92cdbed59a26a075101a858e630b8cc05f34b0b843972b8dcfd6", "examples/library/go/triage-issue/SKILL.md": "a3a0c383196cd981e64c1fd311e608cb50facfe55409981d4f92d28a4b346862", "examples/library/go/triage-issue/fixtures/responses.json": "68f36fb5a7723a5d2a5477bed3e8a245908e6157a7eeb9205a604a05c9e3998f", - "examples/library/go/triage-issue/skill.json": "e1ab226cad4ee921efebb93840cdcfe49af7e25bcea28eb293b7dde2d548dc7e", + "examples/library/go/triage-issue/skill.json": "7117c9c44ebc29cfa4c667da3787504ee20c14a09251f111ed4c55b43a6d6a21", "examples/library/go/upgrade-dependency/SKILL.md": "11b6b4258640ff60af1446b97d907ea15d819a714de2736eda16621f5adbf186", "examples/library/go/upgrade-dependency/fixtures/responses.json": "17eeef53bb7a4cc9ad70f0b24d50305db8266b4edb8c911570da7141830f2b9d", - "examples/library/go/upgrade-dependency/skill.json": "2d3d47c56bd73b1c727eda77c917b11495ef1ee265b7a2ed729126381da551e3", + "examples/library/go/upgrade-dependency/skill.json": "100c63e44dcc21ff657c4bf03f4779ff941e672bfd6f4942ba649f9a0cf11910", "examples/library/python/audit-security/SKILL.md": "3ca2a8ffdb4504854cc45879e4c8bb795fc073560c1994eaf20f3d42d00d62f1", "examples/library/python/audit-security/fixtures/responses.json": "d738404c2e2912705de936c5948c4520ae4145bae0068d478f7689aae9aaedaa", - "examples/library/python/audit-security/skill.json": "b5a256f76511e2533127924c27aff8b328aee5174e421a3d737019e1a86fb6cf", + "examples/library/python/audit-security/skill.json": "51c7cc438336c781bd9860d516ba81a77d11baa428b18a92ca715da036b0bdd0", "examples/library/python/investigate-failure/SKILL.md": "73d7f356adee39ffac667659ff875c2e3632f1fe15a94a491e95e88d4a5ac110", "examples/library/python/investigate-failure/fixtures/responses.json": "cd9fd2b16d636ba2098884b011f66008056439a2e34d68b1777f48010653192e", - "examples/library/python/investigate-failure/skill.json": "5820fd75d64bab4961d678081331212b4a35c34d6bd8e7432177ef3ab7182ef1", + "examples/library/python/investigate-failure/skill.json": "85cc911cd12eb5a0be3a13f803b9415371f5b9dcc6317b0b153ffcf23cce06e2", "examples/library/python/migrate-database/SKILL.md": "1328621f6b19da12f642c379456ba24ced1827bd676bf35df1c5f616ff791575", "examples/library/python/migrate-database/fixtures/responses.json": "e7114f5615a134e8afe151b6e9133cc601549392eae53b94a308fd3131b1d77a", - "examples/library/python/migrate-database/skill.json": "80aa82cc7b85f600981825de99de28b8dbe9800b9d2bb333927835d8f79bb9d5", + "examples/library/python/migrate-database/skill.json": "f3182e640a0a348ac5624450124a05616494dfd211dce95a80d8120b98e9f8d2", "examples/library/python/publish-ios/SKILL.md": "1e2cd5e91ea0225793f15440b05e1cdd9f3582f7dfe6ea6346762ccd4ef73ad0", "examples/library/python/publish-ios/fixtures/responses.json": "76721fc014a01ce76a30c804743be83af2299469a3640e6df095971214d2c2a3", - "examples/library/python/publish-ios/skill.json": "56b2070ed4e12ff9676e8f56e222edadeb663fc33d9f39228adeb0c4eaf6d7d9", + "examples/library/python/publish-ios/skill.json": "7e136a98c30fb38195f649033e5a84fc1409ba940004ad890cfbe25fa5694c16", "examples/library/python/qa-web-change/SKILL.md": "c04d21e12b3f05ccf20493088d4546d135b38196c43832a4d75773b6b465e2a4", "examples/library/python/qa-web-change/fixtures/responses.json": "d12ea67b9fde2e179f7a1d4e64f3d341c64c230fbfb61b70bfbe9fc1c2ee2269", - "examples/library/python/qa-web-change/skill.json": "186f6ff25c6bdcfc817b73c79d3e9ac4f8395da7a05197b559192066e19cdb36", + "examples/library/python/qa-web-change/skill.json": "735e69a1c02cbccba78f1b346e1043bc8cc186ae8ee2d68c491da5e069160354", "examples/library/python/release-package/SKILL.md": "c4666ba653113ee812a965960f3b591f9b316a97afaf5a1f80e70218e2bfcf3a", "examples/library/python/release-package/fixtures/responses.json": "7aeb44594f14bd110dcfbe938d4efb0d71a4dc310646a7aaf03f5713574767da", - "examples/library/python/release-package/skill.json": "b157a151295ae2814d3d74803957bb8f8a2d48e7b35adb7f54faf41c49e0559e", + "examples/library/python/release-package/skill.json": "7210b06a2de9e282e8cde3b48dd37e46ea3e56936ce8f2a79e479a7e1e41327d", "examples/library/python/repair-ci/SKILL.md": "eb61f59ada1e1a4a591d87a4b80e921f274dea4fb8ff5657942e129f243f1820", "examples/library/python/repair-ci/fixtures/responses.json": "b9cae86c313eb64033c04082ec40c98d5888ebd996391728373d03856cc90b10", - "examples/library/python/repair-ci/skill.json": "dd358e71c9a6c3ee01a4a8135a0a8bfc24e338cb6f873fea5a5e2850b51c7b77", + "examples/library/python/repair-ci/skill.json": "ceb25fca2a9496a4a71bd48186fbc569f899ed63724f5ff9142673f21ad2722c", "examples/library/python/review-branch/SKILL.md": "722716de93a060dde3453c05804a1c4d3b66af18e76c24f15fd0738510ee735b", "examples/library/python/review-branch/fixtures/responses.json": "9de268b5b0f8ed4bc88901d8bdbd14cc5ff61a93ef01e26f28fae815fda45fac", - "examples/library/python/review-branch/skill.json": "2a6fc1ddfc74be604e061e0e8dc1cfe54aa6736c5bbf8796fa5205ceed148ace", + "examples/library/python/review-branch/skill.json": "939cb32c9b989f076230d9d1a710a0257dc2eadee9ea27bbfe5aa5c6aa8130f5", "examples/library/python/src/audit-security.py": "e1cdb9f0e1d3c757f3fc3495c14448f758d905ec8b4c125fa327e23900a38ba3", "examples/library/python/src/investigate-failure.py": "114b6633554a8988e2a4416f7dc640ab49bb03a4e1953488947319ce383b5c04", "examples/library/python/src/migrate-database.py": "ebbc5b4a2f8b76f07c949e223d5f29b3b708b8d30003129c103a9c00e3b3fc65", @@ -156,36 +165,36 @@ "examples/library/python/src/upgrade-dependency.py": "7201cb69871cdb1d5db9e3dc17da114c437e280fd8d04dcdc5df1ab3de68778c", "examples/library/python/triage-issue/SKILL.md": "a3a0c383196cd981e64c1fd311e608cb50facfe55409981d4f92d28a4b346862", "examples/library/python/triage-issue/fixtures/responses.json": "68f36fb5a7723a5d2a5477bed3e8a245908e6157a7eeb9205a604a05c9e3998f", - "examples/library/python/triage-issue/skill.json": "ed42311ec79ce131312feeda2a27dcb7e8e59b0f750ad68d014c106cdf5e834a", + "examples/library/python/triage-issue/skill.json": "1fda27424f8bf5e98f692610168c72a716b8e1ef27bf9fe6002261464d7af8af", "examples/library/python/upgrade-dependency/SKILL.md": "11b6b4258640ff60af1446b97d907ea15d819a714de2736eda16621f5adbf186", "examples/library/python/upgrade-dependency/fixtures/responses.json": "17eeef53bb7a4cc9ad70f0b24d50305db8266b4edb8c911570da7141830f2b9d", - "examples/library/python/upgrade-dependency/skill.json": "73c93f03c0717217ec0f85a781a39993c64590c9f010d51df3a5f09384f2113b", + "examples/library/python/upgrade-dependency/skill.json": "8c330daaf4e1ed49e41ae2765735de0bb7e44e19f384ac8a11b39fe3e179d875", "examples/library/rust/Cargo.lock": "1d053562f99eebfef5bba6897ae3714f699d3f0e262220d49572be112ff8669e", "examples/library/rust/Cargo.toml": "126a839a0a41841aff8689b6c6e62a75f81387866714f4fe7d3fbbcb809af21f", "examples/library/rust/audit-security/SKILL.md": "3ca2a8ffdb4504854cc45879e4c8bb795fc073560c1994eaf20f3d42d00d62f1", "examples/library/rust/audit-security/fixtures/responses.json": "d738404c2e2912705de936c5948c4520ae4145bae0068d478f7689aae9aaedaa", - "examples/library/rust/audit-security/skill.json": "4b8fdbf6221e993f0495619364b62b0021bcfa61ca5c8b077d86ea13387d094b", + "examples/library/rust/audit-security/skill.json": "efa98ccee6993b0b33467bffe6f0e3b1f26dc142c8947d4780d22bd2874c5b0a", "examples/library/rust/investigate-failure/SKILL.md": "73d7f356adee39ffac667659ff875c2e3632f1fe15a94a491e95e88d4a5ac110", "examples/library/rust/investigate-failure/fixtures/responses.json": "cd9fd2b16d636ba2098884b011f66008056439a2e34d68b1777f48010653192e", - "examples/library/rust/investigate-failure/skill.json": "22903c708635e783bb256988fa91e13f2100419a4d3c16840e8604f4a56923fb", + "examples/library/rust/investigate-failure/skill.json": "9299c81fc070c90c20af83f98a73cce569a232c417f34c36c56e724057f12b28", "examples/library/rust/migrate-database/SKILL.md": "1328621f6b19da12f642c379456ba24ced1827bd676bf35df1c5f616ff791575", "examples/library/rust/migrate-database/fixtures/responses.json": "e7114f5615a134e8afe151b6e9133cc601549392eae53b94a308fd3131b1d77a", - "examples/library/rust/migrate-database/skill.json": "59be5e08ce118bf9d529dca94fc256952a12e7168e349651fc533df584bf5ac7", + "examples/library/rust/migrate-database/skill.json": "73625614cc4f7e5f75ef9663bdb65453d898f834c2d100b4fd4514207fed759c", "examples/library/rust/publish-ios/SKILL.md": "1e2cd5e91ea0225793f15440b05e1cdd9f3582f7dfe6ea6346762ccd4ef73ad0", "examples/library/rust/publish-ios/fixtures/responses.json": "76721fc014a01ce76a30c804743be83af2299469a3640e6df095971214d2c2a3", - "examples/library/rust/publish-ios/skill.json": "3402288b48fb08c680d4ca5ea360e05e101f492755200812e542e82e88f98547", + "examples/library/rust/publish-ios/skill.json": "b28e948368e0bef179cd51576e579904d85c9b6cad20959be98f69838b025be8", "examples/library/rust/qa-web-change/SKILL.md": "c04d21e12b3f05ccf20493088d4546d135b38196c43832a4d75773b6b465e2a4", "examples/library/rust/qa-web-change/fixtures/responses.json": "d12ea67b9fde2e179f7a1d4e64f3d341c64c230fbfb61b70bfbe9fc1c2ee2269", - "examples/library/rust/qa-web-change/skill.json": "87a41584b2a9635b7d0b583c8535f4395f165f805fbb0f4fa555dd3771a070e9", + "examples/library/rust/qa-web-change/skill.json": "d486777fc1553aae3dc42f3138767b99801bf9f08f62609da7e2a9d1d86cb8eb", "examples/library/rust/release-package/SKILL.md": "c4666ba653113ee812a965960f3b591f9b316a97afaf5a1f80e70218e2bfcf3a", "examples/library/rust/release-package/fixtures/responses.json": "7aeb44594f14bd110dcfbe938d4efb0d71a4dc310646a7aaf03f5713574767da", - "examples/library/rust/release-package/skill.json": "cbc126c77bba2bf7855fcf276159d168f37e33d6b202697628c786569104b1a1", + "examples/library/rust/release-package/skill.json": "2590d1d4eb21809550ab1edca585e673699bef25b202ecfb613636689f5002d8", "examples/library/rust/repair-ci/SKILL.md": "eb61f59ada1e1a4a591d87a4b80e921f274dea4fb8ff5657942e129f243f1820", "examples/library/rust/repair-ci/fixtures/responses.json": "b9cae86c313eb64033c04082ec40c98d5888ebd996391728373d03856cc90b10", - "examples/library/rust/repair-ci/skill.json": "2872237c52ed4c1e0f39d2857ca9eaa55601b0fc8d9f0c3f31d1c96c68b055f4", + "examples/library/rust/repair-ci/skill.json": "f89672490d25b54db95d55a0ad94d7cfbe1a72be2a8db22960a4a73b08e7af65", "examples/library/rust/review-branch/SKILL.md": "722716de93a060dde3453c05804a1c4d3b66af18e76c24f15fd0738510ee735b", "examples/library/rust/review-branch/fixtures/responses.json": "9de268b5b0f8ed4bc88901d8bdbd14cc5ff61a93ef01e26f28fae815fda45fac", - "examples/library/rust/review-branch/skill.json": "768d3600f9090b0c6f997c93e53f21ecaa3935c4344cdd154798f8033daacaa7", + "examples/library/rust/review-branch/skill.json": "78923df686bb2a58183fb61a60872e648b1ac3112d5b8d526ac3bae9394cbcdc", "examples/library/rust/src/bin/audit-security.rs": "682ab83b4a4d851c51b7577e56d0fb290185d25c247042db0d308c9b5a9ab277", "examples/library/rust/src/bin/investigate-failure.rs": "9e272dc5f0d246d8a47a6782d2c4627f0fb8fb86641facc8b892e88e92a62f60", "examples/library/rust/src/bin/migrate-database.rs": "64c5eae4a7658d7c4cbe02a6d74cd7c175dc84cf27f43e4658528ddac0b26cf5", @@ -198,36 +207,36 @@ "examples/library/rust/src/bin/upgrade-dependency.rs": "892d7dbfa430a032b1396b96d05b68c5b03aafe5d30a38a661846ad0a13427a7", "examples/library/rust/triage-issue/SKILL.md": "a3a0c383196cd981e64c1fd311e608cb50facfe55409981d4f92d28a4b346862", "examples/library/rust/triage-issue/fixtures/responses.json": "68f36fb5a7723a5d2a5477bed3e8a245908e6157a7eeb9205a604a05c9e3998f", - "examples/library/rust/triage-issue/skill.json": "6072dc7084a6db047df801aac9d82561af33f363b53c92e51d91bbdb44e9cb91", + "examples/library/rust/triage-issue/skill.json": "f5ea171a771755f8a73a99e054494ab65e7aabe0730c3aeee5c4d7abfd329462", "examples/library/rust/upgrade-dependency/SKILL.md": "11b6b4258640ff60af1446b97d907ea15d819a714de2736eda16621f5adbf186", "examples/library/rust/upgrade-dependency/fixtures/responses.json": "17eeef53bb7a4cc9ad70f0b24d50305db8266b4edb8c911570da7141830f2b9d", - "examples/library/rust/upgrade-dependency/skill.json": "4d060455bbea9dfca52ec56d6b48da1b23554744508fd39f9ed8f5c1d662c846", + "examples/library/rust/upgrade-dependency/skill.json": "4d1a107ed7fb56c1ff125d13cc5d755d0faaaf33334a76d3a4f478c157209bff", "examples/library/scripts/generate.mjs": "c03024bc4c978c004fdc6db93876d87cf73c07f2585ad2c83ed71871a6a1990a", "examples/library/test-all.sh": "62ff63221fd6cfa87e31ec3145016410746ddc78e6210140d5c0217d8e1b838f", "examples/library/typescript/audit-security/SKILL.md": "3ca2a8ffdb4504854cc45879e4c8bb795fc073560c1994eaf20f3d42d00d62f1", "examples/library/typescript/audit-security/fixtures/responses.json": "d738404c2e2912705de936c5948c4520ae4145bae0068d478f7689aae9aaedaa", - "examples/library/typescript/audit-security/skill.json": "74c7f48f759ec48178f77a18790056dfd03e0ad84364144bc056194a2b4458b2", + "examples/library/typescript/audit-security/skill.json": "0fa2cb55ef17a4feab8594f686c0c8ee156e0e942968b3cd32023263066b6c1c", "examples/library/typescript/investigate-failure/SKILL.md": "73d7f356adee39ffac667659ff875c2e3632f1fe15a94a491e95e88d4a5ac110", "examples/library/typescript/investigate-failure/fixtures/responses.json": "cd9fd2b16d636ba2098884b011f66008056439a2e34d68b1777f48010653192e", - "examples/library/typescript/investigate-failure/skill.json": "2a830e27434d5216d30b50c7d4cdd22460c0236d7c630aa8b26468f0360d5dff", + "examples/library/typescript/investigate-failure/skill.json": "8851fd3bfed8ade55a66a2352d5cb99254257fb2a2f9ffc22b49b50e336ee942", "examples/library/typescript/migrate-database/SKILL.md": "1328621f6b19da12f642c379456ba24ced1827bd676bf35df1c5f616ff791575", "examples/library/typescript/migrate-database/fixtures/responses.json": "e7114f5615a134e8afe151b6e9133cc601549392eae53b94a308fd3131b1d77a", - "examples/library/typescript/migrate-database/skill.json": "c1229d78c473ebffdd744648d24a02a40e34f4bb6a4ad7d219f4beb1af99f653", + "examples/library/typescript/migrate-database/skill.json": "c958b5017fcb30e41b6cfbc3b919bc3db7fe02f4a398efa4b515031a2ded8d4b", "examples/library/typescript/publish-ios/SKILL.md": "1e2cd5e91ea0225793f15440b05e1cdd9f3582f7dfe6ea6346762ccd4ef73ad0", "examples/library/typescript/publish-ios/fixtures/responses.json": "76721fc014a01ce76a30c804743be83af2299469a3640e6df095971214d2c2a3", - "examples/library/typescript/publish-ios/skill.json": "7c9bd38570d176f100c4a303bf7ad83793ad082b44bdf49ebe4f535cccef0588", + "examples/library/typescript/publish-ios/skill.json": "28c597f6ac349d895e48635e4c813df864ca453a46aae1eaf01c5fe1b25203dc", "examples/library/typescript/qa-web-change/SKILL.md": "c04d21e12b3f05ccf20493088d4546d135b38196c43832a4d75773b6b465e2a4", "examples/library/typescript/qa-web-change/fixtures/responses.json": "d12ea67b9fde2e179f7a1d4e64f3d341c64c230fbfb61b70bfbe9fc1c2ee2269", - "examples/library/typescript/qa-web-change/skill.json": "6ace4effb5c7deb2a6ec6d8b324a1b7b4bffc8b4f06ca636b81627601d27664d", + "examples/library/typescript/qa-web-change/skill.json": "6d552f2acce18d0b299d145984e221ca78242fbd563ac55980ee9eea5f2b3234", "examples/library/typescript/release-package/SKILL.md": "c4666ba653113ee812a965960f3b591f9b316a97afaf5a1f80e70218e2bfcf3a", "examples/library/typescript/release-package/fixtures/responses.json": "7aeb44594f14bd110dcfbe938d4efb0d71a4dc310646a7aaf03f5713574767da", - "examples/library/typescript/release-package/skill.json": "631be1a857cb7222dc3733428b6c81217ea8b0b725e9b611aa05a3cda0f50885", + "examples/library/typescript/release-package/skill.json": "1bfb727e1d39e2b697f540055a343047be147952c0895aafd5aea110683c00ee", "examples/library/typescript/repair-ci/SKILL.md": "eb61f59ada1e1a4a591d87a4b80e921f274dea4fb8ff5657942e129f243f1820", "examples/library/typescript/repair-ci/fixtures/responses.json": "b9cae86c313eb64033c04082ec40c98d5888ebd996391728373d03856cc90b10", - "examples/library/typescript/repair-ci/skill.json": "b44f3ff546c886d20955fa58fd106336d103db660d664d28ebf53199c81e4c1d", + "examples/library/typescript/repair-ci/skill.json": "e07ffae450c07e1ba63704c0805cd3e93814aa9e0815174f399981f61f6fd4bb", "examples/library/typescript/review-branch/SKILL.md": "722716de93a060dde3453c05804a1c4d3b66af18e76c24f15fd0738510ee735b", "examples/library/typescript/review-branch/fixtures/responses.json": "9de268b5b0f8ed4bc88901d8bdbd14cc5ff61a93ef01e26f28fae815fda45fac", - "examples/library/typescript/review-branch/skill.json": "1d334999a78d50fd7856e7b02a59cb710f9cf6304d498d69ebd41461032c312f", + "examples/library/typescript/review-branch/skill.json": "80cab01cbdc3ed907ce53e44cc50e0cf2eb14a98b13052a4a53df55214f2fea2", "examples/library/typescript/src/audit-security.ts": "2d82b50c698417597da913b1a67c0dbb56f0df80f2b346b709843102e521dbd5", "examples/library/typescript/src/investigate-failure.ts": "bad0351af6d7e6b3f73c62b909d43ccb009b87320bfd1de1d2dc87900dd04d80", "examples/library/typescript/src/migrate-database.ts": "ab3cabcfaa3a9a76b00b3ed6d3cbf6ca66e82f3d6ac4b333f8a5cf05d510f523", @@ -240,16 +249,16 @@ "examples/library/typescript/src/upgrade-dependency.ts": "fc499ea33ae71a9500c1c376b128696ecd6584f5f62e6602c9b6eaf26b619c72", "examples/library/typescript/triage-issue/SKILL.md": "a3a0c383196cd981e64c1fd311e608cb50facfe55409981d4f92d28a4b346862", "examples/library/typescript/triage-issue/fixtures/responses.json": "68f36fb5a7723a5d2a5477bed3e8a245908e6157a7eeb9205a604a05c9e3998f", - "examples/library/typescript/triage-issue/skill.json": "9d81882ba30838b48c25c1e66fe400d8169e14360eaca4de1133b8bb6804d167", + "examples/library/typescript/triage-issue/skill.json": "00fcf1ea7c0e0c91db7b8cb8677386ad38d7f1645aa8513feb89c713695d07f3", "examples/library/typescript/upgrade-dependency/SKILL.md": "11b6b4258640ff60af1446b97d907ea15d819a714de2736eda16621f5adbf186", "examples/library/typescript/upgrade-dependency/fixtures/responses.json": "17eeef53bb7a4cc9ad70f0b24d50305db8266b4edb8c911570da7141830f2b9d", - "examples/library/typescript/upgrade-dependency/skill.json": "0105f91c2fe73f6d2da9de793a1eb2f5f7845bbcc3579a60d07ab11ee40b8be6", + "examples/library/typescript/upgrade-dependency/skill.json": "7daf6a73c8bd25a030d71d4d545c864b43d2522ccccb9f23659329ef8a871aad", "examples/release-checklist/SKILL.md": "cd9daf69e3cd347e0db46315267103884a6ccb22735901554d59b3f4aed7cf7a", "examples/release-checklist/fixtures/responses.json": "9545c4795a5f0676e4b84303cc76911a701f1add94c3034f3c9a0695b2ec5a22", "examples/release-checklist/main.ts": "c9a5c695835b0527378e1fe3aa69619b94ac7994c6456e1dec1ff0e5c5a74cec", - "examples/release-checklist/skill.json": "90fe9e0312e05651ed176c27bfdc73dd7fb9989be9dd024fd46444b402750528", - "go.mod": "c35e7f0d4566798616c7021c367bdb87b188246f81a7f7fd540770e6b16e2366", - "go.sum": "63c93a009db9ad922511c645e7216a59837b8c33aec5f77a8fab84ba01d0a13d", + "examples/release-checklist/skill.json": "854fcb4bfd3254208233baf11d2762fddd4064ef55d641916a8b02f52612d18d", + "go.mod": "14c29b33635fdb90f3415474a3c13b08a53316d53d7d06fceb8a255e106080aa", + "go.sum": "248b7f2f978a9b04be0ce4d395789211c06c7d3007c6b75f273d22d7fcc72885", "internal/conformance/conformance_test.go": "cf66fc5bfb0770a69294d17e8d9ee9e643b098f6d805773d6464256e39006db5", "internal/conformance/testdata/skill-go/main.go": "b50d0ae8f978ce9a83f9cec6d3a939b544d8361c519cdf8dd994ddf5adf99ec0", "internal/conformance/testdata/skill-py/main.py": "f34b3315491d0725bce17e8d77cd0b8eb218d2896b51d8c10a660dc658f1cc24", @@ -294,6 +303,7 @@ "release-notes/2026-08-01-multi-language-and-converter.md": "d0cf62d191e6a58e827f3b35d442f88b83be4dde98aa25ad54e4ae3ff787a453", "release-notes/2026-08-01-one-package-per-language.md": "6d0d55b4fdcef20332e98c34c1c42c8564aeeeac84647e9f76005b6842d0c91c", "release-notes/2026-08-01-remove-stray-analysis-traces.md": "0567f78ee97ffd23b3f26b5c39606e9ff6659c50a3fdef04ed9b3aa86cfa99af", + "release-notes/2026-08-02-cross-agent-registration.md": "8f4296fae36468bda08370bad8d13b7fc1e893b682f8c73015311ab01ace853f", "sdk/python/README.md": "415fde10711137e0baf30874844a0482cebbf60fb59cb751eba56dedfebb0ce8", "sdk/python/pyproject.toml": "142249ed41c8ea58560e2b54400a2a778d2ac4b327112b2909ded69d9bd99bdb", "sdk/python/test_cli.py": "b7a2fe9a72299aa86f6012129e00f9c2dc0f6e5c29241373fb956321fae5f0b4", @@ -313,7 +323,7 @@ "generator": "operatorstack/yield:project", "schema_version": 1, "source": { - "commit": "edca07eaf8a7483829ea03b1c1eed21c323005f7", + "commit": "34cac6048389a19a16c4fed1e1f0fdec6e67505f", "path": "labs/22-yield", "repository": "operatorstack/intelligence-flow" } diff --git a/cmd/yskill/agents.go b/cmd/yskill/agents.go new file mode 100644 index 0000000..62c0278 --- /dev/null +++ b/cmd/yskill/agents.go @@ -0,0 +1,538 @@ +package main + +import ( + _ "embed" + "encoding/json" + "errors" + "flag" + "fmt" + "io/fs" + "os" + "os/exec" + "path/filepath" + "sort" + "strings" + + "github.com/operatorstack/yield/internal/protocol" +) + +//go:embed registry/agents.json +var agentRegistryJSON []byte + +const generatedAdapterPrefix = " + +This adapter exposes the canonical Yield workflow at %s. +Read its SKILL.md, then run from the repository root: + + %s run %s + +Follow each returned operation exactly. Resume after each response: + + %s resume --response response.json --skill %s + +Do not skip an operation or invent its response. +`, metadata.Name, yamlString(metadata.Description), generatedAdapterPrefix, sourceRel, digest, runtimeVersion(), "`"+sourceRel+"`", launcher, path, launcher, path) +} + +func writeGeneratedAdapter(path, sourceRel, content string) error { + if existing, err := os.ReadFile(path); err == nil { + marker := generatedAdapterPrefix + sourceRel + ";" + if !strings.Contains(string(existing), marker) { + return fmt.Errorf("refusing to overwrite user-owned or differently sourced adapter %s", path) + } + if string(existing) == content { + return nil + } + } else if !errors.Is(err, fs.ErrNotExist) { + return err + } + if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { + return err + } + tmp, err := os.CreateTemp(filepath.Dir(path), ".yskill-adapter-*") + if err != nil { + return err + } + tmpName := tmp.Name() + defer os.Remove(tmpName) + if _, err := tmp.WriteString(content); err != nil { + tmp.Close() + return err + } + if err := tmp.Chmod(0o644); err != nil { + tmp.Close() + return err + } + if err := tmp.Close(); err != nil { + return err + } + return os.Rename(tmpName, path) +} + +func cmdDoctor(args []string) error { + fs := flag.NewFlagSet("doctor", flag.ContinueOnError) + var agents agentListFlag + fs.Var(&agents, "agent", "agent id, comma-separated ids, or auto") + root := fs.String("root", "", "repository root (detected from .git by default)") + runTest := fs.Bool("test", false, "run the workflow fixture after static checks") + if err := parseOnePositional(fs, args); err != nil { + return err + } + if fs.NArg() != 1 { + return fmt.Errorf("doctor takes exactly one skill directory") + } + skillDir, repoRoot, sourceRel, _, manifest, _, selected, err := registrationInputs(fs.Arg(0), *root, agents) + if err != nil { + return err + } + if _, err := launcherFor(manifest.Language, skillDir, repoRoot); err != nil { + return err + } + digest, err := protocol.DigestSkillDir(skillDir) + if err != nil { + return err + } + for _, agent := range selected { + path := filepath.Join(repoRoot, filepath.FromSlash(agent.ProjectDir), filepath.Base(skillDir), "SKILL.md") + if err := ensureContainedWrite(repoRoot, path); err != nil { + return err + } + b, err := os.ReadFile(path) + if err != nil { + return fmt.Errorf("%s adapter missing at %s; run yskill register", agent.ID, path) + } + text := string(b) + if !strings.Contains(text, generatedAdapterPrefix+sourceRel+";") || !strings.Contains(text, "digest: "+digest+";") { + return fmt.Errorf("%s adapter is stale or points elsewhere; run yskill register", agent.ID) + } + fmt.Printf("ok: %-22s %s\n", agent.ID, filepath.ToSlash(path)) + } + if *runTest { + if err := cmdTest([]string{skillDir}); err != nil { + return err + } + } + fmt.Printf("doctor: %s is ready for %d agent(s)\n", filepath.Base(skillDir), len(selected)) + return nil +} diff --git a/cmd/yskill/agents_test.go b/cmd/yskill/agents_test.go new file mode 100644 index 0000000..e04bba1 --- /dev/null +++ b/cmd/yskill/agents_test.go @@ -0,0 +1,241 @@ +package main + +import ( + "os" + "path/filepath" + "runtime" + "strings" + "testing" +) + +func TestRegistryIsBroadValidAndVerifiedPathsArePinned(t *testing.T) { + registry, err := loadAgentRegistry() + if err != nil { + t.Fatal(err) + } + if len(registry.Agents) < 70 { + t.Fatalf("agent registry has %d entries, want broad registry", len(registry.Agents)) + } + want := map[string]string{ + "cursor": ".cursor/skills", + "codex": ".agents/skills", + "claude-code": ".claude/skills", + } + for _, agent := range registry.Agents { + if path, ok := want[agent.ID]; ok { + if agent.ProjectDir != path || agent.Tier != "verified" { + t.Fatalf("%s = path %q tier %q", agent.ID, agent.ProjectDir, agent.Tier) + } + delete(want, agent.ID) + } + } + if len(want) != 0 { + t.Fatalf("verified agents missing: %v", want) + } +} + +func TestRegisterWritesThinAdaptersAndDeduplicatesSharedDestination(t *testing.T) { + repo := t.TempDir() + writeTestFile(t, filepath.Join(repo, ".git"), "gitdir: fixture\n") + skill := createTypeScriptSkill(t, repo, "review") + registrations, err := registerSkill(skill, repo, []string{"codex", "amp", "cursor", "claude-code"}) + if err != nil { + t.Fatal(err) + } + if len(registrations) != 3 { + t.Fatalf("registrations = %d, want three unique destinations: %+v", len(registrations), registrations) + } + for _, rel := range []string{ + ".agents/skills/review/SKILL.md", + ".cursor/skills/review/SKILL.md", + ".claude/skills/review/SKILL.md", + } { + adapter := readTestFile(t, filepath.Join(repo, filepath.FromSlash(rel))) + if !strings.Contains(adapter, "source: skills/review;") || !strings.Contains(adapter, "npm exec -- yskill run 'skills/review'") { + t.Fatalf("adapter %s does not point to canonical workflow:\n%s", rel, adapter) + } + if strings.Contains(adapter, "defineSkill") || strings.Contains(adapter, "fixtures") { + t.Fatalf("adapter %s duplicated workflow content", rel) + } + } +} + +func TestEveryRegistryAgentGeneratesAContainedAdapter(t *testing.T) { + repo := t.TempDir() + writeTestFile(t, filepath.Join(repo, ".git"), "gitdir: fixture\n") + writeTestFile(t, filepath.Join(repo, "package.json"), `{"dependencies":{"@operatorstack/yield":"0.1.17"}}`) + skill := filepath.Join(repo, "workflows", "review") + writeTestFile(t, filepath.Join(skill, "SKILL.md"), "---\nname: review\ndescription: Review the branch when the user wants code checked before shipping.\n---\n") + writeTestFile(t, filepath.Join(skill, "skill.json"), `{"version":1,"language":"typescript","run":["node","main.ts"]}`) + writeTestFile(t, filepath.Join(skill, "main.ts"), "export {}\n") + registry, err := loadAgentRegistry() + if err != nil { + t.Fatal(err) + } + ids := make([]string, 0, len(registry.Agents)) + for _, agent := range registry.Agents { + ids = append(ids, agent.ID) + } + registrations, err := registerSkill(skill, repo, ids) + if err != nil { + t.Fatal(err) + } + if len(registrations) == 0 || len(registrations) >= len(ids) { + t.Fatalf("unique registrations = %d for %d agents; expected shared destinations to deduplicate", len(registrations), len(ids)) + } + for _, registration := range registrations { + path := filepath.Join(repo, filepath.FromSlash(registration.Path)) + if !within(repo, path) { + t.Fatalf("adapter escaped repository: %s", path) + } + if _, err := readSkillMetadata(filepath.Dir(path)); err != nil { + t.Fatalf("adapter %s is not a portable skill: %v", registration.Path, err) + } + } +} + +func TestRegisterUpdatesOwnedAdapterAndRefusesForeignCollision(t *testing.T) { + repo := t.TempDir() + writeTestFile(t, filepath.Join(repo, ".git"), "gitdir: fixture\n") + skill := createTypeScriptSkill(t, repo, "review") + if _, err := registerSkill(skill, repo, []string{"codex"}); err != nil { + t.Fatal(err) + } + canonical := filepath.Join(skill, "SKILL.md") + updated := strings.Replace(readTestFile(t, canonical), "Review the branch", "Review changed code", 1) + writeTestFile(t, canonical, updated) + if _, err := registerSkill(skill, repo, []string{"codex"}); err != nil { + t.Fatalf("update generated adapter: %v", err) + } + adapterPath := filepath.Join(repo, ".agents", "skills", "review", "SKILL.md") + writeTestFile(t, adapterPath, "user owned\n") + if _, err := registerSkill(skill, repo, []string{"codex"}); err == nil || !strings.Contains(err.Error(), "refusing to overwrite") { + t.Fatalf("foreign collision error = %v", err) + } +} + +func TestRegisterRejectsOutsideRepositoryAndAgentDirectoryCanonical(t *testing.T) { + repo := t.TempDir() + writeTestFile(t, filepath.Join(repo, ".git"), "gitdir: fixture\n") + outside := createTypeScriptSkill(t, t.TempDir(), "outside") + if _, err := registerSkill(outside, repo, []string{"codex"}); err == nil || !strings.Contains(err.Error(), "inside repository root") { + t.Fatalf("outside repository error = %v", err) + } + insideAgent := createTypeScriptSkill(t, filepath.Join(repo, ".cursor"), "inside-agent") + if _, err := registerSkill(insideAgent, repo, []string{"cursor"}); err == nil || !strings.Contains(err.Error(), "must not live inside agent discovery") { + t.Fatalf("agent directory error = %v", err) + } +} + +func TestRegisterRejectsSymlinkEscapes(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("unprivileged Windows test environments cannot reliably create symlinks") + } + repo := t.TempDir() + writeTestFile(t, filepath.Join(repo, ".git"), "gitdir: fixture\n") + outside := t.TempDir() + skill := createTypeScriptSkill(t, outside, "review") + if err := os.Symlink(skill, filepath.Join(repo, "review-link")); err != nil { + t.Fatal(err) + } + if _, err := registerSkill(filepath.Join(repo, "review-link"), repo, []string{"codex"}); err == nil || !strings.Contains(err.Error(), "inside repository root") { + t.Fatalf("source symlink escape error = %v", err) + } + + canonical := createTypeScriptSkill(t, repo, "safe-review") + if err := os.Symlink(outside, filepath.Join(repo, ".agents")); err != nil { + t.Fatal(err) + } + if _, err := registerSkill(canonical, repo, []string{"codex"}); err == nil || !strings.Contains(err.Error(), "resolves outside repository") { + t.Fatalf("destination symlink escape error = %v", err) + } +} + +func TestAutoDetectionUsesProjectAgentDirectory(t *testing.T) { + repo := t.TempDir() + if err := os.MkdirAll(filepath.Join(repo, ".cursor"), 0o755); err != nil { + t.Fatal(err) + } + registry, err := loadAgentRegistry() + if err != nil { + t.Fatal(err) + } + selected, err := selectAgents(registry, []string{"auto"}, repo) + if err != nil { + t.Fatal(err) + } + found := false + for _, agent := range selected { + found = found || agent.ID == "cursor" + } + if !found { + t.Fatal("project-local .cursor directory was not auto-detected") + } +} + +func TestSkillMetadataValidation(t *testing.T) { + dir := filepath.Join(t.TempDir(), "bad-name") + if err := os.MkdirAll(dir, 0o755); err != nil { + t.Fatal(err) + } + writeTestFile(t, filepath.Join(dir, "SKILL.md"), "---\nname: other\ndescription: TODO\n---\n") + if _, err := readSkillMetadata(dir); err == nil { + t.Fatal("invalid metadata was accepted") + } +} + +func TestDoctorDetectsCurrentAndStaleAdapters(t *testing.T) { + repo := t.TempDir() + writeTestFile(t, filepath.Join(repo, ".git"), "gitdir: fixture\n") + skill := createTypeScriptSkill(t, repo, "review") + if _, err := registerSkill(skill, repo, []string{"codex"}); err != nil { + t.Fatal(err) + } + if err := cmdDoctor([]string{skill, "--root", repo, "--agent", "codex"}); err != nil { + t.Fatalf("doctor current adapter: %v", err) + } + writeTestFile(t, filepath.Join(skill, "main.ts"), "export const changed = true\n") + if err := cmdDoctor([]string{skill, "--root", repo, "--agent", "codex"}); err == nil || !strings.Contains(err.Error(), "stale") { + t.Fatalf("stale adapter error = %v", err) + } +} + +func TestShellQuoteEscapesSingleQuote(t *testing.T) { + if got := shellQuote("skills/team's-review"); got != `'skills/team'"'"'s-review'` { + t.Fatalf("shellQuote = %q", got) + } +} + +func TestPythonLauncherUsesRepositoryVirtualEnvironment(t *testing.T) { + repo := t.TempDir() + python := filepath.Join(repo, ".venv", "bin", "python") + t.Setenv("YIELD_PYTHON", python) + got, err := launcherFor("python", filepath.Join(repo, "skills", "review"), repo) + if err != nil { + t.Fatal(err) + } + want := shellQuote(filepath.ToSlash(filepath.Join(".venv", "bin", "python"))) + " -m yieldskill" + if got != want { + t.Fatalf("python launcher = %q, want %q", got, want) + } +} + +func createTypeScriptSkill(t *testing.T, repo, name string) string { + t.Helper() + writeTestFile(t, filepath.Join(repo, "package.json"), `{"dependencies":{"@operatorstack/yield":"0.1.17"}}`) + skill := filepath.Join(repo, "skills", name) + writeTestFile(t, filepath.Join(skill, "SKILL.md"), "---\nname: "+name+"\ndescription: Review the branch when the user wants code checked before shipping.\n---\n") + writeTestFile(t, filepath.Join(skill, "skill.json"), `{"version":1,"language":"typescript","run":["node","main.ts"]}`) + writeTestFile(t, filepath.Join(skill, "main.ts"), "export {}\n") + return skill +} + +func writeTestFile(t *testing.T, path, content string) { + t.Helper() + if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(path, []byte(content), 0o644); err != nil { + t.Fatal(err) + } +} diff --git a/cmd/yskill/main.go b/cmd/yskill/main.go index 0478795..989d378 100644 --- a/cmd/yskill/main.go +++ b/cmd/yskill/main.go @@ -1,6 +1,6 @@ -// yskill is the supervisor CLI for Yield: it starts runs, validates and +// yskill is the command-line interface for Yield: it starts runs, validates and // accepts responses, executes commands as observed fact, and owns the -// append-only run log. The coding agent drives it through six verbs. +// append-only run log. The coding agent drives it through a small set of verbs. package main import ( @@ -21,7 +21,12 @@ const usage = `yskill — turn SKILL.md workflows into resumable programs Usage: yskill init scaffold a skill (or wrap an existing prose skill) - [--language typescript|python|go|rust] + [--language typescript|python|go|rust] [--description text] + yskill register expose one workflow to coding agents + [--agent cursor,codex,...|auto] [--root repo] + yskill agents list supported coding agents and paths + yskill doctor check package, workflow, and adapters + [--agent cursor,codex,...|auto] [--root repo] [--test] yskill run [--input file] start a run; prints the first operation envelope yskill resume --response file feed a response; prints the next operation [--skill dir] [--accept-new-digest] @@ -54,6 +59,12 @@ func main() { switch os.Args[1] { case "init": err = cmdInit(os.Args[2:]) + case "register": + err = cmdRegister(os.Args[2:]) + case "agents": + err = cmdAgents(os.Args[2:]) + case "doctor": + err = cmdDoctor(os.Args[2:]) case "run": err = cmdRun(os.Args[2:]) case "resume": @@ -279,11 +290,12 @@ func cmdInit(args []string) error { fs := flag.NewFlagSet("init", flag.ExitOnError) sdkPath := fs.String("sdk", "", "filesystem path to the yield module (written as a go.mod replace directive)") language := fs.String("language", defaultLanguage(), "workflow language: typescript, python, go, or rust") + description := fs.String("description", "", "what the skill does and when an agent should use it") if err := parseOnePositional(fs, args); err != nil { return err } if fs.NArg() != 1 { return fmt.Errorf("init takes exactly one directory") } - return scaffoldSkill(fs.Arg(0), *language, *sdkPath) + return scaffoldSkill(fs.Arg(0), *language, *sdkPath, *description) } diff --git a/cmd/yskill/main_test.go b/cmd/yskill/main_test.go index b4e84ac..f4cc6ae 100644 --- a/cmd/yskill/main_test.go +++ b/cmd/yskill/main_test.go @@ -78,8 +78,8 @@ func TestScaffoldSkillWritesLanguageSpecificEntrypoints(t *testing.T) { } for _, tt := range tests { t.Run(tt.language, func(t *testing.T) { - dir := filepath.Join(t.TempDir(), "My Skill") - if err := scaffoldSkill(dir, tt.language, ""); err != nil { + dir := filepath.Join(t.TempDir(), "my-skill") + if err := scaffoldSkill(dir, tt.language, "", "Run the test workflow when checking Yield setup."); err != nil { t.Fatal(err) } for _, rel := range append(tt.files, "SKILL.md", "fixtures/responses.json") { @@ -87,6 +87,13 @@ func TestScaffoldSkillWritesLanguageSpecificEntrypoints(t *testing.T) { t.Fatalf("%s: %v", rel, err) } } + generated, err := readSkillManifest(dir) + if err != nil { + t.Fatal(err) + } + if generated.Version != 1 || generated.Language != tt.language { + t.Fatalf("skill.json = version %d language %q", generated.Version, generated.Language) + } skill := readTestFile(t, filepath.Join(dir, "SKILL.md")) if !strings.Contains(skill, tt.command) { t.Fatalf("SKILL.md does not contain %q:\n%s", tt.command, skill) @@ -122,11 +129,11 @@ func TestGoScaffoldCanResolveItsPinnedModuleOnFirstRun(t *testing.T) { tidyGoModule = previousTidyGoModule }) dir := filepath.Join(t.TempDir(), "go-skill") - if err := scaffoldSkill(dir, "go", ""); err != nil { + if err := scaffoldSkill(dir, "go", "", "Run the Go workflow when checking Yield setup."); err != nil { t.Fatal(err) } manifest := readTestFile(t, filepath.Join(dir, "skill.json")) - if manifest != "{\"run\":[\"go\",\"run\",\"-mod=readonly\",\".\"]}\n" { + if manifest != "{\"version\":1,\"language\":\"go\",\"run\":[\"go\",\"run\",\"-mod=readonly\",\".\"]}\n" { t.Fatalf("skill.json = %q", manifest) } } @@ -137,7 +144,7 @@ func TestPythonScaffoldUsesInvokingInterpreter(t *testing.T) { t.Cleanup(func() { version = previousVersion }) t.Setenv("YIELD_PYTHON", "/opt/yield/.venv/bin/python") dir := filepath.Join(t.TempDir(), "python-skill") - if err := scaffoldSkill(dir, "python", ""); err != nil { + if err := scaffoldSkill(dir, "python", "", "Run the Python workflow when checking Yield setup."); err != nil { t.Fatal(err) } skill := readTestFile(t, filepath.Join(dir, "skill.json")) @@ -148,20 +155,27 @@ func TestPythonScaffoldUsesInvokingInterpreter(t *testing.T) { func TestScaffoldSkillPreservesExistingSkillAndRejectsUnknownLanguage(t *testing.T) { dir := t.TempDir() - if err := os.WriteFile(filepath.Join(dir, "SKILL.md"), []byte("keep me\n"), 0o644); err != nil { + existing := "---\nname: " + filepath.Base(dir) + "\ndescription: Keep this existing workflow when wrapping it with Yield.\n---\n\nKeep me.\n" + if err := os.WriteFile(filepath.Join(dir, "SKILL.md"), []byte(existing), 0o644); err != nil { t.Fatal(err) } - if err := scaffoldSkill(dir, "typescript", ""); err != nil { + if err := scaffoldSkill(dir, "typescript", "", ""); err != nil { t.Fatal(err) } - if got := readTestFile(t, filepath.Join(dir, "SKILL.md")); got != "keep me\n" { + if got := readTestFile(t, filepath.Join(dir, "SKILL.md")); got != existing { t.Fatalf("existing SKILL.md changed: %q", got) } - if err := scaffoldSkill(t.TempDir(), "java", ""); err == nil || !strings.Contains(err.Error(), "unsupported language") { + if err := scaffoldSkill(t.TempDir(), "java", "", "A valid description for the invalid language test."); err == nil || !strings.Contains(err.Error(), "unsupported language") { t.Fatalf("unknown language error = %v", err) } } +func TestScaffoldRequiresDescriptionForNewSkill(t *testing.T) { + if err := scaffoldSkill(filepath.Join(t.TempDir(), "new-skill"), "typescript", "", ""); err == nil || !strings.Contains(err.Error(), "--description is required") { + t.Fatalf("missing description error = %v", err) + } +} + func TestPackageVersionFallsBackForDevelopmentBuilds(t *testing.T) { previousVersion := version version = "dev" diff --git a/cmd/yskill/registry/README.md b/cmd/yskill/registry/README.md new file mode 100644 index 0000000..d1106ff --- /dev/null +++ b/cmd/yskill/registry/README.md @@ -0,0 +1,12 @@ +# Agent path registry + +`agents.json` is a Go-embedded snapshot of project skill directories from +[`vercel-labs/skills`](https://github.com/vercel-labs/skills), pinned to the +commit recorded in the file. That project is MIT licensed. + +Yield overrides the verified Cursor, Codex, and Claude Code project paths with +the paths exercised by its integration fixtures. Other entries provide broad, +explicit path registration and are labelled `registry`, not end-to-end +verified. + +The pinned upstream license is included in `VERCEL_SKILLS_LICENSE`. diff --git a/cmd/yskill/registry/VERCEL_SKILLS_LICENSE b/cmd/yskill/registry/VERCEL_SKILLS_LICENSE new file mode 100644 index 0000000..23f6a8f --- /dev/null +++ b/cmd/yskill/registry/VERCEL_SKILLS_LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Vercel, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/cmd/yskill/registry/agents.json b/cmd/yskill/registry/agents.json new file mode 100644 index 0000000..1ca3d8c --- /dev/null +++ b/cmd/yskill/registry/agents.json @@ -0,0 +1,466 @@ +{ + "source": { + "repository": "https://github.com/vercel-labs/skills", + "commit": "1164afa5f0e21ebd01e6fc11249759353f494ad1", + "license": "MIT", + "path": "src/agents.ts" + }, + "agents": [ + { + "id": "adal", + "display_name": "AdaL", + "project_dir": ".adal/skills", + "tier": "registry" + }, + { + "id": "aider-desk", + "display_name": "AiderDesk", + "project_dir": ".aider-desk/skills", + "tier": "registry" + }, + { + "id": "amp", + "display_name": "Amp", + "project_dir": ".agents/skills", + "tier": "registry" + }, + { + "id": "antigravity", + "display_name": "Antigravity", + "project_dir": ".agents/skills", + "tier": "registry" + }, + { + "id": "antigravity-cli", + "display_name": "Antigravity CLI", + "project_dir": ".agents/skills", + "tier": "registry" + }, + { + "id": "astrbot", + "display_name": "AstrBot", + "project_dir": "data/skills", + "tier": "registry" + }, + { + "id": "augment", + "display_name": "Augment", + "project_dir": ".augment/skills", + "tier": "registry" + }, + { + "id": "autohand-code", + "display_name": "Autohand Code CLI", + "project_dir": ".autohand/skills", + "tier": "registry" + }, + { + "id": "bob", + "display_name": "IBM Bob", + "project_dir": ".bob/skills", + "tier": "registry" + }, + { + "id": "claude-code", + "display_name": "Claude Code", + "project_dir": ".claude/skills", + "tier": "verified" + }, + { + "id": "cline", + "display_name": "Cline", + "project_dir": ".agents/skills", + "tier": "registry" + }, + { + "id": "codearts-agent", + "display_name": "CodeArts Agent", + "project_dir": ".codeartsdoer/skills", + "tier": "registry" + }, + { + "id": "codebuddy", + "display_name": "CodeBuddy", + "project_dir": ".codebuddy/skills", + "tier": "registry" + }, + { + "id": "codemaker", + "display_name": "Codemaker", + "project_dir": ".codemaker/skills", + "tier": "registry" + }, + { + "id": "codestudio", + "display_name": "Code Studio", + "project_dir": ".codestudio/skills", + "tier": "registry" + }, + { + "id": "codex", + "display_name": "Codex", + "project_dir": ".agents/skills", + "tier": "verified" + }, + { + "id": "command-code", + "display_name": "Command Code", + "project_dir": ".commandcode/skills", + "tier": "registry" + }, + { + "id": "continue", + "display_name": "Continue", + "project_dir": ".continue/skills", + "tier": "registry" + }, + { + "id": "cortex", + "display_name": "Cortex Code", + "project_dir": ".cortex/skills", + "tier": "registry" + }, + { + "id": "crush", + "display_name": "Crush", + "project_dir": ".crush/skills", + "tier": "registry" + }, + { + "id": "cursor", + "display_name": "Cursor", + "project_dir": ".cursor/skills", + "tier": "verified" + }, + { + "id": "deepagents", + "display_name": "Deep Agents", + "project_dir": ".agents/skills", + "tier": "registry" + }, + { + "id": "devin", + "display_name": "Devin for Terminal", + "project_dir": ".devin/skills", + "tier": "registry" + }, + { + "id": "dexto", + "display_name": "Dexto", + "project_dir": ".agents/skills", + "tier": "registry" + }, + { + "id": "droid", + "display_name": "Droid", + "project_dir": ".factory/skills", + "tier": "registry" + }, + { + "id": "eve", + "display_name": "Eve", + "project_dir": "agent/skills", + "tier": "registry" + }, + { + "id": "firebender", + "display_name": "Firebender", + "project_dir": ".agents/skills", + "tier": "registry" + }, + { + "id": "forgecode", + "display_name": "ForgeCode", + "project_dir": ".forge/skills", + "tier": "registry" + }, + { + "id": "gemini-cli", + "display_name": "Gemini CLI", + "project_dir": ".agents/skills", + "tier": "registry" + }, + { + "id": "github-copilot", + "display_name": "GitHub Copilot", + "project_dir": ".agents/skills", + "tier": "registry" + }, + { + "id": "goose", + "display_name": "Goose", + "project_dir": ".goose/skills", + "tier": "registry" + }, + { + "id": "grok", + "display_name": "Grok Build", + "project_dir": ".grok/skills", + "tier": "registry" + }, + { + "id": "hermes-agent", + "display_name": "Hermes Agent", + "project_dir": ".hermes/skills", + "tier": "registry" + }, + { + "id": "iflow-cli", + "display_name": "iFlow CLI", + "project_dir": ".iflow/skills", + "tier": "registry" + }, + { + "id": "inference-sh", + "display_name": "inference.sh", + "project_dir": ".inferencesh/skills", + "tier": "registry" + }, + { + "id": "jazz", + "display_name": "Jazz", + "project_dir": ".jazz/skills", + "tier": "registry" + }, + { + "id": "junie", + "display_name": "Junie", + "project_dir": ".junie/skills", + "tier": "registry" + }, + { + "id": "kilo", + "display_name": "Kilo Code", + "project_dir": ".kilocode/skills", + "tier": "registry" + }, + { + "id": "kimchi", + "display_name": "Kimchi", + "project_dir": ".kimchi/skills", + "tier": "registry" + }, + { + "id": "kimi-code-cli", + "display_name": "Kimi Code CLI", + "project_dir": ".agents/skills", + "tier": "registry" + }, + { + "id": "kiro-cli", + "display_name": "Kiro CLI", + "project_dir": ".kiro/skills", + "tier": "registry" + }, + { + "id": "kode", + "display_name": "Kode", + "project_dir": ".kode/skills", + "tier": "registry" + }, + { + "id": "lingma", + "display_name": "Lingma", + "project_dir": ".lingma/skills", + "tier": "registry" + }, + { + "id": "loaf", + "display_name": "Loaf", + "project_dir": ".agents/skills", + "tier": "registry" + }, + { + "id": "mcpjam", + "display_name": "MCPJam", + "project_dir": ".mcpjam/skills", + "tier": "registry" + }, + { + "id": "minimax-code", + "display_name": "MiniMax Code", + "project_dir": ".minimax/skills", + "tier": "registry" + }, + { + "id": "mistral-vibe", + "display_name": "Mistral Vibe", + "project_dir": ".vibe/skills", + "tier": "registry" + }, + { + "id": "moxby", + "display_name": "Moxby", + "project_dir": ".moxby/skills", + "tier": "registry" + }, + { + "id": "mux", + "display_name": "Mux", + "project_dir": ".mux/skills", + "tier": "registry" + }, + { + "id": "neovate", + "display_name": "Neovate", + "project_dir": ".neovate/skills", + "tier": "registry" + }, + { + "id": "ona", + "display_name": "Ona", + "project_dir": ".ona/skills", + "tier": "registry" + }, + { + "id": "openclaw", + "display_name": "OpenClaw", + "project_dir": "skills", + "tier": "registry" + }, + { + "id": "opencode", + "display_name": "OpenCode", + "project_dir": ".agents/skills", + "tier": "registry" + }, + { + "id": "openhands", + "display_name": "OpenHands", + "project_dir": ".openhands/skills", + "tier": "registry" + }, + { + "id": "pi", + "display_name": "Pi", + "project_dir": ".pi/skills", + "tier": "registry" + }, + { + "id": "pochi", + "display_name": "Pochi", + "project_dir": ".pochi/skills", + "tier": "registry" + }, + { + "id": "promptscript", + "display_name": "PromptScript", + "project_dir": ".agents/skills", + "tier": "registry" + }, + { + "id": "qoder", + "display_name": "Qoder", + "project_dir": ".qoder/skills", + "tier": "registry" + }, + { + "id": "qoder-cn", + "display_name": "Qoder CN", + "project_dir": ".qoder/skills", + "tier": "registry" + }, + { + "id": "qwen-code", + "display_name": "Qwen Code", + "project_dir": ".qwen/skills", + "tier": "registry" + }, + { + "id": "reasonix", + "display_name": "Reasonix", + "project_dir": ".reasonix/skills", + "tier": "registry" + }, + { + "id": "replit", + "display_name": "Replit", + "project_dir": ".agents/skills", + "tier": "registry" + }, + { + "id": "roo", + "display_name": "Roo Code", + "project_dir": ".roo/skills", + "tier": "registry" + }, + { + "id": "rovodev", + "display_name": "Rovo Dev", + "project_dir": ".rovodev/skills", + "tier": "registry" + }, + { + "id": "tabnine-cli", + "display_name": "Tabnine CLI", + "project_dir": ".tabnine/agent/skills", + "tier": "registry" + }, + { + "id": "terramind", + "display_name": "Terramind", + "project_dir": ".terramind/skills", + "tier": "registry" + }, + { + "id": "tinycloud", + "display_name": "Tinycloud", + "project_dir": ".tinycloud/skills", + "tier": "registry" + }, + { + "id": "trae", + "display_name": "Trae", + "project_dir": ".trae/skills", + "tier": "registry" + }, + { + "id": "trae-cn", + "display_name": "Trae CN", + "project_dir": ".trae/skills", + "tier": "registry" + }, + { + "id": "universal", + "display_name": "Universal", + "project_dir": ".agents/skills", + "tier": "registry" + }, + { + "id": "warp", + "display_name": "Warp", + "project_dir": ".agents/skills", + "tier": "registry" + }, + { + "id": "windsurf", + "display_name": "Windsurf", + "project_dir": ".windsurf/skills", + "tier": "registry" + }, + { + "id": "zcode", + "display_name": "ZCode", + "project_dir": ".zcode/skills", + "tier": "registry" + }, + { + "id": "zed", + "display_name": "Zed", + "project_dir": ".agents/skills", + "tier": "registry" + }, + { + "id": "zencoder", + "display_name": "Zencoder", + "project_dir": ".zencoder/skills", + "tier": "registry" + }, + { + "id": "zenflow", + "display_name": "Zenflow", + "project_dir": ".zencoder/skills", + "tier": "registry" + } + ] +} diff --git a/cmd/yskill/scaffold.go b/cmd/yskill/scaffold.go index 290342b..b28735e 100644 --- a/cmd/yskill/scaffold.go +++ b/cmd/yskill/scaffold.go @@ -11,7 +11,6 @@ import ( ) var releaseVersionPattern = regexp.MustCompile(`^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$`) -var unsafePackageCharacter = regexp.MustCompile(`[^a-z0-9_-]+`) var tidyGoModule = func(dir string) error { cmd := exec.Command("go", "mod", "tidy") cmd.Dir = dir @@ -38,7 +37,7 @@ func packageVersion() string { return "0.0.0" } -func scaffoldSkill(dir, language, sdkPath string) error { +func scaffoldSkill(dir, language, sdkPath, description string) error { language = strings.ToLower(strings.TrimSpace(language)) if language != "typescript" && language != "python" && language != "go" && language != "rust" { return fmt.Errorf("unsupported language %q; choose typescript, python, go, or rust", language) @@ -46,7 +45,16 @@ func scaffoldSkill(dir, language, sdkPath string) error { if sdkPath != "" && language != "go" { return fmt.Errorf("--sdk is only valid with --language go") } - name := safePackageName(filepath.Base(filepath.Clean(dir))) + name := filepath.Base(filepath.Clean(dir)) + if !portableSkillName.MatchString(name) || len(name) > 64 { + return fmt.Errorf("skill directory name must match [a-z0-9]+(-[a-z0-9]+)* and be at most 64 characters") + } + skillPath := filepath.Join(dir, "SKILL.md") + if _, err := os.Stat(skillPath); os.IsNotExist(err) && strings.TrimSpace(description) == "" { + return fmt.Errorf("--description is required for a new skill; describe what it does and when an agent should use it") + } else if err != nil && !os.IsNotExist(err) { + return err + } writeIfAbsent := func(rel, content string) error { path := filepath.Join(dir, filepath.FromSlash(rel)) if _, err := os.Stat(path); err == nil { @@ -68,7 +76,7 @@ func scaffoldSkill(dir, language, sdkPath string) error { "rust": "yskill", }[language] files := scaffoldFiles(name, language, sdkPath) - files["SKILL.md"] = fmt.Sprintf(skillMD, name, launcher, launcher) + files["SKILL.md"] = fmt.Sprintf(skillMD, name, yamlString(strings.TrimSpace(description)), launcher, launcher) files["fixtures/responses.json"] = "{\n \"confirm-start\": {\"value\": \"yes\"}\n}\n" keys := make([]string, 0, len(files)) for key := range files { @@ -85,7 +93,12 @@ func scaffoldSkill(dir, language, sdkPath string) error { return err } } + if _, err := readSkillMetadata(dir); err != nil { + return fmt.Errorf("validate SKILL.md: %w", err) + } fmt.Printf("init: %s skill %q scaffolded in %s\n", language, name, dir) + fmt.Printf("next: %s register %s\n", launcher, shellQuote(dir)) + fmt.Printf("check: %s doctor %s --test\n", launcher, shellQuote(dir)) return nil } @@ -101,7 +114,7 @@ func scaffoldFiles(name, language, sdkPath string) map[string]string { "dependencies": { "@operatorstack/yield": "%s" } } `, v), - "skill.json": "{\"run\":[\"node\",\"main.ts\"]}\n", + "skill.json": "{\"version\":1,\"language\":\"typescript\",\"run\":[\"node\",\"main.ts\"]}\n", } case "python": python := strings.TrimSpace(os.Getenv("YIELD_PYTHON")) @@ -111,14 +124,14 @@ func scaffoldFiles(name, language, sdkPath string) map[string]string { return map[string]string{ "main.py": mainPython, "requirements.txt": fmt.Sprintf("--index-url https://get.operatorstack.systems/pip/simple/\nyieldskill==%s\n", v), - "skill.json": fmt.Sprintf("{\"run\":[%q,\"main.py\"]}\n", python), + "skill.json": fmt.Sprintf("{\"version\":1,\"language\":\"python\",\"run\":[%q,\"main.py\"]}\n", python), } case "rust": return map[string]string{ ".cargo/config.toml": "[registries.operatorstack]\nindex = \"sparse+https://get.operatorstack.systems/cargo/index/\"\n", "Cargo.toml": fmt.Sprintf("[package]\nname = %q\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyieldskill = { version = \"=%s\", registry = \"operatorstack\" }\nserde_json = \"1\"\n", name, v), "src/main.rs": mainRust, - "skill.json": "{\"run\":[\"cargo\",\"run\",\"--quiet\"]}\n", + "skill.json": "{\"version\":1,\"language\":\"rust\",\"run\":[\"cargo\",\"run\",\"--quiet\"]}\n", } default: gomod := fmt.Sprintf("module %s\n\ngo 1.26.5\n\nrequire github.com/operatorstack/yield v%s\n", name, v) @@ -128,23 +141,14 @@ func scaffoldFiles(name, language, sdkPath string) map[string]string { return map[string]string{ "main.go": mainGo, "go.mod": gomod, - "skill.json": "{\"run\":[\"go\",\"run\",\"-mod=readonly\",\".\"]}\n", + "skill.json": "{\"version\":1,\"language\":\"go\",\"run\":[\"go\",\"run\",\"-mod=readonly\",\".\"]}\n", } } } -func safePackageName(value string) string { - value = unsafePackageCharacter.ReplaceAllString(strings.ToLower(value), "-") - value = strings.Trim(value, "-_") - if value == "" { - return "yield-skill" - } - return value -} - const skillMD = `--- name: %s -description: TODO — one line on what this skill does. +description: %s --- Run: diff --git a/cmd/yskill/skillmeta.go b/cmd/yskill/skillmeta.go new file mode 100644 index 0000000..de399e6 --- /dev/null +++ b/cmd/yskill/skillmeta.go @@ -0,0 +1,86 @@ +package main + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + "regexp" + "strconv" + "strings" + + "gopkg.in/yaml.v3" +) + +var portableSkillName = regexp.MustCompile(`^[a-z0-9]+(?:-[a-z0-9]+)*$`) + +type skillManifest struct { + Version int `json:"version"` + Language string `json:"language"` + Run []string `json:"run"` +} + +type skillMetadata struct { + Name string `yaml:"name"` + Description string `yaml:"description"` +} + +func readSkillManifest(dir string) (skillManifest, error) { + b, err := os.ReadFile(filepath.Join(dir, "skill.json")) + if err != nil { + return skillManifest{}, fmt.Errorf("read skill.json: %w", err) + } + var manifest skillManifest + if err := json.Unmarshal(b, &manifest); err != nil { + return skillManifest{}, fmt.Errorf("skill.json does not decode: %w", err) + } + if manifest.Version != 1 { + return skillManifest{}, fmt.Errorf("skill.json version must be 1") + } + switch manifest.Language { + case "typescript", "python", "go", "rust": + default: + return skillManifest{}, fmt.Errorf("skill.json language must be typescript, python, go, or rust") + } + if len(manifest.Run) == 0 { + return skillManifest{}, fmt.Errorf("skill.json run must not be empty") + } + return manifest, nil +} + +func readSkillMetadata(dir string) (skillMetadata, error) { + b, err := os.ReadFile(filepath.Join(dir, "SKILL.md")) + if err != nil { + return skillMetadata{}, fmt.Errorf("read SKILL.md: %w", err) + } + text := strings.ReplaceAll(string(b), "\r\n", "\n") + if !strings.HasPrefix(text, "---\n") { + return skillMetadata{}, fmt.Errorf("SKILL.md must start with YAML frontmatter") + } + rest := text[4:] + end := strings.Index(rest, "\n---\n") + if end < 0 { + return skillMetadata{}, fmt.Errorf("SKILL.md frontmatter is not closed") + } + var metadata skillMetadata + if err := yaml.Unmarshal([]byte(rest[:end]), &metadata); err != nil { + return skillMetadata{}, fmt.Errorf("SKILL.md frontmatter does not decode: %w", err) + } + metadata.Name = strings.TrimSpace(metadata.Name) + metadata.Description = strings.TrimSpace(metadata.Description) + if !portableSkillName.MatchString(metadata.Name) || len(metadata.Name) > 64 { + return skillMetadata{}, fmt.Errorf("skill name must match [a-z0-9]+(-[a-z0-9]+)* and be at most 64 characters") + } + if metadata.Name != filepath.Base(filepath.Clean(dir)) { + return skillMetadata{}, fmt.Errorf("skill name %q must match directory %q", metadata.Name, filepath.Base(filepath.Clean(dir))) + } + if metadata.Description == "" || strings.Contains(strings.ToLower(metadata.Description), "todo") { + return skillMetadata{}, fmt.Errorf("skill description must explain what the skill does and when to use it") + } + if len(metadata.Description) > 1024 { + return skillMetadata{}, fmt.Errorf("skill description must be at most 1024 characters") + } + return metadata, nil +} + +func yamlString(value string) string { return strconv.Quote(value) } diff --git a/docs/README.md b/docs/README.md index 23d3b5f..b43fe38 100644 --- a/docs/README.md +++ b/docs/README.md @@ -14,13 +14,15 @@ is finished. 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 +2. [Register it with your coding agents](agent-setup.md) — keep one workflow + and generate the small discovery adapters each agent needs. +3. [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, +4. [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, +5. [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 +6. [Convert an existing prose skill](convert-existing-skill.md) — use Yield's verified converter after you understand one ordinary workflow. ## The split to remember @@ -41,6 +43,7 @@ next unanswered operation. ## Reference - [CLI commands](reference/cli.md) +- [Coding-agent registration](agent-setup.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/docs/agent-setup.md b/docs/agent-setup.md new file mode 100644 index 0000000..3d3ffe6 --- /dev/null +++ b/docs/agent-setup.md @@ -0,0 +1,61 @@ +# Use one Yield workflow from your coding agents + +Yield workflows belong beside the application and language dependencies they +use. `yskill register` creates only the small `SKILL.md` adapters required for +agent discovery. + +## Register an existing workflow + +```bash +# Detect installed verified agents +yskill register skills/review + +# Or choose agents explicitly +yskill register skills/review --agent cursor,codex,claude-code + +# Check the package and adapters; add --test to run fixture responses +yskill doctor skills/review --agent cursor,codex,claude-code --test +``` + +Use the launcher installed by the selected language package: + +| Language | Launcher | +|---|---| +| TypeScript | `npm exec -- yskill` | +| Python | `python -m yieldskill` | +| Go | `yskill` | +| Rust | `yskill` | + +Run `yskill agents` to see every supported ID and project directory. Cursor, +Codex, and Claude Code are verified. Other entries use paths from a pinned +snapshot of the open `vercel-labs/skills` registry and are labelled +`registry`: path generation is tested, but the product itself has not been run +end to end by Yield. + +Generated adapters are safe to commit. Regenerate them after changing the +canonical workflow. Yield refuses to overwrite a user-owned skill with the +same name. + +## Copy this to your agent + +Replace the bracketed values, then paste this into the coding agent already +open in the project: + +```text +Set up a Yield workflow named [skill-name] in skills/[skill-name]. + +1. Detect whether this project uses TypeScript, Python, Go, or Rust. +2. Install that language's Yield package using the project's existing package + manager. Do not install a second global runtime. +3. Run yskill init with the detected language and this description: + [what the workflow does and when it should run] +4. Keep the workflow beside the project's language dependencies. +5. Run yskill register for the coding agent you are currently using. +6. Use the launcher from the installed language package for every yskill + command: npm exec -- yskill, python -m yieldskill, or yskill. +7. Run yskill doctor with --test. +8. Report the commands, generated adapter path, and every changed file. + +Do not move the workflow into an agent discovery directory and do not copy its +dependencies into an adapter. +``` diff --git a/docs/primitives/agent-task.md b/docs/primitives/agent-task.md index 7da56dc..6cd82f1 100644 --- a/docs/primitives/agent-task.md +++ b/docs/primitives/agent-task.md @@ -29,7 +29,7 @@ The arguments are: 3. optional structured context; 4. an optional JSON Schema for the response. -The supervisor validates the response schema before accepting it. Schema-valid +The Yield CLI 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. diff --git a/docs/quickstart.md b/docs/quickstart.md index 890d1a4..03c29e5 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -1,45 +1,43 @@ # 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. +program: run a real check, ask the coding agent to review the branch, stop on +critical findings, and save the structured result. You need Node.js 24 or newer. ## 1. Install Yield ```bash -mkdir review-skill -cd review-skill +mkdir yield-example +cd yield-example npm init -y npm install @operatorstack/yield \ --registry=https://get.operatorstack.systems/npm/ -npm exec -- yskill init . --language typescript +npm exec -- yskill --version ``` The package includes the TypeScript SDK and its matching Yield runtime. -## 2. Create the package +## 2. Create the canonical workflow + +```bash +npm exec -- yskill init skills/review \ + --language typescript \ + --description "Check and review the current branch before it is shipped." +``` -Create `package.json`: +The workflow stays under `skills/review`, inside the same dependency tree as +`@operatorstack/yield`. The generated `skill.json` records the language and +program entry point: ```json -{ - "private": true, - "type": "module", - "scripts": { - "check": "node --check main.ts" - } -} +{"version":1,"language":"typescript","run":["node","main.ts"]} ``` -## 3. Add the workflow +## 3. Add the workflow logic -Create `main.ts`: +Replace `skills/review/main.ts`: ```ts import { defineSkill } from "@operatorstack/yield"; @@ -72,37 +70,41 @@ defineSkill((ctx) => { }); ``` -Add `skill.json` so Yield knows how to start the program: +Add the real project check to the root `package.json`: ```json -{"run":["node","main.ts"]} +{"scripts":{"check":"node --check skills/review/main.ts"}} ``` -## 4. Add the thin skill file +The generated `skills/review/SKILL.md` remains short. It tells the agent when +to use the workflow and how to follow the yielded operations; the program owns +the order and finish rule. -Create `SKILL.md`: +## 4. Register it with coding agents -```markdown ---- -name: review -description: Check and review the current branch before it is shipped. ---- +```bash +# Detect installed verified agents +npm exec -- yskill register skills/review -Run `npm exec -- yskill run .` and follow each returned operation exactly. +# Or select them explicitly +npm exec -- yskill register skills/review \ + --agent cursor,codex,claude-code +``` -For `agent_task`, perform the task and return schema-valid JSON. Resume with -`npm exec -- yskill resume --response response.json --skill .`. +Yield keeps one workflow and writes only generated adapters: -Do not skip an operation or invent a response. The program owns the order and -the finish rule. +```text +.cursor/skills/review/SKILL.md # Cursor +.agents/skills/review/SKILL.md # Codex +.claude/skills/review/SKILL.md # Claude Code ``` -The file still tells the agent what the skill is for. It no longer has to -describe every branch and gate in prose. +Start a new agent session after registration, then invoke `/review` or ask for +the task described by the skill. ## 5. Prove the workflow locally -Create `fixtures/responses.json`: +Replace `skills/review/fixtures/responses.json`: ```json { @@ -113,24 +115,33 @@ Create `fixtures/responses.json`: } ``` -Run: +Run the complete setup check: ```bash -npm exec -- yskill test . +npm exec -- yskill doctor skills/review \ + --agent cursor,codex,claude-code \ + --test ``` -`run_command` operations execute for real. The fixture supplies only the model -and user responses. A successful result ends with: +`run_command` operations execute for real. The fixture supplies only model and +user responses. A successful result ends with `reached completed` and a doctor +summary. -```text -test: run reached completed -``` +## Run an existing workflow -## 6. Use it from your coding agent +Initialization is only for creating or wrapping a workflow. For an existing +workflow, install the matching language package, register it for the agents in +the project, then run it directly when needed: + +```bash +npm exec -- yskill register skills/review --agent cursor +npm exec -- yskill run skills/review +``` -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. +The agent reads the generated adapter, starts the canonical workflow, performs +each yielded 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). +Next: [set up coding agents](agent-setup.md), [understand each +primitive](primitives/README.md), or follow the [complete review +tutorial](tutorials/code-review.md). diff --git a/docs/reference/cli.md b/docs/reference/cli.md index df4a004..5f4239d 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -6,11 +6,50 @@ commands, and starts the skill program. It comes with each language package. ## `init` ```bash -yskill init --language typescript|python|go|rust +yskill init --description "What it does and when to use it" + [--language typescript|python|go|rust] ``` Scaffolds a new skill or adds a Yield program beside an existing prose skill. Generated dependencies are pinned to the installed `yskill` version. +New skills require a real trigger-oriented description. Existing `SKILL.md` +files are preserved and validated. + +## `register` + +```bash +yskill register [--agent cursor,codex,...|auto] + [--root repository] +``` + +Writes generated, project-local `SKILL.md` adapters for the selected coding +agents. Without `--agent`, Yield detects verified agents. Explicit IDs work for +every entry printed by `yskill agents`. Workflow code, dependencies, fixtures, +and run state remain in the canonical skill directory. + +Registration updates only adapters previously generated from the same source. +It refuses user-owned files, workflows outside the repository, and canonical +workflows stored inside a selected agent's discovery directory. + +## `agents` + +```bash +yskill agents +``` + +Lists agent IDs, project skill directories, detection state, and whether each +entry is verified or registry-supported. + +## `doctor` + +```bash +yskill doctor [--agent cursor,codex,...|auto] + [--root repository] [--test] +``` + +Checks the manifest, package launcher, portable metadata, adapter ownership, +source path, and source digest. `--test` also runs the workflow against +`fixtures/responses.json`. ## `version` diff --git a/docs/reference/guarantees.md b/docs/reference/guarantees.md index e89a5f1..7f27a74 100644 --- a/docs/reference/guarantees.md +++ b/docs/reference/guarantees.md @@ -7,7 +7,7 @@ - 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; +- real command execution by the Yield CLI; - requirements that prevent later completion after failure; - recorded completed, blocked, and refused outcomes. diff --git a/docs/reference/sdk-parity.md b/docs/reference/sdk-parity.md index 87e6102..891b495 100644 --- a/docs/reference/sdk-parity.md +++ b/docs/reference/sdk-parity.md @@ -10,10 +10,10 @@ contract. | 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: +Skills declare their language and runner in `skill.json`, for example: ```json -{"run":["node","main.ts"]} +{"version":1,"language":"typescript","run":["node","main.ts"]} ``` The conformance suite runs the same workflow in all four languages and compares diff --git a/evals/results/latest.json b/evals/results/latest.json index 1fcd04c..d02e533 100644 --- a/evals/results/latest.json +++ b/evals/results/latest.json @@ -1,8 +1,8 @@ { "schema_version": 2, "methodology_version": "1.0", - "generated_at": "2026-08-01T22:15:26.319Z", - "source_digest": "18c4620bc76291a4e8580b488f746cfb0085bf06629cf73ac38c5dbbec4bf099", + "generated_at": "2026-08-02T00:47:04.974Z", + "source_digest": "760c09c309aac72fc15ff1b6b35663717b32a96917bca1be0c61e8536354467a", "status": "passed", "workflow_conformance": { "passed": 40, diff --git a/examples/convert-skill/skill.json b/examples/convert-skill/skill.json new file mode 100644 index 0000000..da0e878 --- /dev/null +++ b/examples/convert-skill/skill.json @@ -0,0 +1,5 @@ +{ + "version": 1, + "language": "go", + "run": ["go", "run", "."] +} diff --git a/examples/data-migration/skill.json b/examples/data-migration/skill.json index 5b767f7..fb837d0 100644 --- a/examples/data-migration/skill.json +++ b/examples/data-migration/skill.json @@ -1,3 +1,9 @@ { - "run": ["cargo", "run", "--quiet"] + "version": 1, + "language": "rust", + "run": [ + "cargo", + "run", + "--quiet" + ] } diff --git a/examples/env-doctor/skill.json b/examples/env-doctor/skill.json index 2334634..5a7ec2a 100644 --- a/examples/env-doctor/skill.json +++ b/examples/env-doctor/skill.json @@ -1,3 +1,8 @@ { - "run": ["python3", "main.py"] + "version": 1, + "language": "python", + "run": [ + "python3", + "main.py" + ] } diff --git a/examples/investigate/skill.json b/examples/investigate/skill.json new file mode 100644 index 0000000..da0e878 --- /dev/null +++ b/examples/investigate/skill.json @@ -0,0 +1,5 @@ +{ + "version": 1, + "language": "go", + "run": ["go", "run", "."] +} diff --git a/examples/library/go/audit-security/skill.json b/examples/library/go/audit-security/skill.json index 8e95b8a..9039b2d 100644 --- a/examples/library/go/audit-security/skill.json +++ b/examples/library/go/audit-security/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "go", "run": [ "go", "run", diff --git a/examples/library/go/investigate-failure/skill.json b/examples/library/go/investigate-failure/skill.json index 3eec0b0..e8e261b 100644 --- a/examples/library/go/investigate-failure/skill.json +++ b/examples/library/go/investigate-failure/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "go", "run": [ "go", "run", diff --git a/examples/library/go/migrate-database/skill.json b/examples/library/go/migrate-database/skill.json index 752dae2..3162de1 100644 --- a/examples/library/go/migrate-database/skill.json +++ b/examples/library/go/migrate-database/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "go", "run": [ "go", "run", diff --git a/examples/library/go/publish-ios/skill.json b/examples/library/go/publish-ios/skill.json index 1ab9b9d..dba9009 100644 --- a/examples/library/go/publish-ios/skill.json +++ b/examples/library/go/publish-ios/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "go", "run": [ "go", "run", diff --git a/examples/library/go/qa-web-change/skill.json b/examples/library/go/qa-web-change/skill.json index b5fc470..677da9f 100644 --- a/examples/library/go/qa-web-change/skill.json +++ b/examples/library/go/qa-web-change/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "go", "run": [ "go", "run", diff --git a/examples/library/go/release-package/skill.json b/examples/library/go/release-package/skill.json index 14c49d9..1615910 100644 --- a/examples/library/go/release-package/skill.json +++ b/examples/library/go/release-package/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "go", "run": [ "go", "run", diff --git a/examples/library/go/repair-ci/skill.json b/examples/library/go/repair-ci/skill.json index e2b15ee..a4debd9 100644 --- a/examples/library/go/repair-ci/skill.json +++ b/examples/library/go/repair-ci/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "go", "run": [ "go", "run", diff --git a/examples/library/go/review-branch/skill.json b/examples/library/go/review-branch/skill.json index 5ce6c00..1a40e27 100644 --- a/examples/library/go/review-branch/skill.json +++ b/examples/library/go/review-branch/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "go", "run": [ "go", "run", diff --git a/examples/library/go/triage-issue/skill.json b/examples/library/go/triage-issue/skill.json index 748427d..2b18059 100644 --- a/examples/library/go/triage-issue/skill.json +++ b/examples/library/go/triage-issue/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "go", "run": [ "go", "run", diff --git a/examples/library/go/upgrade-dependency/skill.json b/examples/library/go/upgrade-dependency/skill.json index 9e25f22..df74f8f 100644 --- a/examples/library/go/upgrade-dependency/skill.json +++ b/examples/library/go/upgrade-dependency/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "go", "run": [ "go", "run", diff --git a/examples/library/python/audit-security/skill.json b/examples/library/python/audit-security/skill.json index e5e59ab..57b14bf 100644 --- a/examples/library/python/audit-security/skill.json +++ b/examples/library/python/audit-security/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "python", "run": [ "python3", "../src/audit-security.py" diff --git a/examples/library/python/investigate-failure/skill.json b/examples/library/python/investigate-failure/skill.json index c1c33c3..44c2e78 100644 --- a/examples/library/python/investigate-failure/skill.json +++ b/examples/library/python/investigate-failure/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "python", "run": [ "python3", "../src/investigate-failure.py" diff --git a/examples/library/python/migrate-database/skill.json b/examples/library/python/migrate-database/skill.json index db51723..f9f04e3 100644 --- a/examples/library/python/migrate-database/skill.json +++ b/examples/library/python/migrate-database/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "python", "run": [ "python3", "../src/migrate-database.py" diff --git a/examples/library/python/publish-ios/skill.json b/examples/library/python/publish-ios/skill.json index efad712..4d1c494 100644 --- a/examples/library/python/publish-ios/skill.json +++ b/examples/library/python/publish-ios/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "python", "run": [ "python3", "../src/publish-ios.py" diff --git a/examples/library/python/qa-web-change/skill.json b/examples/library/python/qa-web-change/skill.json index 8f2774d..c8b2ed3 100644 --- a/examples/library/python/qa-web-change/skill.json +++ b/examples/library/python/qa-web-change/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "python", "run": [ "python3", "../src/qa-web-change.py" diff --git a/examples/library/python/release-package/skill.json b/examples/library/python/release-package/skill.json index a5942f5..39707ca 100644 --- a/examples/library/python/release-package/skill.json +++ b/examples/library/python/release-package/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "python", "run": [ "python3", "../src/release-package.py" diff --git a/examples/library/python/repair-ci/skill.json b/examples/library/python/repair-ci/skill.json index eba3c65..a17bf94 100644 --- a/examples/library/python/repair-ci/skill.json +++ b/examples/library/python/repair-ci/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "python", "run": [ "python3", "../src/repair-ci.py" diff --git a/examples/library/python/review-branch/skill.json b/examples/library/python/review-branch/skill.json index 8400ee2..223fd5c 100644 --- a/examples/library/python/review-branch/skill.json +++ b/examples/library/python/review-branch/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "python", "run": [ "python3", "../src/review-branch.py" diff --git a/examples/library/python/triage-issue/skill.json b/examples/library/python/triage-issue/skill.json index 38d476f..7a84c88 100644 --- a/examples/library/python/triage-issue/skill.json +++ b/examples/library/python/triage-issue/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "python", "run": [ "python3", "../src/triage-issue.py" diff --git a/examples/library/python/upgrade-dependency/skill.json b/examples/library/python/upgrade-dependency/skill.json index 50fd9b5..6512802 100644 --- a/examples/library/python/upgrade-dependency/skill.json +++ b/examples/library/python/upgrade-dependency/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "python", "run": [ "python3", "../src/upgrade-dependency.py" diff --git a/examples/library/rust/audit-security/skill.json b/examples/library/rust/audit-security/skill.json index d69c827..1bd1f2d 100644 --- a/examples/library/rust/audit-security/skill.json +++ b/examples/library/rust/audit-security/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "rust", "run": [ "cargo", "run", diff --git a/examples/library/rust/investigate-failure/skill.json b/examples/library/rust/investigate-failure/skill.json index bb2ddc8..a358d69 100644 --- a/examples/library/rust/investigate-failure/skill.json +++ b/examples/library/rust/investigate-failure/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "rust", "run": [ "cargo", "run", diff --git a/examples/library/rust/migrate-database/skill.json b/examples/library/rust/migrate-database/skill.json index ca11a48..0fd48dd 100644 --- a/examples/library/rust/migrate-database/skill.json +++ b/examples/library/rust/migrate-database/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "rust", "run": [ "cargo", "run", diff --git a/examples/library/rust/publish-ios/skill.json b/examples/library/rust/publish-ios/skill.json index 25f6073..507524c 100644 --- a/examples/library/rust/publish-ios/skill.json +++ b/examples/library/rust/publish-ios/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "rust", "run": [ "cargo", "run", diff --git a/examples/library/rust/qa-web-change/skill.json b/examples/library/rust/qa-web-change/skill.json index 8f940f3..7ce1e22 100644 --- a/examples/library/rust/qa-web-change/skill.json +++ b/examples/library/rust/qa-web-change/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "rust", "run": [ "cargo", "run", diff --git a/examples/library/rust/release-package/skill.json b/examples/library/rust/release-package/skill.json index 6bebf4d..f5c4340 100644 --- a/examples/library/rust/release-package/skill.json +++ b/examples/library/rust/release-package/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "rust", "run": [ "cargo", "run", diff --git a/examples/library/rust/repair-ci/skill.json b/examples/library/rust/repair-ci/skill.json index 0a034f1..6e6271c 100644 --- a/examples/library/rust/repair-ci/skill.json +++ b/examples/library/rust/repair-ci/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "rust", "run": [ "cargo", "run", diff --git a/examples/library/rust/review-branch/skill.json b/examples/library/rust/review-branch/skill.json index ca6384b..76823f4 100644 --- a/examples/library/rust/review-branch/skill.json +++ b/examples/library/rust/review-branch/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "rust", "run": [ "cargo", "run", diff --git a/examples/library/rust/triage-issue/skill.json b/examples/library/rust/triage-issue/skill.json index a2994fb..4ff4f09 100644 --- a/examples/library/rust/triage-issue/skill.json +++ b/examples/library/rust/triage-issue/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "rust", "run": [ "cargo", "run", diff --git a/examples/library/rust/upgrade-dependency/skill.json b/examples/library/rust/upgrade-dependency/skill.json index 5d80d02..a4694f5 100644 --- a/examples/library/rust/upgrade-dependency/skill.json +++ b/examples/library/rust/upgrade-dependency/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "rust", "run": [ "cargo", "run", diff --git a/examples/library/typescript/audit-security/skill.json b/examples/library/typescript/audit-security/skill.json index 86e81d9..71602c4 100644 --- a/examples/library/typescript/audit-security/skill.json +++ b/examples/library/typescript/audit-security/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "typescript", "run": [ "node", "../src/audit-security.ts" diff --git a/examples/library/typescript/investigate-failure/skill.json b/examples/library/typescript/investigate-failure/skill.json index 291e572..25f2c12 100644 --- a/examples/library/typescript/investigate-failure/skill.json +++ b/examples/library/typescript/investigate-failure/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "typescript", "run": [ "node", "../src/investigate-failure.ts" diff --git a/examples/library/typescript/migrate-database/skill.json b/examples/library/typescript/migrate-database/skill.json index e436e40..8cf2dd5 100644 --- a/examples/library/typescript/migrate-database/skill.json +++ b/examples/library/typescript/migrate-database/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "typescript", "run": [ "node", "../src/migrate-database.ts" diff --git a/examples/library/typescript/publish-ios/skill.json b/examples/library/typescript/publish-ios/skill.json index 0ec603d..d9709e5 100644 --- a/examples/library/typescript/publish-ios/skill.json +++ b/examples/library/typescript/publish-ios/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "typescript", "run": [ "node", "../src/publish-ios.ts" diff --git a/examples/library/typescript/qa-web-change/skill.json b/examples/library/typescript/qa-web-change/skill.json index 4799997..e1bce27 100644 --- a/examples/library/typescript/qa-web-change/skill.json +++ b/examples/library/typescript/qa-web-change/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "typescript", "run": [ "node", "../src/qa-web-change.ts" diff --git a/examples/library/typescript/release-package/skill.json b/examples/library/typescript/release-package/skill.json index 290467b..6ce7a80 100644 --- a/examples/library/typescript/release-package/skill.json +++ b/examples/library/typescript/release-package/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "typescript", "run": [ "node", "../src/release-package.ts" diff --git a/examples/library/typescript/repair-ci/skill.json b/examples/library/typescript/repair-ci/skill.json index 7324bf8..71c3376 100644 --- a/examples/library/typescript/repair-ci/skill.json +++ b/examples/library/typescript/repair-ci/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "typescript", "run": [ "node", "../src/repair-ci.ts" diff --git a/examples/library/typescript/review-branch/skill.json b/examples/library/typescript/review-branch/skill.json index 84488ec..1d897e4 100644 --- a/examples/library/typescript/review-branch/skill.json +++ b/examples/library/typescript/review-branch/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "typescript", "run": [ "node", "../src/review-branch.ts" diff --git a/examples/library/typescript/triage-issue/skill.json b/examples/library/typescript/triage-issue/skill.json index 67bb078..584ce67 100644 --- a/examples/library/typescript/triage-issue/skill.json +++ b/examples/library/typescript/triage-issue/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "typescript", "run": [ "node", "../src/triage-issue.ts" diff --git a/examples/library/typescript/upgrade-dependency/skill.json b/examples/library/typescript/upgrade-dependency/skill.json index c35ca5c..536fd2d 100644 --- a/examples/library/typescript/upgrade-dependency/skill.json +++ b/examples/library/typescript/upgrade-dependency/skill.json @@ -1,4 +1,6 @@ { + "version": 1, + "language": "typescript", "run": [ "node", "../src/upgrade-dependency.ts" diff --git a/examples/release-checklist/skill.json b/examples/release-checklist/skill.json index 36115dd..a09b572 100644 --- a/examples/release-checklist/skill.json +++ b/examples/release-checklist/skill.json @@ -1,3 +1,8 @@ { - "run": ["node", "main.ts"] + "version": 1, + "language": "typescript", + "run": [ + "node", + "main.ts" + ] } diff --git a/go.mod b/go.mod index 60e26d9..88e2725 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,9 @@ module github.com/operatorstack/yield go 1.26.5 -require github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 +require ( + github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 + gopkg.in/yaml.v3 v3.0.1 +) require golang.org/x/text v0.14.0 // indirect diff --git a/go.sum b/go.sum index 8fee20f..7e38d45 100644 --- a/go.sum +++ b/go.sum @@ -4,3 +4,7 @@ github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEV github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/release-notes/2026-08-02-cross-agent-registration.md b/release-notes/2026-08-02-cross-agent-registration.md new file mode 100644 index 0000000..fd38f60 --- /dev/null +++ b/release-notes/2026-08-02-cross-agent-registration.md @@ -0,0 +1,8 @@ +# Use one workflow from several coding agents + +- Add `yskill register` to create small adapters for coding-agent skill directories. +- Add `yskill agents` to show supported agents, paths, detection state, and verification level. +- Add `yskill doctor` to check a workflow, its launcher, and generated adapters; `--test` also runs its fixture. +- Keep workflow code and dependencies in one canonical directory instead of copying them per agent. +- Verify Cursor, Codex, and Claude paths end to end, while keeping other registry entries explicitly selectable. +- Require a useful description when scaffolding a new workflow and print the exact register, doctor, and test commands.