diff --git a/cms/envs/dev.py b/cms/envs/dev.py
index fd0249d..7a485d2 100644
--- a/cms/envs/dev.py
+++ b/cms/envs/dev.py
@@ -27,6 +27,10 @@ update_module_store_settings(
     }
 )
 
+DJFS = {'type': 'osfs',
+        'directory_root': 'cms/static/djpyfs',
+        'url_root': '/static/djpyfs'}
+
 # cdodge: This is the specifier for the MongoDB (using GridFS) backed static content store
 # This is for static content for courseware, not system static content (e.g. javascript, css, edX branding, etc)
 CONTENTSTORE = {
@@ -129,7 +133,7 @@ CELERY_ALWAYS_EAGER = True
 
 ################################ DEBUG TOOLBAR #################################
 INSTALLED_APPS += ('debug_toolbar', 'debug_toolbar_mongo')
-MIDDLEWARE_CLASSES += ('debug_toolbar.middleware.DebugToolbarMiddleware',)
+MIDDLEWARE_CLASSES += ('debug_toolbar.middleware.DebugToolbarMiddleware', 'djpyfs')
 INTERNAL_IPS = ('127.0.0.1',)
 
 DEBUG_TOOLBAR_PANELS = (
diff --git a/common/lib/xmodule/xmodule/modulestore/django.py b/common/lib/xmodule/xmodule/modulestore/django.py
index 84f694f..ac0ac72 100644
--- a/common/lib/xmodule/xmodule/modulestore/django.py
+++ b/common/lib/xmodule/xmodule/modulestore/django.py
@@ -19,6 +19,7 @@ import threading
 from xmodule.util.django import get_current_request_hostname
 import xmodule.modulestore  # pylint: disable=unused-import
 from xmodule.contentstore.django import contentstore
+import xblock.reference.plugins
 
 # We may not always have the request_cache module available
 try:
@@ -41,7 +42,7 @@ def load_function(path):
     return getattr(import_module(module_path), name)
 
 
-def create_modulestore_instance(engine, content_store, doc_store_config, options, i18n_service=None):
+def create_modulestore_instance(engine, content_store, doc_store_config, options, i18n_service=None, pyfs_service=None):
     """
     This will return a new instance of a modulestore given an engine and options
     """
@@ -73,6 +74,7 @@ def create_modulestore_instance(engine, content_store, doc_store_config, options
         xblock_select=getattr(settings, 'XBLOCK_SELECT_FUNCTION', None),
         doc_store_config=doc_store_config,
         i18n_service=i18n_service or ModuleI18nService(),
+        pyfs_service=pyfs_service or xblock.reference.plugins.FSService(),
         branch_setting_func=_get_modulestore_branch_setting,
         create_modulestore_instance=create_modulestore_instance,
         **_options
diff --git a/common/lib/xmodule/xmodule/modulestore/mixed.py b/common/lib/xmodule/xmodule/modulestore/mixed.py
index 5cb862c..0f0d0e4 100644
--- a/common/lib/xmodule/xmodule/modulestore/mixed.py
+++ b/common/lib/xmodule/xmodule/modulestore/mixed.py
@@ -91,7 +91,7 @@ class MixedModuleStore(ModuleStoreDraftAndPublished, ModuleStoreWriteBase):
     """
     ModuleStore knows how to route requests to the right persistence ms
     """
-    def __init__(self, contentstore, mappings, stores, i18n_service=None, create_modulestore_instance=None, **kwargs):
+    def __init__(self, contentstore, mappings, stores, i18n_service=None, pyfs_service=None, create_modulestore_instance=None, **kwargs):
         """
         Initialize a MixedModuleStore. Here we look into our passed in kwargs which should be a
         collection of other modulestore configuration information
@@ -130,6 +130,7 @@ class MixedModuleStore(ModuleStoreDraftAndPublished, ModuleStoreWriteBase):
                 store_settings.get('DOC_STORE_CONFIG', {}),
                 store_settings.get('OPTIONS', {}),
                 i18n_service=i18n_service,
+                pyfs_service=pyfs_service,
             )
             # replace all named pointers to the store into actual pointers
             for course_key, store_name in self.mappings.iteritems():
diff --git a/common/lib/xmodule/xmodule/modulestore/mongo/base.py b/common/lib/xmodule/xmodule/modulestore/mongo/base.py
index 7568d56..9e1adc4 100644
--- a/common/lib/xmodule/xmodule/modulestore/mongo/base.py
+++ b/common/lib/xmodule/xmodule/modulestore/mongo/base.py
@@ -366,6 +366,7 @@ class MongoModuleStore(ModuleStoreDraftAndPublished, ModuleStoreWriteBase):
                  default_class=None,
                  error_tracker=null_error_tracker,
                  i18n_service=None,
+                 pyfs_service=None,
                  **kwargs):
         """
         :param doc_store_config: must have a host, db, and collection entries. Other common entries: port, tz_aware.
@@ -409,6 +410,7 @@ class MongoModuleStore(ModuleStoreDraftAndPublished, ModuleStoreWriteBase):
         self.error_tracker = error_tracker
         self.render_template = render_template
         self.i18n_service = i18n_service
+        self.pyfs_service = pyfs_service
 
         # performance optimization to prevent updating the meta-data inheritance tree during
         # bulk write operations
@@ -696,6 +698,9 @@ class MongoModuleStore(ModuleStoreDraftAndPublished, ModuleStoreWriteBase):
         if self.i18n_service:
             services["i18n"] = self.i18n_service
 
+        if self.pyfs_service:
+            services["fs"] = self.pyfs_service
+
         system = CachingDescriptorSystem(
             modulestore=self,
             course_key=course_key,
@@ -989,6 +994,9 @@ class MongoModuleStore(ModuleStoreDraftAndPublished, ModuleStoreWriteBase):
             if self.i18n_service:
                 services["i18n"] = self.i18n_service
 
+            if self.pyfs_service:
+                services["fs"] = self.pyfs_service
+
             runtime = CachingDescriptorSystem(
                 modulestore=self,
                 module_data={},
diff --git a/common/lib/xmodule/xmodule/modulestore/split_mongo/split.py b/common/lib/xmodule/xmodule/modulestore/split_mongo/split.py
index 25b8391..9255dc8 100644
--- a/common/lib/xmodule/xmodule/modulestore/split_mongo/split.py
+++ b/common/lib/xmodule/xmodule/modulestore/split_mongo/split.py
@@ -120,8 +120,8 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
     def __init__(self, contentstore, doc_store_config, fs_root, render_template,
                  default_class=None,
                  error_tracker=null_error_tracker,
-                 i18n_service=None, services=None,
-                 **kwargs):
+                 i18n_service=None, pyfs_service=None,
+                 services=None, **kwargs):
         """
         :param doc_store_config: must have a host, db, and collection entries. Other common entries: port, tz_aware.
         """
@@ -148,6 +148,9 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
         if i18n_service is not None:
             self.services["i18n"] = i18n_service
 
+        if pyfs_service is not None:
+            self.services["fs"] = pyfs_service
+
     def close_connections(self):
         """
         Closes any open connections to the underlying databases
diff --git a/common/lib/xmodule/xmodule/modulestore/xml.py b/common/lib/xmodule/xmodule/modulestore/xml.py
index b329fdc..907e8e4 100644
--- a/common/lib/xmodule/xmodule/modulestore/xml.py
+++ b/common/lib/xmodule/xmodule/modulestore/xml.py
@@ -370,7 +370,7 @@ class XMLModuleStore(ModuleStoreReadBase):
     """
     def __init__(
         self, data_dir, default_class=None, course_dirs=None, course_ids=None,
-        load_error_modules=True, i18n_service=None, **kwargs
+        load_error_modules=True, i18n_service=None, pyfs_service=None, **kwargs
     ):
         """
         Initialize an XMLModuleStore from data_dir
@@ -409,6 +409,7 @@ class XMLModuleStore(ModuleStoreReadBase):
         self.field_data = inheriting_field_data(kvs=DictKeyValueStore())
 
         self.i18n_service = i18n_service
+        self.pyfs_service = pyfs_service
 
         # If we are specifically asked for missing courses, that should
         # be an error.  If we are asked for "all" courses, find the ones
@@ -554,6 +555,9 @@ class XMLModuleStore(ModuleStoreReadBase):
             if self.i18n_service:
                 services['i18n'] = self.i18n_service
 
+            if self.pyfs_service:
+                services['fs'] = self.pyfs_service
+
             system = ImportSystem(
                 xmlstore=self,
                 course_id=course_id,
diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py
index d1ebdfb..b8accd9 100644
--- a/lms/djangoapps/courseware/module_render.py
+++ b/lms/djangoapps/courseware/module_render.py
@@ -3,6 +3,7 @@ import logging
 import mimetypes
 
 import static_replace
+import xblock.reference.plugins
 
 from functools import partial
 from requests.auth import HTTPBasicAuth
@@ -535,6 +536,7 @@ def get_module_system_for_user(user, field_data_cache,
         get_real_user=user_by_anonymous_id,
         services={
             'i18n': ModuleI18nService(),
+            'fs': xblock.reference.plugins.FSService(),
         },
         get_user_role=lambda: get_user_role(user, course_id),
         descriptor_runtime=descriptor.runtime,
diff --git a/lms/envs/dev.py b/lms/envs/dev.py
index 1193c84..2a8771a 100644
--- a/lms/envs/dev.py
+++ b/lms/envs/dev.py
@@ -50,6 +50,10 @@ LOGGING = get_logger_config(ENV_ROOT / "log",
                             dev_env=True,
                             debug=True)
 
+DJFS = {'type': 'osfs',
+        'directory_root': 'lms/static/djpyfs',
+        'url_root': '/static/djpyfs'}
+
 # If there is a database called 'read_replica', you can use the use_read_replica_if_available
 # function in util/query.py, which is useful for very large database reads
 DATABASES = {
@@ -217,7 +221,8 @@ CELERY_ALWAYS_EAGER = True
 
 INSTALLED_APPS += ('debug_toolbar',)
 MIDDLEWARE_CLASSES += ('django_comment_client.utils.QueryCountDebugMiddleware',
-                       'debug_toolbar.middleware.DebugToolbarMiddleware',)
+                       'debug_toolbar.middleware.DebugToolbarMiddleware',
+                       'djpyfs')
 INTERNAL_IPS = ('127.0.0.1',)
 
 DEBUG_TOOLBAR_PANELS = (
diff --git a/lms/lib/xblock/runtime.py b/lms/lib/xblock/runtime.py
index 4c547be..f02657c 100644
--- a/lms/lib/xblock/runtime.py
+++ b/lms/lib/xblock/runtime.py
@@ -3,6 +3,7 @@ Module implementing `xblock.runtime.Runtime` functionality for the LMS
 """
 
 import re
+import xblock.reference.plugins
 
 from django.core.urlresolvers import reverse
 from django.conf import settings
@@ -193,4 +194,5 @@ class LmsModuleSystem(LmsHandlerUrls, ModuleSystem):  # pylint: disable=abstract
             course_id=kwargs.get('course_id', None),
             track_function=kwargs.get('track_function', None),
         )
+        services['fs'] = xblock.reference.plugins.FSService()
         super(LmsModuleSystem, self).__init__(**kwargs)
diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt
index a8eacf2..471041a 100644
--- a/requirements/edx/base.txt
+++ b/requirements/edx/base.txt
@@ -138,3 +138,5 @@ git+https://github.com/mitocw/django-cas.git
 
 # edX packages
 edx-submissions==0.0.6
+
+-e git+https://github.com/pmitros/django-pyfs.git@514607d78535fd80bfd23184cd292ee5799b500d#egg=djpyfs
diff --git a/requirements/edx/edx-private.txt b/requirements/edx/edx-private.txt
index 1f3d45a..4a10aed 100644
--- a/requirements/edx/edx-private.txt
+++ b/requirements/edx/edx-private.txt
@@ -15,4 +15,3 @@
 # It is an R&D prototype, intended for roll-out one location in one course. 
 # It should not be used without learning sciences support in the current state. 
 -e git+https://github.com/pmitros/RecommenderXBlock.git@fae9e5bc8a8297cb15001f0d674430e3d22ffa35#egg=recommender-xblock
-