diff --git a/.gitignore b/.gitignore
index 2e63818e..39a14113 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,8 @@
 *.db
 *~
 local_settings.py
+storyboard.db
+.tox
+AUTHORS
+ChangeLog
+*.egg-info
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 00000000..c978a52d
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,6 @@
+include AUTHORS
+include ChangeLog
+exclude .gitignore
+exclude .gitreview
+
+global-exclude *.pyc
diff --git a/README.rst b/README.rst
index 5e2b44e4..52a0eef7 100644
--- a/README.rst
+++ b/README.rst
@@ -118,9 +118,13 @@ Prerequisites
 
 You'll need the following Python modules installed:
  - django (1.4+)
- - python-django-auth-openid
- - python-markdown
+ - django-openid-auth
+ - markdown
+ - python-openid
 
+You can get them by running::
+
+  pip install -r requirements.txt
 
 Configuration and DB creation
 -----------------------------
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 00000000..1e31be08
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,7 @@
+d2to1>=0.2.10,<0.3
+pbr>=0.5.10,<0.6
+
+django>=1.4
+django-openid-auth
+markdown
+python-openid
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 00000000..2b05bec8
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,30 @@
+[metadata]
+name = storyboard
+summary = OpenStack StoryBoard
+description-file =
+    README.rst
+author = OpenStack
+author-email = openstack-dev@lists.openstack.org
+home-page = http://www.openstack.org/
+classifier =
+    Environment :: OpenStack
+    Framework :: Django
+    Intended Audience :: Developers
+    Intended Audience :: Information Technology
+    Intended Audience :: System Administrators
+    License :: OSI Approved :: Apache Software License
+    Operating System :: OS Independent
+    Operating System :: POSIX :: Linux
+    Programming Language :: Python
+    Programming Language :: Python :: 2
+    Programming Language :: Python :: 2.7
+    Programming Language :: Python :: 2.6
+    Topic :: Internet :: WWW/HTTP
+
+[global]
+setup-hooks =
+    pbr.hooks.setup_hook
+
+[files]
+packages =
+    storyboard
diff --git a/setup.py b/setup.py
new file mode 100755
index 00000000..b3e85a71
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import setuptools
+
+setuptools.setup(
+    setup_requires=['d2to1>=0.2.10,<0.3', 'pbr>=0.5.10,<0.6'],
+    d2to1=True)
diff --git a/about/__init__.py b/storyboard/about/__init__.py
similarity index 100%
rename from about/__init__.py
rename to storyboard/about/__init__.py
diff --git a/about/static/css/bootstrap-responsive.css b/storyboard/about/static/css/bootstrap-responsive.css
similarity index 100%
rename from about/static/css/bootstrap-responsive.css
rename to storyboard/about/static/css/bootstrap-responsive.css
diff --git a/about/static/css/bootstrap-responsive.min.css b/storyboard/about/static/css/bootstrap-responsive.min.css
similarity index 100%
rename from about/static/css/bootstrap-responsive.min.css
rename to storyboard/about/static/css/bootstrap-responsive.min.css
diff --git a/about/static/css/bootstrap.css b/storyboard/about/static/css/bootstrap.css
similarity index 100%
rename from about/static/css/bootstrap.css
rename to storyboard/about/static/css/bootstrap.css
diff --git a/about/static/css/bootstrap.min.css b/storyboard/about/static/css/bootstrap.min.css
similarity index 100%
rename from about/static/css/bootstrap.min.css
rename to storyboard/about/static/css/bootstrap.min.css
diff --git a/about/static/img/glyphicons-halflings-white.png b/storyboard/about/static/img/glyphicons-halflings-white.png
similarity index 100%
rename from about/static/img/glyphicons-halflings-white.png
rename to storyboard/about/static/img/glyphicons-halflings-white.png
diff --git a/about/static/img/glyphicons-halflings.png b/storyboard/about/static/img/glyphicons-halflings.png
similarity index 100%
rename from about/static/img/glyphicons-halflings.png
rename to storyboard/about/static/img/glyphicons-halflings.png
diff --git a/about/static/js/bootstrap.js b/storyboard/about/static/js/bootstrap.js
similarity index 100%
rename from about/static/js/bootstrap.js
rename to storyboard/about/static/js/bootstrap.js
diff --git a/about/static/js/bootstrap.min.js b/storyboard/about/static/js/bootstrap.min.js
similarity index 100%
rename from about/static/js/bootstrap.min.js
rename to storyboard/about/static/js/bootstrap.min.js
diff --git a/about/static/js/jquery.min.js b/storyboard/about/static/js/jquery.min.js
similarity index 100%
rename from about/static/js/jquery.min.js
rename to storyboard/about/static/js/jquery.min.js
diff --git a/about/templates/about.base.html b/storyboard/about/templates/about.base.html
similarity index 100%
rename from about/templates/about.base.html
rename to storyboard/about/templates/about.base.html
diff --git a/about/templates/about.welcome.html b/storyboard/about/templates/about.welcome.html
similarity index 100%
rename from about/templates/about.welcome.html
rename to storyboard/about/templates/about.welcome.html
diff --git a/about/templates/base.html b/storyboard/about/templates/base.html
similarity index 100%
rename from about/templates/base.html
rename to storyboard/about/templates/base.html
diff --git a/about/urls.py b/storyboard/about/urls.py
similarity index 93%
rename from about/urls.py
rename to storyboard/about/urls.py
index 8948918b..6b3a77c5 100644
--- a/about/urls.py
+++ b/storyboard/about/urls.py
@@ -16,6 +16,6 @@
 from django.conf.urls.defaults import *
 
 
