diff --git a/IPython/nbformat/__init__.py b/IPython/nbformat/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/IPython/nbformat/__init__.py
diff --git a/IPython/nbformat/base.py b/IPython/nbformat/base.py
new file mode 100644
index 0000000..833a5ec
--- /dev/null
+++ b/IPython/nbformat/base.py
@@ -0,0 +1,45 @@
+from base64 import encodestring, decodestring
+
+
+def base64_decode(self, nb):
+    """Base64 encode all bytes objects in the notebook."""
+    for ws in nb['worksheets']:
+        for cell in ws['cells']:
+            if cell['cell_type'] == 'code':
+                if cell.get('image/png',''):
+                    cell['image/png'] = bytes(decodestring(cell['image/png']))
+    return nb
+
+
+def base64_encode(self, nb):
+    """Base64 decode all binary objects in the notebook."""
+    for ws in nb['worksheets']:
+        for cell in ws['cells']:
+            if cell['cell_type'] == 'code':
+                if cell.get('image/png',''):
+                    cell['image/png'] = unicode(encodestring(cell['image/png']))
+    return nb
+
+
+class NotebookReader(object):
+
+    def reads(self, s, **kwargs):
+        """Read a notebook from a string."""
+        raise NotImplementedError("loads must be implemented in a subclass")
+
+    def read(self, fp, **kwargs):
+        """Read a notebook from a file like object"""
+        return self.loads(fp.read(), **kwargs)
+
+
+class NotebookWriter(object):
+
+    def writes(self, nb, **kwargs):
+        """Write a notebook to a string."""
+        raise NotImplementedError("loads must be implemented in a subclass")
+
+    def write(self, nb, fp, **kwargs):
+        """Write a notebook to a file like object"""
+        return fp.write(self.dumps(nb,**kwargs))
+
+
diff --git a/IPython/nbformat/nbdict.py b/IPython/nbformat/nbdict.py
new file mode 100644
index 0000000..fa2900d
--- /dev/null
+++ b/IPython/nbformat/nbdict.py
@@ -0,0 +1,76 @@
+"""The basic dict based notebook format."""
+
+import uuid
+
+
+def new_code_cell(input=None, prompt_number=None, output_text=None, output_png=None,
+    output_html=None, output_svg=None, output_latex=None, output_json=None, 
+    output_javascript=None):
+    """Create a new code cell with input and output"""
+    cell = {}
+    cell['cell_type'] = 'code'
+    if input is not None:
+        cell['input'] = unicode(input)
+    if prompt_number is not None:
+        cell['prompt_number'] = int(prompt_number)
+
+    output = {}
+    if output_text is not None:
+        output['text/plain'] = unicode(output_text)
+    if output_png is not None:
+        output['image/png'] = bytes(output_png)
+    if output_html is not None:
+        output['text/html'] = unicode(output_html)
+    if output_svg is not None:
+        output['image/svg+xml'] = unicode(output_svg)
+    if output_latex is not None:
+        output['text/latex'] = unicode(output_latex)
+    if output_json is not None:
+        output['application/json'] = unicode(output_json)
+    if output_javascript is not None:
+        output['application/javascript'] = unicode(output_javascript)
+
+    cell['output'] = output
+    return cell
+
+
+def new_text_cell(text=None):
+    """Create a new text cell."""
+    cell = {}
+    if text is not None:
+        cell['text'] = unicode(text)
+    cell['cell_type'] = 'text'
+    return cell
+
+
+def new_worksheet(name=None, cells=None):
+    """Create a worksheet by name with with a list of cells."""
+    ws = {}
+    if name is not None:
+        ws['name'] = unicode(name)
+    else:
+        ws['name'] = u''
+    if cells is None:
+        ws['cells'] = []
+    else:
+        ws['cells'] = list(cells)
+    return ws
+
+
+def new_notebook(name=None, id=None, worksheets=None):
+    """Create a notebook by name, id and a list of worksheets."""
+    nb = {}
+    if name is not None:
+        nb['name'] = unicode(name)
+    else:
+        nb['name'] = u''
+    if id is None:
+        nb['id'] = unicode(uuid.uuid4())
+    else:
+        nb['id'] = unicode(id)
+    if worksheets is None:
+        nb['worksheets'] = []
+    else:
+        nb['worksheets'] = list(worksheets)
+    return nb
+
diff --git a/IPython/nbformat/nbjson.py b/IPython/nbformat/nbjson.py
new file mode 100644
index 0000000..00b8582
--- /dev/null
+++ b/IPython/nbformat/nbjson.py
@@ -0,0 +1,38 @@
+"""Read and write notebooks in JSON format."""
+
+from base64 import encodestring
+from .base import NotebookReader, NotebookWriter, base64_decode
+import json
+
+
+class BytesEncoder(json.JSONEncoder):
+    def default(self, obj):
+        if isinstance(obj, bytes):
+            return unicode(encodestring(bytes))
+        return json.JSONEncoder.default(self, obj)
+
+
+class JSONReader(NotebookReader):
+
+    def reads(s, **kwargs):
+        nb = json.loads(s, **kwargs)
+        nb = base64_decode(nb)
+        return nb
+
+
+class JSONWriter(NotebookWriter):
+
+    def writes(nb, **kwargs):
+        kwargs['cls'] = BytesEncoder
+        kwargs['indent'] = 4
+        return json.dumps(nb, **kwargs)
+
+
+_reader = JSONReader()
+_writer = JSONWriter()
+
+reads = _reader.reads
+read = _reader.read
+write = _writer.write
+writes = _writer.writes
+
diff --git a/IPython/nbformat/nbpy.py b/IPython/nbformat/nbpy.py
new file mode 100644
index 0000000..a5328e7
--- /dev/null
+++ b/IPython/nbformat/nbpy.py
@@ -0,0 +1,46 @@
+"""Read and write notebooks as regular .py files."""
+
+from .base import NotebookReader, NotebookWriter
+from .nbdict import new_code_cell, new_worksheet, new_notebook
+
+
+class PyReader(NotebookReader):
+
+    def reads(s, **kwargs):
+        lines = s.splitlines()
+        cells = []
+        cell_lines = []
+        for line in lines:
+            if line.startswith('# <codecell>'):
+                code = '\n'.join(cell_lines)
+                code = code.strip('\n')
+                if code:
+                    cells.append(new_code_cell(input=code))
+                    cell_lines = []
+            else:
+                cell_lines.append(line)
+        ws = new_worksheet(cells=cells)
+        nb = new_notebook(worksheets=[ws])
+        return nb
+
+
+class PyWriter(NotebookWriter):
+
+    def writes(nb, **kwargs):
+        lines = []
+        for ws in nb['worksheets']:
+            for cell in ws['cells']:
+                if cell['cell_type'] == 'code':
+                    input = cell['input']
+                    lines.extend(input.splitlines())
+                    lines.extend(['','# <codecell>',''])
+        return ''.join(lines)
+
+
+_reader = PyReader()
+_writer = PyWriter()
+
+reads = _reader.reads
+read = _reader.read
+write = _writer.write
+writes = _writer.writes
diff --git a/IPython/nbformat/nbxml.py b/IPython/nbformat/nbxml.py
new file mode 100644
index 0000000..aa22f3f
--- /dev/null
+++ b/IPython/nbformat/nbxml.py
@@ -0,0 +1,48 @@
+"""Read and write notebook files as XML."""
+
+from xml.etree import ElementTree as ET
+
+from .base import NotebookReader, NotebookWriter
+from .nbdict import new_code_cell, new_worksheet, new_notebook
+
+
+class XMLReader(NotebookReader):
+
+    def reads(s, **kwargs):
+        pass
+
+
+class XMLWriter(NotebookWriter):
+
+    def writes(nb, **kwargs):
+        nb_e = ET.Element('notebook')
+        name_e = ET.SubElement(nb_e, 'name')
+        name_e.text = nb.get('name','')
+        id_e = ET.SubElement(nb_e, 'id')
+        id_e.text = nb.get('id','')
+        for ws in nb['worksheets']:
+            ws_e = ET.SubElement(nb_e, 'worksheet')
+            ws_name_e = ET.SubElement(ws_e, 'name')
+            ws_name_e.text = ws.get('name','')
+            for cell in ws['cells']:
+                cell_type = cell['cell_type']
+                if cell_type == 'code':
+                    output = cell['output']
+                    cell_e = ET.SubElement(ws_e, 'cell')
+                    input_e = ET.SubElement(cell_e, 'input')
+                    input_e.text = cell.get('input','')
+                    output_e = ET.SubElement(cell_e, 'output')
+                    text_e = ET.SubElement(output_e, 'text')
+                    text_e.text = cell.output
+                elif cell_type == 'text':
+                    pass
+                    
+
+
+_reader = XMLReader()
+_writer = XMLWriter()
+
+reads = _reader.reads
+read = _reader.read
+write = _writer.write
+writes = _writer.writes