diff --git a/cmd/skills.go b/cmd/skills.go index 798f51fad..ebbb65536 100644 --- a/cmd/skills.go +++ b/cmd/skills.go @@ -140,6 +140,13 @@ func loadSkillsFromRefs(refs []api.SkillRef) (*skillCatalog, error) { skillDir = path } else if ref.Name != "" { + // Check if this is a local path or a registry reference + if !server.IsLocalSkillPath(ref.Name) { + // Registry reference without a digest - skill needs to be pulled first + // This happens when an agent references a skill that hasn't been bundled + return nil, fmt.Errorf("skill %q is a registry reference but has no digest - the agent may need to be recreated or the skill pulled separately", ref.Name) + } + // Local path - resolve it skillPath := ref.Name if strings.HasPrefix(skillPath, "~") { @@ -486,6 +493,14 @@ func runSkillScript(skillDir, command string) (string, error) { cmd := exec.CommandContext(ctx, "sh", "-c", command) cmd.Dir = absSkillDir + // Inject the current working directory (where ollama run was called from) + // as an environment variable so scripts can reference files in that directory + workingDir, err := os.Getwd() + if err != nil { + return "", fmt.Errorf("failed to get working directory: %w", err) + } + cmd.Env = append(os.Environ(), "OLLAMA_WORKING_DIR="+workingDir) + // Capture both stdout and stderr var stdout, stderr bytes.Buffer cmd.Stdout = &stdout diff --git a/server/skill.go b/server/skill.go index 0e42fabf6..9576e6845 100644 --- a/server/skill.go +++ b/server/skill.go @@ -250,13 +250,14 @@ func CreateSkillLayer(skillDir string) (Layer, error) { } // IsLocalSkillPath checks if a skill reference looks like a local path. +// Local paths are explicitly prefixed with /, ./, ../, or ~. +// Registry references like "skill/calculator:1.0.0" should NOT be treated as local paths. func IsLocalSkillPath(name string) bool { - // Local paths start with /, ./, or contain path separators + // Local paths are explicitly indicated by path prefixes return strings.HasPrefix(name, "/") || strings.HasPrefix(name, "./") || strings.HasPrefix(name, "../") || - strings.HasPrefix(name, "~") || - strings.Contains(name, string(os.PathSeparator)) + strings.HasPrefix(name, "~") } // SkillNamespace is the namespace used for standalone skills in the registry.