diff --git a/app/locale/en.coffee b/app/locale/en.coffee
index 41f9f15b6..4696d8dae 100644
--- a/app/locale/en.coffee
+++ b/app/locale/en.coffee
@@ -15,6 +15,9 @@
     fork: "Fork"
     play: "Play"
     retry: "Retry"
+    watch: "Watch"
+    unwatch: "Unwatch"
+    submit_patch: "Submit Patch"
 
   units:
     second: "second"
diff --git a/app/models/CocoModel.coffee b/app/models/CocoModel.coffee
index c93708ee2..b33177a3a 100644
--- a/app/models/CocoModel.coffee
+++ b/app/models/CocoModel.coffee
@@ -60,6 +60,7 @@ class CocoModel extends Backbone.Model
     return result.errors unless result.valid
 
   save: (attrs, options) ->
+    @set 'editPath', document.location.pathname
     options ?= {}
     success = options.success
     options.success = (resp) =>
@@ -68,7 +69,6 @@ class CocoModel extends Backbone.Model
       @markToRevert()
       @clearBackup()
     @trigger "save", @
-    patch.setStatus 'accepted' for patch in @acceptedPatches or []
     return super attrs, options
 
   fetch: ->
@@ -95,7 +95,6 @@ class CocoModel extends Backbone.Model
   cloneNewMinorVersion: ->
     newData = $.extend(null, {}, @attributes)
     clone = new @constructor(newData)
-    clone.acceptedPatches = @acceptedPatches
     clone
 
   cloneNewMajorVersion: ->
@@ -221,9 +220,11 @@ class CocoModel extends Backbone.Model
     delta = @getDelta()
     deltasLib.expandDelta(delta, @_revertAttributes, @schema())
 
-  addPatchToAcceptOnSave: (patch) ->
-    @acceptedPatches ?= []
-    @acceptedPatches.push patch
-    @acceptedPatches = _.uniq(@acceptedPatches, false, (p) -> p.id)
+  watch: (doWatch=true) ->
+    $.ajax("#{@urlRoot}/#{@id}/watch", {type:'PUT', data:{on:doWatch}})
+    @watching = -> doWatch
+    
+  watching: ->
+    return me.id in (@get('watchers') or [])
 
 module.exports = CocoModel
diff --git a/app/models/Patch.coffee b/app/models/Patch.coffee
index 68b62eca9..c505c93c0 100644
--- a/app/models/Patch.coffee
+++ b/app/models/Patch.coffee
@@ -5,4 +5,7 @@ module.exports = class PatchModel extends CocoModel
   urlRoot: "/db/patch" 
   
   setStatus: (status) ->
-    $.ajax("/db/patch/#{@id}/status", {type:"PUT", data: {status:status}}) 
\ No newline at end of file
+    PatchModel.setStatus @id, status
+    
+  @setStatus: (id, status) ->
+    $.ajax("/db/patch/#{id}/status", {type:"PUT", data: {status:status}})
\ No newline at end of file
diff --git a/app/schemas/schemas.coffee b/app/schemas/schemas.coffee
index 2d7ae0603..9c20c9ba2 100644
--- a/app/schemas/schemas.coffee
+++ b/app/schemas/schemas.coffee
@@ -63,7 +63,7 @@ patchableProps = ->
     status: { enum: ['pending', 'accepted', 'rejected', 'cancelled']}
   })
   allowPatches: { type: 'boolean' }
