diff --git a/PKG-INFO b/PKG-INFO
index b62b00d..b22a155 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,11 +1,200 @@
-Metadata-Version: 1.0
+Metadata-Version: 2.1
 Name: scruffington
-Version: 0.3.3
+Version: 0.3.8.2
 Summary: The janitor
 Home-page: https://github.com/snare/scruffy
 Author: snare
 Author-email: snare@ho.ax
 License: MIT
-Description: UNKNOWN
+Description: Scruffy
+        =======
+        
+        .. image:: https://img.shields.io/travis/snare/scruffy.svg
+            :target: https://travis-ci.org/snare/scruffy
+        
+        .. image:: https://img.shields.io/pypi/format/scruffington.svg
+            :target: https://pypi.python.org/pypi/scruffington
+        
+        .. image:: https://readthedocs.org/projects/scruffy/badge/?version=latest
+            :target: http://scruffy.readthedocs.org/en/latest/
+        
+        
+        *Scruffy. The Janitor.*
+        
+        Scruffy is a framework for taking care of a bunch of boilerplate in Python apps. It handles the loading of configuration files, the loading and management of plugins, and the management of other filesystem resources such as temporary files and directories, log files, etc.
+        
+        A typical use case for Scruffy is a command-line Python tool with some or all of the following requirements:
+        
+        * Read a set of configuration defaults
+        * Read a local configuration file and apply it on top of the defaults
+        * Allow overriding some configuration options with command line flags or at runtime
+        * Load a core set of Python-based plugins
+        * Load a set of user-defined Python-based plugins
+        * Generate log files whose name, location and other logging settings are based on configuration
+        * Store application state between runs in a file or database
+        
+        Scruffy is used by Voltron_ and Calculon_
+        
+        .. _Voltron: https://github.com/snare/voltron
+        .. _Calculon: https://github.com/snare/calculon
+        
+        Installation
+        ------------
+        
+        A standard python setup script is included.
+        
+            $ python setup.py install
+        
+        This will install the Scruffy package wherever that happens on your system.
+        
+        Alternately, Scruffy can be installed with `pip` from PyPi (where it's called `scruffington`, because I didn't check for a conflict before I named it).
+        
+            $ pip install scruffington
+        
+        Documentation
+        -------------
+        
+        Full documentation is hosted at readthedocs_
+        
+        .. _readthedocs: http://scruffy.readthedocs.io/
+        
+        Quick start
+        -----------
+        
+        Config
+        ~~~~~~
+        
+        Load a user config file, and apply it on top of a set of defaults loaded from inside the Python package we're currently running from.
+        
+        *thingy.yaml*:
+        
+        .. code:: yaml
+        
+            some_property:  1
+            other_property: a thing
+        
+        *thingy.py*:
+        
+        .. code:: python
+        
+            from scruffy import ConfigFile
+        
+            c = ConfigFile('thingy.yaml', load=True,
+                defaults=File('defaults.yaml', parent=PackageDirectory())
+            )
+        
+            print("c.some_property == {c.some_property}".format(c=c))
+            print("c.other_property == {c.other_property}".format(c=c))
+        
+        Run it:
+        
+        ::
+        
+            $ python thingy.py
+            c.some_property == 1
+            c.other_property == a thing
+        
+        Plugins
+        ~~~~~~~
+        
+        Load some plugins.
+        
+        *~/.thingy/plugins/example.py*:
+        
+        .. code:: python
+        
+            from scruffy import Plugin
+        
+            class ExamplePlugin(Plugin):
+                def do_a_thing(self):
+                    print('{}.{} is doing a thing'.format(__name__, self.__class__.__name__))
+        
+        *thingy.py*:
+        
+        .. code:: python
+        
+            from scruffy import PluginDirectory, PluginRegistry
+        
+            pd = PluginDirectory('~/.thingy/plugins')
+            pd.load()
+        
+            for p in PluginRegistry.plugins:
+                print("Initialising plugin {}".format(p))
+                p().do_a_thing()
+        
+        Run it:
+        
+        ::
+        
+            $ python thingy.py
+            Initialising plugin <class 'example.ExamplePlugin'>
+            example.ExamplePlugin is doing a thing
+        
+        Logging
+        ~~~~~~~
+        
+        Scruffy's `LogFile` class will do some configuration of Python's `logging` module.
+        
+        *log.py*:
+        
+        .. code:: python
+        
+            import logging
+            from scruffy import LogFile
+        
+            log = logging.getLogger('main')
+            log.setLevel(logging.INFO)
+            LogFile('/tmp/thingy.log', logger='main').configure()
+        
+            log.info('Hello from log.py')
+        
+        */tmp/thingy.log*:
+        
+        ::
+        
+            Hello from log.py
+        
+        Environment
+        ~~~~~~~~~~~
+        
+        Scruffy's `Environment` class ties all the other stuff together. The other classes can be instantiated as named children of an `Environment`, which will load any `Config` objects, apply the configs to the other objects, and then prepare the other objects.
+        
+        *~/.thingy/config*:
+        
+        .. code:: yaml
+        
+            log_dir:    /tmp/logs
+            log_file:   thingy.log
+        
+        *env.py*:
+        
+        .. code:: python
+        
+            from scruffy import *
+        
+            e = Environment(
+                main_dir=Directory('~/.thingy', create=True,
+                    config=ConfigFile('config', defaults=File('defaults.yaml', parent=PackageDirectory())),
+                    lock=LockFile('lock')
+                    user_plugins=PluginDirectory('plugins')
+                ),
+                log_dir=Directory('{config:log_dir}', create=True
+                    LogFile('{config:log_file}', logger='main')
+                ),
+                pkg_plugins=PluginDirectory('plugins', parent=PackageDirectory())
+            )
+        
+        License
+        -------
+        
+        See LICENSE file. If you use this and don't hate it, buy me a beer at a conference some time.
+        
+        Credits
+        -------
+        
+        Props to richo_. Flat duck pride.
+        
+        .. _richo: http://github.com/richo
 Keywords: scruffy
 Platform: UNKNOWN
