diff --git a/clean.sh b/clean.sh
index f4c2eb619564de3ff02127400dc5917ec1fbc86b..d0b85abc22b9656cd310575426f4ee77ea52e734 100755
--- a/clean.sh
+++ b/clean.sh
@@ -5,7 +5,7 @@ source config.sh
 
 if [ $# = 0 ]
 then
-    recipes="$(ls -1 recipes)"
+    recipes="$(target/release/list_recipes)"
 else
     recipes="$@"
 fi
diff --git a/cook.sh b/cook.sh
index ba4a7a12a3f8a2b277b6a6cc2e22efb22da1fec2..fb0104414ff0e498d93b54efa222d1412509143d 100755
--- a/cook.sh
+++ b/cook.sh
@@ -368,9 +368,10 @@ function op {
 
 if [ -n "$1" ]
 then
-    if [ -d "$ROOT/recipes/$1" ]
+    recipe_path=`target/release/find_recipe $1`
+    if [ -d "$ROOT/$recipe_path" ]
     then
-        export COOKBOOK_RECIPE="${ROOT}/recipes/$1"
+        export COOKBOOK_RECIPE="${ROOT}/$recipe_path"
 
         TARGET_DIR="${COOKBOOK_RECIPE}/target/${TARGET}"
         mkdir -p "${TARGET_DIR}"
diff --git a/fetch.sh b/fetch.sh
index 03368c77a54082273bcc0bd52ab3214fef41873c..1c5c57a8d82e5a9cfbbf75364a9143ce7c54676a 100755
--- a/fetch.sh
+++ b/fetch.sh
@@ -5,14 +5,15 @@ source config.sh
 
 if [ $# = 0 ]
 then
-    recipes="$(ls -1 recipes)"
+    recipes="$(target/release/list_recipes)"
 else
     recipes="$@"
 fi
 
 for recipe in $recipes
 do
-    if [ -e "recipes/$recipe/recipe.toml" ]
+    recipe_path=`target/release/find_recipe $recipe`
+    if [ -e "$recipe_path/recipe.toml" ]
     then
         target/release/cook --fetch-only "$recipe"
         continue
diff --git a/repo.sh b/repo.sh
index 1ca42d9983875db8ba7df0dcf96870506aebb8c5..2fad01da22e095f893cbe822744e1ee5269b855a 100755
--- a/repo.sh
+++ b/repo.sh
@@ -17,12 +17,14 @@ done
 
 if [ "$recipes" == "" ]
 then
-    recipes="$(ls -1 recipes)"
+    recipes="$(target/release/list_recipes)"
 fi
 
 for recipe in $recipes
 do
-    COOKBOOK_RECIPE="recipes/$recipe"
+    recipe_path=`target/release/find_recipe $recipe`
+    echo recipe path is $recipe_path
+    COOKBOOK_RECIPE="$recipe_path"
     TARGET_DIR="${COOKBOOK_RECIPE}/target/${TARGET}"
     COOKBOOK_BUILD="${TARGET_DIR}/build"
     COOKBOOK_STAGE="${TARGET_DIR}/stage"
@@ -113,7 +115,8 @@ mkdir -p "$REPO"
 
 for recipe in $recipes
 do
-    COOKBOOK_RECIPE="recipes/$recipe"
+    recipe_path=`target/release/find_recipe $recipe`
+    COOKBOOK_RECIPE="$recipe_path"
     TARGET_DIR="${COOKBOOK_RECIPE}/target/${TARGET}"
     COOKBOOK_STAGE="${TARGET_DIR}/stage"
 
diff --git a/src/bin/cook.rs b/src/bin/cook.rs
index 9fe35867b6602e24674f8da1542a3a551fa3bbdb..6b00832e5ee4b3219f464cd22ca61be0d5479cb1 100644
--- a/src/bin/cook.rs
+++ b/src/bin/cook.rs
@@ -1,6 +1,7 @@
 use cookbook::blake3::blake3_progress;
 use cookbook::recipe::{Recipe, SourceRecipe, BuildKind, BuildRecipe, PackageRecipe};
 use cookbook::sha256::sha256_progress;
+use cookbook::recipe_find::recipe_find;
 use std::{
     env,
     fs,
@@ -399,7 +400,14 @@ fn build(recipe_dir: &Path, source_dir: &Path, target_dir: &Path, build: &BuildR
         for dependency in build.dependencies.iter() {
             let public_path = "build/id_ed25519.pub.toml";
             //TODO: sanitize name
-            let archive_path = format!("recipes/{}/target/{}/stage.pkgar", dependency, redoxer::target());
+            let dependency_dir = recipe_find(dependency, Path::new("recipes"))?;
+            if dependency_dir.is_none() {
+                return Err(format!(
+                    "failed to find recipe directory '{}'",
+                    dependency
+                ));
+            }
+            let archive_path = format!("{}/target/{}/stage.pkgar", dependency_dir.unwrap().display(), redoxer::target());
             pkgar::extract(
                 public_path,
                 &archive_path,
@@ -668,14 +676,14 @@ pub struct CookRecipe {
 impl CookRecipe {
     pub fn new(name: String) -> Result<Self, String> {
         //TODO: sanitize recipe name?
-        let dir = Path::new("recipes").join(&name);
-        if ! dir.is_dir() {
+        let dir = recipe_find(&name, Path::new("recipes"))?;
+        if dir.is_none() {
             return Err(format!(
                 "failed to find recipe directory '{}'",
-                dir.display()
+                name
             ));
         }
-
+        let dir = dir.unwrap();
         let file = dir.join("recipe.toml");
         if ! file.is_file() {
             return Err(format!(
diff --git a/src/bin/find_recipe.rs b/src/bin/find_recipe.rs
new file mode 100644
index 0000000000000000000000000000000000000000..ea84db432804b57bc9b934f261981ba7302305be
--- /dev/null
+++ b/src/bin/find_recipe.rs
@@ -0,0 +1,26 @@
+use cookbook::recipe_find::recipe_find;
+use std::env::args;
+use std::path::Path;
+use std::process::exit;
+// use clap::Parser;
+
+fn usage() {
+    println!("Usage: find_recipe recipe_name");
+}
+fn main() {
+    if args().len() != 2 {
+        usage();
+        exit(2);
+    }
+    let result = recipe_find(&args().last().unwrap(), Path::new("recipes"));
+    if result.is_err() {
+        eprintln!("{}", result.err().unwrap());
+        exit(2);
+    } else if result.as_ref().unwrap().is_none() {
+        eprintln!("recipe {} not found", &args().last().unwrap());
+        exit(1);
+    } else {
+        println!("{}", result.unwrap().unwrap().display());
+        exit(0);
+    }
+}
diff --git a/src/bin/list_recipes.rs b/src/bin/list_recipes.rs
new file mode 100644
index 0000000000000000000000000000000000000000..da3171e1e4e79a6d4cb3e85846c64f07a8e9b06c
--- /dev/null
+++ b/src/bin/list_recipes.rs
@@ -0,0 +1,19 @@
+use cookbook::recipe_find::list_recipes;
+use std::path::Path;
+use std::process::exit;
+// use clap::Parser;
+
+fn main() {
+
+    let result = list_recipes( Path::new("recipes"));
+    if result.is_err() {
+        eprintln!("{}", result.err().unwrap());
+        exit(2);
+    } else if result.as_ref().unwrap().is_empty() {
+        eprintln!("recipes not found");
+        exit(1);
+    } else {
+        result.unwrap().iter().for_each(|recipe| println!("{}", recipe));
+        exit(0);
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 2fbe53530eb8fd54eb204d29a87ae69c30fb6eea..572b1716f87dfa24d4175702651507d0fe4ac17f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,5 +1,6 @@
 pub mod blake3;
 pub mod recipe;
 pub mod sha256;
+pub mod recipe_find;
 
 mod progress_bar;
diff --git a/src/recipe_find.rs b/src/recipe_find.rs
new file mode 100644
index 0000000000000000000000000000000000000000..286e62a895ff60b0340ffb84df12153bef3a2831
--- /dev/null
+++ b/src/recipe_find.rs
@@ -0,0 +1,72 @@
+use std::fs::{self};
+use std::path::{Path, PathBuf};
+
+pub fn recipe_find(recipe: &str, dir: &Path) -> Result<Option<PathBuf>, String> {
+    let mut recipe_path = None;
+    if !dir.is_dir() {
+        return Ok(None);
+    }
+    for entry in fs::read_dir(dir).map_err(|e| e.to_string())? {
+        let entry = entry.map_err(|e| e.to_string())?;
+        if entry.file_name().to_string_lossy() == "recipe.sh"
+            || entry.file_name().to_string_lossy() == "recipe.toml"
+        {
+            // println!("recipe is {:?}", dir.file_name());
+            if dir.file_name().unwrap().to_string_lossy() != recipe {
+                return Ok(None);
+            } else {
+                return Ok(Some(dir.to_path_buf()));
+            }
+        }
+    }
+
+    for entry in fs::read_dir(dir).map_err(|e| e.to_string())? {
+        let entry = entry.map_err(|e| e.to_string())?;
+        if !entry.file_type().map_err(|e| e.to_string())?.is_dir() {
+            continue;
+        }
+        let found = recipe_find(recipe, entry.path().as_path())?;
+        if found.is_none() {
+            continue;
+        }
+        if recipe_path.is_none() {
+            recipe_path = found;
+        } else {
+            return Err(format!(
+                "recipe {} has two or more entries {}, {}",
+                recipe,
+                recipe_path.unwrap().display(),
+                found.unwrap().display()
+            ));
+        }
+    }
+
+    Ok(recipe_path)
+}
+
+pub fn list_recipes(dir: &Path) -> Result<Vec<String>, String> {
+    let mut recipes = Vec::<String>::new();
+    if !dir.is_dir() {
+        return Ok(recipes);
+    }
+    for entry in fs::read_dir(dir).map_err(|e| e.to_string())? {
+        let entry = entry.map_err(|e| e.to_string())?;
+        if entry.file_name().to_string_lossy() == "recipe.sh"
+            || entry.file_name().to_string_lossy() == "recipe.toml"
+        {
+            recipes.push(dir.file_name().ok_or(format!("could not unwrap the filename for {:?}", dir))?.to_string_lossy().to_string());
+            return Ok(recipes);
+        }
+    }
+
+    for entry in fs::read_dir(dir).map_err(|e| e.to_string())? {
+        let entry = entry.map_err(|e| e.to_string())?;
+        if !entry.file_type().map_err(|e| e.to_string())?.is_dir() {
+            continue;
+        }
+        let mut found = list_recipes(entry.path().as_path())?;
+        recipes.append(&mut found);
+    }
+    recipes.sort();
+    Ok(recipes)
+}
diff --git a/status.sh b/status.sh
index fe715ffcfd506b0953f20cfa5e8044485a6a5e46..19aa856e7124cf05f06123d1e9035e14bbf88cdf 100755
--- a/status.sh
+++ b/status.sh
@@ -5,14 +5,15 @@ source config.sh
 
 if [ $# = 0 ]
 then
-    recipes="$(ls -1 recipes)"
+    recipes="$(target/release/list_recipes)"
 else
     recipes="$@"
 fi
 
 for recipe in $recipes
 do
-    if [ -d "recipes/$recipe/source" ]
+    recipe_path=`target/release/find_recipe $recipe`
+    if [ -d "$recipe_path/source" ]
     then
         status="$(COOK_QUIET=1 ./cook.sh "$recipe" status)"
 
diff --git a/status_origin.sh b/status_origin.sh
index cf3e1ab43c9a4659d999778628788cbddd9876b5..b82bcedc74549f296a67ed6feef63129fafd3275 100755
--- a/status_origin.sh
+++ b/status_origin.sh
@@ -5,14 +5,15 @@ source config.sh
 
 if [ $# = 0 ]
 then
-    recipes="$(ls -1 recipes)"
+    recipes="$(target/release/list_recipes)"
 else
     recipes="$@"
 fi
 
 for recipe in $recipes
 do
-    if [ -d "recipes/$recipe/source" ]
+    recipe_path=`target/release/find_recipe $recipe`
+    if [ -d "$recipe_path/source" ]
     then
         status="$(COOK_QUIET=1 ./cook.sh "$recipe" status_origin)"
 
diff --git a/status_upstream.sh b/status_upstream.sh
index defd1c5399e54e2917f93ff0ef7bfa1ade5192c0..eb150c004f362e09fbc5fb67e50d2e4450e8699c 100755
--- a/status_upstream.sh
+++ b/status_upstream.sh
@@ -5,14 +5,15 @@ source config.sh
 
 if [ $# = 0 ]
 then
-    recipes="$(ls -1 recipes)"
+    recipes="$(target/release/list_recipes)"
 else
     recipes="$@"
 fi
 
 for recipe in $recipes
 do
-    if [ -d "recipes/$recipe/source" ]
+    recipe_path=`target/release/find_recipe $recipe`
+    if [ -d "$recipe_path/source" ]
     then
         status="$(COOK_QUIET=1 ./cook.sh "$recipe" status_upstream)"
 
diff --git a/unfetch.sh b/unfetch.sh
index a63be6a73edcec22674398f28fd8727021de865c..b6877cc3084510925f7d96a2e1da7b80113692d0 100755
--- a/unfetch.sh
+++ b/unfetch.sh
@@ -5,7 +5,7 @@ source config.sh
 
 if [ $# = 0 ]
 then
-    recipes="$(ls -1 recipes)"
+    recipes="$(target/release/list_recipes)"
 else
     recipes="$@"
 fi