-  listeners: me.array({title:'Listeners'},
+  watchers: me.array({title:'Watchers'},
     me.objectId(links: [{rel: 'extra', href: "/db/user/{($)}"}]))
   
 me.extendPatchableProperties = (schema) ->
diff --git a/app/styles/base.sass b/app/styles/base.sass
index 0425ba2d6..afa9fbcc9 100644
--- a/app/styles/base.sass
+++ b/app/styles/base.sass
@@ -265,3 +265,8 @@ body[lang='ja']
   font-family: 'Glyphicons Halflings'
   src: url("/fonts/glyphicons-halflings-regular.eot")
   src: url("/fonts/glyphicons-halflings-regular.eot?#iefix") format("embedded-opentype"), url("/fonts/glyphicons-halflings-regular.woff") format("woff"), url("/fonts/glyphicons-halflings-regular.ttf") format("truetype"), url("/fonts/glyphicons-halflings-regular.svg#glyphicons-halflingsregular") format("svg")
+
+.spr:after
+  content: " "
+.spl:before
+  content: " "
\ No newline at end of file
diff --git a/app/styles/editor/level/component/edit.sass b/app/styles/editor/level/component/edit.sass
index 5c9deda4c..7a78534ed 100644
--- a/app/styles/editor/level/component/edit.sass
+++ b/app/styles/editor/level/component/edit.sass
@@ -1,4 +1,11 @@
 #editor-level-component-edit-view
+  nav
+    margin-bottom: 0
+    
+  #component-patches
+    padding: 0 10px 10px
+    background: white
+  
   .navbar-text
     float: left
     
@@ -7,9 +14,13 @@
     left: 0
     right: 0
     bottom: 0
-    top: 50px
+    top: 35px
     border: 2px solid black
     border-top: none
     
-  .active > a, .active > a:hover, .active > a:focus
-    background-color: white !important
\ No newline at end of file
+  .inner-editor
+    position: absolute
+    left: 0
+    right: 0
+    bottom: 0
+    top: 0px
\ No newline at end of file
diff --git a/app/styles/editor/level/components_tab.sass b/app/styles/editor/level/components_tab.sass
index b8a029a5b..c70a5f4d6 100644
--- a/app/styles/editor/level/components_tab.sass
+++ b/app/styles/editor/level/components_tab.sass
@@ -1,4 +1,6 @@
 #editor-level-components-tab-view
+  h3
+    margin-top: 0
 
   .components-container
     position: absolute
@@ -7,7 +9,7 @@
 
     .treema-root
       position: absolute
-      top: 50px
+      top: 35px
       bottom: 0
       width: 250px
       overflow: scroll
@@ -25,13 +27,13 @@
     
     .treema-root
       position: absolute
-      top: 50px
+      top: 35px
       right: 0
       left: 0px
       bottom: 0
       overflow: scroll
 
-    #create-new-component-button
+    #create-new-component-button-no-select
       position: absolute
       top: 0
       right: 0
diff --git a/app/styles/editor/level/edit.sass b/app/styles/editor/level/edit.sass
index f1cfc2303..7d2b5b962 100644
--- a/app/styles/editor/level/edit.sass
+++ b/app/styles/editor/level/edit.sass
@@ -1,10 +1,10 @@
 #editor-level-view
+  &, #level-editor-top-nav
+    min-width: 1024px
+  
   a
     font-family: helvetica, arial, sans serif
   
-  #top-nav
-    display: none
-
   position: absolute
   top: 0px
   left: 0px
@@ -12,22 +12,54 @@
   bottom: 0px
 
   $BG: rgba(228, 207, 140, 1.0)
+  $NAVBG: #2f261d
 
   li.navbar-btn
     margin-right: 5px
   
-  #level-editor-top-nav
-    .nav-tabs
-      border-bottom: 0 !important
-      .active > a, .active > a:hover, .active > a:focus
-        background-color: $BG !important
-        border-color: darken($BG, 50%)
-        border-bottom: 0
+  // custom navbar height rules
+  .navbar-nav > li > a
+    padding: 7px 8px 8px
+    cursor: pointer
+    &:hover
+      background-color: lighten($NAVBG, 10%)
+  .navbar
+    min-height: 0px
+    border-radius: 0
+  .navbar-right // not sure why bootstrap puts a big negative margin in, but this overrides it
+    margin-right: 10px
+    
+  // custom navbar styling
+  .navbar-brand
+    padding-top: 7px
+    padding-bottom: 7px
+    color: lighten(gold, 30%)
+  .navbar-header
+    border-left: 2px solid lighten($NAVBG, 20%)
+    border-right: 2px solid lighten($NAVBG, 20%)
+    background: lighten($NAVBG, 10%)
+    margin-left: 20px
+  .nav-tabs
+    margin-left: 5px
+    border-bottom: 0 !important
+    .active > a, .active > a:hover, .active > a:focus
+      background-color: $BG !important
+      border-color: darken($BG, 50%)
+      border-bottom: 0
+    a
+      padding: 7px 5px !important
+  .dropdown-menu a
+    cursor: pointer
+    &:hover
+      background-color: #d3d3d3
+      
+  .badge
+    background-color: green
 
   .outer-content
     background-color: $BG
     position: absolute
-    top: 0
+    top: 35px
     bottom: 0
     left: 0
     right: 0
@@ -45,12 +77,11 @@
 
   #level-editor-tabs
     position: absolute
-    left: 20px
-    right: 20px
-    top: 66px
-    bottom: 20px
+    left: 15px
+    right: 15px
+    top: 15px
+    bottom: 15px
     
   .treema-root
     background-color: white
-    border-radius: 4px
-    
+    border-radius: 4px
\ No newline at end of file
diff --git a/app/styles/editor/level/system/edit.sass b/app/styles/editor/level/system/edit.sass
index e86dc5a46..567ff5b27 100644
--- a/app/styles/editor/level/system/edit.sass
+++ b/app/styles/editor/level/system/edit.sass
@@ -7,9 +7,13 @@
     left: 0
     right: 0
     bottom: 0
-    top: 50px
+    top: 35px
     border: 2px solid black
     border-top: none
-    
-  .active > a, .active > a:hover, .active > a:focus
-    background-color: white !important
\ No newline at end of file
+
+  .inner-editor
+    position: absolute
+    left: 0
+    right: 0
+    bottom: 0
+    top: 0px
\ No newline at end of file
diff --git a/app/styles/editor/level/systems_tab.sass b/app/styles/editor/level/systems_tab.sass
index 88585504d..0d1aa6b33 100644
--- a/app/styles/editor/level/systems_tab.sass
+++ b/app/styles/editor/level/systems_tab.sass
@@ -1,4 +1,6 @@
 #editor-level-systems-tab-view
+  h3
+    margin-top: 0
   
   .systems-container
     position: absolute
@@ -7,7 +9,7 @@
 
     .treema-root
       position: absolute
-      top: 50px
+      top: 35px
       bottom: 0
       width: 250px
       overflow: scroll
@@ -30,7 +32,7 @@
     
     .treema-root
       position: absolute
-      top: 50px
+      top: 35px
       right: 0
       left: 0px
       bottom: 0
diff --git a/app/styles/editor/patches.sass b/app/styles/editor/patches.sass
index 87c22728e..110370137 100644
--- a/app/styles/editor/patches.sass
+++ b/app/styles/editor/patches.sass
@@ -1,3 +1,3 @@
 .patches-view
   .status-buttons
-    margin: 10px 0
+    margin-bottom: 10px
diff --git a/app/templates/editor/level/component/edit.jade b/app/templates/editor/level/component/edit.jade
index 23c24cf6c..7228ff914 100644
--- a/app/templates/editor/level/component/edit.jade
+++ b/app/templates/editor/level/component/edit.jade
@@ -1,23 +1,44 @@
 nav.navbar.navbar-default(role='navigation')
-  .container-fluid
-    .navbar-header
-      span.navbar-brand
-        span(data-i18n="editor.level_component_edit_title")
-          | Edit Component
-        span : 
-          | "#{editTitle}"
-    .collapse.navbar-collapse
-      ul.nav.navbar-nav.nav-tabs
-        li.active
-          a(href="#component-code" data-toggle="tab" data-i18n="general.code") Code
+  ul.nav.navbar-nav.nav-tabs
+    li.active
+      a(href="#component-code" data-toggle="tab" data-i18n="general.code")#component-code-tab Code
+    li
+      a(href="#component-config-schema" data-toggle="tab" data-i18n="editor.level_component_config_schema")#component-config-schema-tab Config Schema
+    li
+      a(href="#component-settings" data-toggle="tab" data-i18n="editor.level_component_settings")#component-settings-tab Settings
+    li
+      a(href="#component-patches" data-toggle="tab" data-i18n="resources.patches")#component-patches-tab Patches
+
+  .navbar-header
+    span.navbar-brand= editTitle
+
+  ul.nav.navbar-nav.navbar-right
+    li.dropdown
+      a(data-toggle='dropdown')
+        span.glyphicon-chevron-down.glyphicon
+
+      ul.dropdown-menu
+        li.dropdown-header Actions
         li
-          a(href="#component-config-schema" data-toggle="tab" data-i18n="editor.level_component_config_schema") Config Schema
-        li
-          a(href="#component-settings" data-toggle="tab" data-i18n="editor.level_component_settings") Settings
-      ul.nav.navbar-nav.navbar-left
-        li(data-i18n="general.version_history").btn.btn-primary.navbar-btn#history-button Version History
-      ul.nav.navbar-nav.navbar-right
-        li(data-i18n="editor.level_component_btn_new").btn.btn-primary.navbar-btn#create-new-component-button Create New Component
+          a#component-watch-button
+            span.watch
+              span.glyphicon.glyphicon-eye-open
+              span.spl Watch
+            span.unwatch.secret
+              span.glyphicon.glyphicon-eye-close
+              span.spl Unwatch
+  
+        li#patch-component-button
+          a(data-i18n="common.submit_patch") Submit Patch
+  
+        li#create-new-component-button
+          a(data-i18n="editor.level_component_btn_new") Create New Component
+        
+        li.divider
+        li.dropdown-header Info
+  
+        li#component-history-button
+          a(data-i18n="general.version_history") Version History
 
 .tab-content
   .tab-pane.active#component-code
@@ -26,3 +47,5 @@ nav.navbar.navbar-default(role='navigation')
     #config-schema-treema
   .tab-pane#component-settings
     #edit-component-treema
+  .tab-pane#component-patches
+    .patches-view
\ No newline at end of file
diff --git a/app/templates/editor/level/components_tab.jade b/app/templates/editor/level/components_tab.jade
index e97f47aa4..9cd86545e 100644
--- a/app/templates/editor/level/components_tab.jade
+++ b/app/templates/editor/level/components_tab.jade
@@ -4,6 +4,6 @@
 
 .edit-component-container
   if me.isAdmin()
-    button(data-i18n="editor.level_component_btn_new").btn.btn-primary#create-new-component-button Create New Component
+    button(data-i18n="editor.level_component_btn_new").btn.btn-primary#create-new-component-button-no-select Create New Component
   
   #editor-level-component-edit-view
diff --git a/app/templates/editor/level/edit.jade b/app/templates/editor/level/edit.jade
index ba69b27fd..6b010912d 100644
--- a/app/templates/editor/level/edit.jade
+++ b/app/templates/editor/level/edit.jade
@@ -1,74 +1,90 @@
 extends /templates/base
 
-block outer_content
-  .outer-content
-
+block header
+  if level.loading
     nav.navbar.navbar-default(role='navigation')#level-editor-top-nav
       .container-fluid
         ul.nav.navbar-nav
           li
-            a(href="/editor/level", data-i18n="editor.back") Back
-        .navbar-header
-          span.navbar-brand
-            span(data-i18n="editor.level_title") Level Editor
-            span : 
-            span.level-title #{level.attributes.name}
-        .collapse.navbar-collapse
-          ul.nav.navbar-nav.nav-tabs
-
-            li.active
-              a(href="#editor-level-thangs-tab-view", data-toggle="tab", data-i18n="editor.level_tab_thangs") Thangs
-            li
-              a(href="#editor-level-scripts-tab-view", data-toggle="tab", data-i18n="editor.level_tab_scripts") Scripts
-            li
-              a(href="#editor-level-settings-tab-view", data-toggle="tab", data-i18n="editor.level_tab_settings") Settings
-            li
-              a(href="#editor-level-components-tab-view", data-toggle="tab", data-i18n="editor.level_tab_components") Components
-            li
-              a(href="#editor-level-systems-tab-view", data-toggle="tab", data-i18n="editor.level_tab_systems") Systems
-            li
-              a(href="#editor-level-patches", data-toggle="tab", data-i18n="resources.patches")#patches-tab Patches
-
-
-          ul.nav.navbar-nav.navbar-right
-            li(data-toggle="coco-modal", data-target="modal/revert", data-i18n="editor.revert", disabled=authorized === true ? undefined : "true").btn.btn-primary.navbar-btn#revert-button Revert
-            if authorized
-              li(data-i18n="common.save").btn.btn-primary.navbar-btn#commit-level-start-button Save
-            else
-              li(data-i18n="common.patch").btn.btn-primary.navbar-btn#commit-level-patch-button Patch
-            li(data-i18n="common.fork", disabled=anonymous ? "true": undefined).btn.btn-primary.navbar-btn#fork-level-start-button Fork
-            li(title="⌃↩ or ⌘↩: Play preview of current level", data-i18n="common.play")#play-button.btn.btn-inverse.banner.navbar-btn Play!
-
-            li.divider
-
-            li.dropdown
-              a.dropdown-toggle(href='#', data-toggle='dropdown', data-i18n="editor.more")
-                | More
-                b.caret
-              ul.dropdown-menu
-                li#history-button
-                  a(href='#', data-i18n="general.version_history") Version History
-                li
-                  a(href='https://github.com/codecombat/codecombat/wiki/Artisan-Home', data-i18n="editor.wiki") Wiki
-                li
-                  a(href='http://www.hipchat.com/g3plnOKqa', data-i18n="editor.live_chat") Live Chat
-                li
-                  a(href='http://discourse.codecombat.com/category/artisan', data-i18n="nav.forum") Forum
-                li
-                  a(data-toggle="coco-modal", data-target="modal/contact", data-i18n="nav.contact") Email
-
-          
-      
-          ul.dropdown-menu
-            li
-              span(data-i18n="editor.level_some_options").dropdown-menu-header Some Options?
-            li.divider
-            li
-              a(data-delay="1000", href="#", data-i18n="common.delay_1_sec") 1 second
-              a(data-delay="3000", href="#", data-i18n="common.delay_3_sec") 3 seconds
-              a(data-delay="5000", href="#", data-i18n="common.delay_5_sec") 5 seconds
-              a(data-delay="90019001", href="#", data-i18n="common.manual") Manual
+            a(href="/editor/level")
+              span.glyphicon-home.glyphicon
   
+  else
+    nav.navbar.navbar-default(role='navigation')#level-editor-top-nav
+      ul.nav.navbar-nav
+        li
+          a(href="/editor/level")
+            span.glyphicon-home.glyphicon
+      ul.nav.navbar-nav.nav-tabs
+      
+        li.active
+          a(href="#editor-level-thangs-tab-view", data-toggle="tab", data-i18n="editor.level_tab_thangs") Thangs
+        li
+          a(href="#editor-level-scripts-tab-view", data-toggle="tab", data-i18n="editor.level_tab_scripts") Scripts
+        li
+          a(href="#editor-level-settings-tab-view", data-toggle="tab", data-i18n="editor.level_tab_settings") Settings
+        li
+          a(href="#editor-level-components-tab-view", data-toggle="tab", data-i18n="editor.level_tab_components") Components
+        li
+          a(href="#editor-level-systems-tab-view", data-toggle="tab", data-i18n="editor.level_tab_systems") Systems
+        li
+          a(href="#editor-level-patches", data-toggle="tab")#patches-tab
+            span(data-i18n="resources.patches").spr Patches
+            - var patches = level.get('patches')
+            if patches && patches.length
+              span.badge= patches.length
+      
+      .navbar-header
+        span.navbar-brand #{level.attributes.name}
+
+      ul.nav.navbar-nav.navbar-right
+        if authorized
+          li#commit-level-start-button
+            a
+              span.glyphicon-floppy-disk.glyphicon
+        else
+          li#level-patch-button
+            a
+              span.glyphicon-floppy-disk.glyphicon
+        
+        li(title="⌃↩ or ⌘↩: Play preview of current level")#play-button
+          a
+            span.glyphicon-play.glyphicon
+        li.dropdown
+          a(data-toggle='dropdown')
+            span.glyphicon-chevron-down.glyphicon
+          ul.dropdown-menu
+            li.dropdown-header Actions
+            li
+              a#level-watch-button
+                span.watch
+                  span.glyphicon.glyphicon-eye-open
+                  span.spl Watch
+                span.unwatch.secret
+                  span.glyphicon.glyphicon-eye-close
+                  span.spl Unwatch
+                  
+            li(class=anonymous ? "disabled": "")
+              a(data-i18n="common.fork")#fork-level-start-button Fork
+            li(class=anonymous ? "disabled": "")
+              a(data-toggle="coco-modal", data-target="modal/revert", data-i18n="editor.revert")#revert-button Revert
+            li.divider
+            li.dropdown-header Info
+            li#level-history-button
+              a(href='#', data-i18n="general.version_history") Version History
+            li.divider
+            li.dropdown-header Help
+            li
+              a(href='https://github.com/codecombat/codecombat/wiki/Artisan-Home', data-i18n="editor.wiki", target="_blank") Wiki
+            li
+              a(href='http://www.hipchat.com/g3plnOKqa', data-i18n="editor.live_chat", target="_blank") Live Chat
+            li
+              a(href='http://discourse.codecombat.com/category/artisan', data-i18n="nav.forum", target="_blank") Forum
+            li
+              a(data-toggle="coco-modal", data-target="modal/contact", data-i18n="nav.contact") Email
+
+block outer_content
+  .outer-content
     div.tab-content#level-editor-tabs
       div.tab-pane.active#editor-level-thangs-tab-view
         
diff --git a/app/templates/editor/level/system/edit.jade b/app/templates/editor/level/system/edit.jade
index db20287b6..267993ea5 100644
--- a/app/templates/editor/level/system/edit.jade
+++ b/app/templates/editor/level/system/edit.jade
@@ -1,21 +1,40 @@
 nav.navbar.navbar-default(role='navigation')
-  .container-fluid
-    .navbar-header
-      span.navbar-brand
-        span(data-i18n="editor.level_system_edit_title")
-          | Edit System
-        span : 
-          | "#{editTitle}"
-    .collapse.navbar-collapse
-      ul.nav.navbar-nav.nav-tabs
-        li.active
-          a(href="#system-code" data-toggle="tab") Code
+
+  ul.nav.navbar-nav.nav-tabs
+    li.active
+      a(href="#system-code" data-toggle="tab")#system-code-tab Code
+    li
+      a(href="#system-config-schema" data-toggle="tab")#system-config-schema-tab Config Schema
+    li
+      a(href="#system-settings" data-toggle="tab")#system-settings-tab Settings
+    li
+      a(href="#system-patches" data-toggle="tab" data-i18n="resources.patches")#system-patches-tab Patches
+
+  ul.nav.navbar-nav.navbar-right
+    li.dropdown
+      a(data-toggle='dropdown')
+        span.glyphicon-chevron-down.glyphicon
+      ul.dropdown-menu
+        li.dropdown-header Actions
         li
-          a(href="#system-config-schema" data-toggle="tab") Config Schema
-        li
-          a(href="#system-settings" data-toggle="tab") Settings
-      ul.nav.navbar-nav.navbar-right
-        li(data-i18n="editor.level_system_btn_new").btn.btn-primary.navbar-btn#create-new-system-button Create New System
+          a#system-watch-button
+            span.watch
+              span.glyphicon.glyphicon-eye-open
+              span.spl Watch
+            span.unwatch.secret
+              span.glyphicon.glyphicon-eye-close
+              span.spl Unwatch
+        li#patch-system-button
+          a(data-i18n="common.submit_patch") Submit Patch
+        li#create-new-system
+          a(data-i18n="editor.level_system_btn_new") Create New System
+        li.divider
+        li.dropdown-header Info
+        li#system-history-button
+          a(data-i18n="general.version_history") Version History
+
+  .navbar-header
+    span.navbar-brand= editTitle
   
 .tab-content
   .tab-pane.active#system-code
@@ -24,3 +43,5 @@ nav.navbar.navbar-default(role='navigation')
     #config-schema-treema
   .tab-pane#system-settings
     #edit-system-treema
+  .tab-pane#system-patches
+    .patches-view
\ No newline at end of file
diff --git a/app/templates/editor/patch_modal.jade b/app/templates/editor/patch_modal.jade
index 68fed43f7..4d46d8cb5 100644
--- a/app/templates/editor/patch_modal.jade
+++ b/app/templates/editor/patch_modal.jade
@@ -6,6 +6,7 @@ block modal-header-content
 
 block modal-body-content
   .modal-body
+    p= patch.get('commitMessage')
     .changes-stub
 
 
diff --git a/app/templates/modal/versions.jade b/app/templates/modal/versions.jade
index bd5b099eb..af78e7fcd 100755
--- a/app/templates/modal/versions.jade
+++ b/app/templates/modal/versions.jade
@@ -8,7 +8,7 @@ block modal-header-content
 
 block modal-body-content
   if dataList
-    table.table
+    table.table.table-condensed
       tr
         th(data-i18n="general.name") Name
         th(data-i18n="general.version") Version
diff --git a/app/views/editor/delta.coffee b/app/views/editor/delta.coffee
index 09c0981a6..b79b1cda5 100644
--- a/app/views/editor/delta.coffee
+++ b/app/views/editor/delta.coffee
@@ -21,12 +21,12 @@ module.exports = class DeltaView extends CocoView
     if @headModel
       @headDeltas = @headModel.getExpandedDelta()
       @conflicts = deltasLib.getConflicts(@headDeltas, @expandedDeltas)
-    DeltaView.deltaCounter += @expandedDeltas.length
 
   getRenderData: ->
     c = super()
     c.deltas = @expandedDeltas
     c.counter = DeltaView.deltaCounter
+    DeltaView.deltaCounter += @expandedDeltas.length
     c
     
   afterRender: ->
diff --git a/app/views/editor/level/component/edit.coffee b/app/views/editor/level/component/edit.coffee
index 3f91f1467..74c23b567 100644
--- a/app/views/editor/level/component/edit.coffee
+++ b/app/views/editor/level/component/edit.coffee
@@ -1,7 +1,9 @@
 View = require 'views/kinds/CocoView'
-VersionHistoryView = require 'views/editor/component/versions_view'
 template = require 'templates/editor/level/component/edit'
 LevelComponent = require 'models/LevelComponent'
+VersionHistoryView = require 'views/editor/component/versions_view'
+PatchesView = require 'views/editor/patches_view'
+SaveVersionModal = require 'views/modal/save_version_modal'
 
 module.exports = class LevelComponentEditView extends View
   id: "editor-level-component-edit-view"
@@ -10,8 +12,14 @@ module.exports = class LevelComponentEditView extends View
 
   events:
     'click #done-editing-component-button': 'endEditing'
-    'click #history-button': 'showVersionHistory'
     'click .nav a': (e) -> $(e.target).tab('show')
+    'click #component-patches-tab': -> @patchesView.load()
+    'click #component-code-tab': 'buildCodeEditor'
+    'click #component-config-schema-tab': 'buildConfigSchemaTreema'
+    'click #component-settings-tab': 'buildSettingsTreema'
+    'click #component-history-button': 'showVersionHistory'
+    'click #patch-component-button': 'startPatchingComponent'
+    'click #component-watch-button': 'toggleWatchComponent'
 
   constructor: (options) ->
     super options
@@ -21,6 +29,7 @@ module.exports = class LevelComponentEditView extends View
   getRenderData: (context={}) ->
     context = super(context)
     context.editTitle = "#{@levelComponent.get('system')}.#{@levelComponent.get('name')}"
+    context.component = @levelComponent
     context
 
   afterRender: ->
@@ -28,6 +37,8 @@ module.exports = class LevelComponentEditView extends View
     @buildSettingsTreema()
     @buildConfigSchemaTreema()
     @buildCodeEditor()
+    @patchesView = @insertSubView(new PatchesView(@levelComponent), @$el.find('.patches-view'))
+    @$el.find('#component-watch-button').find('> span').toggleClass('secret') if @levelComponent.watching()
 
   buildSettingsTreema: ->
     data = _.pick @levelComponent.attributes, (value, key) => key in @editableSettings
@@ -40,7 +51,6 @@ module.exports = class LevelComponentEditView extends View
       schema: schema
       data: data
       callbacks: {change: @onComponentSettingsEdited}
-    treemaOptions.readOnly = true unless me.isAdmin()
     @componentSettingsTreema = @$el.find('#edit-component-treema').treema treemaOptions
     @componentSettingsTreema.build()
     @componentSettingsTreema.open()
@@ -58,7 +68,6 @@ module.exports = class LevelComponentEditView extends View
       schema: LevelComponent.schema.properties.configSchema
       data: @levelComponent.get 'configSchema'
       callbacks: {change: @onConfigSchemaEdited}
-    treemaOptions.readOnly = true unless me.isAdmin()
     @configSchemaTreema = @$el.find('#config-schema-treema').treema treemaOptions
     @configSchemaTreema.build()
     @configSchemaTreema.open()
@@ -70,10 +79,10 @@ module.exports = class LevelComponentEditView extends View
     Backbone.Mediator.publish 'level-component-edited', levelComponent: @levelComponent
 
   buildCodeEditor: ->
-    editorEl = @$el.find '#component-code-editor'
-    editorEl.text @levelComponent.get('code')
+    @editor?.destroy()
+    editorEl = $('<div></div>').text(@levelComponent.get('code')).addClass('inner-editor')
+    @$el.find('#component-code-editor').empty().append(editorEl)
     @editor = ace.edit(editorEl[0])
-    @editor.setReadOnly(not me.isAdmin())
     session = @editor.getSession()
     session.setMode 'ace/mode/coffee'
     session.setTabSize 2
@@ -90,11 +99,21 @@ module.exports = class LevelComponentEditView extends View
     Backbone.Mediator.publish 'level-component-editing-ended', levelComponent: @levelComponent
     null
 
+  showVersionHistory: (e) ->
+    versionHistoryView = new VersionHistoryView {}, @levelComponent.id
+    @openModalView versionHistoryView
+    Backbone.Mediator.publish 'level:view-switched', e
+    
+  startPatchingComponent: (e) ->
+    @openModalView new SaveVersionModal({model:@levelComponent})
+    Backbone.Mediator.publish 'level:view-switched', e
+
+  toggleWatchComponent: ->
+    button = @$el.find('#component-watch-button')
+    @levelComponent.watch(button.find('.watch').is(':visible'))
+    button.find('> span').toggleClass('secret')
+
   destroy: ->
     @editor?.destroy()
     super()
 
-  showVersionHistory: (e) ->
-    versionHistoryView = new VersionHistoryView component:@levelComponent, @levelComponent.id
-    @openModalView versionHistoryView
-    Backbone.Mediator.publish 'level:view-switched', e
\ No newline at end of file
diff --git a/app/views/editor/level/components_tab_view.coffee b/app/views/editor/level/components_tab_view.coffee
index 823bebed1..0a6ab8518 100644
--- a/app/views/editor/level/components_tab_view.coffee
+++ b/app/views/editor/level/components_tab_view.coffee
@@ -21,6 +21,7 @@ module.exports = class ComponentsTabView extends View
 
   events:
     'click #create-new-component-button': 'createNewLevelComponent'
+    'click #create-new-component-button-no-select': 'createNewLevelComponent'
 
   onLevelThangsChanged: (e) ->
     thangsData = e.thangsData
diff --git a/app/views/editor/level/edit.coffee b/app/views/editor/level/edit.coffee
index dd319e01f..88d50be62 100644
--- a/app/views/editor/level/edit.coffee
+++ b/app/views/editor/level/edit.coffee
@@ -27,10 +27,18 @@ module.exports = class EditorLevelView extends View
     'click #play-button': 'onPlayLevel'
     'click #commit-level-start-button': 'startCommittingLevel'
     'click #fork-level-start-button': 'startForkingLevel'
-    'click #history-button': 'showVersionHistory'
+    'click #level-history-button': 'showVersionHistory'
     'click #patches-tab': -> @patchesView.load()
-    'click #commit-level-patch-button': 'startPatchingLevel'
+    'click #level-patch-button': 'startPatchingLevel'
+    'click #level-watch-button': 'toggleWatchLevel'
+    
+  subscriptions:
+    'refresh-level-editor': 'rerenderAllViews'
 
+  rerenderAllViews: ->
+    for view in [@thangsTab, @settingsTab, @scriptsTab, @componentsTab, @systemsTab, @patchesView]
+      view.render()
+    
   constructor: (options, @levelID) ->
     super options
     @listenToOnce(@supermodel, 'loaded-all', @onAllLoaded)
@@ -93,6 +101,8 @@ module.exports = class EditorLevelView extends View
     Backbone.Mediator.publish 'level-loaded', level: @level
     @showReadOnly() if me.get('anonymous')
     @patchesView = @insertSubView(new PatchesView(@level), @$el.find('.patches-view'))
+    @listenTo @patchesView, 'accepted-patch', -> setTimeout "location.reload()", 400
+    @$el.find('#level-watch-button').find('> span').toggleClass('secret') if @level.watching()
 
   onPlayLevel: (e) ->
     sendLevel = =>
@@ -124,3 +134,8 @@ module.exports = class EditorLevelView extends View
     versionHistoryView = new VersionHistoryView level:@level, @levelID
     @openModalView versionHistoryView
     Backbone.Mediator.publish 'level:view-switched', e
+
+  toggleWatchLevel: ->
+    button = @$el.find('#level-watch-button')
+    @level.watch(button.find('.watch').is(':visible'))
+    button.find('> span').toggleClass('secret')
diff --git a/app/views/editor/level/save_view.coffee b/app/views/editor/level/save_view.coffee
index f47b07657..86ba7e96b 100644
--- a/app/views/editor/level/save_view.coffee
+++ b/app/views/editor/level/save_view.coffee
@@ -30,7 +30,7 @@ module.exports = class LevelSaveView extends SaveVersionModal
     context
 
   afterRender: ->
-    super()
+    super(false)
     changeEls = @$el.find('.changes-stub')
     models = if @lastContext.levelNeedsSave then [@level] else []
     models = models.concat @lastContext.modifiedComponents
diff --git a/app/views/editor/level/system/edit.coffee b/app/views/editor/level/system/edit.coffee
index 338ede1e5..a7699b316 100644
--- a/app/views/editor/level/system/edit.coffee
+++ b/app/views/editor/level/system/edit.coffee
@@ -1,6 +1,9 @@
 View = require 'views/kinds/CocoView'
 template = require 'templates/editor/level/system/edit'
 LevelSystem = require 'models/LevelSystem'
+VersionHistoryView = require 'views/editor/system/versions_view'
+PatchesView = require 'views/editor/patches_view'
+SaveVersionModal = require 'views/modal/save_version_modal'
 
 module.exports = class LevelSystemEditView extends View
   id: "editor-level-system-edit-view"
@@ -10,6 +13,13 @@ module.exports = class LevelSystemEditView extends View
   events:
     'click #done-editing-system-button': 'endEditing'
     'click .nav a': (e) -> $(e.target).tab('show')
+    'click #system-patches-tab': -> @patchesView.load()
+    'click #system-code-tab': 'buildCodeEditor'
+    'click #system-config-schema-tab': 'buildConfigSchemaTreema'
+    'click #system-settings-tab': 'buildSettingsTreema'
+    'click #system-history-button': 'showVersionHistory'
+    'click #patch-system-button': 'startPatchingSystem'
+    'click #system-watch-button': 'toggleWatchSystem'
 
   constructor: (options) ->
     super options
@@ -26,6 +36,7 @@ module.exports = class LevelSystemEditView extends View
     @buildSettingsTreema()
     @buildConfigSchemaTreema()
     @buildCodeEditor()
+    @patchesView = @insertSubView(new PatchesView(@levelSystem), @$el.find('.patches-view'))
 
   buildSettingsTreema: ->
     data = _.pick @levelSystem.attributes, (value, key) => key in @editableSettings
@@ -68,8 +79,9 @@ module.exports = class LevelSystemEditView extends View
     Backbone.Mediator.publish 'level-system-edited', levelSystem: @levelSystem
 
   buildCodeEditor: ->
-    editorEl = @$el.find '#system-code-editor'
-    editorEl.text @levelSystem.get('code')
+    @editor?.destroy()
+    editorEl = $('<div></div>').text(@levelSystem.get('code')).addClass('inner-editor')
+    @$el.find('#system-code-editor').empty().append(editorEl)
     @editor = ace.edit(editorEl[0])
     @editor.setReadOnly(not me.isAdmin())
     session = @editor.getSession()
@@ -88,6 +100,21 @@ module.exports = class LevelSystemEditView extends View
     Backbone.Mediator.publish 'level-system-editing-ended', levelSystem: @levelSystem
     null
 
+  showVersionHistory: (e) ->
+    versionHistoryView = new VersionHistoryView {}, @levelSystem.id
+    @openModalView versionHistoryView
+    Backbone.Mediator.publish 'level:view-switched', e
+
+  startPatchingSystem: (e) ->
+    @openModalView new SaveVersionModal({model:@levelSystem})
+    Backbone.Mediator.publish 'level:view-switched', e
+
+  toggleWatchSystem: ->
+    console.log 'toggle watch system?'
+    button = @$el.find('#system-watch-button')
+    @levelSystem.watch(button.find('.watch').is(':visible'))
+    button.find('> span').toggleClass('secret')
+
   destroy: ->
     @editor?.destroy()
     super()
diff --git a/app/views/editor/level/systems_tab_view.coffee b/app/views/editor/level/systems_tab_view.coffee
index eb4747b0e..e3f4fa626 100644
--- a/app/views/editor/level/systems_tab_view.coffee
+++ b/app/views/editor/level/systems_tab_view.coffee
@@ -23,6 +23,7 @@ module.exports = class SystemsTabView extends View
   events:
     'click #add-system-button': 'addLevelSystem'
     'click #create-new-system-button': 'createNewLevelSystem'
+    'click #create-new-system': 'createNewLevelSystem'
 
   constructor: (options) ->
     super options
diff --git a/app/views/editor/level/thangs_tab_view.coffee b/app/views/editor/level/thangs_tab_view.coffee
index b4ddc0e0f..d19a93eab 100644
--- a/app/views/editor/level/thangs_tab_view.coffee
+++ b/app/views/editor/level/thangs_tab_view.coffee
@@ -255,7 +255,7 @@ module.exports = class ThangsTabView extends View
 #      @thangsTreema.deselectAll()
 
   selectAddThang: (e) =>
-    return unless $(e.target).closest('.editor-level-thangs-tab-view').length
+    return unless e? and $(e.target).closest('.editor-level-thangs-tab-view').length
     if e then target = $(e.target) else target = @$el.find('.add-thangs-palette')  # pretend to click on background if no event
     return true if target.attr('id') is 'surface'
     target = target.closest('.add-thang-palette-icon')
diff --git a/app/views/editor/patch_modal.coffee b/app/views/editor/patch_modal.coffee
index 19f3ebfe6..f5dc339cf 100644
--- a/app/views/editor/patch_modal.coffee
+++ b/app/views/editor/patch_modal.coffee
@@ -7,6 +7,7 @@ module.exports = class PatchModal extends ModalView
   id: "patch-modal"
   template: template
   plain: true
+  modalWidthPercent: 60
   
   events:
     'click #withdraw-button': 'withdrawPatch'
@@ -30,12 +31,15 @@ module.exports = class PatchModal extends ModalView
     c.isPatchCreator = @patch.get('creator') is auth.me.id
     c.isPatchRecipient = @targetModel.hasWriteAccess()
     c.status = @patch.get 'status'
+    c.patch = @patch
     c
     
   afterRender: ->
     return if @originalSource.loading
-    headModel = @originalSource.clone(false)
-    headModel.set(@targetModel.attributes)
+    headModel = null
+    if @targetModel.hasWriteAccess()
+      headModel = @originalSource.clone(false)
+      headModel.set(@targetModel.attributes)
     
     pendingModel = @originalSource.clone(false)
     pendingModel.applyDelta(@patch.get('delta'))
@@ -48,7 +52,8 @@ module.exports = class PatchModal extends ModalView
   acceptPatch: ->
     delta = @deltaView.getApplicableDelta()
     @targetModel.applyDelta(delta)
-    @targetModel.addPatchToAcceptOnSave(@patch)
+    @patch.setStatus('accepted')
+    @trigger 'accepted-patch'
     @hide()
     
   rejectPatch: ->
diff --git a/app/views/editor/patches_view.coffee b/app/views/editor/patches_view.coffee
index f8dd4fa15..8887b44bb 100644
--- a/app/views/editor/patches_view.coffee
+++ b/app/views/editor/patches_view.coffee
@@ -44,8 +44,11 @@ module.exports = class PatchesView extends CocoView
     @$el.find(".#{@status}").addClass 'active'
 
   onStatusButtonsChanged: (e) ->
-    @loaded = false
     @status = $(e.target).val()
+    @reloadPatches()
+    
+  reloadPatches: ->
+    @loaded = false
     @initPatches()
     @load()
     @render()
@@ -53,4 +56,9 @@ module.exports = class PatchesView extends CocoView
   openPatchModal: (e) ->
     patch = _.find @patches.models, {id:$(e.target).data('patch-id')}
     modal = new PatchModal(patch, @model)
-    @openModalView(modal)
\ No newline at end of file
+    @openModalView(modal)
+    @listenTo modal, 'accepted-patch', -> @trigger 'accepted-patch'
+    @listenTo modal, 'hide', ->
+      f = => @reloadPatches()
+      setTimeout(f, 400)
+      @stopListening modal
\ No newline at end of file
diff --git a/app/views/editor/system/versions_view.coffee b/app/views/editor/system/versions_view.coffee
new file mode 100755
index 000000000..562d134ad
--- /dev/null
+++ b/app/views/editor/system/versions_view.coffee
@@ -0,0 +1,9 @@
+VersionsModalView = require 'views/modal/versions_modal'
+
+module.exports = class SystemVersionsView extends VersionsModalView
+  id: "editor-system-versions-view"
+  url: "/db/level.system/"
+  page: "system"
+
+  constructor: (options, @ID) ->
+    super options, ID, require 'models/LevelSystem'
\ No newline at end of file
diff --git a/app/views/kinds/CocoView.coffee b/app/views/kinds/CocoView.coffee
index b368f51ab..5e9275ca3 100644
--- a/app/views/kinds/CocoView.coffee
+++ b/app/views/kinds/CocoView.coffee
@@ -207,6 +207,7 @@ class CocoView extends Backbone.View
   # Modals
 
   toggleModal: (e) ->
+    return if visibleModal
     if $(e.currentTarget).prop('target') is '_blank'
       return true
     # special handler for opening modals that are dynamically loaded, rather than static in the page. It works (or should work) like Bootstrap's modals, except use coco-modal for the data-toggle value.
diff --git a/app/views/kinds/ModalView.coffee b/app/views/kinds/ModalView.coffee
index 2bf6ee8db..26a32081a 100644
--- a/app/views/kinds/ModalView.coffee
+++ b/app/views/kinds/ModalView.coffee
@@ -45,9 +45,11 @@ module.exports = class ModalView extends CocoView
     super($el)
 
   hide: ->
+    @trigger 'hide'
     @$el.removeClass('fade').modal "hide"
 
   onHidden: ->
+    @trigger 'hidden'
 
   destroy: ->
     @hide() unless @hidden
diff --git a/app/views/modal/save_version_modal.coffee b/app/views/modal/save_version_modal.coffee
index 6533a741f..d95fc4166 100644
--- a/app/views/modal/save_version_modal.coffee
+++ b/app/views/modal/save_version_modal.coffee
@@ -8,6 +8,7 @@ module.exports = class SaveVersionModal extends ModalView
   id: 'save-version-modal'
   template: template
   plain: true
+  modalWidthPercent: 60
 
   events:
     'click #save-version-button': 'onClickSaveButton'
@@ -26,15 +27,16 @@ module.exports = class SaveVersionModal extends ModalView
     c.hasChanges = @model.hasLocalChanges()
     c
 
-  afterRender: ->
+  afterRender: (insertDeltaView=true) ->
     super()
     @$el.find(if me.get('signedCLA') then '#accept-cla-wrapper' else '#save-version-button').hide()
     changeEl = @$el.find('.changes-stub')
-    try
-      deltaView = new DeltaView({model:@model})
-      @insertSubView(deltaView, changeEl)
-    catch e
-      console.error "Couldn't create delta view:", e
+    if insertDeltaView
+      try
+        deltaView = new DeltaView({model:@model})
+        @insertSubView(deltaView, changeEl)
+      catch e
+        console.error "Couldn't create delta view:", e
     @$el.find('.commit-message input').attr('placeholder', $.i18n.t('general.commit_msg'))
 
   onClickSaveButton: ->
@@ -54,6 +56,7 @@ module.exports = class SaveVersionModal extends ModalView
     }
     errors = patch.validate()
     forms.applyErrorsToForm(@$el, errors) if errors