+Description-Content-Type: text/x-rst
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..1a86666
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,189 @@
+Scruffy
+=======
+
+.. image:: https://img.shields.io/travis/snare/scruffy.svg
+    :target: https://travis-ci.org/snare/scruffy
+
+.. image:: https://img.shields.io/pypi/format/scruffington.svg
+    :target: https://pypi.python.org/pypi/scruffington
+
+.. image:: https://readthedocs.org/projects/scruffy/badge/?version=latest
+    :target: http://scruffy.readthedocs.org/en/latest/
+
+
+*Scruffy. The Janitor.*
+
+Scruffy is a framework for taking care of a bunch of boilerplate in Python apps. It handles the loading of configuration files, the loading and management of plugins, and the management of other filesystem resources such as temporary files and directories, log files, etc.
+
+A typical use case for Scruffy is a command-line Python tool with some or all of the following requirements:
+
+* Read a set of configuration defaults
+* Read a local configuration file and apply it on top of the defaults
+* Allow overriding some configuration options with command line flags or at runtime
+* Load a core set of Python-based plugins
+* Load a set of user-defined Python-based plugins
+* Generate log files whose name, location and other logging settings are based on configuration
+* Store application state between runs in a file or database
+
+Scruffy is used by Voltron_ and Calculon_
+
+.. _Voltron: https://github.com/snare/voltron
+.. _Calculon: https://github.com/snare/calculon
+
+Installation
+------------
+
+A standard python setup script is included.
+
+    $ python setup.py install
+
+This will install the Scruffy package wherever that happens on your system.
+
+Alternately, Scruffy can be installed with `pip` from PyPi (where it's called `scruffington`, because I didn't check for a conflict before I named it).
+
+    $ pip install scruffington
+
+Documentation
+-------------
+
+Full documentation is hosted at readthedocs_
+
+.. _readthedocs: http://scruffy.readthedocs.io/
+
+Quick start
+-----------
+
+Config
+~~~~~~
+
+Load a user config file, and apply it on top of a set of defaults loaded from inside the Python package we're currently running from.
+
+*thingy.yaml*:
+
+.. code:: yaml
+
+    some_property:  1
+    other_property: a thing
+
+*thingy.py*:
+
+.. code:: python
+
+    from scruffy import ConfigFile
+
+    c = ConfigFile('thingy.yaml', load=True,
+        defaults=File('defaults.yaml', parent=PackageDirectory())
+    )
+
+    print("c.some_property == {c.some_property}".format(c=c))
+    print("c.other_property == {c.other_property}".format(c=c))
+
+Run it:
+
+::
+
+    $ python thingy.py
+    c.some_property == 1
+    c.other_property == a thing
+
+Plugins
+~~~~~~~
+
+Load some plugins.
+
+*~/.thingy/plugins/example.py*:
+
+.. code:: python
+
+    from scruffy import Plugin
+
+    class ExamplePlugin(Plugin):
+        def do_a_thing(self):
+            print('{}.{} is doing a thing'.format(__name__, self.__class__.__name__))
+
+*thingy.py*:
+
+.. code:: python
+
+    from scruffy import PluginDirectory, PluginRegistry
+
+    pd = PluginDirectory('~/.thingy/plugins')
+    pd.load()
+
+    for p in PluginRegistry.plugins:
+        print("Initialising plugin {}".format(p))
+        p().do_a_thing()
+
+Run it:
+
+::
+
+    $ python thingy.py
+    Initialising plugin <class 'example.ExamplePlugin'>
+    example.ExamplePlugin is doing a thing
+
+Logging
+~~~~~~~
+
+Scruffy's `LogFile` class will do some configuration of Python's `logging` module.
+
+*log.py*:
+
+.. code:: python
+
+    import logging
+    from scruffy import LogFile
+
+    log = logging.getLogger('main')
+    log.setLevel(logging.INFO)
+    LogFile('/tmp/thingy.log', logger='main').configure()
+
+    log.info('Hello from log.py')
+
+*/tmp/thingy.log*:
+
+::
+
+    Hello from log.py
+
+Environment
+~~~~~~~~~~~
+
+Scruffy's `Environment` class ties all the other stuff together. The other classes can be instantiated as named children of an `Environment`, which will load any `Config` objects, apply the configs to the other objects, and then prepare the other objects.
+
+*~/.thingy/config*:
+
+.. code:: yaml
+
+    log_dir:    /tmp/logs
+    log_file:   thingy.log
+
+*env.py*:
+
+.. code:: python
+
+    from scruffy import *
+
+    e = Environment(
+        main_dir=Directory('~/.thingy', create=True,
+            config=ConfigFile('config', defaults=File('defaults.yaml', parent=PackageDirectory())),
+            lock=LockFile('lock')
+            user_plugins=PluginDirectory('plugins')
+        ),
+        log_dir=Directory('{config:log_dir}', create=True
+            LogFile('{config:log_file}', logger='main')
+        ),
+        pkg_plugins=PluginDirectory('plugins', parent=PackageDirectory())
+    )
+
+License
+-------
+
+See LICENSE file. If you use this and don't hate it, buy me a beer at a conference some time.
+
+Credits
+-------
+
+Props to richo_. Flat duck pride.
+
+.. _richo: http://github.com/richo
\ No newline at end of file
diff --git a/scruffington.egg-info/PKG-INFO b/scruffington.egg-info/PKG-INFO
index b62b00d..b22a155 100644
--- a/scruffington.egg-info/PKG-INFO
+++ b/scruffington.egg-info/PKG-INFO
@@ -1,11 +1,200 @@
-Metadata-Version: 1.0
+Metadata-Version: 2.1
 Name: scruffington
