basic $[] functionality
diff --git a/reclass/__init__.py b/reclass/__init__.py
index c86b880..eeb8f7f 100644
--- a/reclass/__init__.py
+++ b/reclass/__init__.py
@@ -11,9 +11,9 @@
 from storage.loader import StorageBackendLoader
 from storage.memcache_proxy import MemcacheProxy
 
-def get_storage(storage_type, nodes_uri, classes_uri, **kwargs):
+def get_storage(storage_type, nodes_uri, classes_uri, exports_uri, **kwargs):
     storage_class = StorageBackendLoader(storage_type).load()
-    return MemcacheProxy(storage_class(nodes_uri, classes_uri, **kwargs))
+    return MemcacheProxy(storage_class(nodes_uri, classes_uri, exports_uri, **kwargs))
 
 
 def output(data, fmt, pretty_print=False, no_refs=False):
diff --git a/reclass/cli.py b/reclass/cli.py
index 1f7213d..17467cd 100644
--- a/reclass/cli.py
+++ b/reclass/cli.py
@@ -28,7 +28,8 @@
                               defaults=defaults)
 
         storage = get_storage(options.storage_type, options.nodes_uri,
-                              options.classes_uri, default_environment='base')
+                              options.classes_uri, options.exports_uri,
+                              default_environment='base')
         class_mappings = defaults.get('class_mappings')
         reclass = Core(storage, class_mappings)
 
diff --git a/reclass/config.py b/reclass/config.py
index 3d218d8..52fbe4c 100644
--- a/reclass/config.py
+++ b/reclass/config.py
@@ -28,7 +28,10 @@
                    help='the URI to the nodes storage [%default]'),
     ret.add_option('-c', '--classes-uri', dest='classes_uri',
                    default=defaults.get('classes_uri', OPT_CLASSES_URI),
-                   help='the URI to the classes storage [%default]')
+                   help='the URI to the classes storage [%default]'),
+    ret.add_option('-e', '--exports-uri', dest='exports_uri',
+                   default=defaults.get('exports_uri', OPT_EXPORTS_URI),
+                   help='the URI to the exports file [%default]')
     return ret
 
 
@@ -127,11 +130,13 @@
             parser.error('Must specify --inventory-base-uri or --nodes-uri')
         elif options.inventory_base_uri is None and options.classes_uri is None:
             parser.error('Must specify --inventory-base-uri or --classes-uri')
+        elif options.inventory_base_uri is None and options.exports_uri is None:
+            parser.error('Must specify --inventory-base-uri or --exports-uri')
 
     return parser, option_checker
 
 
-def path_mangler(inventory_base_uri, nodes_uri, classes_uri):
+def path_mangler(inventory_base_uri, nodes_uri, classes_uri, exports_uri):
 
     if inventory_base_uri is None:
         # if inventory_base is not given, default to current directory
@@ -139,20 +144,21 @@
 
     nodes_uri = nodes_uri or 'nodes'
     classes_uri = classes_uri or 'classes'
+    exports_uri = exports_uri or 'exports'
 
     def _path_mangler_inner(path):
         ret = os.path.join(inventory_base_uri, path)
         ret = os.path.expanduser(ret)
         return os.path.abspath(ret)
 
-    n, c = map(_path_mangler_inner, (nodes_uri, classes_uri))
-    if n == c:
-        raise errors.DuplicateUriError(n, c)
+    n, c, e = map(_path_mangler_inner, (nodes_uri, classes_uri, exports_uri))
+    if n == c or n == e or c == e:
+        raise errors.DuplicateUriError(n, c, e)
     common = os.path.commonprefix((n, c))
     if common == n or common == c:
         raise errors.UriOverlapError(n, c)
 
-    return n, c
+    return n, c, e
 
 
 def get_options(name, version, description,
@@ -178,9 +184,9 @@
     options, args = parser.parse_args()
     checker(options, args)
 
-    options.nodes_uri, options.classes_uri = \
+    options.nodes_uri, options.classes_uri, options.exports_uri  = \
             path_mangler(options.inventory_base_uri, options.nodes_uri,
-                         options.classes_uri)
+                         options.classes_uri, options.exports_uri)
 
     return options
 