+    patch.set 'editPath', document.location.pathname
     res = patch.save()
     return unless res
     @enableModalInProgress(@$el)
diff --git a/app/views/modal/versions_modal.coffee b/app/views/modal/versions_modal.coffee
index 97aeafb33..6bf511396 100755
--- a/app/views/modal/versions_modal.coffee
+++ b/app/views/modal/versions_modal.coffee
@@ -13,6 +13,8 @@ class VersionsViewCollection extends Backbone.Collection
 module.exports = class VersionsModalView extends ModalView
   template: template
   startsLoading: true
+  plain: true
+  modalWidthPercent: 80
 
   # needs to be overwritten by child
   id: ""
diff --git a/server/commons/Handler.coffee b/server/commons/Handler.coffee
index b486b79b0..aed496fd8 100644
--- a/server/commons/Handler.coffee
+++ b/server/commons/Handler.coffee
@@ -4,6 +4,8 @@ Grid = require 'gridfs-stream'
 errors = require './errors'
 log = require 'winston'
 Patch = require '../patches/Patch'
+User = require '../users/User'
+sendwithus = require '../sendwithus'
 
 PROJECT = {original:1, name:1, version:1, description: 1, slug:1, kind: 1}
 FETCH_LIMIT = 200
@@ -95,7 +97,7 @@ module.exports = class Handler
     # this handler should be overwritten by subclasses
     if @modelClass.schema.is_patchable
       return @getPatchesFor(req, res, args[0]) if req.route.method is 'get' and args[1] is 'patches'