-Version: 0.3.3
+Version: 0.3.8.2
 Summary: The janitor
 Home-page: https://github.com/snare/scruffy
 Author: snare
 Author-email: snare@ho.ax
 License: MIT
-Description: UNKNOWN
+Description: Scruffy
+        =======
+        
+        .. image:: https://img.shields.io/travis/snare/scruffy.svg
+            :target: https://travis-ci.org/snare/scruffy
+        
+        .. image:: https://img.shields.io/pypi/format/scruffington.svg
+            :target: https://pypi.python.org/pypi/scruffington
+        
+        .. image:: https://readthedocs.org/projects/scruffy/badge/?version=latest
+            :target: http://scruffy.readthedocs.org/en/latest/
+        
+        
+        *Scruffy. The Janitor.*
+        
+        Scruffy is a framework for taking care of a bunch of boilerplate in Python apps. It handles the loading of configuration files, the loading and management of plugins, and the management of other filesystem resources such as temporary files and directories, log files, etc.
+        
+        A typical use case for Scruffy is a command-line Python tool with some or all of the following requirements:
+        
+        * Read a set of configuration defaults
+        * Read a local configuration file and apply it on top of the defaults
+        * Allow overriding some configuration options with command line flags or at runtime
+        * Load a core set of Python-based plugins
+        * Load a set of user-defined Python-based plugins
+        * Generate log files whose name, location and other logging settings are based on configuration
+        * Store application state between runs in a file or database
+        
+        Scruffy is used by Voltron_ and Calculon_
+        
+        .. _Voltron: https://github.com/snare/voltron
+        .. _Calculon: https://github.com/snare/calculon
+        
+        Installation
+        ------------
+        
+        A standard python setup script is included.
+        
+            $ python setup.py install
+        
+        This will install the Scruffy package wherever that happens on your system.
+        
+        Alternately, Scruffy can be installed with `pip` from PyPi (where it's called `scruffington`, because I didn't check for a conflict before I named it).
+        
+            $ pip install scruffington
+        
+        Documentation
+        -------------
+        
+        Full documentation is hosted at readthedocs_
+        
+        .. _readthedocs: http://scruffy.readthedocs.io/
+        
+        Quick start
+        -----------
+        
+        Config
+        ~~~~~~
+        
+        Load a user config file, and apply it on top of a set of defaults loaded from inside the Python package we're currently running from.
+        
+        *thingy.yaml*:
+        
+        .. code:: yaml
+        
+            some_property:  1
+            other_property: a thing
+        
+        *thingy.py*:
+        
+        .. code:: python
+        
+            from scruffy import ConfigFile
+        
+            c = ConfigFile('thingy.yaml', load=True,
+                defaults=File('defaults.yaml', parent=PackageDirectory())
+            )
+        
+            print("c.some_property == {c.some_property}".format(c=c))
+            print("c.other_property == {c.other_property}".format(c=c))
+        
+        Run it:
+        
+        ::
+        
+            $ python thingy.py
+            c.some_property == 1
+            c.other_property == a thing
+        
+        Plugins
+        ~~~~~~~
+        
+        Load some plugins.
+        
+        *~/.thingy/plugins/example.py*:
+        
+        .. code:: python
+        
+            from scruffy import Plugin
+        
+            class ExamplePlugin(Plugin):
+                def do_a_thing(self):
+                    print('{}.{} is doing a thing'.format(__name__, self.__class__.__name__))
+        
+        *thingy.py*:
+        
+        .. code:: python
+        
+            from scruffy import PluginDirectory, PluginRegistry
+        
+            pd = PluginDirectory('~/.thingy/plugins')
+            pd.load()
+        
+            for p in PluginRegistry.plugins:
+                print("Initialising plugin {}".format(p))
+                p().do_a_thing()
+        
+        Run it:
+        
+        ::
+        
+            $ python thingy.py
+            Initialising plugin <class 'example.ExamplePlugin'>
+            example.ExamplePlugin is doing a thing
+        
+        Logging
+        ~~~~~~~
+        
+        Scruffy's `LogFile` class will do some configuration of Python's `logging` module.
+        
+        *log.py*:
+        
+        .. code:: python
+        
+            import logging
+            from scruffy import LogFile
+        
+            log = logging.getLogger('main')
+            log.setLevel(logging.INFO)
+            LogFile('/tmp/thingy.log', logger='main').configure()
+        
+            log.info('Hello from log.py')
+        
+        */tmp/thingy.log*:
+        
+        ::
+        
+            Hello from log.py
+        
+        Environment
+        ~~~~~~~~~~~
+        
+        Scruffy's `Environment` class ties all the other stuff together. The other classes can be instantiated as named children of an `Environment`, which will load any `Config` objects, apply the configs to the other objects, and then prepare the other objects.
+        
+        *~/.thingy/config*:
+        
+        .. code:: yaml
+        
+            log_dir:    /tmp/logs
+            log_file:   thingy.log
+        
+        *env.py*:
+        
+        .. code:: python
+        
+            from scruffy import *
+        
+            e = Environment(
+                main_dir=Directory('~/.thingy', create=True,
+                    config=ConfigFile('config', defaults=File('defaults.yaml', parent=PackageDirectory())),
+                    lock=LockFile('lock')
+                    user_plugins=PluginDirectory('plugins')
+                ),
+                log_dir=Directory('{config:log_dir}', create=True
+                    LogFile('{config:log_file}', logger='main')
+                ),
+                pkg_plugins=PluginDirectory('plugins', parent=PackageDirectory())
+            )
+        
+        License
+        -------
+        
+        See LICENSE file. If you use this and don't hate it, buy me a beer at a conference some time.
+        
+        Credits
+        -------
+        
+        Props to richo_. Flat duck pride.
+        
+        .. _richo: http://github.com/richo
 Keywords: scruffy
 Platform: UNKNOWN