diff --git a/reclass/core.py b/reclass/core.py
index b9da0d2..b3620b6 100644
--- a/reclass/core.py
+++ b/reclass/core.py
@@ -7,6 +7,7 @@
 # Released under the terms of the Artistic Licence 2.0
 #
 
+import copy
 import time
 #import types
 import re
@@ -14,6 +15,8 @@
 import fnmatch
 import shlex
 import string
+import yaml
+from reclass.output.yaml_outputter import ExplicitDumper
 from reclass.datatypes import Entity, Classes, Parameters
 from reclass.errors import MappingFormatError, ClassNotFound
 from reclass.defaults import AUTOMATIC_RECLASS_PARAMETERS
@@ -111,20 +114,25 @@
         merge_base.merge(entity)
         return merge_base
 
-    def _nodeinfo(self, nodename):
+    def _get_automatic_parameters(self, nodename):
+        if AUTOMATIC_RECLASS_PARAMETERS:
+            return Parameters({ '_reclass_': { 'name': { 'full': nodename, 'short': string.split(nodename, '.')[0] } } })
+        else:
+            return Parameters()
+
+
+    def _nodeinfo(self, nodename, exports):
         node_entity = self._storage.get_node(nodename)
         base_entity = Entity(name='base')
         base_entity.merge(self._get_class_mappings_entity(node_entity.name))
         base_entity.merge(self._get_input_data_entity())
-        if AUTOMATIC_RECLASS_PARAMETERS:
-            params = { '_reclass_': { 'name': { 'full': nodename, 'short': string.split(nodename, '.')[0] } } }
-            base_entity.merge_parameters(params)
+        base_entity.merge_parameters(self._get_automatic_parameters(nodename))
         seen = {}
         merge_base = self._recurse_entity(base_entity, seen=seen,
                                           nodename=base_entity.name)
         ret = self._recurse_entity(node_entity, merge_base, seen=seen,
                                    nodename=node_entity.name)
-        ret.interpolate()
+        ret.interpolate(nodename, exports)
         return ret
 
     def _nodeinfo_as_dict(self, nodename, entity):
@@ -137,13 +145,28 @@
         ret.update(entity.as_dict())
         return ret
 
+    def _update_exports(self, old, new):
+        old_yaml = yaml.dump(old.as_dict(), default_flow_style=True, Dumper=ExplicitDumper)
+        new_yaml = yaml.dump(new.as_dict(), default_flow_style=True, Dumper=ExplicitDumper)
+        if old_yaml != new_yaml:
+            self._storage.put_exports(new)
+
     def nodeinfo(self, nodename):
-        return self._nodeinfo_as_dict(nodename, self._nodeinfo(nodename))
+        original_exports = Parameters(self._storage.get_exports())
+        exports = copy.deepcopy(original_exports)
+        original_exports.render_simple()
+        ret = self._nodeinfo_as_dict(nodename, self._nodeinfo(nodename, exports))
+        self._update_exports(original_exports, exports)
+        return ret
 
     def inventory(self):
+        original_exports = Parameters(self._storage.get_exports())
+        exports = copy.deepcopy(original_exports)
+        original_exports.render_simple()
         entities = {}
         for n in self._storage.enumerate_nodes():
-            entities[n] = self._nodeinfo(n)
+            entities[n] = self._nodeinfo(n, exports)
+        self._update_exports(original_exports, exports)
 
         nodes = {}
         applications = {}
diff --git a/reclass/datatypes/entity.py b/reclass/datatypes/entity.py
index c6c3b28..41c9db6 100644
--- a/reclass/datatypes/entity.py
+++ b/reclass/datatypes/entity.py
@@ -75,9 +75,11 @@
     def merge_parameters(self, params):
         self._parameters.merge(params)
 
-    def interpolate(self):
+    def interpolate(self, nodename, exports):
         self._exports.interpolate_from_external(self._parameters)
-        self._parameters.interpolate(exports={ self._name: self._exports.as_dict() })
+        exports.merge({ nodename: self._exports.as_dict() })
+        exports.render_simple()
+        self._parameters.interpolate(exports=exports.as_dict())
 
     def __eq__(self, other):
         return isinstance(other, type(self)) \
@@ -92,7 +94,7 @@
         return not self.__eq__(other)
 
     def __repr__(self):