-      return @setListening(req, res, args[0]) if req.route.method is 'put' and args[1] is 'listen'
+      return @setWatching(req, res, args[0]) if req.route.method is 'put' and args[1] is 'watch'
     return @sendNotFoundError(res)
 
   getPatchesFor: (req, res, id) ->
@@ -105,16 +107,16 @@ module.exports = class Handler
       patches = (patch.toObject() for patch in patches) 
       @sendSuccess(res, patches)
 
-  setListening: (req, res, id) ->
+  setWatching: (req, res, id) ->
     @getDocumentForIdOrSlug id, (err, document) =>
       return @sendUnauthorizedError(res) unless @hasAccessToDocument(req, document, 'get')
       return @sendDatabaseError(res, err) if err
       return @sendNotFoundError(res) unless document?
-      listeners = document.get('listeners') or []
+      watchers = document.get('watchers') or []
       me = req.user.get('_id')
-      listeners = (l for l in listeners when not l.equals(me))
-      listeners.push me if req.body.on
-      document.set 'listeners', listeners
+      watchers = (l for l in watchers when not l.equals(me))
+      watchers.push me if req.body.on and req.body.on isnt 'false'
+      document.set 'watchers', watchers
       document.save (err, document) =>
         return @sendDatabaseError(res, err) if err
         @sendSuccess(res, @formatEntity(req, document))