+Description-Content-Type: text/x-rst
diff --git a/scruffington.egg-info/SOURCES.txt b/scruffington.egg-info/SOURCES.txt
index b147ef5..fb4f8be 100644
--- a/scruffington.egg-info/SOURCES.txt
+++ b/scruffington.egg-info/SOURCES.txt
@@ -1,3 +1,4 @@
+README.rst
 setup.cfg
 setup.py
 scruffington.egg-info/PKG-INFO
diff --git a/scruffington.egg-info/requires.txt b/scruffington.egg-info/requires.txt
index 4f1e759..2cd03d5 100644
--- a/scruffington.egg-info/requires.txt
+++ b/scruffington.egg-info/requires.txt
@@ -1,2 +1,2 @@
 pyyaml
-six
\ No newline at end of file
+six
diff --git a/scruffy/config.py b/scruffy/config.py
index 1177430..9ba4552 100644
--- a/scruffy/config.py
+++ b/scruffy/config.py
@@ -1,9 +1,18 @@
+"""
+Config
+------
+
+Classes for loading and accessing configuration data.
+"""
+from six import string_types
+
 import copy
 import os
 import ast
 import yaml
 import re
 
+from six import string_types
 from .file import File
 
 
@@ -13,15 +22,15 @@ class ConfigNode(object):
 
     Can be accessed as a dictionary, like this:
 
