diff --git a/bin/is b/bin/is
index 05b4e90a4310950bdeb8a940bf308fb20533eb99..b5505987693107d1ab935f9c082837739d214708 100755
--- a/bin/is
+++ b/bin/is
@@ -24,6 +24,10 @@ from installsystems.repository import RepositoryConfig
 from installsystems.image import PackageImage, SourceImage
 from installsystems.config import MainConfigFile, RepoConfigFile
 
+################################################################################
+# Common functions
+################################################################################
+
 def load_repositories(args):
     '''
     Load repositories on a repository manager
@@ -31,6 +35,10 @@ def load_repositories(args):
     # remove cache is asked
     if hasattr(args, "no_cache") and args.no_cache:
         args.cache = None
+    # split filter in list
+    if args.repo_filter is not None:
+        args.repo_filter = [f for f in  re.split("[ ,\n\t\v]+", args.repo_filter)
+                            if f != ""]
     # init repo cache object
     repoman = RepositoryManager(args.cache, timeout=args.timeout, filter=args.repo_filter)
     # register repositories (order matter)
@@ -56,19 +64,37 @@ def select_image(name, repoman, best=False):
 
     Return the repository as second argument
     '''
+    # image is a local file
     if istools.isfile(name) and os.path.isfile(name):
         return PackageImage(name), None
+    # we need to find image in a repository
     else:
-        x = re.match("^(([-_\w]+)/)?([-_\w]+)(:v?(\d+))?$", name)
-        if x is None:
-            raise Exception("%s is not a valid image" % name)
-        (repo, image, version) = x.group(2,3,5)
-        debug("Selected image is %s v%s in %s" % (image, version, repo))
+        if len(repoman.onlines) == 0:
+            raise Exception('No online repository')
+        (repo, image, version) = istools.split_image_path(name)
+        debug("Requested image: %s v%s in %s" % (image, version, repo))
+        # repo is not specified, we need to crawl in path
         if repo is None:
-            return repoman.get(image, version, best)
+            # split search path as a list
+            if args.repo_search is not None:
+                args.repo_search = [s for s in re.split("[ ,\n\t\v]+", args.repo_search)
+                                    if s in repoman.onlines]
+            else:
+                args.repo_search = []
+            # if we have only one repo, search in it
+            if len(args.repo_search) == 0 and len(repoman.onlines) == 1:
+                args.repo_search = repoman.onlines
+            elif len(args.repo_search) == 0 and len(repoman.onlines) > 1:
+                raise Exception('You must use a full image path or set a valid search path')
+            return repoman.get(image, version, search=args.repo_search, best=best)
+        # we can ask directly repository about image
         else:
             return repoman[repo].get(image, version), repoman[repo]
 
+################################################################################
+# Commands functions
+################################################################################
+
 def c_add(parser, args):
     '''
     Add an image package into a repository
@@ -328,6 +354,10 @@ def c_version(parser, args):
     '''
     out(installsystems.version)
 