@@ -233,6 +235,9 @@ module.exports = class Handler
       return @sendBadInputError(res, err.errors) if err?.valid is false
       return @sendDatabaseError(res, err) if err
       @sendSuccess(res, @formatEntity(req, document))
+      @onPostSuccess(req, document)
+
+  onPostSuccess: (req, doc) ->
 
   ###
   TODO: think about pulling some common stuff out of postFirstVersion/postNewVersion
@@ -248,7 +253,6 @@ module.exports = class Handler
     document.set('original', document._id)
     document.set('creator', req.user._id)
     @saveChangesToDocument req, document, (err) =>
-      console.log 'saved new version', document.toObject()
       return @sendBadInputError(res, err.errors) if err?.valid is false
       return @sendDatabaseError(res, err) if err
       @sendSuccess(res, @formatEntity(req, document))
@@ -291,6 +295,7 @@ module.exports = class Handler
         newDocument.save (err) =>
           return @sendDatabaseError(res, err) if err
           @sendSuccess(res, @formatEntity(req, newDocument))
+          @notifyWatchersOfChange(req.user, newDocument, req.body.editPath) if @modelClass.schema.is_patchable
 
       if major?
         parentDocument.makeNewMinorVersion(updatedObject, major, done)
@@ -298,8 +303,31 @@ module.exports = class Handler
       else
         parentDocument.makeNewMajorVersion(updatedObject, done)
 