-        return "%s(%r, %r, %r, uri=%r, name=%r)" % (self.__class__.__name__,
+        return "%s(%r, %r, %r, %r, uri=%r, name=%r)" % (self.__class__.__name__,
                                                     self.classes,
                                                     self.applications,
                                                     self.parameters,
diff --git a/reclass/defaults.py b/reclass/defaults.py
index 557d511..24801ef 100644
--- a/reclass/defaults.py
+++ b/reclass/defaults.py
@@ -14,6 +14,7 @@
 OPT_INVENTORY_BASE_URI = os.path.join('/etc', RECLASS_NAME)
 OPT_NODES_URI = 'nodes'
 OPT_CLASSES_URI = 'classes'
+OPT_EXPORTS_URI = 'exports'
 OPT_PRETTY_PRINT = True
 OPT_NO_REFS = False
 OPT_OUTPUT = 'yaml'
@@ -37,3 +38,4 @@
 MERGE_ALLOW_DICT_OVER_SCALAR = False
 
 AUTOMATIC_RECLASS_PARAMETERS = True
+AUTOMATIC_EXPORT_PARAMETERS = True
diff --git a/reclass/storage/__init__.py b/reclass/storage/__init__.py
index 8ae2408..001fdce 100644
--- a/reclass/storage/__init__.py
+++ b/reclass/storage/__init__.py
@@ -22,6 +22,14 @@
         msg = "Storage class '{0}' does not implement class entity retrieval."
         raise NotImplementedError(msg.format(self.name))
 
+    def get_exports(self):
+        msg = "Storage class '{0}' does not implement get_exports."
+        raise NotImplementedError(msg.format(self.name))
+
+    def put_exports(self, new):
+        msg = "Storage class '{0}' does not implement put_exports."
+        raise NotImplementedError(msg.format(self.name))
+
     def enumerate_nodes(self):
         msg = "Storage class '{0}' does not implement node enumeration."
         raise NotImplementedError(msg.format(self.name))
diff --git a/reclass/storage/memcache_proxy.py b/reclass/storage/memcache_proxy.py
index 7d9ab5e..545c68f 100644
--- a/reclass/storage/memcache_proxy.py
+++ b/reclass/storage/memcache_proxy.py
@@ -14,7 +14,7 @@
 class MemcacheProxy(NodeStorageBase):
 
     def __init__(self, real_storage, cache_classes=True, cache_nodes=True,
-                 cache_nodelist=True):
+                 cache_nodelist=True, cache_exports=True):
         name = '{0}({1})'.format(STORAGE_NAME, real_storage.name)
         super(MemcacheProxy, self).__init__(name)
         self._real_storage = real_storage
@@ -27,6 +27,9 @@
         self._cache_nodelist = cache_nodelist
         if cache_nodelist:
             self._nodelist_cache = None
+        self._cache_exports = cache_exports
+        if cache_exports:
+            self._exports_cache = None
 
     name = property(lambda self: self._real_storage.name)
 
@@ -41,6 +44,12 @@
 
         return ret
 
+    @staticmethod
+    def _cache(cache, getter):
+        if cache is None:
+            cache = getter()
+        return cache
+
     def get_node(self, name):
         if not self._cache_nodes:
             return self._real_storage.get_node(name)
@@ -55,6 +64,14 @@
         return MemcacheProxy._cache_proxy(name, self._classes_cache,
                                           self._real_storage.get_class)
 
+    def get_exports(self):
+        if not self._cache_exports:
+             return self._real_storage.get_exports()
+        return MemcacheProxy._cache(self._exports_cache, self._real_storage.get_exports)
+
+    def put_exports(self, new):
+        self._real_storage.put_exports(new)
+
     def enumerate_nodes(self):
         if not self._cache_nodelist:
             return self._real_storage.enumerate_nodes()
diff --git a/reclass/storage/yaml_fs/__init__.py b/reclass/storage/yaml_fs/__init__.py
index 5a13050..50fdc2d 100644
--- a/reclass/storage/yaml_fs/__init__.py
+++ b/reclass/storage/yaml_fs/__init__.py
@@ -8,6 +8,8 @@
 #
 import os, sys
 import fnmatch
+import yaml
+from reclass.output.yaml_outputter import ExplicitDumper
 from reclass.storage import NodeStorageBase
 from yamlfile import YamlFile
 from directory import Directory
@@ -23,7 +25,7 @@
 
 class ExternalNodeStorage(NodeStorageBase):
 
-    def __init__(self, nodes_uri, classes_uri, default_environment=None):
+    def __init__(self, nodes_uri, classes_uri, exports_uri, default_environment=None):
         super(ExternalNodeStorage, self).__init__(STORAGE_NAME)
 
         def name_mangler(relpath, name):
@@ -47,11 +49,12 @@
             return relpath, '.'.join(parts)
         self._classes_uri = classes_uri
         self._classes = self._enumerate_inventory(classes_uri, name_mangler)
-
+        self._exports_uri = exports_uri
         self._default_environment = default_environment
 
     nodes_uri = property(lambda self: self._nodes_uri)
     classes_uri = property(lambda self: self._classes_uri)
+    exports_uri = property(lambda self: self._exports_uri)
 
     def _enumerate_inventory(self, basedir, name_mangler):
         ret = {}
@@ -96,5 +99,17 @@
         entity = YamlFile(path).get_entity(name)
         return entity
 
+    def get_exports(self):
+        vvv('GET EXPORTS')
+        path = os.path.join(self.exports_uri, 'exports{0}'.format(FILE_EXTENSION))
+        entity = YamlFile(path).get_data()
+        return entity
+
+    def put_exports(self, new):
+        vvv('PUT EXPORTS')
+        path = os.path.join(self.exports_uri, 'exports{0}'.format(FILE_EXTENSION))
+        with open(path, 'w') as yaml_file:
+            yaml.dump(new.as_dict(), yaml_file, default_flow_style=False, Dumper=ExplicitDumper)
+
     def enumerate_nodes(self):
         return self._nodes.keys()
diff --git a/reclass/storage/yaml_fs/yamlfile.py b/reclass/storage/yaml_fs/yamlfile.py
index 03a5c11..dcd6df4 100644
--- a/reclass/storage/yaml_fs/yamlfile.py
+++ b/reclass/storage/yaml_fs/yamlfile.py
@@ -31,6 +31,9 @@
             self._data = data
         fp.close()
 
+    def get_data(self):
+        return self._data
+
     def get_entity(self, name=None, default_environment=None):
         classes = self._data.get('classes')
         if classes is None:
@@ -52,11 +55,11 @@
             exports = {}
         exports = datatypes.Parameters(exports)
 
-        env = self._data.get('environment', default_environment)
-
         if name is None:
             name = self._path
 
+        env = self._data.get('environment', default_environment)
+
         return datatypes.Entity(classes, applications, parameters, exports,
                                 name=name, environment=env,
                                 uri='yaml_fs://{0}'.format(self._path))
diff --git a/reclass/values/expitem.py b/reclass/values/expitem.py
index fddf0da..22a473b 100644
--- a/reclass/values/expitem.py
+++ b/reclass/values/expitem.py
@@ -4,9 +4,12 @@
 # This file is part of reclass
 #
 
+import copy
+
 from item import Item
 from reclass.utils.dictpath import DictPath
 from reclass.errors import UndefinedVariableError
+from reclass.defaults import AUTOMATIC_EXPORT_PARAMETERS
 
 class ExpItem(Item):
 
@@ -41,7 +44,10 @@
         exp_path.drop_first()
         for node, items in exports.iteritems():
             if exp_path.exists_in(items):
-                result.append(self._resolve(exp_path, exp_key, items))
+                value = copy.deepcopy(self._resolve(exp_path, exp_key, items))
+                if isinstance(value, dict) and AUTOMATIC_EXPORT_PARAMETERS:
+                    value['_node_'] = node
+                result.append(value)
         return result
 
     def __repr__(self):
diff --git a/reclass/values/item.py b/reclass/values/item.py
index 035f3fb..9ee301e 100644
--- a/reclass/values/item.py
+++ b/reclass/values/item.py
@@ -23,3 +23,15 @@
 
     def is_complex():
         return (self.has_references | self.has_exports)
+
+    def contents(self):
+        msg = "Item class {0} does not implement contents()"
+        raise NotImplementedError(msg.format(self.__class__.__name__))
+
+    def merge_over(self, item, options):
+        msg = "Item class {0} does not implement merge_over()"
+        raise NotImplementedError(msg.format(self.__class__.__name__))
+
+    def render(self, context, exports):
+        msg = "Item class {0} does not implement render()"
+        raise NotImplementedError(msg.format(self.__class__.__name__))