diff --git a/app/views/play/ladder/my_matches_tab.coffee b/app/views/play/ladder/my_matches_tab.coffee
index cb7697bae..672d74a52 100644
--- a/app/views/play/ladder/my_matches_tab.coffee
+++ b/app/views/play/ladder/my_matches_tab.coffee
@@ -205,6 +205,7 @@ module.exports = class MyMatchesTabView extends CocoView
     for thang, spells of submittedCode
       transpiledCode[thang] = {}
       for spellID, spell of spells
+        unless _.contains(session.get('teamSpells')[session.get('team')], thang + "/" + spellID) then continue
         #DRY this
         aetherOptions =
           problems: {}
diff --git a/app/views/play/level/modal/multiplayer_modal.coffee b/app/views/play/level/modal/multiplayer_modal.coffee
index 941dd0491..5ab5d0591 100644
--- a/app/views/play/level/modal/multiplayer_modal.coffee
+++ b/app/views/play/level/modal/multiplayer_modal.coffee
@@ -76,6 +76,7 @@ module.exports = class MultiplayerModal extends View
     for thang, spells of submittedCode
       transpiledCode[thang] = {}
       for spellID, spell of spells
+        unless _.contains(session.get('teamSpells')[session.get('team')], thang + "/" + spellID) then continue
         #DRY this
         aetherOptions =
           problems: {}
diff --git a/app/views/play/level/modal/victory_modal.coffee b/app/views/play/level/modal/victory_modal.coffee
index 4b5517d7b..2a0b02c89 100644
--- a/app/views/play/level/modal/victory_modal.coffee
+++ b/app/views/play/level/modal/victory_modal.coffee
@@ -85,6 +85,7 @@ module.exports = class VictoryModal extends View
       transpiledCode[thang] = {}
       for spellID, spell of spells
         #DRY this
+        unless _.contains(session.get('teamSpells')[session.get('team')], thang + "/" + spellID) then continue
         aetherOptions =
           problems: {}
           language: "javascript"
diff --git a/app/views/play/level/tome/spell.coffee b/app/views/play/level/tome/spell.coffee
index b2832d596..b87d21c2b 100644
--- a/app/views/play/level/tome/spell.coffee
+++ b/app/views/play/level/tome/spell.coffee
@@ -14,6 +14,7 @@ module.exports = class Spell
     @spellKey = options.spellKey
     @pathComponents = options.pathComponents
     @session = options.session
+    @spectateView = options.spectateView
     @supermodel = options.supermodel
     @skipProtectAPI = options.skipProtectAPI
     @worker = options.worker
@@ -21,6 +22,7 @@ module.exports = class Spell
 
     @name = p.name
     @permissions = read: p.permissions?.read ? [], readwrite: p.permissions?.readwrite ? []  # teams
+    @useTranspiledCode = @permissions.readwrite.length and ((not _.contains(@session.get('teamSpells')[@session.get('team')],@spellKey)) or (@session.get('creator') isnt me.id) or @spectateView)
     @source = @originalSource = p.source
     @parameters = p.parameters
     if @permissions.readwrite.length and sessionSource = @session.getSourceFor(@spellKey)
@@ -64,10 +66,15 @@ module.exports = class Spell
     else
       source = @getSource()
     [pure, problems] = [null, null]
+    if @useTranspiledCode
+      transpiledCode = @session.get('code')
     for thangID, spellThang of @thangs
       unless pure
-        pure = spellThang.aether.transpile source
-        problems = spellThang.aether.problems
+        if @useTranspiledCode and transpiledSpell = transpiledCode[_.string.slugify thangID]?[@name]
+          spellThang.aether.pure = transpiledSpell
+        else
+          pure = spellThang.aether.transpile source
+          problems = spellThang.aether.problems
         #console.log "aether transpiled", source.length, "to", pure.length, "for", thangID, @spellKey
       else
         spellThang.aether.pure = pure
diff --git a/app/views/play/level/tome/tome_view.coffee b/app/views/play/level/tome/tome_view.coffee
index 01f03af71..b15537724 100644
--- a/app/views/play/level/tome/tome_view.coffee
+++ b/app/views/play/level/tome/tome_view.coffee
@@ -121,7 +121,17 @@ module.exports = class TomeView extends View
         @thangSpells[thang.id].push spellKey
         unless method.cloneOf
           skipProtectAPI = @getQueryVariable "skip_protect_api", (@options.levelID in ['gridmancer'])
