diff --git a/.gitignore b/.gitignore
index 828fb04e7d07648c6bed803ec23aa73216c8bb22..1c6ca4c99e181cc853d9dd78e685a0a912b913cc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@
 *~
 .DS_Store
 .idea
+/etc/spack/*
 /etc/spackconfig
 /share/spack/dotkit
 /share/spack/modules
diff --git a/lib/spack/spack/cmd/compiler.py b/lib/spack/spack/cmd/compiler.py
index e37f44b3b7290d5467424caa85df3cd536543b3e..2a64dc914ed53cf65c12e879057f3ab3cb020579 100644
--- a/lib/spack/spack/cmd/compiler.py
+++ b/lib/spack/spack/cmd/compiler.py
@@ -68,7 +68,7 @@ def compiler_add(args):
         spack.compilers.add_compilers_to_config('user', *compilers)
         n = len(compilers)
         tty.msg("Added %d new compiler%s to %s" % (
-            n, 's' if n > 1 else '', spack.config.get_filename('user')))
+            n, 's' if n > 1 else '', spack.config.get_config_scope_filename('user', 'compilers')))
         colify(reversed(sorted(c.spec for c in compilers)), indent=4)
     else:
         tty.msg("Found no new compilers")
diff --git a/lib/spack/spack/cmd/config.py b/lib/spack/spack/cmd/config.py
index 283bfc19b9f2dd18fb36f41b9e93455b66e25088..8c18f88b648179ba2a9a24fc62ebd2c79bb1df5b 100644
--- a/lib/spack/spack/cmd/config.py
+++ b/lib/spack/spack/cmd/config.py
@@ -43,42 +43,27 @@ def setup_parser(subparser):
 
     sp = subparser.add_subparsers(metavar='SUBCOMMAND', dest='config_command')
 
-    set_parser = sp.add_parser('set', help='Set configuration values.')
-    set_parser.add_argument('key', help="Key to set value for.")
-    set_parser.add_argument('value', nargs='?', default=None,
-                            help="Value to associate with key")
-
-    get_parser = sp.add_parser('get', help='Get configuration values.')
-    get_parser.add_argument('key', help="Key to get value for.")
+    get_parser = sp.add_parser('get', help='Print configuration values.')
+    get_parser.add_argument('category', help="Configuration category to print.")
 
     edit_parser = sp.add_parser('edit', help='Edit configuration file.')
-
-
-def config_set(args):
-    # default scope for writing is 'user'
-    if not args.scope:
-        args.scope = 'user'
-
-    config = spack.config.get_config(args.scope)
-    config.set_value(args.key, args.value)
-    config.write()
+    edit_parser.add_argument('category', help="Configuration category to edit")
 
 
 def config_get(args):
-    config = spack.config.get_config(args.scope)
-    print config.get_value(args.key)
+    spack.config.print_category(args.category)
 
 
 def config_edit(args):
     if not args.scope:
         args.scope = 'user'
-    config_file = spack.config.get_filename(args.scope)
+    if not args.category:
+        args.category = None
+    config_file = spack.config.get_config_scope_filename(args.scope, args.category)
     spack.editor(config_file)
 
 
 def config(parser, args):
-    action = { 'set'  : config_set,
-               'get'  : config_get,
+    action = { 'get' : config_get,
                'edit' : config_edit }
     action[args.config_command](args)
-
diff --git a/lib/spack/spack/cmd/mirror.py b/lib/spack/spack/cmd/mirror.py
index 22838e134499295b789767b862ccb378a0443a7c..02a1467ee63294800bdd5ffc649ca89a9c2b45d9 100644
--- a/lib/spack/spack/cmd/mirror.py
+++ b/lib/spack/spack/cmd/mirror.py
@@ -75,27 +75,22 @@ def mirror_add(args):
     if url.startswith('/'):
         url = 'file://' + url
 
-    config = spack.config.get_config('user')
-    config.set_value('mirror', args.name, 'url', url)
-    config.write()
+    mirror_dict = { args.name : url }
+    spack.config.add_to_mirror_config({ args.name : url })
 
 
 def mirror_remove(args):
     """Remove a mirror by name."""
-    config = spack.config.get_config('user')
     name = args.name
 
-    if not config.has_named_section('mirror', name):
+    rmd_something = spack.config.remove_from_config('mirrors', name)
+    if not rmd_something:
         tty.die("No such mirror: %s" % name)
-    config.remove_named_section('mirror', name)
-    config.write()
 
 
 def mirror_list(args):
     """Print out available mirrors to the console."""
-    config = spack.config.get_config()
-    sec_names = config.get_section_names('mirror')
-
+    sec_names = spack.config.get_mirror_config()
     if not sec_names:
         tty.msg("No mirrors configured.")
         return
@@ -103,8 +98,7 @@ def mirror_list(args):
     max_len = max(len(s) for s in sec_names)
     fmt = "%%-%ds%%s" % (max_len + 4)
 
-    for name in sec_names:
-        val = config.get_value('mirror', name, 'url')
+    for name, val in sec_names.iteritems():
         print fmt % (name, val)
 
 
diff --git a/lib/spack/spack/compilers/__init__.py b/lib/spack/spack/compilers/__init__.py
index 8cb11c32085d0938b475a214fb5b36d20a8fd401..b7b021a1ac88dcd95aace14b6e83a9cd8d1f5fb3 100644
--- a/lib/spack/spack/compilers/__init__.py
+++ b/lib/spack/spack/compilers/__init__.py
@@ -60,24 +60,25 @@ def _get_config():
        first."""
     # If any configuration file has compilers, just stick with the
     # ones already configured.
-    config = spack.config.get_config()
+    config = spack.config.get_compilers_config()
     existing = [spack.spec.CompilerSpec(s)
-                for s in config.get_section_names('compiler')]
+                for s in config]
     if existing:
         return config
 
     compilers = find_compilers(*get_path('PATH'))
-    new_compilers = [
-        c for c in compilers if c.spec not in existing]
-    add_compilers_to_config('user', *new_compilers)
+    add_compilers_to_config('user', *compilers)
 
     # After writing compilers to the user config, return a full config
     # from all files.
-    return spack.config.get_config(refresh=True)
+    return spack.config.get_compilers_config()
 
 
-@memoized
+_cached_default_compiler = None
 def default_compiler():
+    global _cached_default_compiler
+    if _cached_default_compiler:
+        return _cached_default_compiler
     versions = []
     for name in _default_order:  # TODO: customize order.
         versions = find(name)
@@ -86,7 +87,8 @@ def default_compiler():
     if not versions:
         raise NoCompilersError()
 
-    return sorted(versions)[-1]
+    _cached_default_compiler = sorted(versions)[-1]
+    return _cached_default_compiler
 
 
 def find_compilers(*path):
@@ -122,19 +124,17 @@ def find_compilers(*path):
 
 
 def add_compilers_to_config(scope, *compilers):
-    config = spack.config.get_config(scope)
+    compiler_config_tree = {}
     for compiler in compilers:
-        add_compiler(config, compiler)
-    config.write()
-
-
-def add_compiler(config, compiler):
-    def setup_field(cspec, name, exe):
-        path = exe if exe else "None"
-        config.set_value('compiler', cspec, name, path)
+        compiler_entry = {}
+        for c in _required_instance_vars:
+            val = getattr(compiler, c)
+            if not val:
+                val = "None"
+            compiler_entry[c] = val
+        compiler_config_tree[str(compiler.spec)] = compiler_entry
+    spack.config.add_to_compiler_config(compiler_config_tree, scope)
 
-    for c in _required_instance_vars:
-        setup_field(compiler.spec, c, getattr(compiler, c))
 
 
 def supported_compilers():
@@ -157,8 +157,7 @@ def all_compilers():
        available to build with.  These are instances of CompilerSpec.
     """
     configuration = _get_config()
-    return [spack.spec.CompilerSpec(s)
-            for s in configuration.get_section_names('compiler')]
+    return [spack.spec.CompilerSpec(s) for s in configuration]
 
 
 @_auto_compiler_spec
@@ -176,7 +175,7 @@ def compilers_for_spec(compiler_spec):
     config = _get_config()
 
     def get_compiler(cspec):
-        items = dict((k,v) for k,v in config.items('compiler "%s"' % cspec))
+        items = config[str(cspec)]
 
         if not all(n in items for n in _required_instance_vars):
             raise InvalidCompilerConfigurationError(cspec)
diff --git a/lib/spack/spack/config.py b/lib/spack/spack/config.py
index 85ee16a1c2070a3eb58fc7cdee6ff122b827c27e..34dee864732115236b0a8f27a77148ae94eb28ab 100644
--- a/lib/spack/spack/config.py
+++ b/lib/spack/spack/config.py
@@ -28,452 +28,315 @@
 ===============================
 
 When Spack runs, it pulls configuration data from several config
-files, much like bash shells.  In Spack, there are two configuration
-scopes:
+directories, each of which contains configuration files.  In Spack,
+there are two configuration scopes:
 
  1. ``site``: Spack loads site-wide configuration options from
-   ``$(prefix)/etc/spackconfig``.
+   ``$(prefix)/etc/spack/``.
 
  2. ``user``: Spack next loads per-user configuration options from
-    ~/.spackconfig.
-
-If user options have the same names as site options, the user options
-take precedence.
+    ~/.spack/.
 
+Spack may read configuration files from both of these locations.  When
+configurations conflict, the user config options take precedence over
+the site configurations.  Each configuration directory may contain
+several configuration files, such as compilers.yaml or mirrors.yaml.
 
 Configuration file format
 ===============================
 
-Configuration files are formatted using .gitconfig syntax, which is
-much like Windows .INI format.  This format is implemented by Python's
-ConfigParser class, and it's easy to read and versatile.
-
-The file is divided into sections, like this ``compiler`` section::
-
-     [compiler]
-         cc = /usr/bin/gcc
-
-In each section there are options (cc), and each option has a value
-(/usr/bin/gcc).
-
-Borrowing from git, we also allow named sections, e.g.:
-
-     [compiler "gcc@4.7.3"]
-         cc = /usr/bin/gcc
-
-This is a compiler section, but it's for the specific compiler,
-``gcc@4.7.3``.  ``gcc@4.7.3`` is the name.
-
-
-Keys
-===============================
-
-Together, the section, name, and option, separated by periods, are
-called a ``key``.  Keys can be used on the command line to set
-configuration options explicitly (this is also borrowed from git).
-
-For example, to change the C compiler used by gcc@4.7.3, you could do
-this:
-
-    spack config compiler.gcc@4.7.3.cc /usr/local/bin/gcc
-
-That will create a named compiler section in the user's .spackconfig
-like the one shown above.
+Configuration files are formatted using YAML syntax.
+This format is implemented by Python's
+yaml class, and it's easy to read and versatile.
+
+The config files are structured as trees, like this ``compiler`` section::
+
+     compilers:
+       chaos_5_x86_64_ib:
+          gcc@4.4.7:
+            cc: /usr/bin/gcc
+            cxx: /usr/bin/g++
+            f77: /usr/bin/gfortran
+            fc: /usr/bin/gfortran
+       bgqos_0:
+          xlc@12.1:
+            cc: /usr/local/bin/mpixlc
+            ...
+
+In this example, entries like ''compilers'' and ''xlc@12.1'' are used to
+categorize entries beneath them in the tree.  At the root of the tree,
+entries like ''cc'' and ''cxx'' are specified as name/value pairs.
+
+Spack returns these trees as nested dicts.  The dict for the above example
+would looks like:
+
+  { 'compilers' :
+      { 'chaos_5_x86_64_ib' :
+         { 'gcc@4.4.7' :
+             { 'cc' : '/usr/bin/gcc',
+               'cxx' : '/usr/bin/g++'
+               'f77' : '/usr/bin/gfortran'
+               'fc' : '/usr/bin/gfortran' }
+         }
+     { 'bgqos_0' :
+         { 'cc' : '/usr/local/bin/mpixlc' }
+     }
+  }
+
+Some routines, like get_mirrors_config and get_compilers_config may strip
+off the top-levels of the tree and return subtrees.
 """
 import os
-import re
-import inspect
-import ConfigParser as cp
+import exceptions
+import sys
 
 from external.ordereddict import OrderedDict
 from llnl.util.lang import memoized
 import spack.error
 
-__all__ = [
-    'SpackConfigParser', 'get_config', 'SpackConfigurationError',
-    'InvalidConfigurationScopeError', 'InvalidSectionNameError',
-    'ReadOnlySpackConfigError', 'ConfigParserError', 'NoOptionError',
-    'NoSectionError']
-
-_named_section_re = r'([^ ]+) "([^"]+)"'
+from contextlib import closing
+from external import yaml
+from external.yaml.error import MarkedYAMLError
+import llnl.util.tty as tty
+from llnl.util.filesystem import mkdirp
+
+_config_sections = {}
+class _ConfigCategory:
+    name = None
+    filename = None
+    merge = True
+    def __init__(self, n, f, m):
+        self.name = n
+        self.filename = f
+        self.merge = m
+        self.files_read_from = []
+        self.result_dict = {}
+        _config_sections[n] = self
+
+_ConfigCategory('compilers', 'compilers.yaml', True)
+_ConfigCategory('mirrors', 'mirrors.yaml', True)
+_ConfigCategory('view', 'views.yaml', True)
+_ConfigCategory('order', 'orders.yaml', True)
 
 """Names of scopes and their corresponding configuration files."""
-_scopes = OrderedDict({
-    'site' : os.path.join(spack.etc_path, 'spackconfig'),
-    'user' : os.path.expanduser('~/.spackconfig')
-})
-
-_field_regex = r'^([\w-]*)'        \
-               r'(?:\.(.*(?=.)))?' \
-               r'(?:\.([\w-]+))?$'
-
-_section_regex = r'^([\w-]*)\s*' \
-                 r'\"([^"]*\)\"$'
-
-
-# Cache of configs -- we memoize this for performance.
-_config = {}
-
-def get_config(scope=None, **kwargs):
-    """Get a Spack configuration object, which can be used to set options.
-
-       With no arguments, this returns a SpackConfigParser with config
-       options loaded from all config files.  This is how client code
-       should read Spack configuration options.
-
-       Optionally, a scope parameter can be provided.  Valid scopes
-       are ``site`` and ``user``.  If a scope is provided, only the
-       options from that scope's configuration file are loaded.  The
-       caller can set or unset options, then call ``write()`` on the
-       config object to write it back out to the original config file.
-
-       By default, this will cache configurations and return the last
-       read version of the config file.  If the config file is
-       modified and you need to refresh, call get_config with the
-       refresh=True keyword argument.  This will force all files to be
-       re-read.
-    """
-    refresh = kwargs.get('refresh', False)
-    if refresh:
-        _config.clear()
-
-    if scope not in _config:
-        if scope is None:
-            _config[scope] = SpackConfigParser([path for path in _scopes.values()])
-        elif scope not in _scopes:
-            raise UnknownConfigurationScopeError(scope)
+config_scopes = [('site', os.path.join(spack.etc_path, 'spack')),
+                 ('user', os.path.expanduser('~/.spack'))]
+
+_compiler_by_arch = {}
+_read_config_file_result = {}
+def _read_config_file(filename):
+    """Read a given YAML configuration file"""
+    global _read_config_file_result
+    if filename in _read_config_file_result:
+        return _read_config_file_result[filename]
+
+    try:
+        with open(filename) as f:
+            ydict = yaml.load(f)
+    except MarkedYAMLError, e:
+        tty.die("Error parsing yaml%s: %s" % (str(e.context_mark), e.problem))
+    except exceptions.IOError, e:
+        _read_config_file_result[filename] = None
+        return None
+    _read_config_file_result[filename] = ydict
+    return ydict
+
+
+def clear_config_caches():
+    """Clears the caches for configuration files, which will cause them
+       to be re-read upon the next request"""
+    for key,s in _config_sections.iteritems():
+        s.files_read_from = []
+        s.result_dict = {}
+    spack.config._read_config_file_result = {}
+    spack.config._compiler_by_arch = {}
+    spack.compilers._cached_default_compiler = None
+
+
+def _merge_dicts(d1, d2):
+    """Recursively merges two configuration trees, with entries
+       in d2 taking precedence over d1"""
+    if not d1:
+        return d2.copy()
+    if not d2:
+        return d1
+
+    for key2, val2 in d2.iteritems():
+        if not key2 in d1:
+            d1[key2] = val2
+            continue
+        val1 = d1[key2]
+        if isinstance(val1, dict) and isinstance(val2, dict):
+            d1[key2] = _merge_dicts(val1, val2)
+            continue
+        if isinstance(val1, list) and isinstance(val2, list):
+            val1.extend(val2)
+            seen = set()
+            d1[key2] = [ x for x in val1 if not (x in seen or seen.add(x)) ]
+            continue
+        d1[key2] = val2
+    return d1
+
+
+def get_config(category_name):
+    """Get the confguration tree for the names category.  Strips off the
+       top-level category entry from the dict"""
+    global config_scopes
+    category = _config_sections[category_name]
+    if category.result_dict:
+        return category.result_dict
+
+    category.result_dict = {}
+    for scope, scope_path in config_scopes:
+        path = os.path.join(scope_path, category.filename)
+        result = _read_config_file(path)
+        if not result:
+            continue
+        if not category_name in result:
+            continue
+        category.files_read_from.insert(0, path)
+        result = result[category_name]
+        if category.merge:
+            category.result_dict = _merge_dicts(category.result_dict, result)
         else:
-            _config[scope] = SpackConfigParser(_scopes[scope])
-
-    return _config[scope]
-
-
-def get_filename(scope):
-    """Get the filename for a particular config scope."""
-    if not scope in _scopes:
-        raise UnknownConfigurationScopeError(scope)
-    return _scopes[scope]
-
-
-def _parse_key(key):
-    """Return the section, name, and option the field describes.
-       Values are returned in a 3-tuple.
-
-       e.g.:
-       The field name ``compiler.gcc@4.7.3.cc`` refers to the 'cc' key
-       in a section that looks like this:
-
-          [compiler "gcc@4.7.3"]
-              cc = /usr/local/bin/gcc
-
-       * The section is ``compiler``
-       * The name is ``gcc@4.7.3``
-       * The key is ``cc``
-    """
-    match = re.search(_field_regex, key)
-    if match:
-        return match.groups()
+            category.result_dict = result
+    return category.result_dict
+
+
+def get_compilers_config(arch=None):
+    """Get the compiler configuration from config files for the given
+       architecture.  Strips off the architecture component of the
+       configuration"""
+    global _compiler_by_arch
+    if not arch:
+        arch = spack.architecture.sys_type()
+    if arch in _compiler_by_arch:
+        return _compiler_by_arch[arch]
+
+    cc_config = get_config('compilers')
+    if arch in cc_config and 'all' in cc_config:
+        arch_compiler = dict(cc_config[arch])
+        _compiler_by_arch[arch] = _merge_dict(arch_compiler, cc_config['all'])
+    elif arch in cc_config:
+        _compiler_by_arch[arch] = cc_config[arch]
+    elif 'all' in cc_config:
+        _compiler_by_arch[arch] = cc_config['all']
     else:
-        raise InvalidSectionNameError(key)
-
-
-def _make_section_name(section, name):
-    if not name:
-        return section
-    return '%s "%s"' % (section, name)
-
-
-def _autokey(fun):
-    """Allow a function to be called with a string key like
-       'compiler.gcc.cc', or with the section, name, and option
-       separated. Function should take at least three args, e.g.:
-
-           fun(self, section, name, option, [...])
-
-       This will allow the function above to be called normally or
-       with a string key, e.g.:
-
-           fun(self, key, [...])
-    """
-    argspec = inspect.getargspec(fun)
-    fun_nargs = len(argspec[0])
-
-    def string_key_func(*args):
-        nargs = len(args)
-        if nargs == fun_nargs - 2:
-            section, name, option = _parse_key(args[1])
-            return fun(args[0], section, name, option, *args[2:])
-
-        elif nargs == fun_nargs:
-            return fun(*args)
-
-        else:
-            raise TypeError(
-                "%s takes %d or %d args (found %d)."
-                % (fun.__name__, fun_nargs - 2, fun_nargs, len(args)))
-    return string_key_func
-
-
-
-class SpackConfigParser(cp.RawConfigParser):
-    """Slightly modified from Python's raw config file parser to accept
-       leading whitespace and preserve comments.
-    """
-    # Slightly modify Python option expressions to allow leading whitespace
-    OPTCRE    = re.compile(r'\s*' + cp.RawConfigParser.OPTCRE.pattern)
-
-    def __init__(self, file_or_files):
-        cp.RawConfigParser.__init__(self, dict_type=OrderedDict)
-
-        if isinstance(file_or_files, basestring):
-            self.read([file_or_files])
-            self.filename = file_or_files
-
-        else:
-            self.read(file_or_files)
-            self.filename = None
-
-
-    @_autokey
-    def set_value(self, section, name, option, value):
-        """Set the value for a key.  If the key is in a section or named
-           section that does not yet exist, add that section.
-        """
-        sn = _make_section_name(section, name)
-        if not self.has_section(sn):
-            self.add_section(sn)
-
-        # Allow valueless config options to be set like this:
-        #     spack config set mirror https://foo.bar.com
-        #
-        # Instead of this, which parses incorrectly:
-        #     spack config set mirror.https://foo.bar.com
-        #
-        if option is None:
-            option = value
-            value = None
-
-        self.set(sn, option, value)
-
-
-    @_autokey
-    def get_value(self, section, name, option):
-        """Get the value for a key.  Raises NoOptionError or NoSectionError if
-           the key is not present."""
-        sn = _make_section_name(section, name)
-
+        _compiler_by_arch[arch] = {}
+    return _compiler_by_arch[arch]
+
+
+def get_mirror_config():
+    """Get the mirror configuration from config files"""
+    return get_config('mirrors')
+
+
+def get_config_scope_dirname(scope):
+    """For a scope return the config directory"""
+    global config_scopes
+    for s,p in config_scopes:
+        if s == scope:
+            return p
+    tty.die("Unknown scope %s.  Valid options are %s" %
+            (scope, ", ".join([s for s,p in config_scopes])))
+
+
+def get_config_scope_filename(scope, category_name):
+    """For some scope and category, get the name of the configuration file"""
+    if not category_name in _config_sections:
+        tty.die("Unknown config category %s.  Valid options are: %s" %
+                (category_name, ", ".join([s for s in _config_sections])))
+    return os.path.join(get_config_scope_dirname(scope), _config_sections[category_name].filename)
+
+
+def add_to_config(category_name, addition_dict, scope=None):
+    """Merge a new dict into a configuration tree and write the new
+       configuration to disk"""
+    global _read_config_file_result
+    get_config(category_name)
+    category = _config_sections[category_name]
+
+    #If scope is specified, use it.  Otherwise use the last config scope that
+    #we successfully parsed data from.
+    file = None
+    path = None
+    if not scope and not category.files_read_from:
+        scope = 'user'
+    if scope:
         try:
-            if not option:
-                # TODO: format this better
-                return self.items(sn)
-
-            return self.get(sn, option)
-
-        # Wrap ConfigParser exceptions in SpackExceptions
-        except cp.NoOptionError, e:  raise NoOptionError(e)
-        except cp.NoSectionError, e: raise NoSectionError(e)
-        except cp.Error, e:          raise ConfigParserError(e)
-
-
-    @_autokey
-    def has_value(self, section, name, option):
-        """Return whether the configuration file has a value for a
-           particular key."""
-        sn = _make_section_name(section, name)
-        return self.has_option(sn, option)
-
-
-    def has_named_section(self, section, name):
-        sn = _make_section_name(section, name)
-        return self.has_section(sn)
-
-
-    def remove_named_section(self, section, name):
-        sn = _make_section_name(section, name)
-        self.remove_section(sn)
-
-
-    def get_section_names(self, sectype):
-        """Get all named sections with the specified type.
-           A named section looks like this:
-
-               [compiler "gcc@4.7"]
-
-           Names of sections are returned as a list, e.g.:
-
-               ['gcc@4.7', 'intel@12.3', 'pgi@4.2']
-
-           You can get items in the sections like this:
-        """
-        sections = []
-        for secname in self.sections():
-            match = re.match(_named_section_re, secname)
-            if match:
-                t, name = match.groups()
-                if t == sectype:
-                    sections.append(name)
-        return sections
-
-
-    def write(self, path_or_fp=None):
-        """Write this configuration out to a file.
-
-           If called with no arguments, this will write the
-           configuration out to the file from which it was read.  If
-           this config was read from multiple files, e.g. site
-           configuration and then user configuration, write will
-           simply raise an error.
-
-           If called with a path or file object, this will write the
-           configuration out to the supplied path or file object.
-        """
-        if path_or_fp is None:
-            if not self.filename:
-                raise ReadOnlySpackConfigError()
-            path_or_fp = self.filename
-
-        if isinstance(path_or_fp, basestring):
-            path_or_fp = open(path_or_fp, 'w')
-
-        self._write(path_or_fp)
-
-
-    def _read(self, fp, fpname):
-        """This is a copy of Python 2.6's _read() method, with support for
-           continuation lines removed."""
-        cursect = None                            # None, or a dictionary
-        optname = None
-        comment = 0
-        lineno = 0
-        e = None                                  # None, or an exception
-        while True:
-            line = fp.readline()
-            if not line:
-                break
-            lineno = lineno + 1
-            # comment or blank line?
-            if ((line.strip() == '' or line[0] in '#;') or
-                (line.split(None, 1)[0].lower() == 'rem' and line[0] in "rR")):
-                self._sections["comment-%d" % comment] = line
-                comment += 1
-            # a section header or option header?
-            else:
-                # is it a section header?
-                mo = self.SECTCRE.match(line)
-                if mo:
-                    sectname = mo.group('header')
-                    if sectname in self._sections:
-                        cursect = self._sections[sectname]
-                    elif sectname == cp.DEFAULTSECT:
-                        cursect = self._defaults
-                    else:
-                        cursect = self._dict()
-                        cursect['__name__'] = sectname
-                        self._sections[sectname] = cursect
-                    # So sections can't start with a continuation line
-                    optname = None
-                # no section header in the file?
-                elif cursect is None:
-                    raise cp.MissingSectionHeaderError(fpname, lineno, line)
-                # an option line?
-                else:
-                    mo = self.OPTCRE.match(line)
-                    if mo:
-                        optname, vi, optval = mo.group('option', 'vi', 'value')
-                        if vi in ('=', ':') and ';' in optval:
-                            # ';' is a comment delimiter only if it follows
-                            # a spacing character
-                            pos = optval.find(';')
-                            if pos != -1 and optval[pos-1].isspace():
-                                optval = optval[:pos]
-                        optval = optval.strip()
-                        # allow empty values
-                        if optval == '""':
-                            optval = ''
-                        optname = self.optionxform(optname.rstrip())
-                        cursect[optname] = optval
-                    else:
-                        # a non-fatal parsing error occurred.  set up the
-                        # exception but keep going. the exception will be
-                        # raised at the end of the file and will contain a
-                        # list of all bogus lines
-                        if not e:
-                            e = cp.ParsingError(fpname)
-                        e.append(lineno, repr(line))
-        # if any parsing errors occurred, raise an exception
-        if e:
-            raise e
-
-
-
-
-    def _write(self, fp):
-        """Write an .ini-format representation of the configuration state.
-
-           This is taken from the default Python 2.6 source.  It writes 4
-           spaces at the beginning of lines instead of no leading space.
-        """
-        if self._defaults:
-            fp.write("[%s]\n" % cp.DEFAULTSECT)
-            for (key, value) in self._defaults.items():
-                fp.write("    %s = %s\n" % (key, str(value).replace('\n', '\n\t')))
-            fp.write("\n")
-
-        for section in self._sections:
-            # Handles comments and blank lines.
-            if isinstance(self._sections[section], basestring):
-                fp.write(self._sections[section])
-                continue
-
-            else:
-                # Allow leading whitespace
-                fp.write("[%s]\n" % section)
-                for (key, value) in self._sections[section].items():
-                    if key != "__name__":
-                        fp.write("    %s = %s\n" %
-                                 (key, str(value).replace('\n', '\n\t')))
-
-
-class SpackConfigurationError(spack.error.SpackError):
-    def __init__(self, *args):
-        super(SpackConfigurationError, self).__init__(*args)
-
-
-class InvalidConfigurationScopeError(SpackConfigurationError):
-    def __init__(self, scope):
-        super(InvalidConfigurationScopeError, self).__init__(
-            "Invalid configuration scope: '%s'" % scope,
-            "Options are: %s" % ", ".join(*_scopes.values()))
-
-
-class InvalidSectionNameError(SpackConfigurationError):
-    """Raised when the name for a section is invalid."""
-    def __init__(self, name):
-        super(InvalidSectionNameError, self).__init__(
-            "Invalid section specifier: '%s'" % name)
-
-
-class ReadOnlySpackConfigError(SpackConfigurationError):
-    """Raised when user attempts to write to a config read from multiple files."""
-    def __init__(self):
-        super(ReadOnlySpackConfigError, self).__init__(
-            "Can only write to a single-file SpackConfigParser")
-
-
-class ConfigParserError(SpackConfigurationError):
-    """Wrapper for the Python ConfigParser's errors"""
-    def __init__(self, error):
-        super(ConfigParserError, self).__init__(str(error))
-        self.error = error
-
-
-class NoOptionError(ConfigParserError):
-    """Wrapper for ConfigParser NoOptionError"""
-    def __init__(self, error):
-        super(NoOptionError, self).__init__(error)
-
-
-class NoSectionError(ConfigParserError):
-    """Wrapper for ConfigParser NoOptionError"""
-    def __init__(self, error):
-        super(NoSectionError, self).__init__(error)
+            dir = get_config_scope_dirname(scope)
+            if not os.path.exists(dir):
+                mkdirp(dir)
+            path = os.path.join(dir, category.filename)
+            file = open(path, 'w')
+        except exceptions.IOError, e:
+            pass
+    else:
+        for p in category.files_read_from:
+            try:
+                file = open(p, 'w')
+            except exceptions.IOError, e:
+                pass
+            if file:
+                path = p
+                break;
+    if not file:
+        tty.die('Unable to write to config file %s' % path)
+
+    #Merge the new information into the existing file info, then write to disk
+    new_dict = _read_config_file_result[path]
+    if new_dict and category_name in new_dict:
+        new_dict = new_dict[category_name]
+    new_dict = _merge_dicts(new_dict, addition_dict)
+    new_dict = { category_name : new_dict }
+    _read_config_file_result[path] = new_dict
+    yaml.dump(new_dict, stream=file, default_flow_style=False)
+    file.close()
+
+    #Merge the new information into the cached results
+    category.result_dict = _merge_dicts(category.result_dict, addition_dict)
+
+
+def add_to_mirror_config(addition_dict, scope=None):
+    """Add mirrors to the configuration files"""
+    add_to_config('mirrors', addition_dict, scope)
+
+
+def add_to_compiler_config(addition_dict, scope=None, arch=None):
+    """Add compilerss to the configuration files"""
+    if not arch:
+        arch = spack.architecture.sys_type()
+    add_to_config('compilers', { arch : addition_dict }, scope)
+    clear_config_caches()
+
+
+def remove_from_config(category_name, key_to_rm, scope=None):
+    """Remove a configuration key and write a new configuration to disk"""
+    global config_scopes
+    get_config(category_name)
+    scopes_to_rm_from = [scope] if scope else [s for s,p in config_scopes]
+    category = _config_sections[category_name]
+
+    rmd_something = False
+    for s in scopes_to_rm_from:
+        path = get_config_scope_filename(scope, category_name)
+        result = _read_config_file(path)
+        if not result:
+            continue
+        if not key_to_rm in result[category_name]:
+            continue
+        with closing(open(path, 'w')) as f:
+            result[category_name].pop(key_to_rm, None)
+            yaml.dump(result, stream=f, default_flow_style=False)
+            category.result_dict.pop(key_to_rm, None)
+            rmd_something = True
+    return rmd_something
+
+
+"""Print a configuration to stdout"""
+def print_category(category_name):
+    if not category_name in _config_sections:
+        tty.die("Unknown config category %s.  Valid options are: %s" %
+                (category_name, ", ".join([s for s in _config_sections])))
+    yaml.dump(get_config(category_name), stream=sys.stdout, default_flow_style=False)
+
diff --git a/lib/spack/spack/stage.py b/lib/spack/spack/stage.py
index d451743508644ac91e8adec1d8a11f8bb3a00c11..008c5f04298baa650d69602bc9d35d60cd0b95db 100644
--- a/lib/spack/spack/stage.py
+++ b/lib/spack/spack/stage.py
@@ -344,13 +344,9 @@ def destroy(self):
 
 def _get_mirrors():
     """Get mirrors from spack configuration."""
-    config = spack.config.get_config()
+    config = spack.config.get_mirror_config()
+    return [val for name, val in config.iteritems()]
 
-    mirrors = []
-    sec_names = config.get_section_names('mirror')
-    for name in sec_names:
-        mirrors.append(config.get_value('mirror', name, 'url'))
-    return mirrors
 
 
 def ensure_access(file=spack.stage_path):
diff --git a/lib/spack/spack/test/config.py b/lib/spack/spack/test/config.py
index c676e9a35bd4bddb9331a24023f10e42f581ae97..790b22f3b0a3388abd7611f07487ef49fb55e2e7 100644
--- a/lib/spack/spack/test/config.py
+++ b/lib/spack/spack/test/config.py
@@ -26,44 +26,49 @@
 import shutil
 import os
 from tempfile import mkdtemp
+import spack
+from spack.packages import PackageDB
+from spack.test.mock_packages_test import *
 
-from spack.config import *
+class ConfigTest(MockPackagesTest):
 
+    def setUp(self):
+        self.initmock()
+        self.tmp_dir = mkdtemp('.tmp', 'spack-config-test-')
+        spack.config.config_scopes = [('test_low_priority', os.path.join(self.tmp_dir, 'low')),
+                                      ('test_high_priority', os.path.join(self.tmp_dir, 'high'))]
 
-class ConfigTest(unittest.TestCase):
+    def tearDown(self):
+        self.cleanmock()
+        shutil.rmtree(self.tmp_dir, True)
 
-    @classmethod
-    def setUp(cls):
-        cls.tmp_dir = mkdtemp('.tmp', 'spack-config-test-')
+    def check_config(self, comps):
+        config = spack.config.get_compilers_config()
+        compiler_list = ['cc', 'cxx', 'f77', 'f90']
+        for key in comps:
+            for c in compiler_list:
+                if comps[key][c] == '/bad':
+                    continue
+                self.assertEqual(comps[key][c], config[key][c])
 
 
-    @classmethod
-    def tearDown(cls):
-        shutil.rmtree(cls.tmp_dir, True)
-
-
-    def get_path(self):
-        return os.path.join(ConfigTest.tmp_dir, "spackconfig")
+    def test_write_key(self):
+        a_comps =  {"gcc@4.7.3" : { "cc" : "/gcc473", "cxx" : "/g++473", "f77" : None, "f90" : None },
+         "gcc@4.5.0" : { "cc" : "/gcc450", "cxx" : "/g++450", "f77" : "/gfortran", "f90" : "/gfortran" },
+         "clang@3.3"  : { "cc" : "/bad", "cxx" : "/bad", "f77" : "/bad", "f90" : "/bad" }}
 
+        b_comps = {"icc@10.0" : { "cc" : "/icc100", "cxx" : "/icc100", "f77" : None, "f90" : None },
+         "icc@11.1" : { "cc" : "/icc111", "cxx" : "/icp111", "f77" : "/ifort", "f90" : "/ifort" },
+         "clang@3.3" : { "cc" : "/clang", "cxx" : "/clang++", "f77" :  None, "f90" : None}}
 
-    def test_write_key(self):
-        config = SpackConfigParser(self.get_path())
-        config.set_value('compiler.cc',  'a')
-        config.set_value('compiler.cxx', 'b')
-        config.set_value('compiler', 'gcc@4.7.3', 'cc',  'c')
-        config.set_value('compiler', 'gcc@4.7.3', 'cxx', 'd')
-        config.write()
+        spack.config.add_to_compiler_config(a_comps, 'test_low_priority')
+        spack.config.add_to_compiler_config(b_comps, 'test_high_priority')
 
-        config = SpackConfigParser(self.get_path())
+        self.check_config(a_comps)
+        self.check_config(b_comps)
 
-        self.assertEqual(config.get_value('compiler.cc'),  'a')
-        self.assertEqual(config.get_value('compiler.cxx'), 'b')
-        self.assertEqual(config.get_value('compiler', 'gcc@4.7.3', 'cc'), 'c')
-        self.assertEqual(config.get_value('compiler', 'gcc@4.7.3', 'cxx'), 'd')
+        spack.config.clear_config_caches()
 
-        self.assertEqual(config.get_value('compiler', None, 'cc'),  'a')
-        self.assertEqual(config.get_value('compiler', None, 'cxx'), 'b')
-        self.assertEqual(config.get_value('compiler.gcc@4.7.3.cc'), 'c')
-        self.assertEqual(config.get_value('compiler.gcc@4.7.3.cxx'), 'd')
+        self.check_config(a_comps)
+        self.check_config(b_comps)
 
-        self.assertRaises(NoOptionError, config.get_value, 'compiler', None, 'fc')
diff --git a/lib/spack/spack/test/mock_packages_test.py b/lib/spack/spack/test/mock_packages_test.py
index 09fb9ebe30b4989b9623248d7473fb00e0553dc4..00f81114af35e21256f1848af76317f12c1d7fa9 100644
--- a/lib/spack/spack/test/mock_packages_test.py
+++ b/lib/spack/spack/test/mock_packages_test.py
@@ -31,7 +31,7 @@
 
 
 def set_pkg_dep(pkg, spec):
-    """Alters dependence information for a pacakge.
+    """Alters dependence information for a package.
        Use this to mock up constraints.
     """
     spec = Spec(spec)
@@ -39,21 +39,32 @@ def set_pkg_dep(pkg, spec):
 
 
 class MockPackagesTest(unittest.TestCase):
-    def setUp(self):
+    def initmock(self):
         # Use the mock packages database for these tests.  This allows
         # us to set up contrived packages that don't interfere with
         # real ones.
         self.real_db = spack.db
         spack.db = PackageDB(spack.mock_packages_path)
 
-        self.real_scopes = spack.config._scopes
-        spack.config._scopes = {
-            'site' : spack.mock_site_config,
-            'user' : spack.mock_user_config }
+        spack.config.clear_config_caches()
+        self.real_scopes = spack.config.config_scopes
+        spack.config.config_scopes = [
+            ('site', spack.mock_site_config),
+            ('user', spack.mock_user_config)]
 
 
-    def tearDown(self):
+    def cleanmock(self):
         """Restore the real packages path after any test."""
         spack.db = self.real_db
-        spack.config._scopes = self.real_scopes
+        spack.config.config_scopes = self.real_scopes
+        spack.config.clear_config_caches()
+
+
+    def setUp(self):
+        self.initmock()
+
+
+    def tearDown(self):
+        self.cleanmock()
+
 
diff --git a/var/spack/mock_configs/site_spackconfig b/var/spack/mock_configs/site_spackconfig
deleted file mode 100644
index 135872036224e3480b2f1f650d1f8c7b91a01047..0000000000000000000000000000000000000000
--- a/var/spack/mock_configs/site_spackconfig
+++ /dev/null
@@ -1,12 +0,0 @@
-[compiler "gcc@4.5.0"]
-    cc  = /path/to/gcc
-    cxx = /path/to/g++
-    f77 = /path/to/gfortran
-    fc  = /path/to/gfortran
-
-[compiler "clang@3.3"]
-    cc  = /path/to/clang
-    cxx = /path/to/clang++
-    f77 = None
-    fc  = None
-
diff --git a/var/spack/mock_configs/site_spackconfig/compilers.yaml b/var/spack/mock_configs/site_spackconfig/compilers.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..0a2dc893e293bfdbee05deb35fd70893dfdebde8
--- /dev/null
+++ b/var/spack/mock_configs/site_spackconfig/compilers.yaml
@@ -0,0 +1,12 @@
+compilers:
+  all:
+    clang@3.3:
+      cc: /path/to/clang
+      cxx: /path/to/clang++
+      f77: None
+      fc: None
+    gcc@4.5.0:
+      cc: /path/to/gcc
+      cxx: /path/to/g++
+      f77: /path/to/gfortran
+      fc: /path/to/gfortran
diff --git a/var/spack/mock_configs/user_spackconfig b/var/spack/mock_configs/user_spackconfig
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000