about summary refs log tree commit diff stats
path: root/edit
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2016-12-11 16:18:18 -0800
committerKartik K. Agaram <vc@akkartik.com>2016-12-11 16:18:18 -0800
commit294b2ab35983ebe95698835bb54bca8bd3eec101 (patch)
treefbc74bea6cefd7b8f527d36a7b7c6804dd886414 /edit
parentd5c86dfd8706e6b3ceee7843464797e6fcad4259 (diff)
downloadmu-294b2ab35983ebe95698835bb54bca8bd3eec101.tar.gz
3705 - switch to tested file-system primitives
Diffstat (limited to 'edit')
-rw-r--r--edit/004-programming-environment.mu81
-rw-r--r--edit/005-sandbox.mu170
-rw-r--r--edit/006-sandbox-copy.mu128
-rw-r--r--edit/007-sandbox-delete.mu42
-rw-r--r--edit/008-sandbox-edit.mu108
-rw-r--r--edit/009-sandbox-test.mu45
-rw-r--r--edit/010-sandbox-trace.mu90
-rw-r--r--edit/011-errors.mu341
8 files changed, 543 insertions, 462 deletions
diff --git a/edit/004-programming-environment.mu b/edit/004-programming-environment.mu
index 332b7e18..7efa3d47 100644
--- a/edit/004-programming-environment.mu
+++ b/edit/004-programming-environment.mu
@@ -6,12 +6,9 @@
 def! main [
   local-scope
   open-console
-  initial-recipe:text <- restore [recipes.mu]
-  initial-sandbox:text <- new []
-  hide-screen 0/screen
-  env:&:environment <- new-programming-environment 0/screen, initial-recipe, initial-sandbox
+  env:&:environment <- new-programming-environment 0/filesystem, 0/screen
   render-all 0/screen, env, render
-  event-loop 0/screen, 0/console, env
+  event-loop 0/screen, 0/console, env, 0/filesystem
   # never gets here
 ]
 
@@ -21,24 +18,25 @@ container environment [
   sandbox-in-focus?:bool  # false => cursor in recipes; true => cursor in current-sandbox
 ]
 
