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

Filter by extension

Filter by extension

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

Pin the installed runtime during Rust and Go workflow creation, and remove the obsolete private Cargo registry check from Rust diagnostics.
3 changes: 0 additions & 3 deletions cmd/yskill/agents.go
Original file line number Diff line number Diff line change
Expand Up @@ -980,9 +980,6 @@ func languageDiagnostics(language, skillDir string) error {
if !commandExists("cargo") {
return fmt.Errorf("Rust workflow needs the cargo command")
}
if _, err := os.Stat(filepath.Join(skillDir, ".cargo", "config.toml")); err != nil {
return fmt.Errorf("Rust workflow needs .cargo/config.toml in the workflow directory: %w", err)
}
var missing []string
if !commandExists("rustfmt") {
missing = append(missing, "rustfmt")
Expand Down
48 changes: 48 additions & 0 deletions cmd/yskill/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,54 @@ func TestLocalGoAndRustScaffoldsKeepTheInvokedRuntime(t *testing.T) {
}
}

func TestRustScaffoldPinsTheInvokedRuntimeWithoutPrivateRegistryConfig(t *testing.T) {
previousVersion := version
previousExecutable := currentExecutable
previousInspect := inspectRuntimeVersion
version = "0.1.37"
t.Cleanup(func() {
version = previousVersion
currentExecutable = previousExecutable
inspectRuntimeVersion = previousInspect
})

repo := t.TempDir()
writeTestFile(t, filepath.Join(repo, ".git"), "gitdir: fixture\n")
t.Chdir(repo)
sourceRoot := t.TempDir()
source := filepath.Join(sourceRoot, "yskill")
writeTestFile(t, source, "packaged runtime")
currentExecutable = func() (string, error) { return source, nil }
inspectRuntimeVersion = func(path string) (string, error) {
if path != source && path != localRuntimePath(repo) {
t.Fatalf("inspected unexpected runtime %s", path)
}
return "0.1.37", nil
}

dir := filepath.Join("skills", "safe-change")
if err := scaffoldSkill(dir, "rust", "", "Check a safe change before applying it."); err != nil {
t.Fatal(err)
}
if got := readTestFile(t, localRuntimePath(repo)); got != "packaged runtime" {
t.Fatalf("pinned runtime = %q", got)
}
if got := readTestFile(t, filepath.Join(repo, ".yield", ".gitignore")); got != "*\n" {
t.Fatalf("local state ignore = %q", got)
}
if _, err := os.Stat(filepath.Join(repo, dir, ".cargo", "config.toml")); !os.IsNotExist(err) {
t.Fatalf("Rust scaffold created private registry config: %v", err)
}
if err := languageDiagnostics("rust", dir); err != nil {
t.Fatalf("Rust diagnostics required private registry config: %v", err)
}
skill := readTestFile(t, filepath.Join(repo, dir, "SKILL.md"))
launcher := repositoryRuntimeLauncher(filepath.Join(".yield", "bin", filepath.Base(localRuntimePath(repo))), runtime.GOOS)
if !strings.Contains(skill, launcher+" run") {
t.Fatalf("SKILL.md does not use pinned runtime %q:\n%s", launcher, skill)
}
}

func TestPythonScaffoldUsesRelocatableInterpreter(t *testing.T) {
previousVersion := version
version = "0.1.9"
Expand Down
94 changes: 90 additions & 4 deletions cmd/yskill/scaffold.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,18 @@ func scaffoldCommand(language, dir string) (launcher, workflow string) {
}
root, ok := repositoryRootFromLocalRuntime()
if !ok {
return launcher, workflow
var err error
root, err = findRepoRoot(dir, "")
if err != nil {
return launcher, workflow
}
root, err = filepath.Abs(root)
if err != nil {
return launcher, workflow
}
if verifyLocalRuntime(localRuntimePath(root), runtimeVersion(), language) != nil {
return launcher, workflow
}
}
absDir, err := filepath.Abs(dir)
if err != nil || !within(root, absDir) {
Expand Down Expand Up @@ -93,6 +104,11 @@ func scaffoldSkill(dir, language, sdkPath, description string) error {
} else if err != nil && !os.IsNotExist(err) {
return err
}
if language == "go" || language == "rust" {
if err := pinCurrentRuntime(dir); err != nil {
return err
}
}
writeIfAbsent := func(rel, content string) error {
path := filepath.Join(dir, filepath.FromSlash(rel))
if _, err := os.Stat(path); err == nil {
Expand Down Expand Up @@ -137,6 +153,76 @@ func scaffoldSkill(dir, language, sdkPath, description string) error {
return nil
}

func pinCurrentRuntime(dir string) error {
root, err := findRepoRoot(dir, "")
if err != nil {
return nil
}
source := strings.TrimSpace(os.Getenv("YIELD_LAUNCHER_PATH"))
if source == "" {
source, err = currentExecutable()
if err != nil {
return fmt.Errorf("locate current Yield runtime: %w", err)
}
}
source, err = filepath.Abs(source)
if err != nil {
return fmt.Errorf("resolve current Yield runtime: %w", err)
}
name := strings.ToLower(filepath.Base(source))
if name != "yskill" && name != "yskill.exe" {
return nil
}
destination := localRuntimePath(root)
if filepath.Clean(source) == filepath.Clean(destination) {
return ensureLocalStateIgnored(root)
}
got, err := inspectRuntimeVersion(source)
if err != nil {
return fmt.Errorf("verify current Yield runtime: %w", err)
}
if expected := runtimeVersion(); got != expected {
return fmt.Errorf("current Yield launcher version is %s, but the runtime is %s", got, expected)
}
contents, err := os.ReadFile(source)
if err != nil {
return fmt.Errorf("read current Yield runtime: %w", err)
}
if err := os.MkdirAll(filepath.Dir(destination), 0o755); err != nil {
return err
}
temporary, err := os.CreateTemp(filepath.Dir(destination), ".yskill-pin-*")
if err != nil {
return err
}
temporaryPath := temporary.Name()
defer os.Remove(temporaryPath)
if _, err := temporary.Write(contents); err != nil {
temporary.Close()
return err
}
if err := temporary.Chmod(0o755); err != nil {
temporary.Close()
return err
}
if err := temporary.Close(); err != nil {
return err
}
if runtime.GOOS == "windows" {
if err := os.Remove(destination); err != nil && !os.IsNotExist(err) {
return err
}
}
if err := os.Rename(temporaryPath, destination); err != nil {
return fmt.Errorf("pin repository-local Yield runtime: %w", err)
}
if err := ensureLocalStateIgnored(root); err != nil {
return err
}
fmt.Printf("init: pinned Yield %s at %s\n", got, filepath.ToSlash(destination))
return nil
}

func scaffoldFiles(name, language, sdkPath string) map[string]string {
v := packageVersion()
switch language {
Expand All @@ -159,9 +245,9 @@ func scaffoldFiles(name, language, sdkPath string) map[string]string {
}
case "rust":
return map[string]string{
"Cargo.toml": fmt.Sprintf("[package]\nname = %q\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyieldskill = { version = \"=%s\" }\nserde_json = \"1\"\n", name, v),
"src/main.rs": mainRust,
"skill.json": fmt.Sprintf("{\"version\":1,\"language\":\"rust\",\"run\":[\"cargo\",\"run\",\"--quiet\",\"--bin\",%q]}\n", name),
"Cargo.toml": fmt.Sprintf("[package]\nname = %q\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyieldskill = { version = \"=%s\" }\nserde_json = \"1\"\n", name, v),
"src/main.rs": mainRust,
"skill.json": fmt.Sprintf("{\"version\":1,\"language\":\"rust\",\"run\":[\"cargo\",\"run\",\"--quiet\",\"--bin\",%q]}\n", name),
}
default:
gomod := fmt.Sprintf("module %s\n\ngo 1.26.5\n\nrequire github.com/operatorstack/yield v%s\n", name, v)
Expand Down
4 changes: 2 additions & 2 deletions evals/results/latest.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"schema_version": 2,
"methodology_version": "1.1",
"generated_at": "2026-08-07T21:46:28.142Z",
"source_digest": "e70b0de3a9db5924311609a33e3ce91b539da02a6822acbf57d00471d8f6b63a",
"generated_at": "2026-08-07T22:52:34.977Z",
"source_digest": "b5c66a96530cc9d100c388a4df9bbbc8d0aea6e78ef0fe2cfa0009b8aa1da778",
"status": "passed",
"workflow_conformance": {
"passed": 40,
Expand Down