+  notifyWatchersOfChange: (editor, changedDocument, editPath) ->
+    watchers = changedDocument.get('watchers') or []
+    watchers = (w for w in watchers when not w.equals(editor.get('_id')))
+    return unless watchers.length
+    User.find({_id:{$in:watchers}}).select({email:1, name:1}).exec (err, watchers) =>
+      for watcher in watchers
+        @notifyWatcherOfChange editor, watcher, changedDocument, editPath
+
+  notifyWatcherOfChange: (editor, watcher, changedDocument, editPath) ->
+    context =
+      email_id: sendwithus.templates.change_made_notify_watcher
+      recipient:
+        address: watcher.get('email')
+        name: watcher.get('name')
+      email_data:
+        doc_name: changedDocument.get('name') or '???'
+        submitter_name: editor.get('name') or '???'
+        doc_link: if editPath then "http://codecombat.com#{editPath}" else null
+        commit_message: changedDocument.get('commitMessage')
+    sendwithus.api.send context, (err, result) ->
+
   makeNewInstance: (req) ->
-    new @modelClass({})
+    model = new @modelClass({})
+    model.set 'watchers', [req.user.get('_id')] if @modelClass.schema.is_patchable
+    model
 
   validateDocumentInput: (input) ->
     tv4 = require('tv4').tv4