+################################################################################
+# Parser definition
+################################################################################
+
 # Top level argument parsing
 p_main = argparse.ArgumentParser()
 p_main.add_argument("-V", "--version", action="version",
@@ -340,22 +370,24 @@ ex_group.add_argument("-d", "--debug", action="store_true", default=None,
 ex_group.add_argument("-q", "--quiet", action="store_true", default=None,
                       help="active quiet mode")
 # common options
-p_main.add_argument("-c", "--config", default="installsystems",
+p_main.add_argument("-c", "--config", default="installsystems", metavar="PATH",
                     help="config file path")
-p_main.add_argument("-R", "--repo-config", default="repository",
+p_main.add_argument("-R", "--repo-config", default="repository", metavar="REPO",
                     help="repository config file path")
-p_main.add_argument("-f", "--repo-filter", default=None,
-                    help="select repository by name in config files")
-p_main.add_argument("-r", "--repo-path", default=None,
-                    help="repository path")
-p_main.add_argument("-C", "--cache", default=None,
+p_main.add_argument("-s", "--repo-search", metavar="REPO,REPO,...",
+                    help="search for images inside those repositories")
+p_main.add_argument("-f", "--repo-filter", metavar="REPO,REPO,...",
+                    help="filter repositories by name")
+p_main.add_argument("-r", "--repo-path", metavar="PATH",
+                    help="define a temporary repository")
+p_main.add_argument("-C", "--cache", metavar="PATH",
                     help="path of the repository cache")
 p_main.add_argument("--no-cache", action="store_true", default=None,
                     help="not use persistent db caching")
 p_main.add_argument("--no-color", action="store_true", default=None,
                     help="dot not display colored output")
 p_main.add_argument("-t", "--timeout", dest="timeout", type=int, default=None,
-                    help="download timeout (default 3)")
+                    metavar="SECONDS", help="download timeout (default 3)")
 
 # create a subparsers for each command
 subparsers = p_main.add_subparsers()
@@ -382,7 +414,7 @@ p_build.set_defaults(func=c_build)
 # cat command parser
 p_cat = subparsers.add_parser("cat", help=c_cat.__doc__.lower())
 p_cat.add_argument("-b", "--best", action="store_true", default=False,
-                   help="in best mode, image is the most recent in all repositories")
+                   help="take the most recent image in all searchable repositories")
 p_cat.add_argument("image", help="<path|[repository/]image[:version]>")
 p_cat.add_argument("file", nargs="+",
                    help="file inside image to cat (globbing allowed)")
@@ -391,7 +423,7 @@ p_cat.set_defaults(func=c_cat)
 # changelog command parser
 p_changelog = subparsers.add_parser("changelog", help=c_changelog.__doc__.lower())
 p_changelog.add_argument("-b", "--best", action="store_true", default=False,
-                         help="in best mode, image is the most recent in all repositories")
+                         help="take the most recent image in all searchable repositories")
 p_changelog.add_argument("-v", "--all-version",  action="store_true", default=False,
                          help="display changelog for all versions")
 p_changelog.add_argument("image", help="<path|[repository/]image[:version]>")
@@ -419,7 +451,7 @@ p_clean.set_defaults(func=c_clean)
 # copy command parser
 p_copy = subparsers.add_parser("copy", help=c_copy.__doc__.lower())
 p_copy.add_argument("-b", "--best", action="store_true", default=False,
-                   help="in best mode, image is the most recent in all repositories")
+                   help="take the most recent image in all searchable repositories")
 p_copy.add_argument("image", nargs="+",
                     help="image syntax is <path|[repository/]image[:version]>")
 p_copy.add_argument("repository", help="destination repository")
@@ -430,7 +462,7 @@ p_del =  subparsers.add_parser("del", help=c_del.__doc__.lower())
 p_del.add_argument("image", nargs="+",
                    help="image syntax is <path|[repository/]image[:version]>")
 p_del.add_argument("-b", "--best", action="store_true", default=False,
-                   help="in best mode, image is the most recent in all repositories")
+                   help="take the most recent image in all searchable repositories")
 p_del.add_argument("-f", "--force", action="store_true", default=False,
                    help="delete image without confirmation")
 p_del.add_argument("-p", "--preserve", action="store_true", default=False,
@@ -442,13 +474,13 @@ p_diff = subparsers.add_parser("diff", help=c_diff.__doc__.lower())
 p_diff.add_argument("object", nargs=2,
                     help="object syntax is <path|repository|[repository/]image[:version]>")
 p_diff.add_argument("-b", "--best", action="store_true", default=False,
-                    help="in best mode, image is the most recent in all repositories")
+                    help="take the most recent image in all searchable repositories")
 p_diff.set_defaults(func=c_diff)
 
 # extract command parser
 p_extract = subparsers.add_parser("extract", help=c_extract.__doc__.lower())
 p_extract.add_argument("-b", "--best", action="store_true", default=False,
-                       help="in best mode, image is the most recent in all repositories")
+                       help="take the most recent image in all searchable repositories")
 p_extract.add_argument("-f", "--force", action="store_true", default=False,
                        help="overwrite existing destinations")
 p_extract.add_argument("-g", "--gen-description", action="store_true", default=False,
@@ -463,7 +495,7 @@ p_extract.set_defaults(func=c_extract)
 # get command parser
 p_get = subparsers.add_parser("get", help=c_get.__doc__.lower())
 p_get.add_argument("-b", "--best", action="store_true", default=False,
-                   help="in best mode, image is the most recent in all repositories")
+                   help="take the most recent image in all searchable repositories")
 p_get.add_argument("-f", "--force", action="store_true", default=False,
                    help="overwrite existing destinations")
 p_get.add_argument("-I", "--no-image", action="store_true", default=False,
@@ -482,7 +514,7 @@ p_help.set_defaults(func=c_help, subparser=subparsers)
 # info command parser
 p_info = subparsers.add_parser("info", help=c_info.__doc__.lower())
 p_info.add_argument("-b", "--best", action="store_true", default=False,
-                    help="in best mode, image is the most recent in all repositories")
+                    help="take the most recent image in all searchable repositories")
 p_info.add_argument("-c", "--changelog", action="store_true", default=False,
                     help="display image changelog")
 p_info.add_argument("-v", "--verbose", action="store_true", default=False,
@@ -535,7 +567,7 @@ p_list.set_defaults(func=c_list)
 # move command parser
 p_move = subparsers.add_parser("move", help=c_move.__doc__.lower())
 p_move.add_argument("-b", "--best", action="store_true", default=False,
-                    help="in best mode, image is the most recent in all repositories")
+                    help="take the most recent image in all searchable repositories")
 p_move.add_argument("-f", "--force", action="store_true", default=False,
                     help="move image without confirmation")
 p_move.add_argument("image", nargs="+",
@@ -594,6 +626,10 @@ p_unprepare_chroot.set_defaults(func=c_unprepare_chroot)
 p_version = subparsers.add_parser("version", help=c_version.__doc__.lower())
 p_version.set_defaults(func=c_version)
 
+################################################################################
+# Main
+################################################################################
+
 try:
     # first (partial) parsing
     args = p_main.parse_known_args()[0]
diff --git a/installsystems/config.py b/installsystems/config.py
index 78fd510a11e271637de6e6ce58c9f9a7e9525bae..7fef69d6d273b19c620a650c725ce16ed8554d47 100644
--- a/installsystems/config.py
+++ b/installsystems/config.py
@@ -51,6 +51,8 @@ class MainConfigFile(ConfigFile):
     Program configuration file
     '''
 
+    valid_options = ("debug", "quiet", "no_cache", "no_color", "timeout", "cache", "repo_search", "repo_filter", "repo_config")
+
     def __init__(self, filename, prefix=os.path.basename(sys.argv[0])):
         self.prefix = prefix
         ConfigFile.__init__(self, filename)
@@ -81,8 +83,14 @@ class MainConfigFile(ConfigFile):
         Merge current loaded option with a namespace from argparse
         '''
         for option, value in self._config.items():
+            # check option is valid
+            if option not in self.valid_options:
+                warn("Invalid option %s in %s, skipped" % (option, self.path))
+                continue
+            # no option is specified in command line, set it
             if not hasattr(namespace, option):
                 setattr(namespace, option, value)
+            # handle by default none options
             elif getattr(namespace, option) == None:
                 # we need to handle boolean differently
                 if option in ("debug", "quiet", "no_cache", "no_color"):
@@ -94,11 +102,12 @@ class MainConfigFile(ConfigFile):
                     except ValueError:
                         raise Exception("Invalid %s: Not a number" % option)
                     setattr(namespace, option, n)
-                # we can handle string more carefuly
-                elif option in ("cache", "repo_filter", "repo_config"):
+                # handle strings
+                elif option in ("cache", "repo_search", "repo_filter"):
                     setattr(namespace, option, value)
-                else:
-                    warn("Invalid option %s in %s, skipped" % (option, self.path))
+            # repo_config is a special parameter, default value is repository
+            elif option == "repo_config" and option.repo_config == "repository":
+                setattr(namespace, option, value)
 
     def _cache_paths(self):
         '''
diff --git a/installsystems/repository.py b/installsystems/repository.py
index ede1ac9757e6f3892a4c0eadc77b25f22272ea30..8128c0fc52c0994cfc5eb00affdf1f67da7f9f9d 100644
--- a/installsystems/repository.py
+++ b/installsystems/repository.py
@@ -391,7 +391,8 @@ class Repository(object):
         r = self.db.ask("select md5 from image where name = ? and version = ? limit 1",
                         (name, version)).fetchone()
         if r is None:
-            raise Exception("Unable to find image %s v%s" % (name, version))
+            raise Exception("Unable to find image %s v%s in %s" % (name, version,
+                                                                   self.config.name))
         path = os.path.join(self.config.path, r[0])
         # getting the file
         arrow("Loading image %s v%s from repository %s" % (name,
@@ -436,7 +437,7 @@ class RepositoryManager(object):
         self.timeout = 3 if timeout is None else timeout
         self.repos = []
         self.tempfiles = []
-        self.filter = filter
+        self.filter = [] if filter is None else filter
         if cache_path is None:
             self.cache_path = None
             debug("No repository cache")
@@ -500,8 +501,9 @@ class RepositoryManager(object):
         offline: repository is marked offline
         '''
         # check filter on name
-        if self.filter is not None:
-            if not fnmatch.fnmatch(config.name, self.filter):
+        if len(self.filter) > 0:
+            if config.name not in self.filter:
+                debug("Filtering repository %s" % config.name)
                 return
         # repository is offline
         if config.offline or offline:
@@ -622,19 +624,20 @@ class RepositoryManager(object):
                         del images["%s/%s:%s" % (repo, img, rmv)]
         return images
 
-    def get(self, name, version=None, best=False):
+    def get(self, name, version=None, search=None, best=False):
         '''
-        Crawl repositories to get an image
+        Crawl searchable repositories to get an image
 
         best mode search the most recent version accross all repo
         else it search the first match
         '''
+        if search is None:
+            search = []
         # search last version if needed
         if version is None:
             version = -1
-            for repo in self.repos:
-                if repo.config.offline: continue
-                current = repo.last(name)
+            for repo in search:
+                current = self[repo].last(name)
                 # if not best mode, we found our version
                 if not best and current > 0:
                     version = current
@@ -642,13 +645,14 @@ class RepositoryManager(object):
                 version = max(version, current)
             # if version < 0, il n'y a pas d'image
             if version < 0:
-                raise Exception("Unable to find image %s" % name)
+                raise Exception("Unable to find image %s in %s" % (
+                        name, search))
         # search image in repos
-        for repo in self.repos:
-            if repo.config.offline:  continue
-            if repo.has(name, version):
-                return repo.get(name, version), repo
-        raise Exception("Unable to find image %s v%s" % (name, version))
+        for repo in search:
+            if self[repo].has(name, version):
+                return self[repo].get(name, version), repo
+        raise Exception("No image %s v%s in %s" % (
+                name, version, search))
 
     def show_repos(self, pattern, local=None, online=None, url=False, state=True):
         '''
@@ -722,8 +726,7 @@ class RepositoryManager(object):
         '''
         Search pattern accross all registered repositories
         '''
-        for repo in self.repos:
-            if repo.config.offline:  continue
+        for repo in self.onlines:
             arrow(repo.config.name)
             repo.search(pattern)
 
diff --git a/installsystems/tools.py b/installsystems/tools.py
index 713dd35544e0e32c6af1c45fcd1a4462534cfdb2..757ffd2ae4ce2eaa2c74e4340d3222d0b0c69378 100644
--- a/installsystems/tools.py
+++ b/installsystems/tools.py
@@ -493,3 +493,13 @@ def compare_versions(v1, v2):
     fv1 = get_ver(v1)
     fv2 = get_ver(v2)
     return fv1 - fv2
+
+def split_image_path(path):
+    '''
+    Split an image path (repo/image:version)
+    in a tuple (repo, image, version)
+    '''
+    x = re.match(u"^(?:([-_\w]+)/)?([-_\w]+)(?::v?(\d+))?$", path)
+    if x is None:
+        raise Exception("invalid image path: %s" % path)
+    return x.group(1,2,3)
diff --git a/samples/installsystems.conf b/samples/installsystems.conf
index 4808d260c892d92265fb4d56b09d82a277bde7ef..c8b5f2430a87ed667279b9d563d2bae7d7a40af5 100644
--- a/samples/installsystems.conf
+++ b/samples/installsystems.conf
@@ -23,8 +23,11 @@
 # define connection timeout
 #timeout = 30
 
-# default repository name
-#repo_filter = local
+# search images inside repositories
+#repo_search = stable testing
+
+# filter repository list
+#repo_filter = stable testing
 
 # custom repository config file
 #repo_config =