-        config['top-level-section']['second-level-property']
+        >>> config['top-level-section']['second-level-property']
 
     Or as a dictionary with a key path, like this:
 
-        config['top_level_section.second_level_property']
+        >>> config['top_level_section.second_level_property']
 
     Or as an object, like this:
 
-        config.top_level_section.second_level_property
+        >>> config.top_level_section.second_level_property
     """
     def __init__(self, data={}, defaults={}, root=None, path=None):
         super(ConfigNode, self).__init__()
@@ -72,9 +81,6 @@ class ConfigNode(object):
     def __le__(self, other):
         return self._get_value() <= other
 
-    def __le__(self, other):
-        return self._get_value() <= other
-
     def __eq__(self, other):
         return self._get_value() == other
 
@@ -90,6 +96,12 @@ class ConfigNode(object):
     def __contains__(self, key):
         return key in self._get_value()
 
+    def __nonzero__(self):
+        return self._get_value() != None
+
+    def __bool__(self):
+        return self._get_value() != None
+
     def items(self):
         return self._get_value().items()
 
@@ -133,7 +145,7 @@ class ConfigNode(object):
         the item referred to by the key path.
         """
         # Split up the key path
-        if type(self._path) == str:
+        if isinstance(self._path, string_types):
             key_path = self._path.split('.')
         else:
             key_path = [self._path]