diff --git a/server/patches/Patch.coffee b/server/patches/Patch.coffee
index df621f2a4..3e12638cf 100644
--- a/server/patches/Patch.coffee
+++ b/server/patches/Patch.coffee
@@ -39,8 +39,10 @@ PatchSchema.pre 'save', (next) ->
       target.original = targetID
     
     patches = document.get('patches') or []
+    patches = _.clone patches
     patches.push @_id
-    document.set 'patches', patches
+    document.set 'patches', patches, {strict: false}
+    @targetLoaded = document
     document.save (err) -> next(err)
 
 module.exports = mongoose.model('patch', PatchSchema)
diff --git a/server/patches/patch_handler.coffee b/server/patches/patch_handler.coffee
index 12a68ed9a..4e134d73d 100644
--- a/server/patches/patch_handler.coffee
+++ b/server/patches/patch_handler.coffee
@@ -1,8 +1,11 @@
 Patch = require('./Patch')
+User = require '../users/User'
 Handler = require('../commons/Handler')
 schema = require '../../app/schemas/models/patch'
 {handlers} = require '../commons/mapping'
 mongoose = require('mongoose')
+log = require 'winston'
+sendwithus = require '../sendwithus'
 
 PatchHandler = class PatchHandler extends Handler
   modelClass: Patch
@@ -50,6 +53,29 @@ PatchHandler = class PatchHandler extends Handler
         patch.update {$set:{status:newStatus}}, {}, ->
         target.update {$pull:{patches:patch.get('_id')}}, {}, ->
         @sendSuccess(res, null)
