diff --git a/lms/djangoapps/track/__init__.py b/cms/__init__.py
similarity index 100%
rename from lms/djangoapps/track/__init__.py
rename to cms/__init__.py
diff --git a/lms/lib/cache_toolbox/templatetags/__init__.py b/cms/envs/__init__.py
similarity index 100%
rename from lms/lib/cache_toolbox/templatetags/__init__.py
rename to cms/envs/__init__.py
diff --git a/cms/envs/common.py b/cms/envs/common.py
new file mode 100644
index 0000000000000000000000000000000000000000..9b349a06d0d3b2c03bc49785e132b5526fc302ec
--- /dev/null
+++ b/cms/envs/common.py
@@ -0,0 +1,151 @@
+"""
+This is the common settings file, intended to set sane defaults. If you have a
+piece of configuration that's dependent on a set of feature flags being set,
+then create a function that returns the calculated value based on the value of
+MITX_FEATURES[...]. Modules that extend this one can change the feature
+configuration in an environment specific config file and re-calculate those
+values.
+
+We should make a method that calls all these config methods so that you just
+make one call at the end of your site-specific dev file to reset all the
+dependent variables (like INSTALLED_APPS) for you.
+
+Longer TODO:
+1. Right now our treatment of static content in general and in particular
+   course-specific static content is haphazard.
+2. We should have a more disciplined approach to feature flagging, even if it
+   just means that we stick them in a dict called MITX_FEATURES.
+3. We need to handle configuration for multiple courses. This could be as
+   multiple sites, but we do need a way to map their data assets.
+"""
+
+import sys
+import tempfile
+from path import path
+
+############################# SET PATH INFORMATION #############################
+PROJECT_ROOT = path(__file__).abspath().dirname().dirname()  # /mitx/cms
+COMMON_ROOT = PROJECT_ROOT.dirname() / "common"
+ENV_ROOT = PROJECT_ROOT.dirname().dirname()  # virtualenv dir /mitx is in
+ASKBOT_ROOT = ENV_ROOT / "askbot-devel"
+COURSES_ROOT = ENV_ROOT / "data"
+
+# FIXME: To support multiple courses, we should walk the courses dir at startup
+DATA_DIR = COURSES_ROOT
+
+sys.path.append(ENV_ROOT)
+sys.path.append(ASKBOT_ROOT)
+sys.path.append(ASKBOT_ROOT / "askbot" / "deps")
+sys.path.append(PROJECT_ROOT / 'djangoapps')
+sys.path.append(PROJECT_ROOT / 'lib')
+sys.path.append(COMMON_ROOT / 'djangoapps')
+sys.path.append(COMMON_ROOT / 'lib')
+
+
+############################# WEB CONFIGURATION #############################
+# This is where we stick our compiled template files.
+MAKO_MODULE_DIR = tempfile.mkdtemp('mako')
+MAKO_TEMPLATES = {}
+MAKO_TEMPLATES['main'] = [PROJECT_ROOT / 'templates']
+
+MITX_ROOT_URL = ''
+
+TEMPLATE_CONTEXT_PROCESSORS = (
+    'django.core.context_processors.request',
+    'django.core.context_processors.static',
+    'django.contrib.messages.context_processors.messages',
+    'django.core.context_processors.auth',  # this is required for admin
+    'django.core.context_processors.csrf',  # necessary for csrf protection
+)
+
+################################# Middleware ###################################
+# List of finder classes that know how to find static files in
+# various locations.
+STATICFILES_FINDERS = (
+    'django.contrib.staticfiles.finders.FileSystemFinder',
+    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
+)
+
+# List of callables that know how to import templates from various sources.
+TEMPLATE_LOADERS = (
+    'django.template.loaders.filesystem.Loader',
+    'django.template.loaders.app_directories.Loader',
+)
+
+MIDDLEWARE_CLASSES = (
+    'django.middleware.cache.UpdateCacheMiddleware',
+    'django.middleware.common.CommonMiddleware',
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.middleware.csrf.CsrfViewMiddleware',
+
+    # Instead of AuthenticationMiddleware, we use a cached backed version
+    'cache_toolbox.middleware.CacheBackedAuthenticationMiddleware',
+
+    'django.contrib.messages.middleware.MessageMiddleware',
+    'track.middleware.TrackMiddleware',
+    'mitxmako.middleware.MakoMiddleware',
+
+    'django.middleware.transaction.TransactionMiddleware',
+)
+
+############################ SIGNAL HANDLERS ################################
+import monitoring.exceptions  # noqa
+
+############################ DJANGO_BUILTINS ################################
+# Change DEBUG/TEMPLATE_DEBUG in your environment settings files, not here
+DEBUG = False
+TEMPLATE_DEBUG = False
+
+# Site info
+SITE_ID = 1
+SITE_NAME = "localhost:8000"
+HTTPS = 'on'
+ROOT_URLCONF = 'mitx.cms.urls'
+IGNORABLE_404_ENDS = ('favicon.ico')
+
+# Email
+EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
+DEFAULT_FROM_EMAIL = 'registration@mitx.mit.edu'
+DEFAULT_FEEDBACK_EMAIL = 'feedback@mitx.mit.edu'
+ADMINS = (
+    ('MITx Admins', 'admin@mitx.mit.edu'),
+)
+MANAGERS = ADMINS
+
+# Static content
+STATIC_URL = '/static/'
+ADMIN_MEDIA_PREFIX = '/static/admin/'
+STATIC_ROOT = ENV_ROOT / "staticfiles" 
+
+# FIXME: We should iterate through the courses we have, adding the static 
+#        contents for each of them. (Right now we just use symlinks.)
+STATICFILES_DIRS = [
+    PROJECT_ROOT / "static",
+
+# This is how you would use the textbook images locally
+#    ("book", ENV_ROOT / "book_images")
+]
+
+# Locale/Internationalization
+TIME_ZONE = 'America/New_York'  # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
+LANGUAGE_CODE = 'en'            # http://www.i18nguy.com/unicode/language-identifiers.html
+USE_I18N = True
+USE_L10N = True
+
+# Messages
+MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'
+
+############################ APPS #####################################
+
+INSTALLED_APPS = (
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.sites',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+    # Uncomment the next line to enable the admin:
+    # 'django.contrib.admin',
+    # Uncomment the next line to enable admin documentation:
+    # 'django.contrib.admindocs',
+)
diff --git a/cms/envs/dev.py b/cms/envs/dev.py
new file mode 100644
index 0000000000000000000000000000000000000000..72a5e512c4dd34c0374bec4a00b35b752ae36c19
--- /dev/null
+++ b/cms/envs/dev.py
@@ -0,0 +1,37 @@
+"""
+This config file runs the simplest dev environment"""
+
+from .common import *
+
+DEBUG = True
+TEMPLATE_DEBUG = DEBUG
+
+DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.sqlite3',
+        'NAME': ENV_ROOT / "db" / "mitx.db",
+    }
+}
+
+CACHES = {
+    # This is the cache used for most things. Askbot will not work without a 
+    # functioning cache -- it relies on caching to load its settings in places.
+    # In staging/prod envs, the sessions also live here.
+    'default': {
+        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
+        'LOCATION': 'mitx_loc_mem_cache',
+        'KEY_FUNCTION': 'util.memcache.safe_key',
+    },
+
+    # The general cache is what you get if you use our util.cache. It's used for
+    # things like caching the course.xml file for different A/B test groups.
+    # We set it to be a DummyCache to force reloading of course.xml in dev.
+    # In staging environments, we would grab VERSION from data uploaded by the
+    # push process.
+    'general': {
+        'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
+        'KEY_PREFIX': 'general',
+        'VERSION': 4,
+        'KEY_FUNCTION': 'util.cache.memcache_safe_key',
+    }
+}
diff --git a/cms/manage.py b/cms/manage.py
new file mode 100644
index 0000000000000000000000000000000000000000..3e4eedc9ff5862c99e999b544a5b34c4e9af877a
--- /dev/null
+++ b/cms/manage.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+from django.core.management import execute_manager
+import imp
+try:
+    imp.find_module('settings') # Assumed to be in the same directory.
+except ImportError:
+    import sys
+    sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n" % __file__)
+    sys.exit(1)
+
+import settings
+
+if __name__ == "__main__":
+    execute_manager(settings)
diff --git a/lms/lib/util/__init__.py b/cms/models.py
similarity index 100%
rename from lms/lib/util/__init__.py
rename to cms/models.py
diff --git a/cms/templates/calendar.html b/cms/templates/calendar.html
new file mode 100644
index 0000000000000000000000000000000000000000..05b2f888065e63369e65cff747cbe7b7befa09ad
--- /dev/null
+++ b/cms/templates/calendar.html
@@ -0,0 +1,3 @@
+% for week in weeks:
+${week}
+% endfor
diff --git a/cms/urls.py b/cms/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..80e2b19e9d32802acd72a12dc71e41611de364bd
--- /dev/null
+++ b/cms/urls.py
@@ -0,0 +1,9 @@
+from django.conf.urls.defaults import patterns, url
+
+# Uncomment the next two lines to enable the admin:
+# from django.contrib import admin
+# admin.autodiscover()
+
+urlpatterns = patterns('cms.views',
+    url(r'^(?P<course>[^/]+)/calendar/', 'calendar', name='calendar'),
+)
diff --git a/cms/views.py b/cms/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..d0d4f4871cf5f1e84a2fb3db0cf3fde3d1c859fd
--- /dev/null
+++ b/cms/views.py
@@ -0,0 +1,5 @@
+from mitxmako.shortcuts import render_to_response
+
+
+def calendar(request, course):
+    return render_to_response('calendar.html', {})
diff --git a/common/djangoapps/track/__init__.py b/common/djangoapps/track/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/lms/djangoapps/track/middleware.py b/common/djangoapps/track/middleware.py
similarity index 100%
rename from lms/djangoapps/track/middleware.py
rename to common/djangoapps/track/middleware.py
diff --git a/lms/djangoapps/track/models.py b/common/djangoapps/track/models.py
similarity index 100%
rename from lms/djangoapps/track/models.py
rename to common/djangoapps/track/models.py
diff --git a/lms/djangoapps/track/tests.py b/common/djangoapps/track/tests.py
similarity index 100%
rename from lms/djangoapps/track/tests.py
rename to common/djangoapps/track/tests.py
diff --git a/lms/djangoapps/track/views.py b/common/djangoapps/track/views.py
similarity index 100%
rename from lms/djangoapps/track/views.py
rename to common/djangoapps/track/views.py
diff --git a/lms/lib/cache_toolbox/COPYING b/common/lib/cache_toolbox/COPYING
similarity index 100%
rename from lms/lib/cache_toolbox/COPYING
rename to common/lib/cache_toolbox/COPYING
diff --git a/lms/lib/cache_toolbox/README.rst b/common/lib/cache_toolbox/README.rst
similarity index 100%
rename from lms/lib/cache_toolbox/README.rst
rename to common/lib/cache_toolbox/README.rst
diff --git a/lms/lib/cache_toolbox/__init__.py b/common/lib/cache_toolbox/__init__.py
similarity index 100%
rename from lms/lib/cache_toolbox/__init__.py
rename to common/lib/cache_toolbox/__init__.py
diff --git a/lms/lib/cache_toolbox/app_settings.py b/common/lib/cache_toolbox/app_settings.py
similarity index 100%
rename from lms/lib/cache_toolbox/app_settings.py
rename to common/lib/cache_toolbox/app_settings.py
diff --git a/lms/lib/cache_toolbox/core.py b/common/lib/cache_toolbox/core.py
similarity index 100%
rename from lms/lib/cache_toolbox/core.py
rename to common/lib/cache_toolbox/core.py
diff --git a/lms/lib/cache_toolbox/middleware.py b/common/lib/cache_toolbox/middleware.py
similarity index 100%
rename from lms/lib/cache_toolbox/middleware.py
rename to common/lib/cache_toolbox/middleware.py
diff --git a/lms/lib/cache_toolbox/model.py b/common/lib/cache_toolbox/model.py
similarity index 100%
rename from lms/lib/cache_toolbox/model.py
rename to common/lib/cache_toolbox/model.py
diff --git a/lms/lib/cache_toolbox/relation.py b/common/lib/cache_toolbox/relation.py
similarity index 100%
rename from lms/lib/cache_toolbox/relation.py
rename to common/lib/cache_toolbox/relation.py
diff --git a/common/lib/cache_toolbox/templatetags/__init__.py b/common/lib/cache_toolbox/templatetags/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/lms/lib/cache_toolbox/templatetags/cache_toolbox.py b/common/lib/cache_toolbox/templatetags/cache_toolbox.py
similarity index 100%
rename from lms/lib/cache_toolbox/templatetags/cache_toolbox.py
rename to common/lib/cache_toolbox/templatetags/cache_toolbox.py
diff --git a/common/lib/monitoring/__init__.py b/common/lib/monitoring/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/common/lib/monitoring/exceptions.py b/common/lib/monitoring/exceptions.py
new file mode 100644
index 0000000000000000000000000000000000000000..6a34d9a38f077a9ec999f653a668580ad8ed1499
--- /dev/null
+++ b/common/lib/monitoring/exceptions.py
@@ -0,0 +1,10 @@
+from django.core.signals import got_request_exception
+from django.dispatch import receiver
+import logging
+
+
+@receiver(got_request_exception)
+def record_request_exception(sender, **kwargs):
+    logging.exception("Uncaught exception from {sender}".format(
+        sender=sender
+    ))
diff --git a/common/lib/util/__init__.py b/common/lib/util/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/lms/lib/util/cache.py b/common/lib/util/cache.py
similarity index 100%
rename from lms/lib/util/cache.py
rename to common/lib/util/cache.py
diff --git a/lms/lib/util/memcache.py b/common/lib/util/memcache.py
similarity index 100%
rename from lms/lib/util/memcache.py
rename to common/lib/util/memcache.py
diff --git a/lms/lib/util/middleware.py b/common/lib/util/middleware.py
similarity index 100%
rename from lms/lib/util/middleware.py
rename to common/lib/util/middleware.py
diff --git a/lms/lib/util/models.py b/common/lib/util/models.py
similarity index 100%
rename from lms/lib/util/models.py
rename to common/lib/util/models.py
diff --git a/lms/lib/util/tests.py b/common/lib/util/tests.py
similarity index 100%
rename from lms/lib/util/tests.py
rename to common/lib/util/tests.py
diff --git a/lms/lib/util/views.py b/common/lib/util/views.py
similarity index 100%
rename from lms/lib/util/views.py
rename to common/lib/util/views.py
diff --git a/lms/envs/common.py b/lms/envs/common.py
index 806c379747f79e04adb2b372ab4f7b0a0d6febec..3ac026fd818390adf654fb40ac7e7cb01a913804 100644
--- a/lms/envs/common.py
+++ b/lms/envs/common.py
@@ -60,6 +60,7 @@ sys.path.append(ASKBOT_ROOT)
 sys.path.append(ASKBOT_ROOT / "askbot" / "deps")
 sys.path.append(PROJECT_ROOT / 'djangoapps')
 sys.path.append(PROJECT_ROOT / 'lib')