-          spell = @spells[spellKey] = new Spell programmableMethod: method, spellKey: spellKey, pathComponents: pathPrefixComponents.concat(pathComponents), session: @options.session, supermodel: @supermodel, skipProtectAPI: skipProtectAPI, worker: @worker, language: language
+          spell = @spells[spellKey] = new Spell 
+            programmableMethod: method
+            spellKey: spellKey
+            pathComponents: pathPrefixComponents.concat(pathComponents)
+            session: @options.session
+            supermodel: @supermodel
+            skipProtectAPI: skipProtectAPI
+            worker: @worker
+            language: language
+            spectateView: @options.spectateView
+            
     for thangID, spellKeys of @thangSpells
       thang = world.getThangByID thangID
       if thang
diff --git a/app/views/play/level_view.coffee b/app/views/play/level_view.coffee
index dc06eb9ac..46b6804e0 100644
--- a/app/views/play/level_view.coffee
+++ b/app/views/play/level_view.coffee
@@ -199,7 +199,7 @@ module.exports = class PlayLevelView extends View
       continue if spellTeam is myTeam or not myTeam
       opponentSpells = opponentSpells.concat spells
 
-    opponentCode = @otherSession?.get('submittedCode') or {}
+    opponentCode = @otherSession?.get('transpiledCode') or {}
     myCode = @session.get('code') or {}
     for spell in opponentSpells
       [thang, spell] = spell.split '/'
diff --git a/app/views/play/spectate_view.coffee b/app/views/play/spectate_view.coffee
index b7b35cadc..76e5430ca 100644
--- a/app/views/play/spectate_view.coffee
+++ b/app/views/play/spectate_view.coffee
@@ -196,13 +196,14 @@ module.exports = class SpectateLevelView extends View
       continue if spellTeam is myTeam or not myTeam
       opponentSpells = opponentSpells.concat spells
 
-    opponentCode = @otherSession?.get('submittedCode') or {}
-    myCode = @session.get('submittedCode') or {}
+    opponentCode = @otherSession?.get('transpiledCode') or {}
+    myCode = @session.get('transpiledCode') or {}
     for spell in opponentSpells
       [thang, spell] = spell.split '/'
       c = opponentCode[thang]?[spell]
       myCode[thang] ?= {}
       if c then myCode[thang][spell] = c else delete myCode[thang][spell]
+    
     @session.set('code', myCode)
     if @session.get('multiplayer') and @otherSession?
       # For now, ladderGame will disallow multiplayer, because session code combining doesn't play nice yet.
@@ -231,7 +232,7 @@ module.exports = class SpectateLevelView extends View
     ctx.fillText("Loaded #{@modelsLoaded} thingies",50,50)
 
   insertSubviews: ->
-    @insertSubView @tome = new TomeView levelID: @levelID, session: @session, thangs: @world.thangs, supermodel: @supermodel
+    @insertSubView @tome = new TomeView levelID: @levelID, session: @session, thangs: @world.thangs, supermodel: @supermodel, spectateView: true
     @insertSubView new PlaybackView {}
 
     @insertSubView new GoldView {}
diff --git a/server/levels/sessions/level_session_handler.coffee b/server/levels/sessions/level_session_handler.coffee
index 5436a02dd..0a5b61ca8 100644
--- a/server/levels/sessions/level_session_handler.coffee
+++ b/server/levels/sessions/level_session_handler.coffee
@@ -14,7 +14,14 @@ class LevelSessionHandler extends Handler
   getByRelationship: (req, res, args...) ->
     return @getActiveSessions req, res if args.length is 2 and args[1] is 'active'
     super(arguments...)
-
+    
+  formatEntity: (req, document) ->
+    documentObject = super(req, document)
+    if req.user.isAdmin() or req.user.id is document.creator
+      return documentObject
+    else
+      return _.omit documentObject, ['submittedCode','code']
+      
   getActiveSessions: (req, res) ->
     return @sendUnauthorizedError(res) unless req.user.isAdmin()
     start = new Date()