@@ -195,22 +207,24 @@ class ConfigNode(object):
 
         `options` is a dict of keypath/value pairs like this (similar to
         CherryPy's config mechanism:
-        {
-            'server.port': 8080,
-            'server.host': 'localhost',
-            'admin.email': 'admin@lol'
-        }
+
+            >>> c.update(options={
+            ...     'server.port': 8080,
+            ...     'server.host': 'localhost',
+            ...     'admin.email': 'admin@lol'
+            ... })
 
         `data` is a dict of actual config data, like this:
-        {
-            'server': {
-                'port': 8080,
-                'host': 'localhost'
-            },
-            'admin': {
-                'email': 'admin@lol'
-            }
-        }
+
+            >>> c.update(data={
+            ...     'server': {
+            ...         'port': 8080,
+            ...         'host': 'localhost'
+            ...     },
+            ...     'admin': {
+            ...         'email': 'admin@lol'
+            ...     }
+            ... })
         """
         # Handle an update with a set of options like CherryPy does
         for key in options:
@@ -244,17 +258,17 @@ class ConfigEnv(ConfigNode):
     """
     Config based on based on environment variables.
     """
-    def __init__(self, *args, **kwargs):
+    def __init__(self, prefix='SCRUFFY', *args, **kwargs):
         super(ConfigEnv, self).__init__(*args, **kwargs)
 
-        # build options dictionary from environment variables starting with __SC_
+        # build options dictionary from environment variables starting with the prefix
         options = {}
-        for key in filter(lambda x: x.startswith('__SC_'), os.environ):
+        for key in [v for v in os.environ if v.startswith('__SC_') or v.startswith(prefix + '_')]:
             try:
                 val = ast.literal_eval(os.environ[key])
             except:
                 val = os.environ[key]
-            options[key.replace('__SC_', '').lower()] = val
+            options[key.replace('__SC_', '').replace(prefix + '_', '').lower()] = val
 
         # update config with the values we've found
         self.update(options=options)
@@ -264,10 +278,11 @@ class ConfigFile(Config, File):
     """
     Config based on a loaded YAML or JSON file.
     """
-    def __init__(self, path=None, defaults=None, load=False, apply_env=False, *args, **kwargs):
+    def __init__(self, path=None, defaults=None, load=False, apply_env=False, env_prefix='SCRUFFY', *args, **kwargs):
         self._loaded = False
         self._defaults_file = defaults
         self._apply_env = apply_env
+        self._env_prefix = env_prefix
         Config.__init__(self)
         File.__init__(self, path=path, *args, **kwargs)
 
@@ -280,7 +295,7 @@ class ConfigFile(Config, File):
         """
         if reload or not self._loaded:
             # load defaults
-            if self._defaults_file and type(self._defaults_file) == str:
+            if self._defaults_file and isinstance(self._defaults_file, string_types):
                 self._defaults_file = File(self._defaults_file, parent=self._parent)
             defaults = {}
             if self._defaults_file:
@@ -298,7 +313,7 @@ class ConfigFile(Config, File):
 
             # if specified, apply environment variables
             if self._apply_env:
-                self.update(ConfigEnv())
+                self.update(ConfigEnv(self._env_prefix))
 
             self._loaded = True
 
@@ -308,7 +323,7 @@ class ConfigFile(Config, File):
         """
         Save the config back to the config file.
         """
-        self.write(yaml.safe_dump(self._data))
+        self.write(yaml.safe_dump(self._data, default_flow_style=False))
 
     def prepare(self):
         """
@@ -328,7 +343,7 @@ class ConfigApplicator(object):
         """
         Apply the config to an object.
         """
-        if type(obj) == str:
+        if isinstance(obj, string_types):
             return self.apply_to_str(obj)
 
     def apply_to_str(self, obj):
@@ -370,20 +385,23 @@ def update_dict(target, source):
     dictionary.
 
     For example:
-    target before = {
-        'thing': 123,
-        'thang': {
-            'a': 1,
-            'b': 2
-        }
-    }
-    source = {
-        'thang': {
-            'a': 666,
-            'c': 777
-        }
-    }
-    target after = {
+
+    >>> target = {
+    ...     'thing': 123,
+    ...     'thang': {
+    ...         'a': 1,
+    ...         'b': 2
+    ...     }
+    ... }
+    >>> source = {
+    ...     'thang': {
+    ...         'a': 666,
+    ...         'c': 777
+    ...     }
+    ... }
+    >>> update_dict(target, source)
+    >>> target
+    {
         'thing': 123,
         'thang': {
             'a': 666,
diff --git a/scruffy/env.py b/scruffy/env.py
index 826493b..ae08693 100644
--- a/scruffy/env.py
+++ b/scruffy/env.py
@@ -1,3 +1,10 @@
+"""
+Environment
+-----------
+
+Classes for representing the encompassing environment in which your application
+runs.
+"""
 import os
 import yaml
 import itertools
@@ -5,9 +12,11 @@ import errno
 import logging
 import logging.config
 
+from six import string_types
+
 from .file import Directory
 from .plugin import PluginManager
-from .config import ConfigNode, Config, ConfigEnv, ConfigApplicator
+from .config import ConfigNode, Config, ConfigEnv, ConfigApplicator, ConfigFile
 
 
 class Environment(object):
@@ -61,7 +70,7 @@ class Environment(object):
 
         # first see if we got a kwarg named 'config', as this guy is special
         if 'config' in children:
-            if type(children['config']) == str:
+            if isinstance(children['config'], string_types):
                 children['config'] = ConfigFile(children['config'])
             elif isinstance(children['config'], Config):
                 children['config'] = children['config']
@@ -96,7 +105,7 @@ class Environment(object):
         Add objects to the environment.
         """
         for key in kwargs:
-            if type(kwargs[key]) == str:
+            if isinstance(kwargs[key], string_types):
                 self._children[key] = Directory(kwargs[key])
             else:
                 self._children[key] = kwargs[key]
diff --git a/scruffy/file.py b/scruffy/file.py
index cd913f7..2db91e1 100644
--- a/scruffy/file.py
+++ b/scruffy/file.py
@@ -1,4 +1,12 @@
+"""
+File
+----
+
+Classes for representing and performing operations on files and directories.
+"""
+from __future__ import unicode_literals
 import os
+from six import string_types
 import yaml
 import copy
 import logging
@@ -38,9 +46,9 @@ class File(object):
 
     def apply_config(self, applicator):
         """
-        Replace any config tokens with values from the config.
+        Replace any config tokens in the file's path with values from the config.
         """
-        if type(self._fpath) == str:
+        if isinstance(self._fpath, string_types):
             self._fpath = applicator.apply(self._fpath)
 
     def create(self):
@@ -51,7 +59,7 @@ class File(object):
 
     def remove(self):
         """
-        Remove the file.
+        Remove the file if it exists.
         """
         if self.exists:
             os.unlink(self.path)
@@ -166,7 +174,7 @@ class LogFile(File):
 
         # if we got a string for the formatter, assume it's the name of a
         # formatter in the environment's config
-        if type(self._formatter) == str:
+        if isinstance(self._format, string_types):
             if self._env and self._env.config.logging.dict_config.formatters[self._formatter]:
                 d = self._env.config.logging.dict_config.formatters[self._formatter].to_dict()
                 handler.setFormatter(logging.Formatter(**d))
@@ -237,14 +245,14 @@ class Directory(object):
     A Scruffy Environment usually encompasses a number of these. For example,
     the main Directory object may represent `~/.myproject`.
 
-    d = Directory({
-        path='~/.myproject',
-        create=True,
-        cleanup=False,
-        children=[
-        ...
-        ]
-    })
+    >>> d = Directory({
+    ...     path='~/.myproject',
+    ...     create=True,
+    ...     cleanup=False,
+    ...     children=[
+    ...     ...
+    ...     ]
+    ... })
 
     `path` can be either a string representing the path to the directory, or
     a nested Directory object. If a Directory object is passed as the `path`
@@ -261,7 +269,7 @@ class Directory(object):
         self._env = None
         self._parent = parent
 
-        if self._path and type(self._path) == str:
+        if self._path and isinstance(self._path, string_types):
             self._path = os.path.expanduser(self._path)
 
         self.add(**kwargs)
@@ -283,7 +291,7 @@ class Directory(object):
         """
         Replace any config tokens with values from the config.
         """
-        if type(self._path) == str:
+        if isinstance(self._path, string_types):
             self._path = applicator.apply(self._path)
 
         for key in self._children:
@@ -390,7 +398,7 @@ class Directory(object):
         Add objects to the directory.
         """
         for key in kwargs:
-            if isinstance(kwargs[key], str):
+            if isinstance(kwargs[key], string_types):
                 self._children[key] = File(kwargs[key])
             else:
                 self._children[key] = kwargs[key]
@@ -403,7 +411,7 @@ class Directory(object):
                 self._children[arg.name] = arg
                 self._children[arg.name]._parent = self
                 self._children[arg.name]._env = self._env
-            elif isinstance(arg, str):
+            elif isinstance(arg, string_types):
                 f = File(arg)
                 added.append(f)
                 self._children[arg] = f
diff --git a/scruffy/plugin.py b/scruffy/plugin.py
index 267b2d2..9c6853b 100644
--- a/scruffy/plugin.py
+++ b/scruffy/plugin.py
@@ -1,3 +1,9 @@
+"""
+Plugin
+------
+
+Classes for representing and loading plugins.
+"""
 import os
 import imp
 import six
diff --git a/scruffy/state.py b/scruffy/state.py
index f73881a..3931d47 100644
--- a/scruffy/state.py
+++ b/scruffy/state.py
@@ -1,6 +1,14 @@
+"""
+State
+-----
+
+Classes for storing a program's state.
+"""
 import os
+import atexit
 import yaml
 
+
 try:
     from sqlalchemy import create_engine, Column, Integer, String
     from sqlalchemy.ext.declarative import declarative_base
@@ -28,6 +36,7 @@ class State(object):
         self.path = path
         self.d = {}
         self.load()
+        atexit.register(self._exit_handler)
 
     def __enter__(self):
         self.load()
@@ -45,6 +54,9 @@ class State(object):
     def __setitem__(self, key, value):
         self.d[key] = value
 
+    def _exit_handler(self):
+        self.save()
+
     def save(self):
         """
         Save the state to a file.
@@ -58,7 +70,11 @@ class State(object):
         """
         if os.path.exists(self.path):
             with open(self.path, 'r') as f:
-                self.d = yaml.safe_load(f.read().replace('\t', ' '*4))
+                d = yaml.safe_load(f.read().replace('\t', ' '*4))
+                # don't clobber self.d if we successfully opened the state file
+                # but it was empty
+                if d:
+                    self.d = d
 
     def cleanup(self):
         """
diff --git a/setup.cfg b/setup.cfg
index 6f08d0e..adf5ed7 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -4,5 +4,4 @@ universal = 1
 [egg_info]
 tag_build = 
 tag_date = 0
-tag_svn_revision = 0
 
diff --git a/setup.py b/setup.py
index aef1603..7c63b7e 100755
--- a/setup.py
+++ b/setup.py
@@ -1,10 +1,15 @@
 from setuptools import setup
 
+with open("README.rst", "r") as fp:
+    long_description = fp.read()
+
 setup(
     name="scruffington",
-    version="0.3.3",
+    version="0.3.8.2",
     author="snare",
     author_email="snare@ho.ax",
+    long_description=long_description,
+    long_description_content_type="text/x-rst",
     description=("The janitor"),
     license="MIT",
     keywords="scruffy",