+
+  onPostSuccess: (req, doc) ->
+    log.error "Error sending patch created: could not find the loaded target on the patch object." unless doc.targetLoaded
+    return unless doc.targetLoaded
+    watchers = doc.targetLoaded.get('watchers') or []
+    watchers = (w for w in watchers when not w.equals(editor.get('_id')))
+    return unless watchers?.length
+    User.find({_id:{$in:watchers}}).select({email:1, name:1}).exec (err, watchers) =>
+      for watcher in watchers
+        @sendPatchCreatedEmail req.user, watcher, doc, doc.targetLoaded, req.body.editPath
     
+  sendPatchCreatedEmail: (patchCreator, watcher, patch, target, editPath) ->
+#    return if watcher._id is patchCreator._id
+    context =
+      email_id: sendwithus.templates.patch_created
+      recipient:
+        address: watcher.get('email')
+        name: watcher.get('name')
+      email_data:
+        doc_name: target.get('name') or '???'
+        submitter_name: patchCreator.get('name') or '???'
+        doc_link: "http://codecombat.com#{editPath}"
+        commit_message: patch.get('commitMessage')
+    sendwithus.api.send context, (err, result) ->
 
 module.exports = new PatchHandler()
diff --git a/server/sendwithus.coffee b/server/sendwithus.coffee
index bda58d896..04d8205c3 100644
--- a/server/sendwithus.coffee
+++ b/server/sendwithus.coffee
@@ -14,3 +14,5 @@ if config.unittest
 module.exports.templates =
   welcome_email: 'utnGaBHuSU4Hmsi7qrAypU'
   ladder_update_email: 'JzaZxf39A4cKMxpPZUfWy4'
+  patch_created: 'tem_xhxuNosLALsizTNojBjNcL'
+  change_made_notify_watcher: 'tem_7KVkfmv9SZETb25dtHbUtG'
diff --git a/test/server/common.coffee b/test/server/common.coffee
index e68c27b72..80aa6e47e 100644
--- a/test/server/common.coffee
+++ b/test/server/common.coffee
@@ -64,13 +64,13 @@ GLOBAL.unittest = {}
 unittest.users = unittest.users or {}
 
 unittest.getNormalJoe = (done, force) ->
-  unittest.getUser('normal@jo.com', 'food', done, force)
+  unittest.getUser('Joe', 'normal@jo.com', 'food', done, force)
 unittest.getOtherSam = (done, force) ->
-  unittest.getUser('other@sam.com', 'beer', done, force)
+  unittest.getUser('Sam', 'other@sam.com', 'beer', done, force)
 unittest.getAdmin = (done, force) ->
-  unittest.getUser('admin@afc.com', '80yqxpb38j', done, force)
+  unittest.getUser('Admin', 'admin@afc.com', '80yqxpb38j', done, force)
 
-unittest.getUser = (email, password, done, force) ->
+unittest.getUser = (name, email, password, done, force) ->
   # Creates the user if it doesn't already exist.
 
   return done(unittest.users[email]) if unittest.users[email] and not force
@@ -81,6 +81,7 @@ unittest.getUser = (email, password, done, force) ->
         throw err if err
         User.findOne({email:email}).exec((err, user) ->
           user.set('permissions', if password is '80yqxpb38j' then [ 'admin' ] else [])
+          user.set('name', name)
           user.save (err) ->
             wrapUpGetUser(email, user, done)
         )
@@ -88,7 +89,6 @@ unittest.getUser = (email, password, done, force) ->
       form = req.form()
       form.append('email', email)
       form.append('password', password)
-      
 
 wrapUpGetUser = (email, user, done) ->
   unittest.users[email] = user
diff --git a/test/server/functional/patch.spec.coffee b/test/server/functional/patch.spec.coffee
index d8694baf0..9d0f4265d 100644
--- a/test/server/functional/patch.spec.coffee
+++ b/test/server/functional/patch.spec.coffee
@@ -16,13 +16,14 @@ describe '/db/patch', ->
   patch =
     commitMessage: 'Accept this patch!'
     delta: {name:['test']}
+    editPath: '/who/knows/yes'
     target:
       id:null
       collection: 'article'
 
   it 'creates an Article to patch', (done) ->
     loginAdmin ->
-      request.post {uri:articleURL, json:patch}, (err, res, body) ->
+      request.post {uri:articleURL, json:article}, (err, res, body) ->
         articles[0] = body
         patch.target.id = articles[0]._id
         done()
@@ -51,29 +52,29 @@ describe '/db/patch', ->
       body = JSON.parse(body)
       expect(res.statusCode).toBe(200)
       expect(body.length).toBe(1)
-      done()
+      done() 
       
-  it 'allows you to set yourself as listening', (done) ->
-    listeningURL = getURL("/db/article/#{articles[0]._id}/listen")
-    request.put {uri: listeningURL, json: {on:true}}, (err, res, body) ->
-      expect(body.listeners[0]).toBeDefined()
+  it 'allows you to set yourself as watching', (done) ->
+    watchingURL = getURL("/db/article/#{articles[0]._id}/watch")
+    request.put {uri: watchingURL, json: {on:true}}, (err, res, body) ->
+      expect(body.watchers[1]).toBeDefined()
       done()
 
-  it 'added the listener to the target document', (done) ->
+  it 'added the watcher to the target document', (done) ->
     Article.findOne({}).exec (err, article) ->
-      expect(article.toObject().listeners[0]).toBeDefined()
+      expect(article.toObject().watchers[1]).toBeDefined()
       done()
 
-  it 'does not add duplicate listeners', (done) ->
-    listeningURL = getURL("/db/article/#{articles[0]._id}/listen")
-    request.put {uri: listeningURL, json: {on:true}}, (err, res, body) ->
-      expect(body.listeners.length).toBe(1)
+  it 'does not add duplicate watchers', (done) ->
+    watchingURL = getURL("/db/article/#{articles[0]._id}/watch")
+    request.put {uri: watchingURL, json: {on:true}}, (err, res, body) ->
+      expect(body.watchers.length).toBe(2)
       done()
       
   it 'allows removing yourself', (done) ->
-    listeningURL = getURL("/db/article/#{articles[0]._id}/listen")
-    request.put {uri: listeningURL, json: {on:false}}, (err, res, body) ->
-      expect(body.listeners.length).toBe(0)
+    watchingURL = getURL("/db/article/#{articles[0]._id}/watch")
+    request.put {uri: watchingURL, json: {on:false}}, (err, res, body) ->
+      expect(body.watchers.length).toBe(1)
       done()
       
   it 'allows the submitter to withdraw the pull request', (done) ->
diff --git a/test/server/functional/user.spec.coffee b/test/server/functional/user.spec.coffee
index 29e1360a9..0ee2ff364 100644
--- a/test/server/functional/user.spec.coffee
+++ b/test/server/functional/user.spec.coffee
@@ -112,7 +112,7 @@ ghlfarghlarghlfarghlarghlfarghlarghlfarghlarghlfarghlarghlfarghlarghlfarghlarghl
     unittest.getNormalJoe (joe) ->
       req = request.put getURL(urlUser), (err, res) ->
         expect(res.statusCode).toBe(200)
-        unittest.getUser('New@email.com', 'null', (joe) ->
+        unittest.getUser('Wilhelm', 'New@email.com', 'null', (joe) ->
           expect(joe.get('name')).toBe('Wilhelm')
           expect(joe.get('emailLower')).toBe('new@email.com')
           expect(joe.get('email')).toBe('New@email.com')