-def new-programming-environment screen:&:screen, initial-recipe-contents:text, initial-sandbox-contents:text -> result:&:environment [
+def new-programming-environment resources:&:resources, screen:&:screen, test-sandbox-editor-contents:text -> result:&:environment [
   local-scope
   load-ingredients
   width:num <- screen-width screen
   result <- new environment:type
   # recipe editor on the left
+  initial-recipe-contents:text <- slurp resources, [lesson/recipes.mu]  # ignore errors
   divider:num, _ <- divide-with-remainder width, 2
   recipes:&:editor <- new-editor initial-recipe-contents, 0/left, divider/right
   # sandbox editor on the right
   sandbox-left:num <- add divider, 1
-  current-sandbox:&:editor <- new-editor initial-sandbox-contents, sandbox-left, width/right
+  current-sandbox:&:editor <- new-editor test-sandbox-editor-contents, sandbox-left, width/right
   *result <- put *result, recipes:offset, recipes
   *result <- put *result, current-sandbox:offset, current-sandbox
   *result <- put *result, sandbox-in-focus?:offset, 0/false
   <programming-environment-initialization>
 ]
 
-def event-loop screen:&:screen, console:&:console, env:&:environment -> screen:&:screen, console:&:console, env:&:environment [
+def event-loop screen:&:screen, console:&:console, env:&:environment, resources:&:resources -> screen:&:screen, console:&:console, env:&:environment, resources:&:resources [
   local-scope
   load-ingredients
   recipes:&:editor <- get *env, recipes:offset
@@ -286,7 +284,12 @@ scenario point-at-multiple-editors [
   trace-until 100/app  # trace too long
   assume-screen 30/width, 5/height
   # initialize both halves of screen
-  env:&:environment <- new-programming-environment screen, [abc], [def]
+  assume-resources [
+    [lesson/recipes.mu] <- [
+      |abc|
+    ]
+  ]
+  env:&:environment <- new-programming-environment resources, screen, [def]  # contents of sandbox editor
   # focus on both sides
   assume-console [
     left-click 1, 1
@@ -294,7 +297,7 @@ scenario point-at-multiple-editors [
   ]
   # check cursor column in each
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
     recipes:&:editor <- get *env, recipes:offset
     5:num/raw <- get *recipes, cursor-column:offset
     sandbox:&:editor <- get *env, current-sandbox:offset
@@ -311,7 +314,12 @@ scenario edit-multiple-editors [
   trace-until 100/app  # trace too long
   assume-screen 30/width, 5/height
   # initialize both halves of screen
-  env:&:environment <- new-programming-environment screen, [abc], [def]
+  assume-resources [
+    [lesson/recipes.mu] <- [
+      |abc|
+    ]
+  ]
+  env:&:environment <- new-programming-environment resources, screen, [def]  # contents of sandbox
   render-all screen, env, render
   # type one letter in each of them
   assume-console [
@@ -321,7 +329,7 @@ scenario edit-multiple-editors [
     type [1]
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
     recipes:&:editor <- get *env, recipes:offset
     5:num/raw <- get *recipes, cursor-column:offset
     sandbox:&:editor <- get *env, current-sandbox:offset
@@ -330,7 +338,8 @@ scenario edit-multiple-editors [
   screen-should-contain [
     .           run (F4)           .  # this line has a different background, but we don't test that yet
     .a0bc           ┊d1ef          .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊──────────────.
+    .               ┊──────────────.
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊              .
     .               ┊              .
   ]
   memory-should-contain [
@@ -345,39 +354,27 @@ scenario edit-multiple-editors [
   screen-should-contain [
     .           run (F4)           .
     .a0bc           ┊d1␣f          .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊──────────────.
+    .               ┊──────────────.
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊              .
     .               ┊              .
   ]
 ]
 
-scenario multiple-editors-cover-only-their-own-areas [
-  local-scope
-  trace-until 100/app  # trace too long
-  assume-screen 60/width, 10/height
-  run [
-    env:&:environment <- new-programming-environment screen, [abc], [def]
-    render-all screen, env, render
-  ]
-  # divider isn't messed up
-  screen-should-contain [
-    .                                         run (F4)           .
-    .abc                           ┊def                          .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────.
-    .                              ┊                             .
-    .                              ┊                             .
-  ]
-]
-
 scenario editor-in-focus-keeps-cursor [
   local-scope
   trace-until 100/app  # trace too long
   assume-screen 30/width, 5/height
-  env:&:environment <- new-programming-environment screen, [abc], [def]
+  assume-resources [
+    [lesson/recipes.mu] <- [
+      |abc|
+    ]
+  ]
+  env:&:environment <- new-programming-environment resources, screen, [def]
   render-all screen, env, render
   # initialize programming environment and highlight cursor
   assume-console []
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
     cursor:char <- copy 9251/␣
     print screen, cursor
   ]
@@ -385,7 +382,8 @@ scenario editor-in-focus-keeps-cursor [
   screen-should-contain [
     .           run (F4)           .
     .␣bc            ┊def           .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊──────────────.
+    .               ┊──────────────.
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊              .
     .               ┊              .
   ]
   # now try typing a letter
@@ -393,7 +391,7 @@ scenario editor-in-focus-keeps-cursor [
     type [z]
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
     cursor:char <- copy 9251/␣
     print screen, cursor
   ]
@@ -401,7 +399,8 @@ scenario editor-in-focus-keeps-cursor [
   screen-should-contain [
     .           run (F4)           .
     .z␣bc           ┊def           .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊──────────────.
+    .               ┊──────────────.
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊              .
     .               ┊              .
   ]
 ]
@@ -410,10 +409,12 @@ scenario backspace-in-sandbox-editor-joins-lines [
   local-scope
   trace-until 100/app  # trace too long
   assume-screen 30/width, 5/height
+  assume-resources [
+  ]
   # initialize sandbox side with two lines
-  s:text <- new [abc
+  test-sandbox-editor-contents:text <- new [abc
 def]
-  env:&:environment <- new-programming-environment screen, [], s:text
+  env:&:environment <- new-programming-environment resources, screen, test-sandbox-editor-contents
   render-all screen, env, render
   screen-should-contain [
     .           run (F4)           .
@@ -428,7 +429,7 @@ def]
     press backspace
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
     cursor:char <- copy 9251/␣
     print screen, cursor
   ]
diff --git a/edit/005-sandbox.mu b/edit/005-sandbox.mu
index 0b1b82f1..7476875d 100644
--- a/edit/005-sandbox.mu
+++ b/edit/005-sandbox.mu
@@ -10,13 +10,10 @@
 def! main [
   local-scope
   open-console
-  initial-recipe:text <- restore [recipes.mu]
-  initial-sandbox:text <- new []
-  hide-screen 0/screen
-  env:&:environment <- new-programming-environment 0/screen, initial-recipe, initial-sandbox
+  env:&:environment <- new-programming-environment 0/filesystem, 0/screen
   env <- restore-sandboxes env
   render-all 0/screen, env, render
-  event-loop 0/screen, 0/console, env
+  event-loop 0/screen, 0/console, env, 0/filesystem
   # never gets here
 ]
 
@@ -46,14 +43,16 @@ scenario run-and-show-results [
   trace-until 100/app  # trace too long
   assume-screen 100/width, 15/height
   # recipe editor is empty
+  assume-resources [
+  ]
   # sandbox editor contains an instruction without storing outputs
-  env:&:environment <- new-programming-environment screen, [], [divide-with-remainder 11, 3]
+  env:&:environment <- new-programming-environment resources, screen, [divide-with-remainder 11, 3]
   # run the code in the editors
   assume-console [
     press F4
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # check that screen prints the results
   screen-should-contain [
@@ -103,7 +102,7 @@ scenario run-and-show-results [
     press F4
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # check that screen prints both sandboxes
   screen-should-contain [
@@ -129,7 +128,7 @@ after <global-keypress> [
     do-run?:bool <- equal k, 65532/F4
     break-unless do-run?
     screen <- update-status screen, [running...       ], 245/grey
-    error?:bool, env, screen <- run-sandboxes env, screen
+    error?:bool <- run-sandboxes env, resources, screen
     # F4 might update warnings and results on both sides
     screen <- render-all screen, env, render
     {
@@ -141,10 +140,10 @@ after <global-keypress> [
   }
 ]
 
-def run-sandboxes env:&:environment, screen:&:screen -> errors-found?:bool, env:&:environment, screen:&:screen [
+def run-sandboxes env:&:environment, resources:&:resources, screen:&:screen -> errors-found?:bool, env:&:environment, resources:&:resources, screen:&:screen [
   local-scope
   load-ingredients
-  errors-found?:bool, env, screen <- update-recipes env, screen
+  errors-found?:bool <- update-recipes env, resources, screen
   return-if errors-found?
   # check contents of right editor (sandbox)
   <run-sandboxes-begin>
@@ -170,7 +169,7 @@ def run-sandboxes env:&:environment, screen:&:screen -> errors-found?:bool, env:
     *current-sandbox <- put *current-sandbox, top-of-screen:offset, init
   }
   # save all sandboxes before running, just in case we die when running
-  save-sandboxes env
+  save-sandboxes env, resources
   # run all sandboxes
   curr:&:sandbox <- get *env, sandbox:offset
   idx:num <- copy 0
@@ -184,14 +183,14 @@ def run-sandboxes env:&:environment, screen:&:screen -> errors-found?:bool, env:
   <run-sandboxes-end>
 ]
 
-# copy code from recipe editor, persist to disk, load
+# load code from disk
 # replaced in a later layer (whereupon errors-found? will actually be set)
-def update-recipes env:&:environment, screen:&:screen -> errors-found?:bool, env:&:environment, screen:&:screen [
+def update-recipes env:&:environment, resources:&:resources, screen:&:screen -> errors-found?:bool, env:&:environment, resources:&:resources, screen:&:screen [
   local-scope
   load-ingredients
   recipes:&:editor <- get *env, recipes:offset
   in:text <- editor-contents recipes
-  save [recipes.mu], in  # newlayer: persistence
+  resources <- dump resources, [lesson/recipes.mu], in
   reload in
   errors-found? <- copy 0/false
 ]
@@ -213,7 +212,7 @@ def update-status screen:&:screen, msg:text, color:num -> screen:&:screen [
   screen <- print screen, msg, color, 238/grey/background
 ]
 
-def save-sandboxes env:&:environment [
+def save-sandboxes env:&:environment, resources:&:resources -> resources:&:resources [
   local-scope
   load-ingredients
   current-sandbox:&:editor <- get *env, current-sandbox:offset
@@ -224,8 +223,8 @@ def save-sandboxes env:&:environment [
   {
     break-unless curr
     data:text <- get *curr, data:offset
-    filename:text <- to-text idx
-    save filename, data
+    filename:text <- append [lesson/], idx
+    resources <- dump resources, filename, data
     <end-save-sandbox>
     idx <- add idx, 1
     curr <- get *curr, next-sandbox:offset
@@ -415,7 +414,7 @@ def render-text screen:&:screen, s:text, left:num, right:num, color:num, row:num
 ]
 
 # assumes programming environment has no sandboxes; restores them from previous session
-def restore-sandboxes env:&:environment -> env:&:environment [
+def restore-sandboxes env:&:environment, resources:&:resources -> env:&:environment [
   local-scope
   load-ingredients
   # read all scenarios, pushing them to end of a list of scenarios
@@ -423,8 +422,8 @@ def restore-sandboxes env:&:environment -> env:&:environment [
   curr:&:sandbox <- copy 0
   prev:&:sandbox <- copy 0
   {
-    filename:text <- to-text idx
-    contents:text <- restore filename
+    filename:text <- append [lesson/], idx
+    contents:text <- slurp resources, filename
     break-unless contents  # stop at first error; assuming file didn't exist
                            # todo: handle empty sandbox
     # create new sandbox for file
@@ -519,27 +518,32 @@ scenario run-updates-results [
   trace-until 100/app  # trace too long
   assume-screen 100/width, 12/height
   # define a recipe (no indent for the 'add' line below so column numbers are more obvious)
-  recipes:text <- new [ 
-recipe foo [
-local-scope
-z:num <- add 2, 2
-reply z
-]]
+  assume-resources [
+    [lesson/recipes.mu] <- [
+      ||
+      |recipe foo [|
+      |  local-scope|
+      |  z:num <- add 2, 2|
+      |  reply z|
+      |]|
+    ]
+  ]
   # sandbox editor contains an instruction without storing outputs
-  env:&:environment <- new-programming-environment screen, recipes, [foo]
+  env:&:environment <- new-programming-environment resources, screen, [foo]  # contents of sandbox editor
   # run the code in the editors
   assume-console [
     press F4
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   screen-should-contain [
     .                                                                                 run (F4)           .
     .                                                  ┊                                                 .
     .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .local-scope                                       ┊0   edit          copy            delete         .
-    .z:num <- add 2, 2                                 ┊foo                                              .
-    .reply z                                           ┊4                                                .
+    .  local-scope                                     ┊0   edit          copy            delete         .
+    .  z:num <- add 2, 2                               ┊foo                                              .
+    .  reply z                                         ┊4                                                .
     .]                                                 ┊─────────────────────────────────────────────────.
+    .                                                  ┊                                                 .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
     .                                                  ┊                                                 .
   ]
@@ -551,17 +555,18 @@ reply z
     press F4
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # check that screen updates the result on the right
   screen-should-contain [
     .                                                                                 run (F4)           .
     .                                                  ┊                                                 .
     .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .local-scope                                       ┊0   edit          copy            delete         .
-    .z:num <- add 2, 3                                 ┊foo                                              .
-    .reply z                                           ┊5                                                .
+    .  local-scope                                     ┊0   edit          copy            delete         .
+    .  z:num <- add 2, 3                               ┊foo                                              .
+    .  reply z                                         ┊5                                                .
     .]                                                 ┊─────────────────────────────────────────────────.
+    .                                                  ┊                                                 .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
     .                                                  ┊                                                 .
   ]
@@ -571,15 +576,17 @@ scenario run-instruction-manages-screen-per-sandbox [
   local-scope
   trace-until 100/app  # trace too long
   assume-screen 100/width, 20/height
-  # left editor is empty
-  # right editor contains an instruction
-  env:&:environment <- new-programming-environment screen, [], [print-integer screen, 4]
+  # empty recipes
+  assume-resources [
+  ]
+  # sandbox editor contains an instruction
+  env:&:environment <- new-programming-environment resources, screen, [print-integer screen, 4]  # contents of sandbox editor
   # run the code in the editor
   assume-console [
     press F4
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # check that it prints a little toy screen
   screen-should-contain [
@@ -642,13 +649,15 @@ scenario scrolling-down-past-bottom-of-recipe-editor [
   local-scope
   trace-until 100/app
   assume-screen 100/width, 10/height
-  env:&:environment <- new-programming-environment screen, [], []
+  assume-resources [
+  ]
+  env:&:environment <- new-programming-environment resources, screen, []
   render-all screen, env, render
   assume-console [
     press enter
     press down-arrow
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   # no scroll
   screen-should-contain [
     .                                                                                 run (F4)           .
@@ -663,14 +672,16 @@ scenario cursor-down-in-recipe-editor [
   local-scope
   trace-until 100/app
   assume-screen 100/width, 10/height
-  env:&:environment <- new-programming-environment screen, [], []
+  assume-resources [
+  ]
+  env:&:environment <- new-programming-environment resources, screen, []
   render-all screen, env, render
   assume-console [
     press enter
     press up-arrow
     press down-arrow  # while cursor isn't at bottom
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   cursor:char <- copy 9251/␣
   print screen, cursor
   # cursor moves back to bottom
@@ -741,7 +752,9 @@ scenario scrolling-down-past-bottom-of-recipe-editor-2 [
   local-scope
   trace-until 100/app
   assume-screen 100/width, 10/height
-  env:&:environment <- new-programming-environment screen, [], []
+  assume-resources [
+  ]
+  env:&:environment <- new-programming-environment resources, screen, []
   render-all screen, env, render
   assume-console [
     # add a line
@@ -751,7 +764,7 @@ scenario scrolling-down-past-bottom-of-recipe-editor-2 [
     # try to scroll
     press page-down  # or ctrl-f
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   # no scroll, and cursor remains at top line
   screen-should-contain [
     .                                                                                 run (F4)           .
@@ -766,7 +779,9 @@ scenario scrolling-down-past-bottom-of-recipe-editor-3 [
   local-scope
   trace-until 100/app
   assume-screen 100/width, 10/height
-  env:&:environment <- new-programming-environment screen, [], [ab
+  assume-resources [
+  ]
+  env:&:environment <- new-programming-environment resources, screen, [ab
 cd]
   render-all screen, env, render
   assume-console [
@@ -777,7 +792,7 @@ cd]
     # move cursor
     press down-arrow
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   cursor:char <- copy 9251/␣
   print screen, cursor
   # no scroll on recipe side, cursor moves on sandbox side
@@ -796,14 +811,16 @@ scenario scrolling-down-past-bottom-of-sandbox-editor [
   local-scope
   trace-until 100/app  # trace too long
   assume-screen 100/width, 10/height
-  # initialize sandbox side
-  env:&:environment <- new-programming-environment screen, [], [add 2, 2]
+  # initialize
+  assume-resources [
+  ]
+  env:&:environment <- new-programming-environment resources, screen, [add 2, 2]
   render-all screen, env, render
   assume-console [
     # create a sandbox
     press F4
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   screen-should-contain [
     .                                                                                 run (F4)           .
     .                                                  ┊                                                 .
@@ -817,7 +834,7 @@ scenario scrolling-down-past-bottom-of-sandbox-editor [
     press page-down
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
     cursor:char <- copy 9251/␣
     print screen, cursor
   ]
@@ -835,7 +852,7 @@ scenario scrolling-down-past-bottom-of-sandbox-editor [
     press page-up
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
     cursor:char <- copy 9251/␣
     print screen, cursor
   ]
@@ -924,30 +941,33 @@ def previous-sandbox env:&:environment, in:&:sandbox -> out:&:sandbox [
   return curr
 ]
 
-scenario scrolling-down-on-recipe-side [
+scenario scrolling-down-past-bottom-on-recipe-side [
   local-scope
   trace-until 100/app  # trace too long
   assume-screen 100/width, 10/height
   # initialize sandbox side and create a sandbox
-  recipes:text <- new [ 
-]
+  assume-resources [
+    [lesson/recipes.mu] <- [
+      ||  # file containing just a newline
+    ]
+  ]
   # create a sandbox
-  env:&:environment <- new-programming-environment screen, recipes:text, [add 2, 2]
+  env:&:environment <- new-programming-environment resources, screen, [add 2, 2]
   render-all screen, env, render
   assume-console [
     press F4
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   # hit 'down' in recipe editor
   assume-console [
     press page-down
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
     cursor:char <- copy 9251/␣
     print screen, cursor
   ]
-  # cursor moves down on recipe side
+  # cursor doesn't move when the end is already on-screen
   screen-should-contain [
     .                                                                                 run (F4)           .
     .␣                                                 ┊                                                 .
@@ -962,7 +982,9 @@ scenario scrolling-through-multiple-sandboxes [
   trace-until 100/app  # trace too long
   assume-screen 100/width, 10/height
   # initialize environment
-  env:&:environment <- new-programming-environment screen, [], []
+  assume-resources [
+  ]
+  env:&:environment <- new-programming-environment resources, screen, []
   render-all screen, env, render
   # create 2 sandboxes
   assume-console [
@@ -972,7 +994,7 @@ scenario scrolling-through-multiple-sandboxes [
     type [add 1, 1]
     press F4
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   cursor:char <- copy 9251/␣
   print screen, cursor
   screen-should-contain [
@@ -992,7 +1014,7 @@ scenario scrolling-through-multiple-sandboxes [
     press page-down
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
     cursor:char <- copy 9251/␣
     print screen, cursor
   ]
@@ -1014,7 +1036,7 @@ scenario scrolling-through-multiple-sandboxes [
     press page-down
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # just second sandbox displayed
   screen-should-contain [
@@ -1031,7 +1053,7 @@ scenario scrolling-through-multiple-sandboxes [
     press page-down
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # no change
   screen-should-contain [
@@ -1048,7 +1070,7 @@ scenario scrolling-through-multiple-sandboxes [
     press page-up
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # back to displaying both sandboxes without editor
   screen-should-contain [
@@ -1067,7 +1089,7 @@ scenario scrolling-through-multiple-sandboxes [
     press page-up
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
     cursor:char <- copy 9251/␣
     print screen, cursor
   ]
@@ -1089,7 +1111,7 @@ scenario scrolling-through-multiple-sandboxes [
     press page-up
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
     cursor:char <- copy 9251/␣
     print screen, cursor
   ]
@@ -1113,7 +1135,9 @@ scenario scrolling-manages-sandbox-index-correctly [
   trace-until 100/app  # trace too long
   assume-screen 100/width, 10/height
   # initialize environment
-  env:&:environment <- new-programming-environment screen, [], []
+  assume-resources [
+  ]
+  env:&:environment <- new-programming-environment resources, screen, []
   render-all screen, env, render
   # create a sandbox
   assume-console [
@@ -1121,7 +1145,7 @@ scenario scrolling-manages-sandbox-index-correctly [
     type [add 1, 1]
     press F4
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   screen-should-contain [
     .                                                                                 run (F4)           .
     .                                                  ┊                                                 .
@@ -1137,7 +1161,7 @@ scenario scrolling-manages-sandbox-index-correctly [
     press page-down
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # sandbox editor hidden; first sandbox displayed
   # cursor moves to first sandbox
@@ -1155,7 +1179,7 @@ scenario scrolling-manages-sandbox-index-correctly [
     press page-up
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # back to displaying both sandboxes as well as editor
   screen-should-contain [
@@ -1173,7 +1197,7 @@ scenario scrolling-manages-sandbox-index-correctly [
     press page-down
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # sandbox editor hidden; first sandbox displayed
   # cursor moves to first sandbox
diff --git a/edit/006-sandbox-copy.mu b/edit/006-sandbox-copy.mu
index c966ae78..9df5e625 100644
--- a/edit/006-sandbox-copy.mu
+++ b/edit/006-sandbox-copy.mu
@@ -5,24 +5,22 @@ scenario copy-a-sandbox-to-editor [
   local-scope
   trace-until 100/app  # trace too long
   assume-screen 100/width, 10/height
-  # basic recipe
-  recipes:text <- new [ 
-recipe foo [
-  reply 4
-]]
-  env:&:environment <- new-programming-environment screen, recipes, [foo]
+  # empty recipes
+  assume-resources [
+  ]
+  env:&:environment <- new-programming-environment resources, screen, [add 1, 1]  # contents of sandbox editor
   # run it
   assume-console [
     press F4
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   screen-should-contain [
     .                                                                                 run (F4)           .
     .                                                  ┊                                                 .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  reply 4                                         ┊0   edit          copy            delete         .
-    .]                                                 ┊foo                                              .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4                                                .
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────.
+    .                                                  ┊0   edit          copy            delete         .
+    .                                                  ┊add 1, 1                                         .
+    .                                                  ┊2                                                .
     .                                                  ┊─────────────────────────────────────────────────.
     .                                                  ┊                                                 .
   ]
@@ -31,16 +29,16 @@ recipe foo [
     left-click 3, 69
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # it copies into editor
   screen-should-contain [
     .                                                                                 run (F4)           .
-    .                                                  ┊foo                                              .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  reply 4                                         ┊0   edit          copy            delete         .
-    .]                                                 ┊foo                                              .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4                                                .
+    .                                                  ┊add 1, 1                                         .
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────.
+    .                                                  ┊0   edit          copy            delete         .
+    .                                                  ┊add 1, 1                                         .
+    .                                                  ┊2                                                .
     .                                                  ┊─────────────────────────────────────────────────.
     .                                                  ┊                                                 .
   ]
@@ -49,15 +47,15 @@ recipe foo [
     type [0]
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   screen-should-contain [
     .                                                                                 run (F4)           .
-    .                                                  ┊0foo                                             .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  reply 4                                         ┊0   edit          copy            delete         .
-    .]                                                 ┊foo                                              .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4                                                .
+    .                                                  ┊0add 1, 1                                        .
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────.
+    .                                                  ┊0   edit          copy            delete         .
+    .                                                  ┊add 1, 1                                         .
+    .                                                  ┊2                                                .
     .                                                  ┊─────────────────────────────────────────────────.
     .                                                  ┊                                                 .
   ]
@@ -67,24 +65,22 @@ scenario copy-a-sandbox-to-editor-2 [
   local-scope
   trace-until 100/app  # trace too long
   assume-screen 100/width, 10/height
-  # basic recipe
-  recipes:text <- new [ 
-recipe foo [
-  reply 4
-]]
-  env:&:environment <- new-programming-environment screen, recipes, [foo]
+  # empty recipes
+  assume-resources [
+  ]
+  env:&:environment <- new-programming-environment resources, screen, [add 1, 1]  # contents of sandbox editor
   # run it
   assume-console [
     press F4
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   screen-should-contain [
     .                                                                                 run (F4)           .
     .                                                  ┊                                                 .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  reply 4                                         ┊0   edit          copy            delete         .
-    .]                                                 ┊foo                                              .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4                                                .
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────.
+    .                                                  ┊0   edit          copy            delete         .
+    .                                                  ┊add 1, 1                                         .
+    .                                                  ┊2                                                .
     .                                                  ┊─────────────────────────────────────────────────.
     .                                                  ┊                                                 .
   ]
@@ -93,16 +89,16 @@ recipe foo [
     left-click 3, 84
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # it copies into editor
   screen-should-contain [
     .                                                                                 run (F4)           .
-    .                                                  ┊foo                                              .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  reply 4                                         ┊0   edit          copy            delete         .
-    .]                                                 ┊foo                                              .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4                                                .
+    .                                                  ┊add 1, 1                                         .
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────.
+    .                                                  ┊0   edit          copy            delete         .
+    .                                                  ┊add 1, 1                                         .
+    .                                                  ┊2                                                .
     .                                                  ┊─────────────────────────────────────────────────.
     .                                                  ┊                                                 .
   ]
@@ -111,15 +107,15 @@ recipe foo [
     type [0]
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   screen-should-contain [
     .                                                                                 run (F4)           .
-    .                                                  ┊0foo                                             .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  reply 4                                         ┊0   edit          copy            delete         .
-    .]                                                 ┊foo                                              .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4                                                .
+    .                                                  ┊0add 1, 1                                        .
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────.
+    .                                                  ┊0   edit          copy            delete         .
+    .                                                  ┊add 1, 1                                         .
+    .                                                  ┊2                                                .
     .                                                  ┊─────────────────────────────────────────────────.
     .                                                  ┊                                                 .
   ]
@@ -224,24 +220,22 @@ scenario copy-fails-if-sandbox-editor-not-empty [
   local-scope
   trace-until 100/app  # trace too long
   assume-screen 100/width, 10/height
-  # basic recipe
-  recipes:text <- new [ 
-recipe foo [
-  reply 4
-]]
-  env:&:environment <- new-programming-environment screen, recipes, [foo]
+  # empty recipes
+  assume-resources [
+  ]
+  env:&:environment <- new-programming-environment resources, screen, [add 1, 1]  # contents of sandbox editor
   # run it
   assume-console [
     press F4
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   screen-should-contain [
     .                                                                                 run (F4)           .
     .                                                  ┊                                                 .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  reply 4                                         ┊0   edit          copy            delete         .
-    .]                                                 ┊foo                                              .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4                                                .
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────.
+    .                                                  ┊0   edit          copy            delete         .
+    .                                                  ┊add 1, 1                                         .
+    .                                                  ┊2                                                .
     .                                                  ┊─────────────────────────────────────────────────.
     .                                                  ┊                                                 .
   ]
@@ -252,16 +246,16 @@ recipe foo [
     left-click 3, 70  # click 'copy' button
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # copy doesn't happen
   screen-should-contain [
     .                                                                                 run (F4)           .
     .                                                  ┊0                                                .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  reply 4                                         ┊0   edit          copy            delete         .
-    .]                                                 ┊foo                                              .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4                                                .
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────.
+    .                                                  ┊0   edit          copy            delete         .
+    .                                                  ┊add 1, 1                                         .
+    .                                                  ┊2                                                .
     .                                                  ┊─────────────────────────────────────────────────.
     .                                                  ┊                                                 .
   ]
@@ -270,15 +264,15 @@ recipe foo [
     type [1]
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   screen-should-contain [
     .                                                                                 run (F4)           .
     .                                                  ┊01                                               .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  reply 4                                         ┊0   edit          copy            delete         .
-    .]                                                 ┊foo                                              .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4                                                .
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────.
+    .                                                  ┊0   edit          copy            delete         .
+    .                                                  ┊add 1, 1                                         .
+    .                                                  ┊2                                                .
     .                                                  ┊─────────────────────────────────────────────────.
     .                                                  ┊                                                 .
   ]
diff --git a/edit/007-sandbox-delete.mu b/edit/007-sandbox-delete.mu
index 555d2859..4fa3c37d 100644
--- a/edit/007-sandbox-delete.mu
+++ b/edit/007-sandbox-delete.mu
@@ -4,7 +4,9 @@ scenario deleting-sandboxes [
   local-scope
   trace-until 100/app  # trace too long
   assume-screen 100/width, 15/height
-  env:&:environment <- new-programming-environment screen, [], []
+  assume-resources [
+  ]
+  env:&:environment <- new-programming-environment resources, screen, []
   # run a few commands
   assume-console [
     left-click 1, 80
@@ -13,7 +15,7 @@ scenario deleting-sandboxes [
     type [add 2, 2]
     press F4
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   screen-should-contain [
     .                                                                                 run (F4)           .
     .                                                  ┊                                                 .
@@ -34,7 +36,7 @@ scenario deleting-sandboxes [
     left-click 7, 85
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   screen-should-contain [
     .                                                                                 run (F4)           .
@@ -52,7 +54,7 @@ scenario deleting-sandboxes [
     left-click 3, 99
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   screen-should-contain [
     .                                                                                 run (F4)           .
@@ -151,7 +153,9 @@ scenario deleting-sandbox-after-scroll [
   trace-until 100/app  # trace too long
   assume-screen 100/width, 10/height
   # initialize environment
-  env:&:environment <- new-programming-environment screen, [], []
+  assume-resources [
+  ]
+  env:&:environment <- new-programming-environment resources, screen, []
   render-all screen, env, render
   # create 2 sandboxes and scroll to second
   assume-console [
@@ -162,7 +166,7 @@ scenario deleting-sandbox-after-scroll [
     press F4
     press page-down
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   screen-should-contain [
     .                                                                                 run (F4)           .
     .                                                  ┊─────────────────────────────────────────────────.
@@ -177,7 +181,7 @@ scenario deleting-sandbox-after-scroll [
     left-click 6, 99
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # second sandbox shows in editor; scroll resets to display first sandbox
   screen-should-contain [
@@ -196,7 +200,9 @@ scenario deleting-top-sandbox-after-scroll [
   trace-until 100/app  # trace too long
   assume-screen 100/width, 10/height
   # initialize environment
-  env:&:environment <- new-programming-environment screen, [], []
+  assume-resources [
+  ]
+  env:&:environment <- new-programming-environment resources, screen, []
   render-all screen, env, render
   # create 2 sandboxes and scroll to second
   assume-console [
@@ -207,7 +213,7 @@ scenario deleting-top-sandbox-after-scroll [
     press F4
     press page-down
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   screen-should-contain [
     .                                                                                 run (F4)           .
     .                                                  ┊─────────────────────────────────────────────────.
@@ -222,7 +228,7 @@ scenario deleting-top-sandbox-after-scroll [
     left-click 2, 99
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # second sandbox shows in editor; scroll resets to display first sandbox
   screen-should-contain [
@@ -241,7 +247,9 @@ scenario deleting-final-sandbox-after-scroll [
   trace-until 100/app  # trace too long
   assume-screen 100/width, 10/height
   # initialize environment
-  env:&:environment <- new-programming-environment screen, [], []
+  assume-resources [
+  ]
+  env:&:environment <- new-programming-environment resources, screen, []
   render-all screen, env, render
   # create 2 sandboxes and scroll to second
   assume-console [
@@ -253,7 +261,7 @@ scenario deleting-final-sandbox-after-scroll [
     press page-down
     press page-down
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   screen-should-contain [
     .                                                                                 run (F4)           .
     .                                                  ┊─────────────────────────────────────────────────.
@@ -268,7 +276,7 @@ scenario deleting-final-sandbox-after-scroll [
     left-click 2, 99
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # implicitly scroll up to first sandbox
   screen-should-contain [
@@ -288,7 +296,9 @@ scenario deleting-updates-sandbox-count [
   trace-until 100/app  # trace too long
   assume-screen 100/width, 10/height
   # initialize environment
-  env:&:environment <- new-programming-environment screen, [], []
+  assume-resources [
+  ]
+  env:&:environment <- new-programming-environment resources, screen, []
   render-all screen, env, render
   # create 2 sandboxes
   assume-console [
@@ -298,7 +308,7 @@ scenario deleting-updates-sandbox-count [
     type [add 1, 1]
     press F4
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   screen-should-contain [
     .                                                                                 run (F4)           .
     .                                                  ┊                                                 .
@@ -318,7 +328,7 @@ scenario deleting-updates-sandbox-count [
     press page-down
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # shouldn't go past last sandbox
   screen-should-contain [
diff --git a/edit/008-sandbox-edit.mu b/edit/008-sandbox-edit.mu
index dcd0967d..a857e88c 100644
--- a/edit/008-sandbox-edit.mu
+++ b/edit/008-sandbox-edit.mu
@@ -1,27 +1,25 @@
 ## editing sandboxes after they've been created
 
-scenario clicking-on-a-sandbox-moves-it-to-editor [
+scenario clicking-on-sandbox-edit-button-moves-it-to-editor [
   local-scope
   trace-until 100/app  # trace too long
   assume-screen 100/width, 10/height
-  # basic recipe
-  recipes:text <- new [ 
-recipe foo [
-  reply 4
-]]
-  env:&:environment <- new-programming-environment screen, recipes, [foo]
+  # empty recipes
+  assume-resources [
+  ]
+  env:&:environment <- new-programming-environment resources, screen, [add 2, 2]
   # run it
   assume-console [
     press F4
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   screen-should-contain [
     .                                                                                 run (F4)           .
     .                                                  ┊                                                 .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  reply 4                                         ┊0   edit          copy            delete         .
-    .]                                                 ┊foo                                              .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4                                                .
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────.
+    .                                                  ┊0   edit          copy            delete         .
+    .                                                  ┊add 2, 2                                         .
+    .                                                  ┊4                                                .
     .                                                  ┊─────────────────────────────────────────────────.
     .                                                  ┊                                                 .
   ]
@@ -30,16 +28,13 @@ recipe foo [
     left-click 3, 55
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # it pops back into editor
   screen-should-contain [
     .                                                                                 run (F4)           .
-    .                                                  ┊foo                                              .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  reply 4                                         ┊                                                 .
-    .]                                                 ┊                                                 .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
+    .                                                  ┊add 2, 2                                         .
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────.
     .                                                  ┊                                                 .
   ]
   # cursor should be in the right place
@@ -47,41 +42,36 @@ recipe foo [
     type [0]
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   screen-should-contain [
     .                                                                                 run (F4)           .
-    .                                                  ┊0foo                                             .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  reply 4                                         ┊                                                 .
-    .]                                                 ┊                                                 .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
+    .                                                  ┊0add 2, 2                                        .
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────.
     .                                                  ┊                                                 .
   ]
 ]
 
-scenario clicking-on-a-sandbox-moves-it-to-editor-2 [
+scenario clicking-on-sandbox-edit-button-moves-it-to-editor-2 [
   local-scope
   trace-until 100/app  # trace too long
   assume-screen 100/width, 10/height
-  # basic recipe
-  recipes:text <- new [ 
-recipe foo [
-  reply 4
-]]
-  env:&:environment <- new-programming-environment screen, recipes, [foo]
+  # empty recipes
+  assume-resources [
+  ]
+  env:&:environment <- new-programming-environment resources, screen, [add 2, 2]
   # run it
   assume-console [
     press F4
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   screen-should-contain [
     .                                                                                 run (F4)           .
     .                                                  ┊                                                 .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  reply 4                                         ┊0   edit          copy            delete         .
-    .]                                                 ┊foo                                              .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4                                                .
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────.
+    .                                                  ┊0   edit          copy            delete         .
+    .                                                  ┊add 2, 2                                         .
+    .                                                  ┊4                                                .
     .                                                  ┊─────────────────────────────────────────────────.
     .                                                  ┊                                                 .
   ]
@@ -90,16 +80,13 @@ recipe foo [
     left-click 3, 68
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # it pops back into editor
   screen-should-contain [
     .                                                                                 run (F4)           .
-    .                                                  ┊foo                                              .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  reply 4                                         ┊                                                 .
-    .]                                                 ┊                                                 .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
+    .                                                  ┊add 2, 2                                         .
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────.
     .                                                  ┊                                                 .
   ]
   # cursor should be in the right place
@@ -107,15 +94,12 @@ recipe foo [
     type [0]
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   screen-should-contain [
     .                                                                                 run (F4)           .
-    .                                                  ┊0foo                                             .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  reply 4                                         ┊                                                 .
-    .]                                                 ┊                                                 .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
+    .                                                  ┊0add 2, 2                                        .
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────.
     .                                                  ┊                                                 .
   ]
 ]
@@ -178,13 +162,15 @@ scenario sandbox-with-print-can-be-edited [
   trace-until 100/app  # trace too long
   assume-screen 100/width, 20/height
   # left editor is empty
-  # right editor contains an instruction
-  env:&:environment <- new-programming-environment screen, [], [print-integer screen, 4]
+  assume-resources [
+  ]
+  # right editor contains a print instruction
+  env:&:environment <- new-programming-environment resources, screen, [print-integer screen, 4]
   # run the sandbox
   assume-console [
     press F4
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   screen-should-contain [
     .                                                                                 run (F4)           .
     .                                                  ┊                                                 .
@@ -205,7 +191,7 @@ scenario sandbox-with-print-can-be-edited [
     left-click 3, 65
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   screen-should-contain [
     .                                                                                 run (F4)           .
@@ -221,7 +207,9 @@ scenario editing-sandbox-after-scrolling-resets-scroll [
   trace-until 100/app  # trace too long
   assume-screen 100/width, 10/height
   # initialize environment
-  env:&:environment <- new-programming-environment screen, [], []
+  assume-resources [
+  ]
+  env:&:environment <- new-programming-environment resources, screen, []
   render-all screen, env, render
   # create 2 sandboxes and scroll to second
   assume-console [
@@ -233,7 +221,7 @@ scenario editing-sandbox-after-scrolling-resets-scroll [
     press page-down
     press page-down
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   screen-should-contain [
     .                                                                                 run (F4)           .
     .                                                  ┊─────────────────────────────────────────────────.
@@ -248,7 +236,7 @@ scenario editing-sandbox-after-scrolling-resets-scroll [
     left-click 2, 55
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # second sandbox shows in editor; scroll resets to display first sandbox
   screen-should-contain [
@@ -268,7 +256,9 @@ scenario editing-sandbox-updates-sandbox-count [
   trace-until 100/app  # trace too long
   assume-screen 100/width, 10/height
   # initialize environment
-  env:&:environment <- new-programming-environment screen, [], []
+  assume-resources [
+  ]
+  env:&:environment <- new-programming-environment resources, screen, []
   render-all screen, env, render
   # create 2 sandboxes
   assume-console [
@@ -278,7 +268,7 @@ scenario editing-sandbox-updates-sandbox-count [
     type [add 1, 1]
     press F4
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   screen-should-contain [
     .                                                                                 run (F4)           .
     .                                                  ┊                                                 .
@@ -297,7 +287,7 @@ scenario editing-sandbox-updates-sandbox-count [
     press F4
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # no change in contents
   screen-should-contain [
@@ -319,7 +309,7 @@ scenario editing-sandbox-updates-sandbox-count [
     press page-down
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # screen should show just final sandbox with the right index (1)
   screen-should-contain [
diff --git a/edit/009-sandbox-test.mu b/edit/009-sandbox-test.mu
index fe9ef059..39b58ecb 100644
--- a/edit/009-sandbox-test.mu
+++ b/edit/009-sandbox-test.mu
@@ -5,22 +5,25 @@ scenario sandbox-click-on-result-toggles-color-to-green [
   trace-until 100/app  # trace too long
   assume-screen 100/width, 10/height
   # basic recipe
-  recipes:text <- new [ 
-recipe foo [
-  reply 4
-]]
-  env:&:environment <- new-programming-environment screen, recipes:text, [foo]
+  assume-resources [
+    [lesson/recipes.mu] <- [
+      |recipe foo [|
+      |  reply 4|
+      |]|
+    ]
+  ]
+  env:&:environment <- new-programming-environment resources, screen, [foo]
   # run it
   assume-console [
     press F4
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   screen-should-contain [
     .                                                                                 run (F4)           .
-    .                                                  ┊                                                 .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  reply 4                                         ┊0   edit          copy            delete         .
-    .]                                                 ┊foo                                              .
+    .recipe foo [                                      ┊                                                 .
+    .  reply 4                                         ┊─────────────────────────────────────────────────.
+    .]                                                 ┊0   edit          copy            delete         .
+    .                                                  ┊foo                                              .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4                                                .
     .                                                  ┊─────────────────────────────────────────────────.
     .                                                  ┊                                                 .
@@ -30,7 +33,7 @@ recipe foo [
     left-click 5, 51
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # color toggles to green
   screen-should-contain-in-color 2/green, [
@@ -50,26 +53,24 @@ recipe foo [
   ]
   screen-should-contain [
     .                                                                                 run (F4)           .
-    .␣                                                 ┊                                                 .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  reply 4                                         ┊0   edit          copy            delete         .
-    .]                                                 ┊foo                                              .
+    .␣ecipe foo [                                      ┊                                                 .
+    .  reply 4                                         ┊─────────────────────────────────────────────────.
+    .]                                                 ┊0   edit          copy            delete         .
+    .                                                  ┊foo                                              .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4                                                .
     .                                                  ┊─────────────────────────────────────────────────.
     .                                                  ┊                                                 .
-    .                                                  ┊                                                 .
-    .                                                  ┊                                                 .
   ]
   # now change the result
   # then rerun
   assume-console [
-    left-click 3, 11  # cursor to end of line
+    left-click 2, 11  # cursor to end of line
     press backspace
     type [3]
     press F4
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # result turns red
   screen-should-contain-in-color 1/red, [
@@ -96,14 +97,14 @@ before <end-save-sandbox> [
     expected-response:text <- get *curr, expected-response:offset
     break-unless expected-response
     filename <- append filename, [.out]
-    save filename, expected-response
+    resources <- dump resources, filename, expected-response
   }
 ]
 
 before <end-restore-sandbox> [
   {
     filename <- append filename, [.out]
-    contents <- restore filename
+    contents <- slurp resources, filename
     break-unless contents
     *curr <- put *curr, expected-response:offset, contents
   }
@@ -128,7 +129,7 @@ after <global-touch> [
     break-unless sandbox
     # toggle its expected-response, and save session
     sandbox <- toggle-expected-response sandbox
-    save-sandboxes env
+    save-sandboxes env, resources
     hide-screen screen
     screen <- render-sandbox-side screen, env, render
     screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env
diff --git a/edit/010-sandbox-trace.mu b/edit/010-sandbox-trace.mu
index 90ee417e..65337127 100644
--- a/edit/010-sandbox-trace.mu
+++ b/edit/010-sandbox-trace.mu
@@ -5,22 +5,25 @@ scenario sandbox-click-on-code-toggles-app-trace [
   trace-until 100/app  # trace too long
   assume-screen 100/width, 10/height
   # basic recipe
-  recipes:text <- new [ 
-recipe foo [
-  stash [abc]
-]]
-  env:&:environment <- new-programming-environment screen, recipes, [foo]
+  assume-resources [
+    [lesson/recipes.mu] <- [
+      |recipe foo [|
+      |  stash [abc]|
+      |]|
+    ]
+  ]
+  env:&:environment <- new-programming-environment resources, screen, [foo]
   # run it
   assume-console [
     press F4
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   screen-should-contain [
     .                                                                                 run (F4)           .
-    .                                                  ┊                                                 .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  stash [abc]                                     ┊0   edit          copy            delete         .
-    .]                                                 ┊foo                                              .
+    .recipe foo [                                      ┊                                                 .
+    .  stash [abc]                                     ┊─────────────────────────────────────────────────.
+    .]                                                 ┊0   edit          copy            delete         .
+    .                                                  ┊foo                                              .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────.
     .                                                  ┊                                                 .
   ]
@@ -29,17 +32,17 @@ recipe foo [
     left-click 4, 51
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
     cursor:char <- copy 9251/␣
     print screen, cursor
   ]
   # trace now printed and cursor shouldn't have budged
   screen-should-contain [
     .                                                                                 run (F4)           .
-    .␣                                                 ┊                                                 .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  stash [abc]                                     ┊0   edit          copy            delete         .
-    .]                                                 ┊foo                                              .
+    .␣ecipe foo [                                      ┊                                                 .
+    .  stash [abc]                                     ┊─────────────────────────────────────────────────.
+    .]                                                 ┊0   edit          copy            delete         .
+    .                                                  ┊foo                                              .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊abc                                              .
   ]
   screen-should-contain-in-color 245/grey, [
@@ -55,16 +58,16 @@ recipe foo [
     left-click 4, 55
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
     print screen, cursor
   ]
   # trace hidden again
   screen-should-contain [
     .                                                                                 run (F4)           .
-    .␣                                                 ┊                                                 .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  stash [abc]                                     ┊0   edit          copy            delete         .
-    .]                                                 ┊foo                                              .
+    .␣ecipe foo [                                      ┊                                                 .
+    .  stash [abc]                                     ┊─────────────────────────────────────────────────.
+    .]                                                 ┊0   edit          copy            delete         .
+    .                                                  ┊foo                                              .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────.
     .                                                  ┊                                                 .
   ]
@@ -75,24 +78,27 @@ scenario sandbox-shows-app-trace-and-result [
   trace-until 100/app  # trace too long
   assume-screen 100/width, 10/height
   # basic recipe
-  recipes:text <- new [ 
-recipe foo [
-  stash [abc]
-  reply 4
-]]
-  env:&:environment <- new-programming-environment screen, recipes, [foo]
+  assume-resources [
+    [lesson/recipes.mu] <- [
+      |recipe foo [|
+      |  stash [abc]|
+      |  reply 4|
+      |]|
+    ]
+  ]
+  env:&:environment <- new-programming-environment resources, screen, [foo]
   # run it
   assume-console [
     press F4
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   screen-should-contain [
     .                                                                                 run (F4)           .
-    .                                                  ┊                                                 .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  stash [abc]                                     ┊0   edit          copy            delete         .
-    .  reply 4                                         ┊foo                                              .
-    .]                                                 ┊4                                                .
+    .recipe foo [                                      ┊                                                 .
+    .  stash [abc]                                     ┊─────────────────────────────────────────────────.
+    .  reply 4                                         ┊0   edit          copy            delete         .
+    .]                                                 ┊foo                                              .
+    .                                                  ┊4                                                .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────.
     .                                                  ┊                                                 .
   ]
@@ -101,16 +107,16 @@ recipe foo [
     left-click 4, 51
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # trace now printed above result
   screen-should-contain [
     .                                                                                 run (F4)           .
-    .                                                  ┊                                                 .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  stash [abc]                                     ┊0   edit          copy            delete         .
-    .  reply 4                                         ┊foo                                              .
-    .]                                                 ┊abc                                              .
+    .recipe foo [                                      ┊                                                 .
+    .  stash [abc]                                     ┊─────────────────────────────────────────────────.
+    .  reply 4                                         ┊0   edit          copy            delete         .
+    .]                                                 ┊foo                                              .
+    .                                                  ┊abc                                              .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊8 instructions run                               .
     .                                                  ┊4                                                .
     .                                                  ┊─────────────────────────────────────────────────.
@@ -122,13 +128,15 @@ scenario clicking-on-app-trace-does-nothing [
   local-scope
   trace-until 100/app  # trace too long
   assume-screen 100/width, 10/height
-  env:&:environment <- new-programming-environment screen, [], [stash 123456789]
+  assume-resources [
+  ]
+  env:&:environment <- new-programming-environment resources, screen, [stash 123456789]
   # create and expand the trace
   assume-console [
     press F4
     left-click 4, 51
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   screen-should-contain [
     .                                                                                 run (F4)           .
     .                                                  ┊                                                 .
@@ -142,7 +150,7 @@ scenario clicking-on-app-trace-does-nothing [
     left-click 5, 57
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # no change; doesn't die
   screen-should-contain [
diff --git a/edit/011-errors.mu b/edit/011-errors.mu
index b48cd5fa..ad4d8836 100644
--- a/edit/011-errors.mu
+++ b/edit/011-errors.mu
@@ -5,12 +5,12 @@ container environment [
 ]
 
 # copy code from recipe editor, persist to disk, load, save any errors
-def! update-recipes env:&:environment, screen:&:screen -> errors-found?:bool, env:&:environment, screen:&:screen [
+def! update-recipes env:&:environment, resources:&:resources, screen:&:screen -> errors-found?:bool, env:&:environment, resources:&:resources, screen:&:screen [
   local-scope
   load-ingredients
   recipes:&:editor <- get *env, recipes:offset
   in:text <- editor-contents recipes
-  save [recipes.mu], in
+  resources <- dump resources, [lesson/recipes.mu], in
   recipe-errors:text <- reload in
   *env <- put *env, recipe-errors:offset, recipe-errors
   # if recipe editor has errors, stop
@@ -118,23 +118,36 @@ scenario run-shows-errors-in-get [
   local-scope
   trace-until 100/app  # trace too long
   assume-screen 100/width, 15/height
-  recipes:text <- new [ 
-recipe foo [
-  get 123:num, foo:offset
-]]
-  env:&:environment <- new-programming-environment screen, recipes, [foo]
+  assume-resources [
+    [lesson/recipes.mu] <- [
+      |recipe foo [|
+      |  get 123:num, foo:offset|
+      |]|
+    ]
+  ]
+  env:&:environment <- new-programming-environment resources, screen, [foo]
+  render-all screen, env, render
+  screen-should-contain [
+    .                                                                                 run (F4)           .
+    .recipe foo [                                      ┊foo                                              .
+    .  get 123:num, foo:offset                         ┊─────────────────────────────────────────────────.
+    .]                                                 ┊                                                 .
+    .                                                  ┊                                                 .
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
+    .                                                  ┊                                                 .
+  ]
   assume-console [
     press F4
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   screen-should-contain [
     .  errors found                                                                   run (F4)           .
-    .                                                  ┊foo                                              .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  get 123:num, foo:offset                         ┊                                                 .
+    .recipe foo [                                      ┊foo                                              .
+    .  get 123:num, foo:offset                         ┊─────────────────────────────────────────────────.
     .]                                                 ┊                                                 .
+    .                                                  ┊                                                 .
     .foo: unknown element 'foo' in container 'number'  ┊                                                 .
     .foo: first ingredient of 'get' should be a contai↩┊                                                 .
     .ner, but got '123:num'                            ┊                                                 .
@@ -158,7 +171,9 @@ scenario run-updates-status-with-first-erroneous-sandbox [
   local-scope
   trace-until 100/app  # trace too long
   assume-screen 100/width, 15/height
-  env:&:environment <- new-programming-environment screen, [], []
+  assume-resources [
+  ]
+  env:&:environment <- new-programming-environment resources, screen, []
   assume-console [
     left-click 3, 80
     # create invalid sandbox 1
@@ -169,7 +184,7 @@ scenario run-updates-status-with-first-erroneous-sandbox [
     press F4
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # status line shows that error is in first sandbox
   screen-should-contain [
@@ -181,7 +196,9 @@ scenario run-updates-status-with-first-erroneous-sandbox-2 [
   local-scope
   trace-until 100/app  # trace too long
   assume-screen 100/width, 15/height
-  env:&:environment <- new-programming-environment screen, [], []
+  assume-resources [
+  ]
+  env:&:environment <- new-programming-environment resources, screen, []
   assume-console [
     left-click 3, 80
     # create invalid sandbox 2
@@ -195,7 +212,7 @@ scenario run-updates-status-with-first-erroneous-sandbox-2 [
     press F4
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # status line shows that error is in second sandbox
   screen-should-contain [
@@ -207,13 +224,13 @@ scenario run-hides-errors-from-past-sandboxes [
   local-scope
   trace-until 100/app  # trace too long
   assume-screen 100/width, 15/height
-  env:&:environment <- new-programming-environment screen, [], [get foo, x:offset]  # invalid
+  assume-resources [
+  ]
+  env:&:environment <- new-programming-environment resources, screen, [get foo, x:offset]  # invalid
   assume-console [
     press F4  # generate error
   ]
-  run [
-    event-loop screen, console, env
-  ]
+  event-loop screen, console, env, resources
   assume-console [
     left-click 3, 58
     press ctrl-k
@@ -221,7 +238,7 @@ scenario run-hides-errors-from-past-sandboxes [
     press F4  # update sandbox
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # error should disappear
   screen-should-contain [
@@ -241,26 +258,31 @@ scenario run-updates-errors-for-shape-shifting-recipes [
   trace-until 100/app  # trace too long
   assume-screen 100/width, 15/height
   # define a shape-shifting recipe with an error
-  recipes:text <- new [recipe foo x:_elem -> z:_elem [
-local-scope
-load-ingredients
-y:&:num <- copy 0
-z <- add x, y
-]]
-  env:&:environment <- new-programming-environment screen, recipes, [foo 2]
+  assume-resources [
+    [lesson/recipes.mu] <- [
+      |recipe foo x:_elem -> z:_elem [|
+      |  local-scope|
+      |  load-ingredients|
+      |  y:&:num <- copy 0|
+      |  z <- add x, y|
+      |]|
+    ]
+  ]
+  env:&:environment <- new-programming-environment resources, screen, [foo 2]
   assume-console [
     press F4
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   screen-should-contain [
     .  errors found (0)                                                               run (F4)           .
     .recipe foo x:_elem -> z:_elem [                   ┊                                                 .
-    .local-scope                                       ┊─────────────────────────────────────────────────.
-    .load-ingredients                                  ┊0   edit          copy            delete         .
-    .y:&:num <- copy 0                                 ┊foo 2                                            .
-    .z <- add x, y                                     ┊foo_2: 'add' requires number ingredients, but go↩.
+    .  local-scope                                     ┊─────────────────────────────────────────────────.
+    .  load-ingredients                                ┊0   edit          copy            delete         .
+    .  y:&:num <- copy 0                               ┊foo 2                                            .
+    .  z <- add x, y                                   ┊foo_2: 'add' requires number ingredients, but go↩.
     .]                                                 ┊t 'y'                                            .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────.
+    .                                                  ┊─────────────────────────────────────────────────.
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
     .                                                  ┊                                                 .
   ]
   # now rerun everything
@@ -268,18 +290,19 @@ z <- add x, y
     press F4
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # error should remain unchanged
   screen-should-contain [
     .  errors found (0)                                                               run (F4)           .
     .recipe foo x:_elem -> z:_elem [                   ┊                                                 .
-    .local-scope                                       ┊─────────────────────────────────────────────────.
-    .load-ingredients                                  ┊0   edit          copy            delete         .
-    .y:&:num <- copy 0                                 ┊foo 2                                            .
-    .z <- add x, y                                     ┊foo_3: 'add' requires number ingredients, but go↩.
+    .  local-scope                                     ┊─────────────────────────────────────────────────.
+    .  load-ingredients                                ┊0   edit          copy            delete         .
+    .  y:&:num <- copy 0                               ┊foo 2                                            .
+    .  z <- add x, y                                   ┊foo_3: 'add' requires number ingredients, but go↩.
     .]                                                 ┊t 'y'                                            .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────.
+    .                                                  ┊─────────────────────────────────────────────────.
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
     .                                                  ┊                                                 .
   ]
 ]
@@ -289,17 +312,21 @@ scenario run-avoids-spurious-errors-on-reloading-shape-shifting-recipes [
   trace-until 100/app  # trace too long
   assume-screen 100/width, 15/height
   # overload a well-known shape-shifting recipe
-  recipes:text <- new [recipe length l:&:list:_elem -> n:num [
-]]
+  assume-resources [
+    [lesson/recipes.mu] <- [
+      |recipe length l:&:list:_elem -> n:num [|
+      |]|
+    ]
+  ]
   # call code that uses other variants of it, but not it itself
-  sandbox:text <- new [x:&:list:num <- copy 0
+  test-sandbox:text <- new [x:&:list:num <- copy 0
 to-text x]
-  env:&:environment <- new-programming-environment screen, recipes, sandbox
+  env:&:environment <- new-programming-environment resources, screen, test-sandbox
   # run it once
   assume-console [
     press F4
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   # no errors anywhere on screen (can't check anything else, since to-text will return an address)
   screen-should-contain-in-color 1/red, [
     .                                                                                                    .
@@ -323,7 +350,7 @@ to-text x]
     press F4
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # still no errors
   screen-should-contain-in-color 1/red, [
@@ -349,24 +376,30 @@ scenario run-shows-missing-type-errors [
   local-scope
   trace-until 100/app  # trace too long
   assume-screen 100/width, 15/height
-  recipes:text <- new [ 
-recipe foo [
-  x <- copy 0
-]]
-  env:&:environment <- new-programming-environment screen, recipes, [foo]
+  assume-resources [
+    [lesson/recipes.mu] <- [
+      |recipe foo [|
+      |  x <- copy 0|
+      |]|
+    ]
+  ]
+  env:&:environment <- new-programming-environment resources, screen, [foo]
   assume-console [
     press F4
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   screen-should-contain [
     .  errors found                                                                   run (F4)           .
-    .                                                  ┊foo                                              .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  x <- copy 0                                     ┊                                                 .
+    .recipe foo [                                      ┊foo                                              .
+    .  x <- copy 0                                     ┊─────────────────────────────────────────────────.
     .]                                                 ┊                                                 .
+    .                                                  ┊                                                 .
     .foo: missing type for 'x' in 'x <- copy 0'        ┊                                                 .
+    .foo: can't copy '0' to 'x'; types don't match     ┊                                                 .
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
+    .                                                  ┊                                                 .
   ]
 ]
 
@@ -375,22 +408,23 @@ scenario run-shows-unbalanced-bracket-errors [
   trace-until 100/app  # trace too long
   assume-screen 100/width, 15/height
   # recipe is incomplete (unbalanced '[')
-  recipes:text <- new [ 
-recipe foo \\[
-  x <- copy 0
-]
-  env:&:environment <- new-programming-environment screen, recipes, [foo]
+  assume-resources [
+    [lesson/recipes.mu] <- [
+      |recipe foo \\\[|
+      |  x <- copy 0|
+    ]
+  ]
+  env:&:environment <- new-programming-environment resources, screen, [foo]
   assume-console [
     press F4
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   screen-should-contain [
     .  errors found                                                                   run (F4)           .
-    .                                                  ┊foo                                              .
-    .recipe foo \\[                                      ┊─────────────────────────────────────────────────.
-    .  x <- copy 0                                     ┊                                                 .
+    .recipe foo \\[                                      ┊foo                                              .
+    .  x <- copy 0                                     ┊─────────────────────────────────────────────────.
     .                                                  ┊                                                 .
     .9: unbalanced '\\[' for recipe                      ┊                                                 .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
@@ -402,27 +436,30 @@ scenario run-shows-get-on-non-container-errors [
   local-scope
   trace-until 100/app  # trace too long
   assume-screen 100/width, 15/height
-  recipes:text <- new [ 
-recipe foo [
-  local-scope
-  x:&:point <- new point:type
-  get x:&:point, 1:offset
-]]
-  env:&:environment <- new-programming-environment screen, recipes, [foo]
+  assume-resources [
+    [lesson/recipes.mu] <- [
+      |recipe foo [|
+      |  local-scope|
+      |  x:&:point <- new point:type|
+      |  get x:&:point, 1:offset|
+      |]|
+    ]
+  ]
+  env:&:environment <- new-programming-environment resources, screen, [foo]
   assume-console [
     press F4
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   screen-should-contain [
     .  errors found                                                                   run (F4)           .
-    .                                                  ┊foo                                              .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  local-scope                                     ┊                                                 .
+    .recipe foo [                                      ┊foo                                              .
+    .  local-scope                                     ┊─────────────────────────────────────────────────.
     .  x:&:point <- new point:type                     ┊                                                 .
     .  get x:&:point, 1:offset                         ┊                                                 .
     .]                                                 ┊                                                 .
+    .                                                  ┊                                                 .
     .foo: first ingredient of 'get' should be a contai↩┊                                                 .
     .ner, but got 'x:&:point'                          ┊                                                 .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
@@ -434,29 +471,32 @@ scenario run-shows-non-literal-get-argument-errors [
   local-scope
   trace-until 100/app  # trace too long
   assume-screen 100/width, 15/height
-  recipes:text <- new [ 
-recipe foo [
-  local-scope
-  x:num <- copy 0
-  y:&:point <- new point:type
-  get *y:&:point, x:num
-]]
-  env:&:environment <- new-programming-environment screen, recipes, [foo]
+  assume-resources [
+    [lesson/recipes.mu] <- [
+      |recipe foo [|
+      |  local-scope|
+      |  x:num <- copy 0|
+      |  y:&:point <- new point:type|
+      |  get *y:&:point, x:num|
+      |]|
+    ]
+  ]
+  env:&:environment <- new-programming-environment resources, screen, [foo]
   assume-console [
     press F4
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   screen-should-contain [
     .  errors found                                                                   run (F4)           .
-    .                                                  ┊foo                                              .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  local-scope                                     ┊                                                 .
+    .recipe foo [                                      ┊foo                                              .
+    .  local-scope                                     ┊─────────────────────────────────────────────────.
     .  x:num <- copy 0                                 ┊                                                 .
     .  y:&:point <- new point:type                     ┊                                                 .
     .  get *y:&:point, x:num                           ┊                                                 .
     .]                                                 ┊                                                 .
+    .                                                  ┊                                                 .
     .foo: second ingredient of 'get' should have type ↩┊                                                 .
     .'offset', but got 'x:num'                         ┊                                                 .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
@@ -467,25 +507,28 @@ recipe foo [
 scenario run-shows-errors-everytime [
   local-scope
   trace-until 100/app  # trace too long
-  # try to run a file with an error
   assume-screen 100/width, 15/height
-  recipes:text <- new [ 
-recipe foo [
-  local-scope
-  x:num <- copy y:num
-]]
-  env:&:environment <- new-programming-environment screen, recipes, [foo]
+  # try to run a file with an error
+  assume-resources [
+    [lesson/recipes.mu] <- [
+      |recipe foo [|
+      |  local-scope|
+      |  x:num <- copy y:num|
+      |]|
+    ]
+  ]
+  env:&:environment <- new-programming-environment resources, screen, [foo]
   assume-console [
     press F4
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   screen-should-contain [
     .  errors found                                                                   run (F4)           .
-    .                                                  ┊foo                                              .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  local-scope                                     ┊                                                 .
+    .recipe foo [                                      ┊foo                                              .
+    .  local-scope                                     ┊─────────────────────────────────────────────────.
     .  x:num <- copy y:num                             ┊                                                 .
     .]                                                 ┊                                                 .
+    .                                                  ┊                                                 .
     .foo: tried to read ingredient 'y' in 'x:num <- co↩┊                                                 .
     .py y:num' but it hasn't been written to yet       ┊                                                 .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
@@ -496,15 +539,15 @@ recipe foo [
     press F4
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   screen-should-contain [
     .  errors found                                                                   run (F4)           .
-    .                                                  ┊foo                                              .
-    .recipe foo [                                      ┊─────────────────────────────────────────────────.
-    .  local-scope                                     ┊                                                 .
+    .recipe foo [                                      ┊foo                                              .
+    .  local-scope                                     ┊─────────────────────────────────────────────────.
     .  x:num <- copy y:num                             ┊                                                 .
     .]                                                 ┊                                                 .
+    .                                                  ┊                                                 .
     .foo: tried to read ingredient 'y' in 'x:num <- co↩┊                                                 .
     .py y:num' but it hasn't been written to yet       ┊                                                 .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
@@ -516,15 +559,15 @@ scenario run-instruction-and-print-errors [
   local-scope
   trace-until 100/app  # trace too long
   assume-screen 100/width, 10/height
-  # right editor contains an illegal instruction
-  sandbox:text <- new [get 1234:num, foo:offset]
-  env:&:environment <- new-programming-environment screen, [], sandbox
-  # run the code in the editors
+  assume-resources [
+  ]
+  # sandbox editor contains an illegal instruction
+  env:&:environment <- new-programming-environment resources, screen, [get 1234:num, foo:offset]
   assume-console [
     press F4
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # check that screen prints error message in red
   screen-should-contain [
@@ -578,16 +621,17 @@ scenario run-instruction-and-print-errors-only-once [
   local-scope
   trace-until 100/app  # trace too long
   assume-screen 100/width, 10/height
-  # right editor contains an illegal instruction
-  sandbox:text <- new [get 1234:num, foo:offset]
-  env:&:environment <- new-programming-environment screen, [], sandbox
+  assume-resources [
+  ]
+  # sandbox editor contains an illegal instruction
+  env:&:environment <- new-programming-environment resources, screen, [get 1234:num, foo:offset]
   # run the code in the editors multiple times
   assume-console [
     press F4
     press F4
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # check that screen prints error message just once
   screen-should-contain [
@@ -608,20 +652,23 @@ scenario sandbox-can-handle-infinite-loop [
   local-scope
   trace-until 100/app  # trace too long
   assume-screen 100/width, 20/height
-  # left editor is empty
-  recipes:text <- new [recipe foo [
-  {
-    loop
-  }
-]]
-  # right editor contains an instruction
-  env:&:environment <- new-programming-environment screen, recipes, [foo]
+  # sandbox editor will trigger an infinite loop
+  assume-resources [
+    [lesson/recipes.mu] <- [
+      |recipe foo [|
+      |  {|
+      |    loop|
+      |  }|
+      |]|
+    ]
+  ]
+  env:&:environment <- new-programming-environment resources, screen, [foo]
   # run the sandbox
   assume-console [
     press F4
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   screen-should-contain [
     .  errors found (0)                                                               run (F4)           .
@@ -630,7 +677,8 @@ scenario sandbox-can-handle-infinite-loop [
     .    loop                                          ┊0   edit          copy            delete         .
     .  }                                               ┊foo                                              .
     .]                                                 ┊took too long!                                   .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────.
+    .                                                  ┊─────────────────────────────────────────────────.
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
     .                                                  ┊                                                 .
   ]
 ]
@@ -640,50 +688,55 @@ scenario sandbox-with-errors-shows-trace [
   trace-until 100/app  # trace too long
   assume-screen 100/width, 10/height
   # generate a stash and a error
-  recipes:text <- new [recipe foo [
-local-scope
-a:num <- next-ingredient
-b:num <- next-ingredient
-stash [dividing by], b
-_, c:num <- divide-with-remainder a, b
-reply b
-]]
-  env:&:environment <- new-programming-environment screen, recipes, [foo 4, 0]
+  assume-resources [
+    [lesson/recipes.mu] <- [
+      |recipe foo [|
+      |  local-scope|
+      |  a:num <- next-ingredient|
+      |  b:num <- next-ingredient|
+      |  stash [dividing by], b|
+      |  _, c:num <- divide-with-remainder a, b|
+      |  reply b|
+      |]|
+    ]
+  ]
+  env:&:environment <- new-programming-environment resources, screen, [foo 4, 0]
   # run
   assume-console [
     press F4
   ]
-  event-loop screen, console, env
+  event-loop screen, console, env, resources
   # screen prints error message
   screen-should-contain [
     .  errors found (0)                                                               run (F4)           .
     .recipe foo [                                      ┊                                                 .
-    .local-scope                                       ┊─────────────────────────────────────────────────.
-    .a:num <- next-ingredient                          ┊0   edit          copy            delete         .
-    .b:num <- next-ingredient                          ┊foo 4, 0                                         .
-    .stash [dividing by], b                            ┊foo: divide by zero in '_, c:num <- divide-with-↩.
-    ._, c:num <- divide-with-remainder a, b            ┊remainder a, b'                                  .
-    .reply b                                           ┊─────────────────────────────────────────────────.
+    .  local-scope                                     ┊─────────────────────────────────────────────────.
+    .  a:num <- next-ingredient                        ┊0   edit          copy            delete         .
+    .  b:num <- next-ingredient                        ┊foo 4, 0                                         .
+    .  stash [dividing by], b                          ┊foo: divide by zero in '_, c:num <- divide-with-↩.
+    .  _, c:num <- divide-with-remainder a, b          ┊remainder a, b'                                  .
+    .  reply b                                         ┊─────────────────────────────────────────────────.
     .]                                                 ┊                                                 .
+    .                                                  ┊                                                 .
   ]
   # click on the call in the sandbox
   assume-console [
     left-click 4, 55
   ]
   run [
-    event-loop screen, console, env
+    event-loop screen, console, env, resources
   ]
   # screen should expand trace
   screen-should-contain [
     .  errors found (0)                                                               run (F4)           .
     .recipe foo [                                      ┊                                                 .
-    .local-scope                                       ┊─────────────────────────────────────────────────.
-    .a:num <- next-ingredient                          ┊0   edit          copy            delete         .
-    .b:num <- next-ingredient                          ┊foo 4, 0                                         .
-    .stash [dividing by], b                            ┊dividing by 0                                    .
-    ._, c:num <- divide-with-remainder a, b            ┊14 instructions run                              .
-    .reply b                                           ┊foo: divide by zero in '_, c:num <- divide-with-↩.
+    .  local-scope                                     ┊─────────────────────────────────────────────────.
+    .  a:num <- next-ingredient                        ┊0   edit          copy            delete         .
+    .  b:num <- next-ingredient                        ┊foo 4, 0                                         .
+    .  stash [dividing by], b                          ┊dividing by 0                                    .
+    .  _, c:num <- divide-with-remainder a, b          ┊14 instructions run                              .
+    .  reply b                                         ┊foo: divide by zero in '_, c:num <- divide-with-↩.
     .]                                                 ┊remainder a, b'                                  .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────.
+    .                                                  ┊─────────────────────────────────────────────────.
   ]
 ]