-urlpatterns = patterns('about.views',
+urlpatterns = patterns('storyboard.about.views',
     (r'^$', 'welcome'),
 )
diff --git a/about/views.py b/storyboard/about/views.py
similarity index 100%
rename from about/views.py
rename to storyboard/about/views.py
diff --git a/projects/__init__.py b/storyboard/projects/__init__.py
similarity index 100%
rename from projects/__init__.py
rename to storyboard/projects/__init__.py
diff --git a/projects/admin.py b/storyboard/projects/admin.py
similarity index 92%
rename from projects/admin.py
rename to storyboard/projects/admin.py
index 111ad981..98d8e5e0 100644
--- a/projects/admin.py
+++ b/storyboard/projects/admin.py
@@ -13,7 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from projects.models import Project, Series, Milestone
+from storyboard.projects.models import Project, Series, Milestone
 from django.contrib import admin
 
 
diff --git a/projects/models.py b/storyboard/projects/models.py
similarity index 100%
rename from projects/models.py
rename to storyboard/projects/models.py
diff --git a/projects/templates/projects.base.html b/storyboard/projects/templates/projects.base.html
similarity index 100%
rename from projects/templates/projects.base.html
rename to storyboard/projects/templates/projects.base.html
diff --git a/projects/templates/projects.dashboard.html b/storyboard/projects/templates/projects.dashboard.html
similarity index 100%
rename from projects/templates/projects.dashboard.html
rename to storyboard/projects/templates/projects.dashboard.html
diff --git a/projects/templates/projects.list.html b/storyboard/projects/templates/projects.list.html
similarity index 100%
rename from projects/templates/projects.list.html
rename to storyboard/projects/templates/projects.list.html
diff --git a/projects/templates/projects.list_tasks.html b/storyboard/projects/templates/projects.list_tasks.html
similarity index 100%
rename from projects/templates/projects.list_tasks.html
rename to storyboard/projects/templates/projects.list_tasks.html
diff --git a/projects/templates/projects.project.html b/storyboard/projects/templates/projects.project.html
similarity index 100%
rename from projects/templates/projects.project.html
rename to storyboard/projects/templates/projects.project.html
diff --git a/projects/urls.py b/storyboard/projects/urls.py
similarity index 94%
rename from projects/urls.py
rename to storyboard/projects/urls.py
index 93d9bb54..7c9f2462 100644
--- a/projects/urls.py
+++ b/storyboard/projects/urls.py
@@ -16,7 +16,7 @@
 from django.conf.urls.defaults import *
 
 
-urlpatterns = patterns('projects.views',
+urlpatterns = patterns('storyboard.projects.views',
     (r'^$', 'default_list'),
     (r'^(\S+)/bugs/triage$', 'list_bugtriage'),
     (r'^(\S+)/bugs$', 'list_bugtasks'),
diff --git a/projects/views.py b/storyboard/projects/views.py
similarity index 96%
rename from projects/views.py
rename to storyboard/projects/views.py
index b5938b79..9b881dc6 100644
--- a/projects/views.py
+++ b/storyboard/projects/views.py
@@ -20,8 +20,8 @@ from django.contrib.auth import logout
 from django.http import HttpResponseRedirect, HttpResponseForbidden
 from django.shortcuts import render
 
-from projects.models import Project
-from stories.models import Task
+from storyboard.projects.models import Project
+from storyboard.stories.models import Task
 
 def default_list(request):
     return render(request, "projects.list.html", {
diff --git a/storyboard/settings.py b/storyboard/settings.py
index 2ad3515c..741c5258 100644
--- a/storyboard/settings.py
+++ b/storyboard/settings.py
@@ -133,9 +133,9 @@ INSTALLED_APPS = [
     'django.contrib.staticfiles',
     'django_openid_auth',
     'django.contrib.admin',
-    'about',
-    'projects',
-    'stories',
+    'storyboard.about',
+    'storyboard.projects',
+    'storyboard.stories',
 ]
 
 AUTHENTICATION_BACKENDS = (
diff --git a/stories/__init__.py b/storyboard/stories/__init__.py
similarity index 100%
rename from stories/__init__.py
rename to storyboard/stories/__init__.py
diff --git a/stories/admin.py b/storyboard/stories/admin.py
similarity index 92%
rename from stories/admin.py
rename to storyboard/stories/admin.py
index 17f359c8..cbdcd1e0 100644
--- a/stories/admin.py
+++ b/storyboard/stories/admin.py
@@ -13,7 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from stories.models import Story, Task, Comment, StoryTag
+from storyboard.stories.models import Story, Task, Comment, StoryTag
 from django.contrib import admin
 
 
diff --git a/stories/models.py b/storyboard/stories/models.py
similarity index 97%
rename from stories/models.py
rename to storyboard/stories/models.py
index 09dd15c2..02c73bbf 100644
--- a/stories/models.py
+++ b/storyboard/stories/models.py
@@ -15,7 +15,7 @@
 
 from django.db import models
 from django.contrib.auth.models import User
-from projects.models import Project, Series, Milestone
+from storyboard.projects.models import Project, Series, Milestone
 
 
 class Story(models.Model):
diff --git a/stories/templates/stories.base.html b/storyboard/stories/templates/stories.base.html
similarity index 100%
rename from stories/templates/stories.base.html
rename to storyboard/stories/templates/stories.base.html
diff --git a/stories/templates/stories.dashboard.html b/storyboard/stories/templates/stories.dashboard.html
similarity index 100%
rename from stories/templates/stories.dashboard.html
rename to storyboard/stories/templates/stories.dashboard.html
diff --git a/stories/templates/stories.modal_addstory.html b/storyboard/stories/templates/stories.modal_addstory.html
similarity index 100%
rename from stories/templates/stories.modal_addstory.html
rename to storyboard/stories/templates/stories.modal_addstory.html
diff --git a/stories/templates/stories.modal_addtask.html b/storyboard/stories/templates/stories.modal_addtask.html
similarity index 100%
rename from stories/templates/stories.modal_addtask.html
rename to storyboard/stories/templates/stories.modal_addtask.html
diff --git a/stories/templates/stories.modal_deltask.html b/storyboard/stories/templates/stories.modal_deltask.html
similarity index 100%
rename from stories/templates/stories.modal_deltask.html
rename to storyboard/stories/templates/stories.modal_deltask.html
diff --git a/stories/templates/stories.modal_editprio.html b/storyboard/stories/templates/stories.modal_editprio.html
similarity index 100%
rename from stories/templates/stories.modal_editprio.html
rename to storyboard/stories/templates/stories.modal_editprio.html
diff --git a/stories/templates/stories.modal_editstory.html b/storyboard/stories/templates/stories.modal_editstory.html
similarity index 100%
rename from stories/templates/stories.modal_editstory.html
rename to storyboard/stories/templates/stories.modal_editstory.html
diff --git a/stories/templates/stories.modal_edittask.html b/storyboard/stories/templates/stories.modal_edittask.html
similarity index 100%
rename from stories/templates/stories.modal_edittask.html
rename to storyboard/stories/templates/stories.modal_edittask.html
diff --git a/stories/templates/stories.view.html b/storyboard/stories/templates/stories.view.html
similarity index 100%
rename from stories/templates/stories.view.html
rename to storyboard/stories/templates/stories.view.html
diff --git a/stories/templatetags/__init__.py b/storyboard/stories/templatetags/__init__.py
similarity index 100%
rename from stories/templatetags/__init__.py
rename to storyboard/stories/templatetags/__init__.py
diff --git a/stories/templatetags/storyviewfilters.py b/storyboard/stories/templatetags/storyviewfilters.py
similarity index 100%
rename from stories/templatetags/storyviewfilters.py
rename to storyboard/stories/templatetags/storyviewfilters.py
diff --git a/stories/tests.py b/storyboard/stories/tests.py
similarity index 100%
rename from stories/tests.py
rename to storyboard/stories/tests.py
diff --git a/stories/urls.py b/storyboard/stories/urls.py
similarity index 95%
rename from stories/urls.py
rename to storyboard/stories/urls.py
index 7ce8c0d5..59d51279 100644
--- a/stories/urls.py
+++ b/storyboard/stories/urls.py
@@ -16,7 +16,7 @@
 from django.conf.urls.defaults import *
 
 
-urlpatterns = patterns('stories.views',
+urlpatterns = patterns('storyboard.stories.views',
     (r'^$', 'dashboard'),
     (r'^(\d+)$', 'view'),
     (r'^(\d+)/addtask$', 'add_task'),
diff --git a/stories/views.py b/storyboard/stories/views.py
similarity index 98%
rename from stories/views.py
rename to storyboard/stories/views.py
index 32b815f1..8bccccda 100644
--- a/stories/views.py
+++ b/storyboard/stories/views.py
@@ -18,8 +18,9 @@ from django.views.decorators.http import require_POST
 from django.http import HttpResponseRedirect, HttpResponseForbidden
 from django.shortcuts import render
 from django.contrib.auth.models import User
-from projects.models import Project, Milestone, Series
-from stories.models import Story, Task, Comment, StoryTag
+
+from storyboard.projects.models import Project, Milestone, Series
+from storyboard.stories.models import Story, Task, Comment, StoryTag
 
 def dashboard(request):
     recent_bugs = Story.objects.order_by("-id")[:5]
diff --git a/storyboard/urls.py b/storyboard/urls.py
index f984509a..4130db1e 100644
--- a/storyboard/urls.py
+++ b/storyboard/urls.py
@@ -21,10 +21,10 @@ admin.autodiscover()
 
 urlpatterns = patterns('',
     (r'^openid/', include('django_openid_auth.urls')),
-    (r'^$', 'about.views.welcome'),
-    (r'^about/',  include('about.urls')),
-    (r'^project/',  include('projects.urls')),
-    (r'^story/',  include('stories.urls')),
+    (r'^$', 'storyboard.about.views.welcome'),
+    (r'^about/',  include('storyboard.about.urls')),
+    (r'^project/',  include('storyboard.projects.urls')),
+    (r'^story/',  include('storyboard.stories.urls')),
     url(r'^admin/', include(admin.site.urls)),
-    (r'^logout$', 'about.views.dologout'),
+    (r'^logout$', 'storyboard.about.views.dologout'),
 )
diff --git a/test-requirements.txt b/test-requirements.txt
new file mode 100644
index 00000000..581beeaa
--- /dev/null
+++ b/test-requirements.txt
@@ -0,0 +1,7 @@
+hacking>=0.5.3,<0.6
+
+coverage
+discover
+fixtures>=0.3.12
+testrepository>=0.0.13
+testtools>=0.9.26
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 00000000..b4157e68
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,29 @@
+[tox]
+envlist = py26,py27,py33,pep8
+
+[testenv]
+setenv = VIRTUAL_ENV={envdir}
+         LANG=en_US.UTF-8
+         LANGUAGE=en_US:en
+         LC_ALL=C
+
+deps = -r{toxinidir}/requirements.txt
+       -r{toxinidir}/test-requirements.txt
+commands = python setup.py testr --testr-args='{posargs}'
+
+[testenv:pep8]
+commands = flake8
+
+[testenv:venv]
+commands = {posargs}
+
+[testenv:cover]
+commands = python setup.py testr --coverage --testr-args='{posargs}'
+
+[tox:jenkins]
+downloadcache = ~/cache/pip
+
+[flake8]
+ignore = H
+show-source = True
+exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build