+sys.path.append(COMMON_ROOT / 'djangoapps')
 sys.path.append(COMMON_ROOT / 'lib')
 
 ################################## MITXWEB #####################################
diff --git a/rakefile b/rakefile
index 8f4966850602333b47f9b20fb48bb60eef22129c..6bd582783e64f6cbe57d668592ee7e6bbe1eda11 100644
--- a/rakefile
+++ b/rakefile
@@ -58,7 +58,7 @@ task :pylint => LMS_REPORT_DIR do
     end
 end
 
-[:lms].each do |system|
+[:lms, :cms].each do |system|
     task_name = "test_#{system}"
     report_dir = File.join(REPORT_DIR, task_name)
     directory report_dir
@@ -69,6 +69,15 @@ end
         sh(django_admin(:lms, :test, 'test', *Dir['lms/djangoapps'].each))
     end
     task :test => task_name
+
+    desc <<-desc
+        Start the #{system} locally with the specified environment (defaults to dev).
+        Other useful environments are devplus (for dev testing with a real local database)
+        desc
+    task system, [:env, :options] => [] do |t, args|
+        args.with_defaults(:env => 'dev', :options => '')
+        sh(django_admin(system, args.env, 'runserver', args.options))
+    end
 end
 
 Dir["common/lib/*"].each do |lib|
@@ -85,15 +94,6 @@ Dir["common/lib/*"].each do |lib|
     task :test => task_name
 end
 
-desc <<-desc
-    Start the lms locally with the specified environment (defaults to dev).
-    Other useful environments are devplus (for dev testing with a real local database)
-    desc
-task :lms, [:env] => [] do |t, args|
-    args.with_defaults(:env => 'dev')
-    sh(django_admin(:lms, args.env, 'runserver'))
-end
-
 task :runserver => :lms
 
 desc "Run django-admin <action> against the specified system and environment"