about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--011load.cc41
-rw-r--r--014literal_string.cc18
-rw-r--r--015literal_noninteger.cc2
-rw-r--r--020run.cc20
-rw-r--r--021check_instruction.cc14
-rw-r--r--022arithmetic.cc86
-rw-r--r--023boolean.cc20
-rw-r--r--024jump.cc12
-rw-r--r--025compare.cc44
-rw-r--r--029tools.cc10
-rw-r--r--030container.cc56
-rw-r--r--031address.cc18
-rw-r--r--032array.cc32
-rw-r--r--033exclusive_container.cc26
-rw-r--r--034call.cc12
-rw-r--r--035call_ingredient.cc20
-rw-r--r--036call_reply.cc59
-rw-r--r--037new.cc46
-rw-r--r--040brace.cc34
-rw-r--r--041jump_target.cc18
-rw-r--r--042name.cc22
-rw-r--r--043space.cc20
-rw-r--r--044space_surround.cc6
-rw-r--r--045closure_name.cc12
-rw-r--r--046global.cc4
-rw-r--r--047check_type_by_name.cc18
-rw-r--r--050scenario.cc36
-rw-r--r--052tangle.cc26
-rw-r--r--054dilated_reagent.cc8
-rw-r--r--055parse_tree.cc8
-rw-r--r--056recipe_header.cc106
-rw-r--r--057static_dispatch.cc118
-rw-r--r--058shape_shifting_container.cc34
-rw-r--r--059shape_shifting_recipe.cc154
-rw-r--r--060immutable.cc84
-rw-r--r--061recipe.cc24
-rw-r--r--062scheduler.cc42
-rw-r--r--063wait.cc8
-rw-r--r--070text.mu146
-rw-r--r--071channel.mu16
-rw-r--r--072array.mu4
-rw-r--r--073list.mu22
-rw-r--r--074random.cc2
-rw-r--r--075duplex_list.mu52
-rw-r--r--076stream.mu8
-rw-r--r--077hash.cc62
-rw-r--r--078table.mu10
-rw-r--r--081print.mu96
-rw-r--r--082scenario_screen.cc2
-rw-r--r--084console.mu28
-rw-r--r--091run_interactive.cc24
-rw-r--r--999spaces.cc6
-rw-r--r--Readme.md58
-rw-r--r--channel.mu6
-rw-r--r--chessboard.mu70
-rw-r--r--console.mu2
-rw-r--r--counters.mu12
-rw-r--r--display.mu2
-rw-r--r--edit/001-editor.mu32
-rw-r--r--edit/002-typing.mu62
-rw-r--r--edit/003-shortcuts.mu126
-rw-r--r--edit/004-programming-environment.mu26
-rw-r--r--edit/005-sandbox.mu44
-rw-r--r--edit/006-sandbox-edit.mu6
-rw-r--r--edit/007-sandbox-delete.mu8
-rw-r--r--edit/008-sandbox-test.mu12
-rw-r--r--edit/009-sandbox-trace.mu10
-rw-r--r--edit/010-errors.mu6
-rw-r--r--edit/011-editor-undo.mu8
-rw-r--r--example1.mu2
-rw-r--r--factorial.mu6
-rw-r--r--fork.mu4
-rw-r--r--global.mu4
-rw-r--r--html/chessboard-test.pngbin17591 -> 21433 bytes
-rw-r--r--html/edit.pngbin37981 -> 39022 bytes
-rw-r--r--html/example1.pngbin9364 -> 14621 bytes
-rw-r--r--html/expected-result.pngbin5492 -> 9417 bytes
-rw-r--r--html/f2c-1.pngbin23711 -> 23997 bytes
-rw-r--r--html/f2c-2.pngbin25218 -> 24630 bytes
-rw-r--r--html/factorial-test.pngbin14982 -> 17652 bytes
-rw-r--r--html/factorial.pngbin30707 -> 31770 bytes
-rw-r--r--html/unexpected-result.pngbin5527 -> 9357 bytes
-rw-r--r--mu.vim4
-rw-r--r--sandbox/001-editor.mu32
-rw-r--r--sandbox/002-typing.mu62
-rw-r--r--sandbox/003-shortcuts.mu126
-rw-r--r--sandbox/004-programming-environment.mu24
-rw-r--r--sandbox/005-sandbox.mu48
-rw-r--r--sandbox/006-sandbox-edit.mu6
-rw-r--r--sandbox/007-sandbox-delete.mu8
-rw-r--r--sandbox/008-sandbox-test.mu20
-rw-r--r--sandbox/009-sandbox-trace.mu8
-rw-r--r--sandbox/010-errors.mu22
-rw-r--r--sandbox/011-editor-undo.mu8
-rw-r--r--screen.mu2
-rw-r--r--static_dispatch.mu6
-rw-r--r--tangle.mu6
-rw-r--r--x.mu2
98 files changed, 1344 insertions, 1342 deletions
diff --git a/011load.cc b/011load.cc
index 9f5bfedc..35d08881 100644
--- a/011load.cc
+++ b/011load.cc
@@ -2,7 +2,7 @@
 
 :(scenarios load)  // use 'load' instead of 'run' in all scenarios in this layer
 :(scenario first_recipe)
-recipe main [
+def main [
   1:number <- copy 23
 ]
 +parse: instruction: copy
@@ -24,10 +24,10 @@ vector<recipe_ordinal> load(istream& in) {
     if (!has_data(in)) break;
     string command = next_word(in);
     // Command Handlers
-    if (command == "recipe") {
+    if (command == "recipe" || command == "def") {
       result.push_back(slurp_recipe(in));
     }
-    else if (command == "recipe!") {
+    else if (command == "recipe!" || command == "def!") {
       Disable_redefine_checks = true;
       result.push_back(slurp_recipe(in));
       Disable_redefine_checks = false;
@@ -248,9 +248,10 @@ void clear_recently_added_recipes() {
 
 :(scenario parse_comment_outside_recipe)
 # this comment will be dropped by the tangler, so we need a dummy recipe to stop that
-recipe f1 [ ]
+def f1 [
+]
 # this comment will go through to 'load'
-recipe main [
+def main [
   1:number <- copy 23
 ]
 +parse: instruction: copy
@@ -258,7 +259,7 @@ recipe main [
 +parse:   product: 1: "number"
 
 :(scenario parse_comment_amongst_instruction)
-recipe main [
+def main [
   # comment
   1:number <- copy 23
 ]
@@ -267,7 +268,7 @@ recipe main [
 +parse:   product: 1: "number"
 
 :(scenario parse_comment_amongst_instruction_2)
-recipe main [
+def main [
   # comment
   1:number <- copy 23
   # comment
@@ -277,7 +278,7 @@ recipe main [
 +parse:   product: 1: "number"
 
 :(scenario parse_comment_amongst_instruction_3)
-recipe main [
+def main [
   1:number <- copy 23
   # comment
   2:number <- copy 23
@@ -290,7 +291,7 @@ recipe main [
 +parse:   product: 2: "number"
 
 :(scenario parse_comment_after_instruction)
-recipe main [
+def main [
   1:number <- copy 23  # comment
 ]
 +parse: instruction: copy
@@ -298,19 +299,19 @@ recipe main [
 +parse:   product: 1: "number"
 
 :(scenario parse_label)
-recipe main [
+def main [
   +foo
 ]
 +parse: label: +foo
 
 :(scenario parse_dollar_as_recipe_name)
-recipe main [
+def main [
   $foo
 ]
 +parse: instruction: $foo
 
 :(scenario parse_multiple_properties)
-recipe main [
+def main [
   1:number <- copy 23/foo:bar:baz
 ]
 +parse: instruction: copy
@@ -318,7 +319,7 @@ recipe main [
 +parse:   product: 1: "number"
 
 :(scenario parse_multiple_products)
-recipe main [
+def main [
   1:number, 2:number <- copy 23
 ]
 +parse: instruction: copy
@@ -327,7 +328,7 @@ recipe main [
 +parse:   product: 2: "number"
 
 :(scenario parse_multiple_ingredients)
-recipe main [
+def main [
   1:number, 2:number <- copy 23, 4:number
 ]
 +parse: instruction: copy
@@ -337,7 +338,7 @@ recipe main [
 +parse:   product: 2: "number"
 
 :(scenario parse_multiple_types)
-recipe main [
+def main [
   1:number, 2:address:number <- copy 23, 4:number
 ]
 +parse: instruction: copy
@@ -347,7 +348,7 @@ recipe main [
 +parse:   product: 2: ("address" "number")
 
 :(scenario parse_properties)
-recipe main [
+def main [
   1:address:number/lookup <- copy 23
 ]
 +parse:   product: 1: ("address" "number"), {"lookup": ()}
@@ -365,19 +366,19 @@ void test_parse_comment_terminated_by_eof() {
 
 :(scenario forbid_redefining_recipes)
 % Hide_errors = true;
-recipe main [
+def main [
   1:number <- copy 23
 ]
-recipe main [
+def main [
   1:number <- copy 24
 ]
 +error: redefining recipe main
 
 :(scenario permit_forcibly_redefining_recipes)
-recipe main [
+def main [
   1:number <- copy 23
 ]
-recipe! main [
+def! main [
   1:number <- copy 24
 ]
 -error: redefining recipe main
diff --git a/014literal_string.cc b/014literal_string.cc
index c06e4f35..7986d0f3 100644
--- a/014literal_string.cc
+++ b/014literal_string.cc
@@ -7,13 +7,13 @@
 
 :(scenarios load)
 :(scenario string_literal)
-recipe main [
+def main [
   1:address:array:character <- copy [abc def]  # copy can't really take a string
 ]
 +parse:   ingredient: "abc def": "literal-string"
 
 :(scenario string_literal_with_colons)
-recipe main [
+def main [
   1:address:array:character <- copy [abc:def/ghi]
 ]
 +parse:   ingredient: "abc:def/ghi": "literal-string"
@@ -145,26 +145,26 @@ void strip_last(string& s) {
 }
 
 :(scenario string_literal_nested)
-recipe main [
+def main [
   1:address:array:character <- copy [abc [def]]
 ]
 +parse:   ingredient: "abc [def]": "literal-string"
 
 :(scenario string_literal_escaped)
-recipe main [
+def main [
   1:address:array:character <- copy [abc \[def]
 ]
 +parse:   ingredient: "abc [def": "literal-string"
 
 :(scenario string_literal_escaped_comment_aware)
-recipe main [
+def main [
   1:address:array:character <- copy [
 abc \\\[def]
 ]
 +parse:   ingredient: "\nabc \[def": "literal-string"
 
 :(scenario string_literal_and_comment)
-recipe main [
+def main [
   1:address:array:character <- copy [abc]  # comment
 ]
 +parse: --- defining main
@@ -174,14 +174,14 @@ recipe main [
 +parse:   product: 1: ("address" "array" "character")
 
 :(scenario string_literal_escapes_newlines_in_trace)
-recipe main [
+def main [
   copy [abc
 def]
 ]
 +parse:   ingredient: "abc\ndef": "literal-string"
 
 :(scenario string_literal_can_skip_past_comments)
-recipe main [
+def main [
   copy [
     # ']' inside comment
     bar
@@ -190,7 +190,7 @@ recipe main [
 +parse:   ingredient: "\n    # ']' inside comment\n    bar\n  ": "literal-string"
 
 :(scenario string_literal_empty)
-recipe main [
+def main [
   copy []
 ]
 +parse:   ingredient: "": "literal-string"
diff --git a/015literal_noninteger.cc b/015literal_noninteger.cc
index 0a45929f..29f539e8 100644
--- a/015literal_noninteger.cc
+++ b/015literal_noninteger.cc
@@ -2,7 +2,7 @@
 
 :(scenarios load)
 :(scenario noninteger_literal)
-recipe main [
+def main [
   1:number <- copy 3.14159
 ]
 +parse:   ingredient: 3.14159: "literal-fractional-number"
diff --git a/020run.cc b/020run.cc
index 32440ea4..3b9cd4d3 100644
--- a/020run.cc
+++ b/020run.cc
@@ -10,14 +10,14 @@
 //: another. Later layers will add more primitives.
 
 :(scenario copy_literal)
-recipe main [
+def main [
   1:number <- copy 23
 ]
 +run: 1:number <- copy 23
 +mem: storing 23 in location 1
 
 :(scenario copy)
-recipe main [
+def main [
   1:number <- copy 23
   2:number <- copy 1:number
 ]
@@ -26,7 +26,7 @@ recipe main [
 +mem: storing 23 in location 2
 
 :(scenario copy_multiple)
-recipe main [
+def main [
   1:number, 2:number <- copy 23, 24
 ]
 +mem: storing 23 in location 1
@@ -330,7 +330,7 @@ void run(string form) {
 }
 
 :(scenario run_label)
-recipe main [
+def main [
   +foo
   1:number <- copy 23
   2:number <- copy 1:number
@@ -340,14 +340,14 @@ recipe main [
 -run: +foo
 
 :(scenario run_dummy)
-recipe main [
+def main [
   _ <- copy 0
 ]
 +run: _ <- copy 0
 
 :(scenario write_to_0_disallowed)
 % Hide_errors = true;
-recipe main [
+def main [
   0:number <- copy 34
 ]
 -mem: storing 34 in location 0
@@ -356,25 +356,25 @@ recipe main [
 //: to put spaces around the '<-'.
 
 :(scenario comma_without_space)
-recipe main [
+def main [
   1:number, 2:number <- copy 2,2
 ]
 +mem: storing 2 in location 1
 
 :(scenario space_without_comma)
-recipe main [
+def main [
   1:number, 2:number <- copy 2 2
 ]
 +mem: storing 2 in location 1
 
 :(scenario comma_before_space)
-recipe main [
+def main [
   1:number, 2:number <- copy 2, 2
 ]
 +mem: storing 2 in location 1
 
 :(scenario comma_after_space)
-recipe main [
+def main [
   1:number, 2:number <- copy 2 ,2
 ]
 +mem: storing 2 in location 1
diff --git a/021check_instruction.cc b/021check_instruction.cc
index d5463fda..9200e5b8 100644
--- a/021check_instruction.cc
+++ b/021check_instruction.cc
@@ -46,34 +46,34 @@ void check_instruction(const recipe_ordinal r) {
 
 :(scenario copy_checks_reagent_count)
 % Hide_errors = true;
-recipe main [
+def main [
   1:number <- copy 34, 35
 ]
 +error: ingredients and products should match in '1:number <- copy 34, 35'
 
 :(scenario write_scalar_to_array_disallowed)
 % Hide_errors = true;
-recipe main [
+def main [
   1:array:number <- copy 34
 ]
 +error: main: can't copy 34 to 1:array:number; types don't match
 
 :(scenario write_scalar_to_array_disallowed_2)
 % Hide_errors = true;
-recipe main [
+def main [
   1:number, 2:array:number <- copy 34, 35
 ]
 +error: main: can't copy 35 to 2:array:number; types don't match
 
 :(scenario write_scalar_to_address_disallowed)
 % Hide_errors = true;
-recipe main [
+def main [
   1:address:number <- copy 34
 ]
 +error: main: can't copy 34 to 1:address:number; types don't match
 
 :(scenario write_address_to_number_allowed)
-recipe main [
+def main [
   1:address:number <- copy 12/unsafe
   2:number <- copy 1:address:number
 ]
@@ -81,7 +81,7 @@ recipe main [
 $error: 0
 
 :(scenario write_boolean_to_number_allowed)
-recipe main [
+def main [
   1:boolean <- copy 1/true
   2:number <- copy 1:boolean
 ]
@@ -89,7 +89,7 @@ recipe main [
 $error: 0
 
 :(scenario write_number_to_boolean_allowed)
-recipe main [
+def main [
   1:number <- copy 34
   2:boolean <- copy 1:number
 ]
diff --git a/022arithmetic.cc b/022arithmetic.cc
index 4628ea6f..89b444ae 100644
--- a/022arithmetic.cc
+++ b/022arithmetic.cc
@@ -35,13 +35,13 @@ case ADD: {
 }
 
 :(scenario add_literal)
-recipe main [
+def main [
   1:number <- add 23, 34
 ]
 +mem: storing 57 in location 1
 
 :(scenario add)
-recipe main [
+def main [
   1:number <- copy 23
   2:number <- copy 34
   3:number <- add 1:number, 2:number
@@ -49,21 +49,21 @@ recipe main [
 +mem: storing 57 in location 3
 
 :(scenario add_multiple)
-recipe main [
+def main [
   1:number <- add 3, 4, 5
 ]
 +mem: storing 12 in location 1
 
 :(scenario add_checks_type)
 % Hide_errors = true;
-recipe main [
+def main [
   1:number <- add 2:boolean, 1
 ]
 +error: main: 'add' requires number ingredients, but got 2:boolean
 
 :(scenario add_checks_return_type)
 % Hide_errors = true;
-recipe main [
+def main [
   1:address:number <- add 2, 2
 ]
 +error: main: 'add' should yield a number, but got 1:address:number
@@ -110,13 +110,13 @@ bool is_raw(const reagent& r) {
 }
 
 :(scenario subtract_literal)
-recipe main [
+def main [
   1:number <- subtract 5, 2
 ]
 +mem: storing 3 in location 1
 
 :(scenario subtract)
-recipe main [
+def main [
   1:number <- copy 23
   2:number <- copy 34
   3:number <- subtract 1:number, 2:number
@@ -124,7 +124,7 @@ recipe main [
 +mem: storing -11 in location 3
 
 :(scenario subtract_multiple)
-recipe main [
+def main [
   1:number <- subtract 6, 3, 2
 ]
 +mem: storing 1 in location 1
@@ -163,13 +163,13 @@ case MULTIPLY: {
 }
 
 :(scenario multiply_literal)
-recipe main [
+def main [
   1:number <- multiply 2, 3
 ]
 +mem: storing 6 in location 1
 
 :(scenario multiply)
-recipe main [
+def main [
   1:number <- copy 4
   2:number <- copy 6
   3:number <- multiply 1:number, 2:number
@@ -177,7 +177,7 @@ recipe main [
 +mem: storing 24 in location 3
 
 :(scenario multiply_multiple)
-recipe main [
+def main [
   1:number <- multiply 2, 3, 4
 ]
 +mem: storing 24 in location 1
@@ -219,13 +219,13 @@ case DIVIDE: {
 }
 
 :(scenario divide_literal)
-recipe main [
+def main [
   1:number <- divide 8, 2
 ]
 +mem: storing 4 in location 1
 
 :(scenario divide)
-recipe main [
+def main [
   1:number <- copy 27
   2:number <- copy 3
   3:number <- divide 1:number, 2:number
@@ -233,7 +233,7 @@ recipe main [
 +mem: storing 9 in location 3
 
 :(scenario divide_multiple)
-recipe main [
+def main [
   1:number <- divide 12, 3, 2
 ]
 +mem: storing 2 in location 1
@@ -287,14 +287,14 @@ case DIVIDE_WITH_REMAINDER: {
 }
 
 :(scenario divide_with_remainder_literal)
-recipe main [
+def main [
   1:number, 2:number <- divide-with-remainder 9, 2
 ]
 +mem: storing 4 in location 1
 +mem: storing 1 in location 2
 
 :(scenario divide_with_remainder)
-recipe main [
+def main [
   1:number <- copy 27
   2:number <- copy 11
   3:number, 4:number <- divide-with-remainder 1:number, 2:number
@@ -303,20 +303,20 @@ recipe main [
 +mem: storing 5 in location 4
 
 :(scenario divide_with_decimal_point)
-recipe main [
+def main [
   1:number <- divide 5, 2
 ]
 +mem: storing 2.5 in location 1
 
 :(scenario divide_by_zero)
-recipe main [
+def main [
   1:number <- divide 4, 0
 ]
 +mem: storing inf in location 1
 
 :(scenario divide_by_zero_2)
 % Hide_errors = true;
-recipe main [
+def main [
   1:number <- divide-with-remainder 4, 0
 ]
 # integer division can't return floating-point infinity
@@ -364,32 +364,32 @@ case SHIFT_LEFT: {
 }
 
 :(scenario shift_left_by_zero)
-recipe main [
+def main [
   1:number <- shift-left 1, 0
 ]
 +mem: storing 1 in location 1
 
 :(scenario shift_left_1)
-recipe main [
+def main [
   1:number <- shift-left 1, 4
 ]
 +mem: storing 16 in location 1
 
 :(scenario shift_left_2)
-recipe main [
+def main [
   1:number <- shift-left 3, 2
 ]
 +mem: storing 12 in location 1
 
 :(scenario shift_left_by_negative)
 % Hide_errors = true;
-recipe main [
+def main [
   1:number <- shift-left 3, -1
 ]
 +error: main: second ingredient can't be negative in '1:number <- shift-left 3, -1'
 
 :(scenario shift_left_ignores_fractional_part)
-recipe main [
+def main [
   1:number <- divide 3, 2
   2:number <- shift-left 1:number, 1
 ]
@@ -435,32 +435,32 @@ case SHIFT_RIGHT: {
 }
 
 :(scenario shift_right_by_zero)
-recipe main [
+def main [
   1:number <- shift-right 1, 0
 ]
 +mem: storing 1 in location 1
 
 :(scenario shift_right_1)
-recipe main [
+def main [
   1:number <- shift-right 1024, 1
 ]
 +mem: storing 512 in location 1
 
 :(scenario shift_right_2)
-recipe main [
+def main [
   1:number <- shift-right 3, 1
 ]
 +mem: storing 1 in location 1
 
 :(scenario shift_right_by_negative)
 % Hide_errors = true;
-recipe main [
+def main [
   1:number <- shift-right 4, -1
 ]
 +error: main: second ingredient can't be negative in '1:number <- shift-right 4, -1'
 
 :(scenario shift_right_ignores_fractional_part)
-recipe main [
+def main [
   1:number <- divide 3, 2
   2:number <- shift-right 1:number, 1
 ]
@@ -501,25 +501,25 @@ case AND_BITS: {
 }
 
 :(scenario and_bits_1)
-recipe main [
+def main [
   1:number <- and-bits 8, 3
 ]
 +mem: storing 0 in location 1
 
 :(scenario and_bits_2)
-recipe main [
+def main [
   1:number <- and-bits 3, 2
 ]
 +mem: storing 2 in location 1
 
 :(scenario and_bits_3)
-recipe main [
+def main [
   1:number <- and-bits 14, 3
 ]
 +mem: storing 2 in location 1
 
 :(scenario and_bits_negative)
-recipe main [
+def main [
   1:number <- and-bits -3, 4
 ]
 +mem: storing 4 in location 1
@@ -559,19 +559,19 @@ case OR_BITS: {
 }
 
 :(scenario or_bits_1)
-recipe main [
+def main [
   1:number <- or-bits 3, 8
 ]
 +mem: storing 11 in location 1
 
 :(scenario or_bits_2)
-recipe main [
+def main [
   1:number <- or-bits 3, 10
 ]
 +mem: storing 11 in location 1
 
 :(scenario or_bits_3)
-recipe main [
+def main [
   1:number <- or-bits 4, 6
 ]
 +mem: storing 6 in location 1
@@ -611,19 +611,19 @@ case XOR_BITS: {
 }
 
 :(scenario xor_bits_1)
-recipe main [
+def main [
   1:number <- xor-bits 3, 8
 ]
 +mem: storing 11 in location 1
 
 :(scenario xor_bits_2)
-recipe main [
+def main [
   1:number <- xor-bits 3, 10
 ]
 +mem: storing 9 in location 1
 
 :(scenario xor_bits_3)
-recipe main [
+def main [
   1:number <- xor-bits 4, 6
 ]
 +mem: storing 2 in location 1
@@ -662,25 +662,25 @@ case FLIP_BITS: {
 }
 
 :(scenario flip_bits_zero)
-recipe main [
+def main [
   1:number <- flip-bits 0
 ]
 +mem: storing -1 in location 1
 
 :(scenario flip_bits_negative)
-recipe main [
+def main [
   1:number <- flip-bits -1
 ]
 +mem: storing 0 in location 1
 
 :(scenario flip_bits_1)
-recipe main [
+def main [
   1:number <- flip-bits 3
 ]
 +mem: storing -4 in location 1
 
 :(scenario flip_bits_2)
-recipe main [
+def main [
   1:number <- flip-bits 12
 ]
 +mem: storing -13 in location 1
diff --git a/023boolean.cc b/023boolean.cc
index 558421a5..fc501a79 100644
--- a/023boolean.cc
+++ b/023boolean.cc
@@ -33,7 +33,7 @@ case AND: {
 }
 
 :(scenario and)
-recipe main [
+def main [
   1:boolean <- copy 1
   2:boolean <- copy 0
   3:boolean <- and 1:boolean, 2:boolean
@@ -41,19 +41,19 @@ recipe main [
 +mem: storing 0 in location 3
 
 :(scenario and_2)
-recipe main [
+def main [
   1:boolean <- and 1, 1
 ]
 +mem: storing 1 in location 1
 
 :(scenario and_multiple)
-recipe main [
+def main [
   1:boolean <- and 1, 1, 0
 ]
 +mem: storing 0 in location 1
 
 :(scenario and_multiple_2)
-recipe main [
+def main [
   1:boolean <- and 1, 1, 1
 ]
 +mem: storing 1 in location 1
@@ -91,7 +91,7 @@ case OR: {
 }
 
 :(scenario or)
-recipe main [
+def main [
   1:boolean <- copy 1
   2:boolean <- copy 0
   3:boolean <- or 1:boolean, 2:boolean
@@ -99,19 +99,19 @@ recipe main [
 +mem: storing 1 in location 3
 
 :(scenario or_2)
-recipe main [
+def main [
   1:boolean <- or 0, 0
 ]
 +mem: storing 0 in location 1
 
 :(scenario or_multiple)
-recipe main [
+def main [
   1:boolean <- and 0, 0, 0
 ]
 +mem: storing 0 in location 1
 
 :(scenario or_multiple_2)
-recipe main [
+def main [
   1:boolean <- or 0, 0, 1
 ]
 +mem: storing 1 in location 1
@@ -151,14 +151,14 @@ case NOT: {
 }
 
 :(scenario not)
-recipe main [
+def main [
   1:boolean <- copy 1
   2:boolean <- not 1:boolean
 ]
 +mem: storing 0 in location 2
 
 :(scenario not_multiple)
-recipe main [
+def main [
   1:boolean, 2:boolean, 3:boolean <- not 1, 0, 1
 ]
 +mem: storing 0 in location 1
diff --git a/024jump.cc b/024jump.cc
index 8b0a012a..c11a6464 100644
--- a/024jump.cc
+++ b/024jump.cc
@@ -1,7 +1,7 @@
 //: Jump primitives
 
 :(scenario jump_can_skip_instructions)
-recipe main [
+def main [
   jump 1:offset
   1:number <- copy 1
 ]
@@ -38,7 +38,7 @@ case JUMP: {
 put(Type_ordinal, "offset", 0);
 
 :(scenario jump_backward)
-recipe main [
+def main [
   jump 1:offset  # 0 -+
   jump 3:offset  #    |   +-+ 1
                  #   \/  /\ |
@@ -81,7 +81,7 @@ case JUMP_IF: {
 }
 
 :(scenario jump_if)
-recipe main [
+def main [
   jump-if 999, 1:offset
   123:number <- copy 1
 ]
@@ -91,7 +91,7 @@ recipe main [
 -mem: storing 1 in location 123
 
 :(scenario jump_if_fallthrough)
-recipe main [
+def main [
   jump-if 0, 1:offset
   123:number <- copy 1
 ]
@@ -133,7 +133,7 @@ case JUMP_UNLESS: {
 }
 
 :(scenario jump_unless)
-recipe main [
+def main [
   jump-unless 0, 1:offset
   123:number <- copy 1
 ]
@@ -143,7 +143,7 @@ recipe main [
 -mem: storing 1 in location 123
 
 :(scenario jump_unless_fallthrough)
-recipe main [
+def main [
   jump-unless 999, 1:offset
   123:number <- copy 1
 ]
diff --git a/025compare.cc b/025compare.cc
index 509e27fe..251d8bc6 100644
--- a/025compare.cc
+++ b/025compare.cc
@@ -36,7 +36,7 @@ case EQUAL: {
 }
 
 :(scenario equal)
-recipe main [
+def main [
   1:number <- copy 34
   2:number <- copy 33
   3:boolean <- equal 1:number, 2:number
@@ -46,7 +46,7 @@ recipe main [
 +mem: storing 0 in location 3
 
 :(scenario equal_2)
-recipe main [
+def main [
   1:number <- copy 34
   2:number <- copy 34
   3:boolean <- equal 1:number, 2:number
@@ -56,13 +56,13 @@ recipe main [
 +mem: storing 1 in location 3
 
 :(scenario equal_multiple)
-recipe main [
+def main [
   1:boolean <- equal 34, 34, 34
 ]
 +mem: storing 1 in location 1
 
 :(scenario equal_multiple_2)
-recipe main [
+def main [
   1:boolean <- equal 34, 34, 35
 ]
 +mem: storing 0 in location 1
@@ -107,7 +107,7 @@ case GREATER_THAN: {
 }
 
 :(scenario greater_than)
-recipe main [
+def main [
   1:number <- copy 34
   2:number <- copy 33
   3:boolean <- greater-than 1:number, 2:number
@@ -115,7 +115,7 @@ recipe main [
 +mem: storing 1 in location 3
 
 :(scenario greater_than_2)
-recipe main [
+def main [
   1:number <- copy 34
   2:number <- copy 34
   3:boolean <- greater-than 1:number, 2:number
@@ -123,13 +123,13 @@ recipe main [
 +mem: storing 0 in location 3
 
 :(scenario greater_than_multiple)
-recipe main [
+def main [
   1:boolean <- greater-than 36, 35, 34
 ]
 +mem: storing 1 in location 1
 
 :(scenario greater_than_multiple_2)
-recipe main [
+def main [
   1:boolean <- greater-than 36, 35, 35
 ]
 +mem: storing 0 in location 1
@@ -174,7 +174,7 @@ case LESSER_THAN: {
 }
 
 :(scenario lesser_than)
-recipe main [
+def main [
   1:number <- copy 32
   2:number <- copy 33
   3:boolean <- lesser-than 1:number, 2:number
@@ -182,7 +182,7 @@ recipe main [
 +mem: storing 1 in location 3
 
 :(scenario lesser_than_2)
-recipe main [
+def main [
   1:number <- copy 34
   2:number <- copy 33
   3:boolean <- lesser-than 1:number, 2:number
@@ -190,13 +190,13 @@ recipe main [
 +mem: storing 0 in location 3
 
 :(scenario lesser_than_multiple)
-recipe main [
+def main [
   1:boolean <- lesser-than 34, 35, 36
 ]
 +mem: storing 1 in location 1
 
 :(scenario lesser_than_multiple_2)
-recipe main [
+def main [
   1:boolean <- lesser-than 34, 35, 35
 ]
 +mem: storing 0 in location 1
@@ -241,7 +241,7 @@ case GREATER_OR_EQUAL: {
 }
 
 :(scenario greater_or_equal)
-recipe main [
+def main [
   1:number <- copy 34
   2:number <- copy 33
   3:boolean <- greater-or-equal 1:number, 2:number
@@ -249,7 +249,7 @@ recipe main [
 +mem: storing 1 in location 3
 
 :(scenario greater_or_equal_2)
-recipe main [
+def main [
   1:number <- copy 34
   2:number <- copy 34
   3:boolean <- greater-or-equal 1:number, 2:number
@@ -257,7 +257,7 @@ recipe main [
 +mem: storing 1 in location 3
 
 :(scenario greater_or_equal_3)
-recipe main [
+def main [
   1:number <- copy 34
   2:number <- copy 35
   3:boolean <- greater-or-equal 1:number, 2:number
@@ -265,13 +265,13 @@ recipe main [
 +mem: storing 0 in location 3
 
 :(scenario greater_or_equal_multiple)
-recipe main [
+def main [
   1:boolean <- greater-or-equal 36, 35, 35
 ]
 +mem: storing 1 in location 1
 
 :(scenario greater_or_equal_multiple_2)
-recipe main [
+def main [
   1:boolean <- greater-or-equal 36, 35, 36
 ]
 +mem: storing 0 in location 1
@@ -316,7 +316,7 @@ case LESSER_OR_EQUAL: {
 }
 
 :(scenario lesser_or_equal)
-recipe main [
+def main [
   1:number <- copy 32
   2:number <- copy 33
   3:boolean <- lesser-or-equal 1:number, 2:number
@@ -324,7 +324,7 @@ recipe main [
 +mem: storing 1 in location 3
 
 :(scenario lesser_or_equal_2)
-recipe main [
+def main [
   1:number <- copy 33
   2:number <- copy 33
   3:boolean <- lesser-or-equal 1:number, 2:number
@@ -332,7 +332,7 @@ recipe main [
 +mem: storing 1 in location 3
 
 :(scenario lesser_or_equal_3)
-recipe main [
+def main [
   1:number <- copy 34
   2:number <- copy 33
   3:boolean <- lesser-or-equal 1:number, 2:number
@@ -340,13 +340,13 @@ recipe main [
 +mem: storing 0 in location 3
 
 :(scenario lesser_or_equal_multiple)
-recipe main [
+def main [
   1:boolean <- lesser-or-equal 34, 35, 35
 ]
 +mem: storing 1 in location 1
 
 :(scenario lesser_or_equal_multiple_2)
-recipe main [
+def main [
   1:boolean <- lesser-or-equal 34, 35, 34
 ]
 +mem: storing 0 in location 1
diff --git a/029tools.cc b/029tools.cc
index 399bf6b5..50d85e55 100644
--- a/029tools.cc
+++ b/029tools.cc
@@ -1,7 +1,7 @@
 //: Allow mu programs to log facts just like we've been doing in C++ so far.
 
 :(scenario trace)
-recipe main [
+def main [
   trace 1, [foo], [this is a trace in mu]
 ]
 +foo: this is a trace in mu
@@ -59,19 +59,19 @@ case STASH: {
 }
 
 :(scenario stash_literal_string)
-recipe main [
+def main [
   stash [foo]
 ]
 +app: foo
 
 :(scenario stash_literal_number)
-recipe main [
+def main [
   stash [foo:], 4
 ]
 +app: foo: 4
 
 :(scenario stash_number)
-recipe main [
+def main [
   1:number <- copy 34
   stash [foo:], 1:number
 ]
@@ -187,7 +187,7 @@ case _SAVE_TRACE: {
 
 :(scenario assert)
 % Hide_errors = true;  // '%' lines insert arbitrary C code into tests before calling 'run' with the lines below. Must be immediately after :(scenario) line.
-recipe main [
+def main [
   assert 0, [this is an assert in mu]
 ]
 +error: this is an assert in mu
diff --git a/030container.cc b/030container.cc
index aeb4837d..3e8f0052 100644
--- a/030container.cc
+++ b/030container.cc
@@ -16,7 +16,7 @@ get(Type, point).elements.push_back(reagent("y:number"));
 //: container. Don't do this in general. I'm tagging exceptions with /raw to
 //: avoid errors.
 :(scenario copy_multiple_locations)
-recipe main [
+def main [
   1:number <- copy 34
   2:number <- copy 35
   3:point <- copy 1:point/unsafe
@@ -27,7 +27,7 @@ recipe main [
 //: trying to copy to a differently-typed destination will fail
 :(scenario copy_checks_size)
 % Hide_errors = true;
-recipe main [
+def main [
   2:point <- copy 1:number
 ]
 +error: main: can't copy 1:number to 2:point; types don't match
@@ -43,7 +43,7 @@ get(Type, point_number).elements.push_back(reagent("xy:point"));
 get(Type, point_number).elements.push_back(reagent("z:number"));
 
 :(scenario copy_handles_nested_container_elements)
-recipe main [
+def main [
   12:number <- copy 34
   13:number <- copy 35
   14:number <- copy 36
@@ -55,7 +55,7 @@ recipe main [
 //: numbers, no matter how large they are.
 
 :(scenario compare_multiple_locations)
-recipe main [
+def main [
   1:number <- copy 34  # first
   2:number <- copy 35
   3:number <- copy 36
@@ -67,7 +67,7 @@ recipe main [
 +mem: storing 1 in location 7
 
 :(scenario compare_multiple_locations_2)
-recipe main [
+def main [
   1:number <- copy 34  # first
   2:number <- copy 35
   3:number <- copy 36
@@ -109,7 +109,7 @@ if (t.kind == CONTAINER) {
 }
 
 :(scenario stash_container)
-recipe main [
+def main [
   1:number <- copy 34  # first
   2:number <- copy 35
   3:number <- copy 36
@@ -119,7 +119,7 @@ recipe main [
 
 //:: To access elements of a container, use 'get'
 :(scenario get)
-recipe main [
+def main [
   12:number <- copy 34
   13:number <- copy 35
   15:number <- get 12:point/raw, 1:offset  # unsafe
@@ -205,7 +205,7 @@ const reagent element_type(const reagent& canonized_base, long long int offset_v
 }
 
 :(scenario get_handles_nested_container_elements)
-recipe main [
+def main [
   12:number <- copy 34
   13:number <- copy 35
   14:number <- copy 36
@@ -215,7 +215,7 @@ recipe main [
 
 :(scenario get_out_of_bounds)
 % Hide_errors = true;
-recipe main [
+def main [
   12:number <- copy 34
   13:number <- copy 35
   14:number <- copy 36
@@ -225,7 +225,7 @@ recipe main [
 
 :(scenario get_out_of_bounds_2)
 % Hide_errors = true;
-recipe main [
+def main [
   12:number <- copy 34
   13:number <- copy 35
   14:number <- copy 36
@@ -235,7 +235,7 @@ recipe main [
 
 :(scenario get_product_type_mismatch)
 % Hide_errors = true;
-recipe main [
+def main [
   12:number <- copy 34
   13:number <- copy 35
   14:number <- copy 36
@@ -246,7 +246,7 @@ recipe main [
 //: we might want to call 'get' without saving the results, say in a sandbox
 
 :(scenario get_without_product)
-recipe main [
+def main [
   12:number <- copy 34
   13:number <- copy 35
   get 12:point/raw, 1:offset  # unsafe
@@ -256,7 +256,7 @@ recipe main [
 //:: To write to elements of containers, you need their address.
 
 :(scenario get_address)
-recipe main [
+def main [
   12:number <- copy 34
   13:number <- copy 35
   15:address:number <- get-address 12:point/raw, 1:offset  # unsafe
@@ -333,7 +333,7 @@ case GET_ADDRESS: {
 
 :(scenario get_address_out_of_bounds)
 % Hide_errors = true;
-recipe main [
+def main [
   12:number <- copy 34
   13:number <- copy 35
   14:number <- copy 36
@@ -343,7 +343,7 @@ recipe main [
 
 :(scenario get_address_out_of_bounds_2)
 % Hide_errors = true;
-recipe main [
+def main [
   12:number <- copy 34
   13:number <- copy 35
   14:number <- copy 36
@@ -357,7 +357,7 @@ container boolbool [
   x:boolean
   y:boolean
 ]
-recipe main [
+def main [
   12:boolean <- copy 1
   13:boolean <- copy 0
   15:boolean <- get-address 12:boolbool, 1:offset
@@ -466,7 +466,7 @@ container foo [
   y:number
 ]
 
-recipe main [
+def main [
   1:number <- copy 34
   2:number <- copy 35
   3:number <- get 1:foo, 0:offset
@@ -515,14 +515,14 @@ Next_type_ordinal = 1000;
 
 :(scenario run_complains_on_unknown_types)
 % Hide_errors = true;
-recipe main [
+def main [
   # integer is not a type
   1:integer <- copy 0
 ]
 +error: main: unknown type integer in '1:integer <- copy 0'
 
 :(scenario run_allows_type_definition_after_use)
-recipe main [
+def main [
   1:bar <- copy 0/unsafe
 ]
 
@@ -616,7 +616,7 @@ container foo [
   y:number
 ]
 
-recipe main [
+def main [
   1:foo <- merge 3, 4
 ]
 +mem: storing 3 in location 1
@@ -643,21 +643,21 @@ case MERGE: {
 //: type-check 'merge' to avoid interpreting numbers as addresses
 
 :(scenario merge_check)
-recipe main [
+def main [
   1:point <- merge 3, 4
 ]
 $error: 0
 
 :(scenario merge_check_missing_element)
 % Hide_errors = true;
-recipe main [
+def main [
   1:point <- merge 3
 ]
 +error: main: too few ingredients in '1:point <- merge 3'
 
 :(scenario merge_check_extra_element)
 % Hide_errors = true;
-recipe main [
+def main [
   1:point <- merge 3, 4, 5
 ]
 +error: main: too many ingredients in '1:point <- merge 3, 4, 5'
@@ -668,7 +668,7 @@ recipe main [
 //: container fields.
 
 :(scenario merge_check_recursive_containers)
-recipe main [
+def main [
   1:point <- merge 3, 4
   1:point-number <- merge 1:point, 5
 ]
@@ -676,21 +676,21 @@ $error: 0
 
 :(scenario merge_check_recursive_containers_2)
 % Hide_errors = true;
-recipe main [
+def main [
   1:point <- merge 3, 4
   2:point-number <- merge 1:point
 ]
 +error: main: too few ingredients in '2:point-number <- merge 1:point'
 
 :(scenario merge_check_recursive_containers_3)
-recipe main [
+def main [
   1:point-number <- merge 3, 4, 5
 ]
 $error: 0
 
 :(scenario merge_check_recursive_containers_4)
 % Hide_errors = true;
-recipe main [
+def main [
   1:point-number <- merge 3, 4
 ]
 +error: main: too few ingredients in '1:point-number <- merge 3, 4'
@@ -807,7 +807,7 @@ void check_merge_call(const vector<reagent>& ingredients, const reagent& product
 
 :(scenario merge_check_product)
 % Hide_errors = true;
-recipe main [
+def main [
   1:number <- merge 3
 ]
 +error: main: 'merge' should yield a container in '1:number <- merge 3'
diff --git a/031address.cc b/031address.cc
index 0577422d..708f698d 100644
--- a/031address.cc
+++ b/031address.cc
@@ -2,7 +2,7 @@
 //: 'lookup' property.
 
 :(scenario copy_indirect)
-recipe main [
+def main [
   1:address:number <- copy 2/unsafe
   2:number <- copy 34
   # This loads location 1 as an address and looks up *that* location.
@@ -16,7 +16,7 @@ canonize(x);
 //: similarly, write to addresses pointing at other locations using the
 //: 'lookup' property
 :(scenario store_indirect)
-recipe main [
+def main [
   1:address:number <- copy 2/unsafe
   1:address:number/lookup <- copy 34
 ]
@@ -32,7 +32,7 @@ if (x.value == 0) {
 //: writes to address 0 always loudly fail
 :(scenario store_to_0_fails)
 % Hide_errors = true;
-recipe main [
+def main [
   1:address:number <- copy 0
   1:address:number/lookup <- copy 34
 ]
@@ -66,7 +66,7 @@ void lookup_memory(reagent& x) {
 
 :(scenario canonize_non_pointer_fails_without_crashing)
 % Hide_errors = true;
-recipe foo [
+def foo [
   1:address:number <- get-address *p, x:offset
 ]
 # don't crash
@@ -130,7 +130,7 @@ void drop_one_lookup(reagent& r) {
 
 //:: 'get' can read from container address
 :(scenario get_indirect)
-recipe main [
+def main [
   1:number <- copy 2
   2:number <- copy 34
   3:number <- copy 35
@@ -139,7 +139,7 @@ recipe main [
 +mem: storing 34 in location 4
 
 :(scenario get_indirect2)
-recipe main [
+def main [
   1:number <- copy 2
   2:number <- copy 34
   3:number <- copy 35
@@ -149,7 +149,7 @@ recipe main [
 +mem: storing 34 in location 5
 
 :(scenario include_nonlookup_properties)
-recipe main [
+def main [
   1:number <- copy 2
   2:number <- copy 34
   3:number <- copy 35
@@ -166,7 +166,7 @@ canonize(base);
 
 :(scenario get_address_indirect)
 # 'get' can read from container address
-recipe main [
+def main [
   1:number <- copy 2
   2:number <- copy 34
   3:number <- copy 35
@@ -184,7 +184,7 @@ canonize(base);
 //:: abbreviation for '/lookup': a prefix '*'
 
 :(scenario lookup_abbreviation)
-recipe main [
+def main [
   1:address:number <- copy 2/unsafe
   2:number <- copy 34
   3:number <- copy *1:address:number
diff --git a/032array.cc b/032array.cc
index 9d5dbda6..5d02b82c 100644
--- a/032array.cc
+++ b/032array.cc
@@ -7,7 +7,7 @@
 
 //: You can create arrays using 'create-array'.
 :(scenario create_array)
-recipe main [
+def main [
   # create an array occupying locations 1 (for the size) and 2-4 (for the elements)
   1:array:number:3 <- create-array
 ]
@@ -67,7 +67,7 @@ case CREATE_ARRAY: {
 :(scenario copy_array)
 # Arrays can be copied around with a single instruction just like numbers,
 # no matter how large they are.
-recipe main [
+def main [
   1:array:number:3 <- create-array
   2:number <- copy 14
   3:number <- copy 15
@@ -80,7 +80,7 @@ recipe main [
 +mem: storing 16 in location 8
 
 :(scenario copy_array_indirect)
-recipe main [
+def main [
   1:array:number:3 <- create-array
   2:number <- copy 14
   3:number <- copy 15
@@ -94,7 +94,7 @@ recipe main [
 +mem: storing 16 in location 9
 
 :(scenario stash_array)
-recipe main [
+def main [
   1:array:number:3 <- create-array
   2:number <- copy 14
   3:number <- copy 15
@@ -149,7 +149,7 @@ container foo [
 //:: To access elements of an array, use 'index'
 
 :(scenario index)
-recipe main [
+def main [
   1:array:number:3 <- create-array
   2:number <- copy 14
   3:number <- copy 15
@@ -159,7 +159,7 @@ recipe main [
 +mem: storing 14 in location 5
 
 :(scenario index_direct_offset)
-recipe main [
+def main [
   1:array:number:3 <- create-array
   2:number <- copy 14
   3:number <- copy 15
@@ -234,7 +234,7 @@ type_tree* array_element(const type_tree* type) {
 }
 
 :(scenario index_indirect)
-recipe main [
+def main [
   1:array:number:3 <- create-array
   2:number <- copy 14
   3:number <- copy 15
@@ -246,7 +246,7 @@ recipe main [
 
 :(scenario index_out_of_bounds)
 % Hide_errors = true;
-recipe main [
+def main [
   1:array:number:3 <- create-array
   2:number <- copy 14
   3:number <- copy 15
@@ -261,7 +261,7 @@ recipe main [
 
 :(scenario index_out_of_bounds_2)
 % Hide_errors = true;
-recipe main [
+def main [
   1:array:point:3 <- create-array
   2:number <- copy 14
   3:number <- copy 15
@@ -276,7 +276,7 @@ recipe main [
 
 :(scenario index_product_type_mismatch)
 % Hide_errors = true;
-recipe main [
+def main [
   1:array:point:3 <- create-array
   2:number <- copy 14
   3:number <- copy 15
@@ -292,7 +292,7 @@ recipe main [
 //: we might want to call 'index' without saving the results, say in a sandbox
 
 :(scenario index_without_product)
-recipe main [
+def main [
   1:array:number:3 <- create-array
   2:number <- copy 14
   3:number <- copy 15
@@ -304,7 +304,7 @@ recipe main [
 //:: To write to elements of containers, you need their address.
 
 :(scenario index_address)
-recipe main [
+def main [
   1:array:number:3 <- create-array
   2:number <- copy 14
   3:number <- copy 15
@@ -366,7 +366,7 @@ case INDEX_ADDRESS: {
 
 :(scenario index_address_out_of_bounds)
 % Hide_errors = true;
-recipe main [
+def main [
   1:array:point:3 <- create-array
   2:number <- copy 14
   3:number <- copy 15
@@ -381,7 +381,7 @@ recipe main [
 
 :(scenario index_address_out_of_bounds_2)
 % Hide_errors = true;
-recipe main [
+def main [
   1:array:point:3 <- create-array
   2:number <- copy 14
   3:number <- copy 15
@@ -396,7 +396,7 @@ recipe main [
 
 :(scenario index_address_product_type_mismatch)
 % Hide_errors = true;
-recipe main [
+def main [
   1:array:point:3 <- create-array
   2:number <- copy 14
   3:number <- copy 15
@@ -412,7 +412,7 @@ recipe main [
 //:: compute the length of an array
 
 :(scenario array_length)
-recipe main [
+def main [
   1:array:number:3 <- create-array
   2:number <- copy 14
   3:number <- copy 15
diff --git a/033exclusive_container.cc b/033exclusive_container.cc
index f8e0e876..cc1922c2 100644
--- a/033exclusive_container.cc
+++ b/033exclusive_container.cc
@@ -20,7 +20,7 @@ get(Type, tmp).elements.push_back(reagent("p:point"));
 //: avoid errors.
 :(scenario copy_exclusive_container)
 # Copying exclusive containers copies all their contents and an extra location for the tag.
-recipe main [
+def main [
   1:number <- copy 1  # 'point' variant
   2:number <- copy 34
   3:number <- copy 35
@@ -56,7 +56,7 @@ if (t.kind == EXCLUSIVE_CONTAINER) {
 put(Type_ordinal, "variant", 0);
 
 :(scenario maybe_convert)
-recipe main [
+def main [
   12:number <- copy 1
   13:number <- copy 35
   14:number <- copy 36
@@ -65,7 +65,7 @@ recipe main [
 +mem: storing 13 in location 20
 
 :(scenario maybe_convert_fail)
-recipe main [
+def main [
   12:number <- copy 1
   13:number <- copy 35
   14:number <- copy 36
@@ -147,7 +147,7 @@ const reagent variant_type(const reagent& canonized_base, long long int tag) {
 
 :(scenario maybe_convert_product_type_mismatch)
 % Hide_errors = true;
-recipe main [
+def main [
   12:number <- copy 1
   13:number <- copy 35
   14:number <- copy 36
@@ -194,7 +194,7 @@ exclusive-container foo [
   y:number
 ]
 
-recipe main [
+def main [
   1:number <- copy 34
   2:foo <- merge 0/x, 1:number  # tag must be a literal when merging exclusive containers
   4:foo <- merge 1/y, 1:number
@@ -214,7 +214,7 @@ exclusive-container foo [
 container bar [
   z:number
 ]
-recipe main [
+def main [
   1:foo <- merge 0/x, 34
 ]
 +mem: storing 0 in location 1
@@ -230,7 +230,7 @@ exclusive-container foo [
 container bar [
   z:number
 ]
-recipe main [
+def main [
   local-scope
   1:number <- copy 0
   2:foo <- merge 1:number, 34
@@ -269,7 +269,7 @@ exclusive-container bar [
   x:number
   y:number
 ]
-recipe main [
+def main [
   1:foo <- merge 23, 1/y, 34
 ]
 +mem: storing 23 in location 1
@@ -287,7 +287,7 @@ exclusive-container bar [
   x:number
   y:number
 ]
-recipe main [
+def main [
   1:foo <- merge 23, 1/y, 34, 35
 ]
 +error: main: too many ingredients in '1:foo <- merge 23, 1/y, 34, 35'
@@ -301,7 +301,7 @@ container bar [
   x:number
   y:number
 ]
-recipe main [
+def main [
   1:foo <- merge 1/y, 23, 34
 ]
 +mem: storing 1 in location 1
@@ -318,7 +318,7 @@ container bar [
   x:number
   y:number
 ]
-recipe main [
+def main [
   1:foo <- merge 0/x, 23
 ]
 $error: 0
@@ -333,7 +333,7 @@ container bar [
   x:number
   y:number
 ]
-recipe main [
+def main [
   1:foo <- merge 1/y, 23
 ]
 +error: main: too few ingredients in '1:foo <- merge 1/y, 23'
@@ -362,7 +362,7 @@ exclusive-container bar [
   y:foo
 ]
 
-recipe main [
+def main [
   1:number <- copy 34
   2:number <- copy 35
   3:bar <- merge 0/x, 1:number
diff --git a/034call.cc b/034call.cc
index 45f4bb52..0cf24966 100644
--- a/034call.cc
+++ b/034call.cc
@@ -1,22 +1,22 @@
 //: So far the recipes we define can't run each other. Let's fix that.
 
 :(scenario calling_recipe)
-recipe main [
+def main [
   f
 ]
-recipe f [
+def f [
   3:number <- add 2, 2
 ]
 +mem: storing 4 in location 3
 
 :(scenario return_on_fallthrough)
-recipe main [
+def main [
   f
   1:number <- copy 0
   2:number <- copy 0
   3:number <- copy 0
 ]
-recipe f [
+def f [
   4:number <- copy 0
   5:number <- copy 0
 ]
@@ -125,14 +125,14 @@ void finish_call_housekeeping(const instruction& call_instruction, const vector<
 
 :(scenario calling_undefined_recipe_fails)
 % Hide_errors = true;
-recipe main [
+def main [
   foo
 ]
 +error: main: undefined operation in 'foo '
 
 :(scenario calling_undefined_recipe_handles_missing_result)
 % Hide_errors = true;
-recipe main [
+def main [
   x:number <- foo
 ]
 +error: main: undefined operation in 'x:number <- foo '
diff --git a/035call_ingredient.cc b/035call_ingredient.cc
index 8a24d083..63fa7a62 100644
--- a/035call_ingredient.cc
+++ b/035call_ingredient.cc
@@ -2,20 +2,20 @@
 //: ingredients, use 'next-ingredient'.
 
 :(scenario next_ingredient)
-recipe main [
+def main [
   f 2
 ]
-recipe f [
+def f [
   12:number <- next-ingredient
   13:number <- add 1, 12:number
 ]
 +mem: storing 3 in location 13
 
 :(scenario next_ingredient_missing)
-recipe main [
+def main [
   f
 ]
-recipe f [
+def f [
   _, 12:number <- next-ingredient
 ]
 +mem: storing 0 in location 12
@@ -86,19 +86,19 @@ case NEXT_INGREDIENT: {
 
 :(scenario next_ingredient_fail_on_missing)
 % Hide_errors = true;
-recipe main [
+def main [
   f
 ]
-recipe f [
+def f [
   11:number <- next-ingredient
 ]
 +error: f: no ingredient to save in 11:number
 
 :(scenario rewind_ingredients)
-recipe main [
+def main [
   f 2
 ]
-recipe f [
+def f [
   12:number <- next-ingredient  # consume ingredient
   _, 1:boolean <- next-ingredient  # will not find any ingredients
   rewind-ingredients
@@ -124,10 +124,10 @@ case REWIND_INGREDIENTS: {
 }
 
 :(scenario ingredient)
-recipe main [
+def main [
   f 1, 2
 ]
-recipe f [
+def f [
   12:number <- ingredient 1  # consume second ingredient first
   13:number, 1:boolean <- next-ingredient  # next-ingredient tries to scan past that
 ]
diff --git a/036call_reply.cc b/036call_reply.cc
index ba0c0a41..299abf10 100644
--- a/036call_reply.cc
+++ b/036call_reply.cc
@@ -1,10 +1,10 @@
-//: Calls can also generate products, using 'reply'.
+//: Calls can also generate products, using 'reply' or 'return'.
 
 :(scenario reply)
-recipe main [
+def main [
   1:number, 2:number <- f 34
 ]
-recipe f [
+def f [
   12:number <- next-ingredient
   13:number <- add 1, 12:number
   reply 12:number, 13:number
@@ -16,6 +16,7 @@ recipe f [
 REPLY,
 :(before "End Primitive Recipe Numbers")
 put(Recipe_ordinal, "reply", REPLY);
+put(Recipe_ordinal, "return", REPLY);
 :(before "End Primitive Recipe Checks")
 case REPLY: {
   break;  // checks will be performed by a transform below
@@ -46,13 +47,13 @@ case REPLY: {
 
 //: Products can include containers and exclusive containers, addresses and arrays.
 :(scenario reply_container)
-recipe main [
+def main [
   3:point <- f 2
 ]
-recipe f [
+def f [
   12:number <- next-ingredient
   13:number <- copy 35
-  reply 12:point/raw
+  return 12:point/raw
 ]
 +run: result 0 is [2, 35]
 +mem: storing 2 in location 3
@@ -86,7 +87,7 @@ void check_types_of_reply_instructions(recipe_ordinal r) {
         reagent rhs = caller_instruction.products.at(i);
         canonize_type(rhs);
         if (!types_coercible(rhs, lhs)) {
-          raise << maybe(callee.name) << "reply ingredient " << lhs.original_string << " can't be saved in " << rhs.original_string << '\n' << end();
+          raise << maybe(callee.name) << reply_inst.name << " ingredient " << lhs.original_string << " can't be saved in " << rhs.original_string << '\n' << end();
           raise << to_string(lhs.type) << " vs " << to_string(rhs.type) << '\n' << end();
           goto finish_reply_check;
         }
@@ -117,16 +118,16 @@ void check_types_of_reply_instructions(recipe_ordinal r) {
 
 :(scenario reply_type_mismatch)
 % Hide_errors = true;
-recipe main [
+def main [
   3:number <- f 2
 ]
-recipe f [
+def f [
   12:number <- next-ingredient
   13:number <- copy 35
   14:point <- copy 12:point/raw
-  reply 14:point
+  return 14:point
 ]
-+error: f: reply ingredient 14:point can't be saved in 3:number
++error: f: return ingredient 14:point can't be saved in 3:number
 
 //: In mu we'd like to assume that any instruction doesn't modify its
 //: ingredients unless they're also products. The /same-as-ingredient inside
@@ -135,24 +136,24 @@ recipe f [
 
 :(scenario reply_same_as_ingredient)
 % Hide_errors = true;
-recipe main [
+def main [
   1:number <- copy 0
   2:number <- test1 1:number  # call with different ingredient and product
 ]
-recipe test1 [
+def test1 [
   10:number <- next-ingredient
-  reply 10:number/same-as-ingredient:0
+  return 10:number/same-as-ingredient:0
 ]
 +error: main: '2:number <- test1 1:number' should write to 1:number rather than 2:number
 
 :(scenario reply_same_as_ingredient_dummy)
-recipe main [
+def main [
   1:number <- copy 0
   _ <- test1 1:number  # call with different ingredient and product
 ]
-recipe test1 [
+def test1 [
   10:number <- next-ingredient
-  reply 10:number/same-as-ingredient:0
+  return 10:number/same-as-ingredient:0
 ]
 $error: 0
 
@@ -176,22 +177,22 @@ string to_string(const vector<double>& in) {
 //: Conditional reply.
 
 :(scenario reply_if)
-recipe main [
+def main [
   1:number <- test1
 ]
-recipe test1 [
-  reply-if 0, 34
-  reply 35
+def test1 [
+  return-if 0, 34
+  return 35
 ]
 +mem: storing 35 in location 1
 
 :(scenario reply_if_2)
-recipe main [
+def main [
   1:number <- test1
 ]
-recipe test1 [
-  reply-if 1, 34
-  reply 35
+def test1 [
+  return-if 1, 34
+  return 35
 ]
 +mem: storing 34 in location 1
 
@@ -201,7 +202,7 @@ recipe test1 [
 //   jump-unless a, 1:offset
 //   reply b, c, ...
 //   ```
-if (curr.name == "reply-if") {
+if (curr.name == "reply-if" || curr.name == "return-if") {
   if (curr.products.empty()) {
     curr.operation = get(Recipe_ordinal, "jump-unless");
     curr.name = "jump-unless";
@@ -216,7 +217,7 @@ if (curr.name == "reply-if") {
     curr.ingredients.swap(results);
   }
   else {
-    raise << "'reply-if' never yields any products\n" << end();
+    raise << "'" << curr.name << "' never yields any products\n" << end();
   }
 }
 // rewrite `reply-unless a, b, c, ...` to
@@ -224,7 +225,7 @@ if (curr.name == "reply-if") {
 //   jump-if a, 1:offset
 //   reply b, c, ...
 //   ```
-if (curr.name == "reply-unless") {
+if (curr.name == "reply-unless" || curr.name == "return-unless") {
   if (curr.products.empty()) {
     curr.operation = get(Recipe_ordinal, "jump-if");
     curr.name = "jump-if";
@@ -239,6 +240,6 @@ if (curr.name == "reply-unless") {
     curr.ingredients.swap(results);
   }
   else {
-    raise << "'reply-unless' never yields any products\n" << end();
+    raise << "'" << curr.name << "' never yields any products\n" << end();
   }
 }
diff --git a/037new.cc b/037new.cc
index cc28640e..a465e335 100644
--- a/037new.cc
+++ b/037new.cc
@@ -47,7 +47,7 @@ if (r.type->name == "shared") {
 :(scenarios run)
 :(scenario new)
 # call new two times with identical arguments; you should get back different results
-recipe main [
+def main [
   1:address:shared:number/raw <- new number:type
   2:address:shared:number/raw <- new number:type
   3:boolean/raw <- equal 1:address:shared:number/raw, 2:address:shared:number/raw
@@ -229,7 +229,7 @@ void ensure_space(long long int size) {
 :(scenario new_initializes)
 % Memory_allocated_until = 10;
 % put(Memory, Memory_allocated_until, 1);
-recipe main [
+def main [
   1:address:shared:number <- new number:type
   2:number <- copy *1:address:shared:number
 ]
@@ -237,13 +237,13 @@ recipe main [
 
 :(scenario new_error)
 % Hide_errors = true;
-recipe main [
+def main [
   1:address:number/raw <- new number:type
 ]
 +error: main: product of 'new' has incorrect type: 1:address:number/raw <- new number:type
 
 :(scenario new_array)
-recipe main [
+def main [
   1:address:shared:array:number/raw <- new number:type, 5
   2:address:shared:number/raw <- new number:type
   3:number/raw <- subtract 2:address:shared:number/raw, 1:address:shared:array:number/raw
@@ -254,7 +254,7 @@ recipe main [
 +mem: storing 7 in location 3
 
 :(scenario new_empty_array)
-recipe main [
+def main [
   1:address:shared:array:number/raw <- new number:type, 0
   2:address:shared:number/raw <- new number:type
   3:number/raw <- subtract 2:address:shared:number/raw, 1:address:shared:array:number/raw
@@ -267,7 +267,7 @@ recipe main [
 //: If a routine runs out of its initial allocation, it should allocate more.
 :(scenario new_overflow)
 % Initial_memory_per_routine = 3;  // barely enough room for point allocation below
-recipe main [
+def main [
   1:address:shared:number/raw <- new number:type
   2:address:shared:point/raw <- new point:type  # not enough room in initial page
 ]
@@ -278,7 +278,7 @@ recipe main [
 //: todo: custodians, etc. Following malloc/free is a temporary hack.
 
 :(scenario new_reclaim)
-recipe main [
+def main [
   1:address:shared:number <- new number:type
   2:address:shared:number <- copy 1:address:shared:number  # because 1 will get reset during abandon below
   abandon 1:address:shared:number  # unsafe
@@ -367,7 +367,7 @@ if (get_or_insert(Free_list, size)) {
 }
 
 :(scenario new_differing_size_no_reclaim)
-recipe main [
+def main [
   1:address:shared:number <- new number:type
   2:address:shared:number <- copy 1:address:shared:number
   abandon 1:address:shared:number
@@ -378,7 +378,7 @@ recipe main [
 +mem: storing 0 in location 4
 
 :(scenario new_reclaim_array)
-recipe main [
+def main [
   1:address:shared:array:number <- new number:type, 2
   2:address:shared:array:number <- copy 1:address:shared:array:number
   abandon 1:address:shared:array:number  # unsafe
@@ -389,7 +389,7 @@ recipe main [
 +mem: storing 1 in location 4
 
 :(scenario reset_on_abandon)
-recipe main [
+def main [
   1:address:shared:number <- new number:type
   abandon 1:address:shared:number
 ]
@@ -400,7 +400,7 @@ recipe main [
 //:: Manage refcounts when copying addresses.
 
 :(scenario refcounts)
-recipe main [
+def main [
   1:address:shared:number <- copy 1000/unsafe
   2:address:shared:number <- copy 1:address:shared:number
   1:address:shared:number <- copy 0
@@ -458,7 +458,7 @@ if (x.type->value == get(Type_ordinal, "address")
 }
 
 :(scenario refcounts_2)
-recipe main [
+def main [
   1:address:shared:number <- new number:type
   # over-writing one allocation with another
   1:address:shared:number <- new number:type
@@ -470,13 +470,13 @@ recipe main [
 +mem: automatically abandoning 1000
 
 :(scenario refcounts_3)
-recipe main [
+def main [
   1:address:shared:number <- new number:type
   # passing in addresses to recipes increments refcount
   foo 1:address:shared:number
   1:address:shared:number <- copy 0
 ]
-recipe foo [
+def foo [
   2:address:shared:number <- next-ingredient
   # return does NOT yet decrement refcount; memory must be explicitly managed
   2:address:shared:number <- copy 0
@@ -492,7 +492,7 @@ recipe foo [
 +mem: automatically abandoning 1000
 
 :(scenario refcounts_4)
-recipe main [
+def main [
   1:address:shared:number <- new number:type
   # idempotent copies leave refcount unchanged
   1:address:shared:number <- copy 1:address:shared:number
@@ -504,14 +504,14 @@ recipe main [
 +mem: incrementing refcount of 1000: 0 -> 1
 
 :(scenario refcounts_5)
-recipe main [
+def main [
   1:address:shared:number <- new number:type
   # passing in addresses to recipes increments refcount
   foo 1:address:shared:number
   # return does NOT yet decrement refcount; memory must be explicitly managed
   1:address:shared:number <- new number:type
 ]
-recipe foo [
+def foo [
   2:address:shared:number <- next-ingredient
 ]
 +run: 1:address:shared:number <- new number:type
@@ -524,7 +524,7 @@ recipe foo [
 //:: Extend 'new' to handle a unicode string literal argument.
 
 :(scenario new_string)
-recipe main [
+def main [
   1:address:shared:array:character <- new [abc def]
   2:character <- index *1:address:shared:array:character, 5
 ]
@@ -532,7 +532,7 @@ recipe main [
 +mem: storing 101 in location 2
 
 :(scenario new_string_handles_unicode)
-recipe main [
+def main [
   1:address:shared:array:character <- new [a«c]
   2:number <- length *1:address:shared:array:character
   3:character <- index *1:address:shared:array:character, 1
@@ -582,7 +582,7 @@ long long int new_mu_string(const string& contents) {
 //: stash recognizes strings
 
 :(scenario stash_string)
-recipe main [
+def main [
   1:address:shared:array:character <- new [abc]
   stash [foo:], 1:address:shared:array:character
 ]
@@ -595,14 +595,14 @@ if (is_mu_string(r)) {
 }
 
 :(scenario unicode_string)
-recipe main [
+def main [
   1:address:shared:array:character <- new [♠]
   stash [foo:], 1:address:shared:array:character
 ]
 +app: foo: ♠
 
 :(scenario stash_space_after_string)
-recipe main [
+def main [
   1:address:shared:array:character <- new [abc]
   stash 1:address:shared:array:character, [foo]
 ]
@@ -611,7 +611,7 @@ recipe main [
 //: Allocate more to routine when initializing a literal string
 :(scenario new_string_overflow)
 % Initial_memory_per_routine = 2;
-recipe main [
+def main [
   1:address:shared:number/raw <- new number:type
   2:address:shared:array:character/raw <- new [a]  # not enough room in initial page, if you take the array size into account
 ]
diff --git a/040brace.cc b/040brace.cc
index 6c5adcb5..d9d60078 100644
--- a/040brace.cc
+++ b/040brace.cc
@@ -21,7 +21,7 @@
 
 :(scenarios transform)
 :(scenario brace_conversion)
-recipe main [
+def main [
   {
     break
     1:number <- copy 0
@@ -145,7 +145,7 @@ long long int matching_brace(long long int index, const list<pair<int, long long
 }
 
 :(scenario loop)
-recipe main [
+def main [
   1:number <- copy 0
   2:number <- copy 0
   {
@@ -160,7 +160,7 @@ recipe main [
 +transform: jump -2:offset
 
 :(scenario break_empty_block)
-recipe main [
+def main [
   1:number <- copy 0
   {
     break
@@ -171,7 +171,7 @@ recipe main [
 +transform: jump 0:offset
 
 :(scenario break_cascading)
-recipe main [
+def main [
   1:number <- copy 0
   {
     break
@@ -186,7 +186,7 @@ recipe main [
 +transform: jump 0:offset
 
 :(scenario break_cascading_2)
-recipe main [
+def main [
   1:number <- copy 0
   2:number <- copy 0
   {
@@ -205,7 +205,7 @@ recipe main [
 +transform: jump 0:offset
 
 :(scenario break_if)
-recipe main [
+def main [
   1:number <- copy 0
   2:number <- copy 0
   {
@@ -224,7 +224,7 @@ recipe main [
 +transform: jump 0:offset
 
 :(scenario break_nested)
-recipe main [
+def main [
   1:number <- copy 0
   {
     2:number <- copy 0
@@ -238,7 +238,7 @@ recipe main [
 +transform: jump 4:offset
 
 :(scenario break_nested_degenerate)
-recipe main [
+def main [
   1:number <- copy 0
   {
     2:number <- copy 0
@@ -251,7 +251,7 @@ recipe main [
 +transform: jump 3:offset
 
 :(scenario break_nested_degenerate_2)
-recipe main [
+def main [
   1:number <- copy 0
   {
     2:number <- copy 0
@@ -264,7 +264,7 @@ recipe main [
 
 :(scenario break_label)
 % Hide_errors = true;
-recipe main [
+def main [
   1:number <- copy 0
   {
     break +foo:offset
@@ -273,7 +273,7 @@ recipe main [
 +transform: jump +foo:offset
 
 :(scenario break_unless)
-recipe main [
+def main [
   1:number <- copy 0
   2:number <- copy 0
   {
@@ -288,7 +288,7 @@ recipe main [
 +transform: copy ...
 
 :(scenario loop_unless)
-recipe main [
+def main [
   1:number <- copy 0
   2:number <- copy 0
   {
@@ -303,7 +303,7 @@ recipe main [
 +transform: copy ...
 
 :(scenario loop_nested)
-recipe main [
+def main [
   1:number <- copy 0
   {
     2:number <- copy 0
@@ -318,7 +318,7 @@ recipe main [
 +transform: jump-if 4, -5:offset
 
 :(scenario loop_label)
-recipe main [
+def main [
   1:number <- copy 0
   +foo
   2:number <- copy 0
@@ -330,7 +330,7 @@ recipe main [
 //: test how things actually run
 :(scenarios run)
 :(scenario brace_conversion_and_run)
-recipe test-factorial [
+def test-factorial [
   1:number <- copy 5
   2:number <- copy 1
   {
@@ -347,14 +347,14 @@ recipe test-factorial [
 
 :(scenario break_outside_braces_fails)
 % Hide_errors = true;
-recipe main [
+def main [
   break
 ]
 +error: break needs a '{' before
 
 :(scenario break_conditional_without_ingredient_fails)
 % Hide_errors = true;
-recipe main [
+def main [
   {
     break-if
   }
diff --git a/041jump_target.cc b/041jump_target.cc
index 36d43df9..f58ff3d1 100644
--- a/041jump_target.cc
+++ b/041jump_target.cc
@@ -8,7 +8,7 @@
 //: iteration of some containing loop nest.
 
 :(scenario jump_to_label)
-recipe main [
+def main [
   jump +target:label
   1:number <- copy 0
   +target
@@ -92,7 +92,7 @@ bool is_jump_target(string label) {
 }
 
 :(scenario break_to_label)
-recipe main [
+def main [
   {
     {
       break +target:label
@@ -104,7 +104,7 @@ recipe main [
 -mem: storing 0 in location 1
 
 :(scenario jump_if_to_label)
-recipe main [
+def main [
   {
     {
       jump-if 1, +target:label
@@ -116,7 +116,7 @@ recipe main [
 -mem: storing 0 in location 1
 
 :(scenario loop_unless_to_label)
-recipe main [
+def main [
   {
     {
       loop-unless 0, +target:label  # loop/break with a label don't care about braces
@@ -128,7 +128,7 @@ recipe main [
 -mem: storing 0 in location 1
 
 :(scenario jump_runs_code_after_label)
-recipe main [
+def main [
   # first a few lines of padding to exercise the offset computation
   1:number <- copy 0
   2:number <- copy 0
@@ -143,21 +143,21 @@ recipe main [
 
 :(scenario jump_fails_without_target)
 % Hide_errors = true;
-recipe main [
+def main [
   jump
 ]
 +error: main: 'jump' expects an ingredient but got none
 
 :(scenario jump_fails_without_target_2)
 % Hide_errors = true;
-recipe main [
+def main [
   jump-if 1/true
 ]
 +error: main: 'jump-if' expects 2 ingredients but got 1
 
 :(scenario recipe_fails_on_duplicate_jump_target)
 % Hide_errors = true;
-recipe main [
+def main [
   +label
   1:number <- copy 0
   +label
@@ -167,7 +167,7 @@ recipe main [
 
 :(scenario jump_ignores_nontarget_label)
 % Hide_errors = true;
-recipe main [
+def main [
   # first a few lines of padding to exercise the offset computation
   1:number <- copy 0
   2:number <- copy 0
diff --git a/042name.cc b/042name.cc
index f7eba9e0..1e386db4 100644
--- a/042name.cc
+++ b/042name.cc
@@ -3,7 +3,7 @@
 //: convenience.
 
 :(scenario transform_names)
-recipe main [
+def main [
   x:number <- copy 0
 ]
 +name: assign x 1
@@ -12,7 +12,7 @@ recipe main [
 :(scenarios transform)
 :(scenario transform_names_fails_on_use_before_define)
 % Hide_errors = true;
-recipe main [
+def main [
   x:number <- copy y:number
 ]
 +error: main: use before set: y
@@ -147,7 +147,7 @@ bool is_special_name(const string& s) {
 
 :(scenario transform_names_passes_dummy)
 # _ is just a dummy result that never gets consumed
-recipe main [
+def main [
   _, x:number <- copy 0, 1
 ]
 +name: assign x 1
@@ -157,7 +157,7 @@ recipe main [
 :(scenarios run)
 :(scenario transform_names_passes_raw)
 % Hide_errors = true;
-recipe main [
+def main [
   x:number/raw <- copy 0
 ]
 -name: assign x 1
@@ -166,28 +166,28 @@ recipe main [
 :(scenarios transform)
 :(scenario transform_names_fails_when_mixing_names_and_numeric_locations)
 % Hide_errors = true;
-recipe main [
+def main [
   x:number <- copy 1:number
 ]
 +error: main: mixing variable names and numeric addresses
 
 :(scenario transform_names_fails_when_mixing_names_and_numeric_locations_2)
 % Hide_errors = true;
-recipe main [
+def main [
   x:number <- copy 1
   1:number <- copy x:number
 ]
 +error: main: mixing variable names and numeric addresses
 
 :(scenario transform_names_does_not_fail_when_mixing_names_and_raw_locations)
-recipe main [
+def main [
   x:number <- copy 1:number/raw
 ]
 -error: main: mixing variable names and numeric addresses
 $error: 0
 
 :(scenario transform_names_does_not_fail_when_mixing_names_and_literals)
-recipe main [
+def main [
   x:number <- copy 1
 ]
 -error: main: mixing variable names and numeric addresses
@@ -196,7 +196,7 @@ $error: 0
 //:: Support element names for containers in 'get' and 'get-address'.
 
 :(scenario transform_names_transforms_container_elements)
-recipe main [
+def main [
   p:address:point <- copy 0
   a:number <- get *p:address:point, y:offset
   b:number <- get *p:address:point, x:offset
@@ -226,7 +226,7 @@ if (inst.name == "get" || inst.name == "get-address") {
 //: this test is actually illegal so can't call run
 :(scenarios transform)
 :(scenario transform_names_handles_containers)
-recipe main [
+def main [
   a:point <- copy 0/unsafe
   b:number <- copy 0/unsafe
 ]
@@ -237,7 +237,7 @@ recipe main [
 
 :(scenarios run)
 :(scenario transform_names_handles_exclusive_containers)
-recipe main [
+def main [
   12:number <- copy 1
   13:number <- copy 35
   14:number <- copy 36
diff --git a/043space.cc b/043space.cc
index 31a4173d..f16240ca 100644
--- a/043space.cc
+++ b/043space.cc
@@ -5,7 +5,7 @@
 :(scenario set_default_space)
 # if default-space is 10, and if an array of 5 locals lies from location 12 to 16 (inclusive),
 # then local 0 is really location 12, local 1 is really location 13, and so on.
-recipe main [
+def main [
   # pretend shared:array:location; in practice we'll use new
   10:number <- copy 0  # refcount
   11:number <- copy 5  # length
@@ -15,7 +15,7 @@ recipe main [
 +mem: storing 23 in location 13
 
 :(scenario lookup_sidesteps_default_space)
-recipe main [
+def main [
   # pretend pointer from outside
   3:number <- copy 34
   # pretend shared:array:location; in practice we'll use new
@@ -31,7 +31,7 @@ recipe main [
 //:: first disable name conversion for 'default-space'
 :(scenario convert_names_passes_default_space)
 % Hide_errors = true;
-recipe main [
+def main [
   default-space:number, x:number <- copy 0, 1
 ]
 +name: assign x 1
@@ -101,7 +101,7 @@ long long int address(long long int offset, long long int base) {
   }
 
 :(scenario get_default_space)
-recipe main [
+def main [
   default-space:address:shared:array:location <- copy 10/unsafe
   1:address:shared:array:location/raw <- copy default-space:address:shared:array:location
 ]
@@ -117,7 +117,7 @@ recipe main [
 //:: fix 'get'
 
 :(scenario lookup_sidesteps_default_space_in_get)
-recipe main [
+def main [
   # pretend pointer to container from outside
   12:number <- copy 34
   13:number <- copy 35
@@ -137,7 +137,7 @@ tmp.properties.push_back(pair<string, string_tree*>("raw", NULL));
 //:: fix 'index'
 
 :(scenario lookup_sidesteps_default_space_in_index)
-recipe main [
+def main [
   # pretend pointer to array from outside
   12:number <- copy 2
   13:number <- copy 34
@@ -159,7 +159,7 @@ tmp.properties.push_back(pair<string, string_tree*>("raw", NULL));
 //:: allocate in a default space with names
 
 :(scenario new_default_space)
-recipe main [
+def main [
   new-default-space
   x:number <- copy 0
   y:number <- copy 3
@@ -198,15 +198,15 @@ if (curr.name == "new-default-space") {
 //:: from a recipe
 
 :(scenario local_scope)
-recipe main [
+def main [
   1:address <- foo
   2:address <- foo
   3:boolean <- equal 1:address, 2:address
 ]
-recipe foo [
+def foo [
   local-scope
   x:number <- copy 34
-  reply default-space:address:shared:array:location
+  return default-space:address:shared:array:location
 ]
 # both calls to foo should have received the same default-space
 +mem: storing 1 in location 3
diff --git a/044space_surround.cc b/044space_surround.cc
index 35cb8f0d..7d16bfbd 100644
--- a/044space_surround.cc
+++ b/044space_surround.cc
@@ -6,7 +6,7 @@
 
 :(scenario surrounding_space)
 # location 1 in space 1 refers to the space surrounding the default space, here 20.
-recipe main [
+def main [
   # pretend shared:array:location; in practice we'll use new
   10:number <- copy 0  # refcount
   11:number <- copy 5  # length
@@ -19,7 +19,7 @@ recipe main [
   1:number <- copy 32
   1:number/space:1 <- copy 33
 ]
-recipe dummy [  # just for the /names: property above
+def dummy [  # just for the /names: property above
 ]
 # chain space: 10 + /*skip refcount*/1 + /*skip length*/1
 +mem: storing 20 in location 12
@@ -57,6 +57,6 @@ long long int space_index(const reagent& x) {
 }
 
 :(scenario permit_space_as_variable_name)
-recipe main [
+def main [
   space:number <- copy 0
 ]
diff --git a/045closure_name.cc b/045closure_name.cc
index 368377fd..33ab8c07 100644
--- a/045closure_name.cc
+++ b/045closure_name.cc
@@ -4,26 +4,26 @@
 //: surrounding space of the surrounding space, etc.
 
 :(scenario closure)
-recipe main [
+def main [
   default-space:address:shared:array:location <- new location:type, 30
   1:address:shared:array:location/names:new-counter <- new-counter
   2:number/raw <- increment-counter 1:address:shared:array:location/names:new-counter
   3:number/raw <- increment-counter 1:address:shared:array:location/names:new-counter
 ]
 
-recipe new-counter [
+def new-counter [
   default-space:address:shared:array:location <- new location:type, 30
   x:number <- copy 23
   y:number <- copy 3  # variable that will be incremented
-  reply default-space:address:shared:array:location
+  return default-space:address:shared:array:location
 ]
 
-recipe increment-counter [
+def increment-counter [
   default-space:address:shared:array:location <- new location:type, 30
   0:address:shared:array:location/names:new-counter <- next-ingredient  # outer space must be created by 'new-counter' above
   y:number/space:1 <- add y:number/space:1, 1  # increment
   y:number <- copy 234  # dummy
-  reply y:number/space:1
+  return y:number/space:1
 ]
 
 +name: lexically surrounding space for recipe increment-counter comes from new-counter
@@ -152,7 +152,7 @@ bool already_transformed(const reagent& r, const map<string, long long int>& nam
 
 :(scenario missing_surrounding_space)
 % Hide_errors = true;
-recipe f [
+def f [
   local-scope
   x:number/space:1 <- copy 34
 ]
diff --git a/046global.cc b/046global.cc
index 80a83863..5c294da3 100644
--- a/046global.cc
+++ b/046global.cc
@@ -10,7 +10,7 @@
 //: entirely.
 
 :(scenario global_space)
-recipe main [
+def main [
   # pretend shared:array:location; in practice we'll use new
   10:number <- copy 0  # refcount
   11:number <- copy 5  # length
@@ -72,7 +72,7 @@ global_space = 0;
 //: don't want to make them too comfortable to use.
 
 :(scenario global_space_with_names)
-recipe main [
+def main [
   global-space:address:shared:array:location <- new location:type, 10
   x:number <- copy 23
   1:number/space:global <- copy 24
diff --git a/047check_type_by_name.cc b/047check_type_by_name.cc
index 043d8089..98214f8a 100644
--- a/047check_type_by_name.cc
+++ b/047check_type_by_name.cc
@@ -8,7 +8,7 @@
 
 :(scenario transform_fails_on_reusing_name_with_different_type)
 % Hide_errors = true;
-recipe main [
+def main [
   x:number <- copy 1
   x:boolean <- copy 1
 ]
@@ -67,19 +67,19 @@ void check_type(set<reagent>& known, const reagent& x, const recipe_ordinal r) {
 }
 
 :(scenario transform_fills_in_missing_types)
-recipe main [
+def main [
   x:number <- copy 1
   y:number <- add x, 1
 ]
 
 :(scenario transform_fills_in_missing_types_in_product)
-recipe main [
+def main [
   x:number <- copy 1
   x <- copy 2
 ]
 
 :(scenario transform_fills_in_missing_types_in_product_and_ingredient)
-recipe main [
+def main [
   x:number <- copy 1
   x <- add x, 1
 ]
@@ -87,7 +87,7 @@ recipe main [
 
 :(scenario transform_fails_on_missing_types_in_first_mention)
 % Hide_errors = true;
-recipe main [
+def main [
   x <- copy 1
   x:number <- copy 2
 ]
@@ -95,7 +95,7 @@ recipe main [
 
 :(scenario typo_in_address_type_fails)
 % Hide_errors = true;
-recipe main [
+def main [
   y:address:shared:charcter <- new character:type
   *y <- copy 67
 ]
@@ -103,16 +103,16 @@ recipe main [
 
 :(scenario array_type_without_size_fails)
 % Hide_errors = true;
-recipe main [
+def main [
   x:array:number <- merge 2, 12, 13
 ]
 +error: main can't determine the size of array variable x. Either allocate it separately and make the type of x address:shared:..., or specify the length of the array in the type of x.
 
 :(scenarios transform)
 :(scenario transform_checks_types_of_identical_reagents_in_multiple_spaces)
-recipe foo [  # dummy
+def foo [  # dummy
 ]
-recipe main [
+def main [
   local-scope
   0:address:shared:array:location/names:foo <- copy 0  # specify surrounding space
   x:boolean <- copy 1/true
diff --git a/050scenario.cc b/050scenario.cc
index a2e28770..3257352f 100644
--- a/050scenario.cc
+++ b/050scenario.cc
@@ -172,11 +172,11 @@ void run_mu_scenario(const scenario& s) {
 :(scenario forbid_redefining_scenario_even_if_forced)
 % Hide_errors = true;
 % Disable_redefine_checks = true;
-recipe scenario-foo [
+def scenario-foo [
   1:number <- copy 34
 ]
 
-recipe scenario-foo [
+def scenario-foo [
   1:number <- copy 35
 ]
 +error: redefining recipe scenario-foo
@@ -190,7 +190,7 @@ recipe scenario-foo [
 //: 'run' interprets a string as a set of instructions
 
 :(scenario run)
-recipe main [
+def main [
   run [
     1:number <- copy 13
   ]
@@ -231,7 +231,7 @@ void bind_special_scenario_names(recipe_ordinal r) {
 }
 
 :(scenario run_multiple)
-recipe main [
+def main [
   run [
     1:number <- copy 13
   ]
@@ -253,7 +253,7 @@ Scenario_testing_scenario = false;
 :(scenario memory_check)
 % Scenario_testing_scenario = true;
 % Hide_errors = true;
-recipe main [
+def main [
   memory-should-contain [
     1 <- 13
   ]
@@ -389,7 +389,7 @@ void check_string(long long int address, const string& literal) {
 :(scenario memory_check_multiple)
 % Scenario_testing_scenario = true;
 % Hide_errors = true;
-recipe main [
+def main [
   memory-should-contain [
     1 <- 0
     1 <- 0
@@ -400,7 +400,7 @@ recipe main [
 :(scenario memory_check_string_length)
 % Scenario_testing_scenario = true;
 % Hide_errors = true;
-recipe main [
+def main [
   1:number <- copy 3
   2:number <- copy 97  # 'a'
   3:number <- copy 98  # 'b'
@@ -412,7 +412,7 @@ recipe main [
 +error: expected location 1 to contain length 2 of string [ab] but saw 3
 
 :(scenario memory_check_string)
-recipe main [
+def main [
   1:number <- copy 3
   2:number <- copy 97  # 'a'
   3:number <- copy 98  # 'b'
@@ -429,7 +429,7 @@ recipe main [
 :(scenario memory_invalid_string_check)
 % Scenario_testing_scenario = true;
 % Hide_errors = true;
-recipe main [
+def main [
   memory-should-contain [
     1 <- [abc]
   ]
@@ -439,7 +439,7 @@ recipe main [
 :(scenario memory_check_with_comment)
 % Scenario_testing_scenario = true;
 % Hide_errors = true;
-recipe main [
+def main [
   memory-should-contain [
     1 <- 34  # comment
   ]
@@ -456,7 +456,7 @@ recipe main [
 :(scenario trace_check_fails)
 % Scenario_testing_scenario = true;
 % Hide_errors = true;
-recipe main [
+def main [
   trace-should-contain [
     a: b
     a: d
@@ -515,7 +515,7 @@ vector<trace_line> parse_trace(const string& expected) {
 :(scenario trace_check_fails_in_nonfirst_line)
 % Scenario_testing_scenario = true;
 % Hide_errors = true;
-recipe main [
+def main [
   run [
     trace 1, [a], [b]
   ]
@@ -528,7 +528,7 @@ recipe main [
 
 :(scenario trace_check_passes_silently)
 % Scenario_testing_scenario = true;
-recipe main [
+def main [
   run [
     trace 1, [a], [b]
   ]
@@ -546,7 +546,7 @@ $error: 0
 :(scenario trace_negative_check_fails)
 % Scenario_testing_scenario = true;
 % Hide_errors = true;
-recipe main [
+def main [
   run [
     trace 1, [a], [b]
   ]
@@ -589,7 +589,7 @@ bool check_trace_missing(const string& in) {
 
 :(scenario trace_negative_check_passes_silently)
 % Scenario_testing_scenario = true;
-recipe main [
+def main [
   trace-should-not-contain [
     a: b
   ]
@@ -600,7 +600,7 @@ $error: 0
 :(scenario trace_negative_check_fails_on_any_unexpected_line)
 % Scenario_testing_scenario = true;
 % Hide_errors = true;
-recipe main [
+def main [
   run [
     trace 1, [a], [d]
   ]
@@ -612,7 +612,7 @@ recipe main [
 +error: unexpected [d] in trace with label a
 
 :(scenario trace_count_check)
-recipe main [
+def main [
   run [
     trace 1, [a], [foo]
   ]
@@ -666,7 +666,7 @@ case CHECK_TRACE_COUNT_FOR_LABEL: {
 :(scenario trace_count_check_2)
 % Scenario_testing_scenario = true;
 % Hide_errors = true;
-recipe main [
+def main [
   run [
     trace 1, [a], [foo]
   ]
diff --git a/052tangle.cc b/052tangle.cc
index e4548f58..f06ea4c0 100644
--- a/052tangle.cc
+++ b/052tangle.cc
@@ -7,7 +7,7 @@
 //: todo: switch recipe.steps to a more efficient data structure.
 
 :(scenario tangle_before)
-recipe main [
+def main [
   1:number <- copy 0
   <label1>
   3:number <- copy 0
@@ -152,7 +152,7 @@ void check_insert_fragments(unused recipe_ordinal) {
 }
 
 :(scenario tangle_before_and_after)
-recipe main [
+def main [
   1:number <- copy 0
   <label1>
   4:number <- copy 0
@@ -173,7 +173,7 @@ $mem: 4
 
 :(scenario tangle_ignores_jump_target)
 % Hide_errors = true;
-recipe main [
+def main [
   1:number <- copy 0
   +label1
   4:number <- copy 0
@@ -184,7 +184,7 @@ before +label1 [
 +error: can't tangle before label +label1
 
 :(scenario tangle_keeps_labels_separate)
-recipe main [
+def main [
   1:number <- copy 0
   <label1>
   <label2>
@@ -215,7 +215,7 @@ after <label2> [
 $mem: 6
 
 :(scenario tangle_stacks_multiple_fragments)
-recipe main [
+def main [
   1:number <- copy 0
   <label1>
   6:number <- copy 0
@@ -245,7 +245,7 @@ after <label1> [
 $mem: 6
 
 :(scenario tangle_supports_fragments_with_multiple_instructions)
-recipe main [
+def main [
   1:number <- copy 0
   <label1>
   6:number <- copy 0
@@ -269,13 +269,13 @@ after <label1> [
 $mem: 6
 
 :(scenario tangle_tangles_into_all_labels_with_same_name)
-recipe main [
+def main [
   1:number <- copy 10
   <label1>
   4:number <- copy 10
   recipe2
 ]
-recipe recipe2 [
+def recipe2 [
   1:number <- copy 11
   <label1>
   4:number <- copy 11
@@ -301,7 +301,7 @@ after <label1> [
 $mem: 8
 
 :(scenario tangle_tangles_into_all_labels_with_same_name_2)
-recipe main [
+def main [
   1:number <- copy 10
   <label1>
   <label1>
@@ -325,7 +325,7 @@ after <label1> [
 $mem: 6
 
 :(scenario tangle_tangles_into_all_labels_with_same_name_3)
-recipe main [
+def main [
   1:number <- copy 10
   <label1>
   <foo>
@@ -352,7 +352,7 @@ after <foo> [
 $mem: 6
 
 :(scenario tangle_handles_jump_target_inside_fragment)
-recipe main [
+def main [
   1:number <- copy 10
   <label1>
   4:number <- copy 10
@@ -373,7 +373,7 @@ before <label1> [
 $mem: 3
 
 :(scenario tangle_renames_jump_target)
-recipe main [
+def main [
   1:number <- copy 10
   <label1>
   +label2
@@ -395,7 +395,7 @@ before <label1> [
 $mem: 3
 
 :(scenario tangle_jump_to_base_recipe)
-recipe main [
+def main [
   1:number <- copy 10
   <label1>
   +label2
diff --git a/054dilated_reagent.cc b/054dilated_reagent.cc
index d90ed4df..71554ae2 100644
--- a/054dilated_reagent.cc
+++ b/054dilated_reagent.cc
@@ -4,13 +4,13 @@
 
 :(scenarios load)
 :(scenario dilated_reagent)
-recipe main [
+def main [
   {1: number, foo: bar} <- copy 34
 ]
 +parse:   product: 1: "number", {"foo": "bar"}
 
 :(scenario load_trailing_space_after_curly_bracket)
-recipe main [
+def main [
   # line below has a space at the end
   { 
 ]
@@ -18,14 +18,14 @@ recipe main [
 
 :(scenarios run)
 :(scenario dilated_reagent_with_comment)
-recipe main [
+def main [
   {1: number, foo: bar} <- copy 34  # test comment
 ]
 +parse:   product: 1: "number", {"foo": "bar"}
 $error: 0
 
 :(scenario dilated_reagent_with_comment_immediately_following)
-recipe main [
+def main [
   1:number <- copy {34: literal}  # test comment
 ]
 $error: 0
diff --git a/055parse_tree.cc b/055parse_tree.cc
index 73e737a4..a65f87e7 100644
--- a/055parse_tree.cc
+++ b/055parse_tree.cc
@@ -4,7 +4,7 @@
 // (address to array of charaters) to (list of numbers)".
 
 :(scenario dilated_reagent_with_nested_brackets)
-recipe main [
+def main [
   {1: number, foo: (bar (baz quux))} <- copy 34
 ]
 +parse:   product: 1: "number", {"foo": ("bar" ("baz" "quux"))}
@@ -59,7 +59,7 @@ string_tree* parse_string_tree(istream& in) {
 
 :(scenario dilated_reagent_with_type_tree)
 % Hide_errors = true;  // 'map' isn't defined yet
-recipe main [
+def main [
   {1: (foo (address array character) (bar number))} <- copy 34
 ]
 # just to avoid errors
@@ -70,7 +70,7 @@ container bar [
 +parse:   product: 1: ("foo" ("address" "array" "character") ("bar" "number"))
 
 :(scenario dilated_reagent_in_static_array)
-recipe main [
+def main [
   {1: (array (address shared number) 3)} <- create-array
   5:address:address:shared:number <- index-address {1: (array (address shared number) 3)}, 0
   *5:address:address:shared:number <- new number:type
@@ -83,7 +83,7 @@ recipe main [
 //: an exception is 'new', which takes a type tree as its ingredient *value*
 
 :(scenario dilated_reagent_with_new)
-recipe main [
+def main [
   x:address:shared:address:number <- new {(address number): type}
 ]
 +new: size of ("address" "number") is 1
diff --git a/056recipe_header.cc b/056recipe_header.cc
index 152f54da..dfe05167 100644
--- a/056recipe_header.cc
+++ b/056recipe_header.cc
@@ -2,14 +2,14 @@
 //: number of ingredients and yields some fixed number of products.
 
 :(scenario recipe_with_header)
-recipe main [
+def main [
   1:number/raw <- add2 3, 5
 ]
-recipe add2 x:number, y:number -> z:number [
+def add2 x:number, y:number -> z:number [
   local-scope
   load-ingredients
   z:number <- add x, y
-  reply z
+  return z
 ]
 +mem: storing 8 in location 1
 
@@ -48,38 +48,38 @@ void load_recipe_header(istream& in, recipe& result) {
 }
 
 :(scenario recipe_handles_stray_comma)
-recipe main [
+def main [
   1:number/raw <- add2 3, 5
 ]
-recipe add2 x:number, y:number -> z:number, [
+def add2 x:number, y:number -> z:number, [
   local-scope
   load-ingredients
   z:number <- add x, y
-  reply z
+  return z
 ]
 +mem: storing 8 in location 1
 
 :(scenario recipe_handles_stray_comma_2)
-recipe main [
+def main [
   foo
 ]
-recipe foo, [
+def foo, [
   1:number/raw <- add 2, 2
 ]
-recipe bar [
+def bar [
   1:number/raw <- add 2, 3
 ]
 +mem: storing 4 in location 1
 
 :(scenario recipe_handles_missing_bracket)
 % Hide_errors = true;
-recipe main
+def main
 ]
 +error: recipe body must begin with '['
 
 :(scenario recipe_handles_missing_bracket_2)
 % Hide_errors = true;
-recipe main
+def main
   local-scope
   {
   }
@@ -90,7 +90,7 @@ recipe main
 
 :(scenario recipe_handles_missing_bracket_3)
 % Hide_errors = true;
-recipe main  # comment
+def main  # comment
   local-scope
   {
   }
@@ -110,7 +110,7 @@ for (long long int i = 0; i < SIZE(x.products); ++i)
 //: If a recipe never mentions any ingredients or products, assume it has a header.
 
 :(scenario recipe_without_ingredients_or_products_has_header)
-recipe test [
+def test [
   1:number <- copy 34
 ]
 +parse: recipe test has a header
@@ -121,6 +121,7 @@ if (!result.has_header) {
   for (long long int i = 0; i < SIZE(result.steps); ++i) {
     const instruction& inst = result.steps.at(i);
     if ((inst.name == "reply" && !inst.ingredients.empty())
+        || (inst.name == "return" && !inst.ingredients.empty())
         || inst.name == "next-ingredient"
         || inst.name == "ingredient"
         || inst.name == "rewind-ingredients") {
@@ -182,25 +183,25 @@ case NEXT_INGREDIENT_WITHOUT_TYPECHECKING: {
 
 :(scenario show_clear_error_on_bad_call)
 % Hide_errors = true;
-recipe main [
+def main [
   1:number <- foo 34
 ]
-recipe foo x:point -> y:number [
+def foo x:point -> y:number [
   local-scope
   load-ingredients
-  reply 35
+  return 35
 ]
 +error: main: ingredient 0 has the wrong type at '1:number <- foo 34'
 
 :(scenario show_clear_error_on_bad_call_2)
 % Hide_errors = true;
-recipe main [
+def main [
   1:point <- foo 34
 ]
-recipe foo x:number -> y:number [
+def foo x:number -> y:number [
   local-scope
   load-ingredients
-  reply x
+  return x
 ]
 +error: main: product 0 has the wrong type at '1:point <- foo 34'
 
@@ -245,11 +246,11 @@ bool is_unique_address(reagent x) {
 
 :(scenario forbid_calls_with_nonshared_addresses)
 % Hide_errors = true;
-recipe main [
+def main [
   1:address:number <- copy 0
   foo 1:address:number
 ]
-recipe foo x:address:number [
+def foo x:address:number [
   local-scope
   load-ingredients
 ]
@@ -257,10 +258,10 @@ recipe foo x:address:number [
 
 :(scenario forbid_calls_with_nonshared_addresses_2)
 % Hide_errors = true;
-recipe main [
+def main [
   1:address:number <- foo
 ]
-recipe foo -> x:address:number [
+def foo -> x:address:number [
   local-scope
   load-ingredients
   x <- copy 0
@@ -272,13 +273,13 @@ recipe foo -> x:address:number [
 :(scenarios transform)
 :(scenario recipe_headers_are_checked)
 % Hide_errors = true;
-recipe add2 x:number, y:number -> z:number [
+def add2 x:number, y:number -> z:number [
   local-scope
   load-ingredients
   z:address:number <- copy 0/unsafe
-  reply z
+  return z
 ]
-+error: add2: replied with the wrong type at 'reply z'
++error: add2: replied with the wrong type at 'return z'
 
 :(before "End Checks")
 Transform.push_back(check_reply_instructions_against_header);  // idempotent
@@ -290,7 +291,7 @@ void check_reply_instructions_against_header(const recipe_ordinal r) {
   trace(9991, "transform") << "--- checking reply instructions against header for " << caller_recipe.name << end();
   for (long long int i = 0; i < SIZE(caller_recipe.steps); ++i) {
     const instruction& inst = caller_recipe.steps.at(i);
-    if (inst.name != "reply") continue;
+    if (inst.name != "reply" && inst.name != "return") continue;
     if (SIZE(caller_recipe.products) != SIZE(inst.ingredients)) {
       raise << maybe(caller_recipe.name) << "replied with the wrong number of products at '" << to_string(inst) << "'\n" << end();
       continue;
@@ -304,20 +305,20 @@ void check_reply_instructions_against_header(const recipe_ordinal r) {
 
 :(scenario recipe_headers_are_checked_2)
 % Hide_errors = true;
-recipe add2 x:number, y:number [
+def add2 x:number, y:number [
   local-scope
   load-ingredients
   z:address:number <- copy 0/unsafe
-  reply z
+  return z
 ]
-+error: add2: replied with the wrong number of products at 'reply z'
++error: add2: replied with the wrong number of products at 'return z'
 
 :(scenario recipe_headers_check_for_duplicate_names)
 % Hide_errors = true;
-recipe add2 x:number, x:number -> z:number [
+def add2 x:number, x:number -> z:number [
   local-scope
   load-ingredients
-  reply z
+  return z
 ]
 +error: add2: x can't repeat in the ingredients
 
@@ -344,14 +345,14 @@ void check_header_ingredients(const recipe_ordinal r) {
 
 :(scenarios run)
 :(scenario deduce_instruction_types_from_recipe_header)
-recipe main [
+def main [
   1:number/raw <- add2 3, 5
 ]
-recipe add2 x:number, y:number -> z:number [
+def add2 x:number, y:number -> z:number [
   local-scope
   load-ingredients
   z <- add x, y  # no type for z
-  reply z
+  return z
 ]
 +mem: storing 8 in location 1
 
@@ -399,14 +400,14 @@ void deduce_types_from_header(const recipe_ordinal r) {
 //: in the header.
 
 :(scenario reply_based_on_header)
-recipe main [
+def main [
   1:number/raw <- add2 3, 5
 ]
-recipe add2 x:number, y:number -> z:number [
+def add2 x:number, y:number -> z:number [
   local-scope
   load-ingredients
   z <- add x, y
-  reply
+  return
 ]
 +mem: storing 8 in location 1
 
@@ -420,11 +421,12 @@ void fill_in_reply_ingredients(recipe_ordinal r) {
   trace(9991, "transform") << "--- fill in reply ingredients from header for recipe " << caller_recipe.name << end();
   for (long long int i = 0; i < SIZE(caller_recipe.steps); ++i) {
     instruction& inst = caller_recipe.steps.at(i);
-    if (inst.name == "reply")
+    if (inst.name == "reply" || inst.name == "return")
       add_header_products(inst, caller_recipe);
   }
   // fall through reply
-  if (caller_recipe.steps.at(SIZE(caller_recipe.steps)-1).name != "reply") {
+  const instruction& final_instruction = caller_recipe.steps.at(SIZE(caller_recipe.steps)-1);
+  if (final_instruction.name != "reply" && final_instruction.name != "return") {
     instruction inst;
     inst.name = "reply";
     add_header_products(inst, caller_recipe);
@@ -433,7 +435,7 @@ void fill_in_reply_ingredients(recipe_ordinal r) {
 }
 
 void add_header_products(instruction& inst, const recipe& caller_recipe) {
-  assert(inst.name == "reply");
+  assert(inst.name == "reply" || inst.name == "return");
   // collect any products with the same names as ingredients
   for (long long int i = 0; i < SIZE(caller_recipe.products); ++i) {
     // if the ingredient is missing, add it from the header
@@ -449,24 +451,24 @@ void add_header_products(instruction& inst, const recipe& caller_recipe) {
 }
 
 :(scenario explicit_reply_ignores_header)
-recipe main [
+def main [
   1:number/raw, 2:number/raw <- add2 3, 5
 ]
-recipe add2 a:number, b:number -> y:number, z:number [
+def add2 a:number, b:number -> y:number, z:number [
   local-scope
   load-ingredients
   y <- add a, b
   z <- subtract a, b
-  reply a, z
+  return a, z
 ]
 +mem: storing 3 in location 1
 +mem: storing -2 in location 2
 
 :(scenario reply_on_fallthrough_based_on_header)
-recipe main [
+def main [
   1:number/raw <- add2 3, 5
 ]
-recipe add2 x:number, y:number -> z:number [
+def add2 x:number, y:number -> z:number [
   local-scope
   load-ingredients
   z <- add x, y
@@ -475,27 +477,27 @@ recipe add2 x:number, y:number -> z:number [
 +mem: storing 8 in location 1
 
 :(scenario reply_on_fallthrough_already_exists)
-recipe main [
+def main [
   1:number/raw <- add2 3, 5
 ]
-recipe add2 x:number, y:number -> z:number [
+def add2 x:number, y:number -> z:number [
   local-scope
   load-ingredients
   z <- add x, y  # no type for z
-  reply z
+  return z
 ]
-+transform: instruction: reply z
++transform: instruction: return z
 -transform: instruction: reply z:number
 +mem: storing 8 in location 1
 
 :(scenario recipe_headers_perform_same_ingredient_check)
 % Hide_errors = true;
-recipe main [
+def main [
   1:number <- copy 34
   2:number <- copy 34
   3:number <- add2 1:number, 2:number
 ]
-recipe add2 x:number, y:number -> x:number [
+def add2 x:number, y:number -> x:number [
   local-scope
   load-ingredients
 ]
diff --git a/057static_dispatch.cc b/057static_dispatch.cc
index e413f083..c160394d 100644
--- a/057static_dispatch.cc
+++ b/057static_dispatch.cc
@@ -3,13 +3,13 @@
 //: names like 'print' or 'length' in many mutually extensible ways.
 
 :(scenario static_dispatch)
-recipe main [
+def main [
   7:number/raw <- test 3
 ]
-recipe test a:number -> z:number [
+def test a:number -> z:number [
   z <- copy 1
 ]
-recipe test a:number, b:number -> z:number [
+def test a:number, b:number -> z:number [
   z <- copy 2
 ]
 +mem: storing 1 in location 7
@@ -115,13 +115,13 @@ string next_unused_recipe_name(const string& recipe_name) {
 //: call with the most suitable variant.
 
 :(scenario static_dispatch_picks_most_similar_variant)
-recipe main [
+def main [
   7:number/raw <- test 3, 4, 5
 ]
-recipe test a:number -> z:number [
+def test a:number -> z:number [
   z <- copy 1
 ]
-recipe test a:number, b:number -> z:number [
+def test a:number, b:number -> z:number [
   z <- copy 2
 ]
 +mem: storing 2 in location 7
@@ -336,37 +336,37 @@ bool next_stash(const call& c, instruction* stash_inst) {
 }
 
 :(scenario static_dispatch_disabled_in_recipe_without_variants)
-recipe main [
+def main [
   1:number <- test 3
 ]
-recipe test [
+def test [
   2:number <- next-ingredient  # ensure no header
-  reply 34
+  return 34
 ]
 +mem: storing 34 in location 1
 
 :(scenario static_dispatch_disabled_on_headerless_definition)
 % Hide_errors = true;
-recipe test a:number -> z:number [
+def test a:number -> z:number [
   z <- copy 1
 ]
-recipe test [
-  reply 34
+def test [
+  return 34
 ]
 +error: redefining recipe test
 
 :(scenario static_dispatch_disabled_on_headerless_definition_2)
 % Hide_errors = true;
-recipe test [
-  reply 34
+def test [
+  return 34
 ]
-recipe test a:number -> z:number [
+def test a:number -> z:number [
   z <- copy 1
 ]
 +error: redefining recipe test
 
 :(scenario static_dispatch_on_primitive_names)
-recipe main [
+def main [
   1:number <- copy 34
   2:number <- copy 34
   3:boolean <- equal 1:number, 2:number
@@ -376,7 +376,7 @@ recipe main [
 ]
 
 # temporarily hardcode number equality to always fail
-recipe equal x:number, y:number -> z:boolean [
+def equal x:number, y:number -> z:boolean [
   local-scope
   load-ingredients
   z <- copy 0/false
@@ -387,15 +387,15 @@ recipe equal x:number, y:number -> z:boolean [
 +mem: storing 1 in location 6
 
 :(scenario static_dispatch_works_with_dummy_results_for_containers)
-recipe main [
+def main [
   _ <- test 3, 4
 ]
-recipe test a:number -> z:point [
+def test a:number -> z:point [
   local-scope
   load-ingredients
   z <- merge a, 0
 ]
-recipe test a:number, b:number -> z:point [
+def test a:number, b:number -> z:point [
   local-scope
   load-ingredients
   z <- merge a, b
@@ -403,14 +403,14 @@ recipe test a:number, b:number -> z:point [
 $error: 0
 
 :(scenario static_dispatch_works_with_compound_type_containing_container_defined_after_first_use)
-recipe main [
+def main [
   x:address:shared:foo <- new foo:type
   test x
 ]
 container foo [
   x:number
 ]
-recipe test a:address:shared:foo -> z:number [
+def test a:address:shared:foo -> z:number [
   local-scope
   load-ingredients
   z:number <- get *a, x:offset
@@ -418,11 +418,11 @@ recipe test a:address:shared:foo -> z:number [
 $error: 0
 
 :(scenario static_dispatch_works_with_compound_type_containing_container_defined_after_second_use)
-recipe main [
+def main [
   x:address:shared:foo <- new foo:type
   test x
 ]
-recipe test a:address:shared:foo -> z:number [
+def test a:address:shared:foo -> z:number [
   local-scope
   load-ingredients
   z:number <- get *a, x:offset
@@ -433,78 +433,78 @@ container foo [
 $error: 0
 
 :(scenario static_dispatch_prefers_literals_to_be_numbers_rather_than_addresses)
-recipe main [
+def main [
   1:number <- foo 0
 ]
-recipe foo x:address:number -> y:number [
-  reply 34
+def foo x:address:number -> y:number [
+  return 34
 ]
-recipe foo x:number -> y:number [
-  reply 35
+def foo x:number -> y:number [
+  return 35
 ]
 +mem: storing 35 in location 1
 
 :(scenario static_dispatch_on_non_literal_character_ignores_variant_with_numbers)
 % Hide_errors = true;
-recipe main [
+def main [
   local-scope
   x:character <- copy 10/newline
   1:number/raw <- foo x
 ]
-recipe foo x:number -> y:number [
+def foo x:number -> y:number [
   load-ingredients
-  reply 34
+  return 34
 ]
 +error: main: ingredient 0 has the wrong type at '1:number/raw <- foo x'
 -mem: storing 34 in location 1
 
 :(scenario static_dispatch_dispatches_literal_to_boolean_before_character)
-recipe main [
+def main [
   1:number/raw <- foo 0  # valid literal for boolean
 ]
-recipe foo x:character -> y:number [
+def foo x:character -> y:number [
   local-scope
   load-ingredients
-  reply 34
+  return 34
 ]
-recipe foo x:boolean -> y:number [
+def foo x:boolean -> y:number [
   local-scope
   load-ingredients
-  reply 35
+  return 35
 ]
 # boolean variant is preferred
 +mem: storing 35 in location 1
 
 :(scenario static_dispatch_dispatches_literal_to_character_when_out_of_boolean_range)
-recipe main [
+def main [
   1:number/raw <- foo 97  # not a valid literal for boolean
 ]
-recipe foo x:character -> y:number [
+def foo x:character -> y:number [
   local-scope
   load-ingredients
-  reply 34
+  return 34
 ]
-recipe foo x:boolean -> y:number [
+def foo x:boolean -> y:number [
   local-scope
   load-ingredients
-  reply 35
+  return 35
 ]
 # character variant is preferred
 +mem: storing 34 in location 1
 
 :(scenario static_dispatch_dispatches_literal_to_number_if_at_all_possible)
-recipe main [
+def main [
   1:number/raw <- foo 97
 ]
-recipe foo x:character -> y:number [
+def foo x:character -> y:number [
   local-scope
   load-ingredients
-  reply 34
+  return 34
 ]
-recipe foo x:number -> y:number [
+def foo x:number -> y:number [
   local-scope
   load-ingredients
-  reply 35
+  return 35
 ]
 # number variant is preferred
 +mem: storing 35 in location 1
@@ -523,42 +523,42 @@ string header_label(recipe_ordinal r) {
 }
 
 :(scenario reload_variant_retains_other_variants)
-recipe main [
+def main [
   1:number <- copy 34
   2:number <- foo 1:number
 ]
-recipe foo x:number -> y:number [
+def foo x:number -> y:number [
   local-scope
   load-ingredients
-  reply 34
+  return 34
 ]
-recipe foo x:address:number -> y:number [
+def foo x:address:number -> y:number [
   local-scope
   load-ingredients
-  reply 35
+  return 35
 ]
-recipe! foo x:address:number -> y:number [
+def! foo x:address:number -> y:number [
   local-scope
   load-ingredients
-  reply 36
+  return 36
 ]
 +mem: storing 34 in location 2
 $error: 0
 
 :(scenario dispatch_errors_come_after_unknown_name_errors)
 % Hide_errors = true;
-recipe main [
+def main [
   y:number <- foo x
 ]
-recipe foo a:number -> b:number [
+def foo a:number -> b:number [
   local-scope
   load-ingredients
-  reply 34
+  return 34
 ]
-recipe foo a:boolean -> b:number [
+def foo a:boolean -> b:number [
   local-scope
   load-ingredients
-  reply 35
+  return 35
 ]
 +error: main: missing type for x in 'y:number <- foo x'
 +error: main: failed to find a matching call for 'y:number <- foo x'
diff --git a/058shape_shifting_container.cc b/058shape_shifting_container.cc
index 89460a8b..d8f3b001 100644
--- a/058shape_shifting_container.cc
+++ b/058shape_shifting_container.cc
@@ -5,7 +5,7 @@ container foo:_t [
   x:_t
   y:number
 ]
-recipe main [
+def main [
   1:foo:number <- merge 12, 13
   3:foo:point <- merge 14, 15, 16
 ]
@@ -21,7 +21,7 @@ container foo:_a:_b [
   x:_a
   y:_b
 ]
-recipe main [
+def main [
   1:foo:number:boolean <- merge 34, 1/true
 ]
 $error: 0
@@ -31,7 +31,7 @@ container foo:_a:_b [
   x:_a
   y:_b
 ]
-recipe main [
+def main [
   1:address:shared:array:character <- new [abc]
   # compound types for type ingredients
   {2: (foo number (address shared array character))} <- merge 34/x, 1:address:shared:array:character/y
@@ -47,7 +47,7 @@ container bar:_a:_b [
   # dilated element
   {data: (foo _a (address shared _b))}
 ]
-recipe main [
+def main [
   1:address:shared:array:character <- new [abc]
   2:bar:number:array:character <- merge 34/x, 1:address:shared:array:character/y
 ]
@@ -112,7 +112,7 @@ exclusive-container foo:_t [
   x:_t
   y:number
 ]
-recipe main [
+def main [
   1:foo:number <- merge 0/x, 34
   3:foo:point <- merge 0/x, 15, 16
   6:foo:point <- merge 1/y, 23
@@ -157,7 +157,7 @@ container foo:_t [
   x:_t
   y:number
 ]
-recipe main [
+def main [
   1:foo:point <- merge 14, 15, 16
   2:number <- get 1:foo:point, y:offset
 ]
@@ -178,7 +178,7 @@ container foo:_t [
   x:_t
   y:number
 ]
-recipe main [
+def main [
   1:foo:point <- merge 14, 15, 16
   2:point <- get 1:foo:point, x:offset
 ]
@@ -190,7 +190,7 @@ container foo:_t [
   x:_t
   y:number
 ]
-recipe main [
+def main [
   1:foo:address:point <- merge 34/unsafe, 48
   2:address:point <- get 1:foo:address:point, x:offset
 ]
@@ -205,7 +205,7 @@ container bar [
   x:foo:point
   y:number
 ]
-recipe main [
+def main [
   1:bar <- merge 14, 15, 16, 17
   2:number <- get 1:bar, 1:offset
 ]
@@ -216,7 +216,7 @@ container foo:_a:_b [
   x:_a
   y:_b
 ]
-recipe main [
+def main [
   1:address:shared:array:character <- new [abc]
   {2: (foo number (address shared array character))} <- merge 34/x, 1:address:shared:array:character/y
   3:address:shared:array:character <- get {2: (foo number (address shared array character))}, y:offset
@@ -488,7 +488,7 @@ container foo:_t [
   x:_t
   y:number
 ]
-recipe main [
+def main [
   10:foo:point <- merge 14, 15, 16
   1:number <- get 10:foo, 1:offset
 ]
@@ -501,7 +501,7 @@ container foo:_t [
   x:_t
   y:number
 ]
-recipe main [
+def main [
   10:foo:point <- merge 14, 15, 16
   1:address:number <- get-address 10:foo:point, 1:offset
 ]
@@ -528,7 +528,7 @@ exclusive-container bar [
   x:number
   y:number
 ]
-recipe main [
+def main [
   1:foo:bar <- merge 23, 1/y, 34
 ]
 +mem: storing 23 in location 1
@@ -546,7 +546,7 @@ exclusive-container bar [
   x:number
   y:number
 ]
-recipe main [
+def main [
   1:foo:bar <- merge 23, 1/y, 34, 35
 ]
 +error: main: too many ingredients in '1:foo:bar <- merge 23, 1/y, 34, 35'
@@ -560,7 +560,7 @@ container bar [
   x:number
   y:number
 ]
-recipe main [
+def main [
   1:foo:bar <- merge 1/y, 23, 34
 ]
 +mem: storing 1 in location 1
@@ -577,7 +577,7 @@ container bar [
   x:number
   y:number
 ]
-recipe main [
+def main [
   1:foo:bar <- merge 0/x, 23
 ]
 $error: 0
@@ -592,7 +592,7 @@ container bar [
   x:number
   y:number
 ]
-recipe main [
+def main [
   1:foo:bar <- merge 1/y, 23
 ]
 +error: main: too few ingredients in '1:foo:bar <- merge 1/y, 23'
diff --git a/059shape_shifting_recipe.cc b/059shape_shifting_recipe.cc
index 13df6388..d1ba0e4a 100644
--- a/059shape_shifting_recipe.cc
+++ b/059shape_shifting_recipe.cc
@@ -1,18 +1,18 @@
 //:: Like container definitions, recipes too can contain type parameters.
 
 :(scenario shape_shifting_recipe)
-recipe main [
+def main [
   10:point <- merge 14, 15
   11:point <- foo 10:point
 ]
 # non-matching variant
-recipe foo a:number -> result:number [
+def foo a:number -> result:number [
   local-scope
   load-ingredients
   result <- copy 34
 ]
 # matching shape-shifting variant
-recipe foo a:_t -> result:_t [
+def foo a:_t -> result:_t [
   local-scope
   load-ingredients
   result <- copy a
@@ -542,18 +542,18 @@ void ensure_all_concrete_types(/*const*/ reagent& x, const recipe& exemplar) {
 }
 
 :(scenario shape_shifting_recipe_2)
-recipe main [
+def main [
   10:point <- merge 14, 15
   11:point <- foo 10:point
 ]
 # non-matching shape-shifting variant
-recipe foo a:_t, b:_t -> result:number [
+def foo a:_t, b:_t -> result:number [
   local-scope
   load-ingredients
   result <- copy 34
 ]
 # matching shape-shifting variant
-recipe foo a:_t -> result:_t [
+def foo a:_t -> result:_t [
   local-scope
   load-ingredients
   result <- copy a
@@ -562,12 +562,12 @@ recipe foo a:_t -> result:_t [
 +mem: storing 15 in location 12
 
 :(scenario shape_shifting_recipe_nonroot)
-recipe main [
+def main [
   10:foo:point <- merge 14, 15, 16
   20:point/raw <- bar 10:foo:point
 ]
 # shape-shifting recipe with type ingredient following some other type
-recipe bar a:foo:_t -> result:_t [
+def bar a:foo:_t -> result:_t [
   local-scope
   load-ingredients
   result <- get a, x:offset
@@ -584,22 +584,22 @@ container c:_a:_b [
   a:_a
   b:_b
 ]
-recipe main [
+def main [
   s:address:shared:array:character <- new [abc]
   {x: (c (address shared array character) number)} <- merge s, 34
   foo x
 ]
-recipe foo x:c:_bar:_baz [
+def foo x:c:_bar:_baz [
   local-scope
   load-ingredients
 ]
 
 :(scenario shape_shifting_recipe_type_deduction_ignores_offsets)
-recipe main [
+def main [
   10:foo:point <- merge 14, 15, 16
   20:point/raw <- bar 10:foo:point
 ]
-recipe bar a:foo:_t -> result:_t [
+def bar a:foo:_t -> result:_t [
   local-scope
   load-ingredients
   x:number <- copy 1
@@ -613,16 +613,16 @@ container foo:_t [
 +mem: storing 15 in location 21
 
 :(scenario shape_shifting_recipe_empty)
-recipe main [
+def main [
   foo 1
 ]
 # shape-shifting recipe with no body
-recipe foo a:_t [
+def foo a:_t [
 ]
 # shouldn't crash
 
 :(scenario shape_shifting_recipe_handles_shape_shifting_new_ingredient)
-recipe main [
+def main [
   1:address:shared:foo:point <- bar 3
   11:foo:point <- copy *1:address:shared:foo:point
 ]
@@ -630,7 +630,7 @@ container foo:_t [
   x:_t
   y:number
 ]
-recipe bar x:number -> result:address:shared:foo:_t [
+def bar x:number -> result:address:shared:foo:_t [
   local-scope
   load-ingredients
   # new refers to _t in its ingredient *value*
@@ -641,11 +641,11 @@ recipe bar x:number -> result:address:shared:foo:_t [
 +mem: storing 0 in location 13
 
 :(scenario shape_shifting_recipe_handles_shape_shifting_new_ingredient_2)
-recipe main [
+def main [
   1:address:shared:foo:point <- bar 3
   11:foo:point <- copy *1:address:shared:foo:point
 ]
-recipe bar x:number -> result:address:shared:foo:_t [
+def bar x:number -> result:address:shared:foo:_t [
   local-scope
   load-ingredients
   # new refers to _t in its ingredient *value*
@@ -661,14 +661,14 @@ container foo:_t [
 +mem: storing 0 in location 13
 
 :(scenario shape_shifting_recipe_supports_compound_types)
-recipe main [
+def main [
   1:address:shared:point <- new point:type
   2:address:number <- get-address *1:address:shared:point, y:offset
   *2:address:number <- copy 34
   3:address:shared:point <- bar 1:address:shared:point  # specialize _t to address:shared:point
   4:point <- copy *3:address:shared:point
 ]
-recipe bar a:_t -> result:_t [
+def bar a:_t -> result:_t [
   local-scope
   load-ingredients
   result <- copy a
@@ -677,26 +677,26 @@ recipe bar a:_t -> result:_t [
 
 :(scenario shape_shifting_recipe_error)
 % Hide_errors = true;
-recipe main [
+def main [
   a:number <- copy 3
   b:address:shared:number <- foo a
 ]
-recipe foo a:_t -> b:_t [
+def foo a:_t -> b:_t [
   load-ingredients
   b <- copy a
 ]
 +error: main: no call found for 'b:address:shared:number <- foo a'
 
 :(scenario specialize_inside_recipe_without_header)
-recipe main [
+def main [
   foo 3
 ]
-recipe foo [
+def foo [
   local-scope
   x:number <- next-ingredient  # ensure no header
   1:number/raw <- bar x  # call a shape-shifting recipe
 ]
-recipe bar x:_elem -> y:_elem [
+def bar x:_elem -> y:_elem [
   local-scope
   load-ingredients
   y <- add x, 1
@@ -704,12 +704,12 @@ recipe bar x:_elem -> y:_elem [
 +mem: storing 4 in location 1
 
 :(scenario specialize_with_literal)
-recipe main [
+def main [
   local-scope
   # permit literal to map to number
   1:number/raw <- foo 3
 ]
-recipe foo x:_elem -> y:_elem [
+def foo x:_elem -> y:_elem [
   local-scope
   load-ingredients
   y <- add x, 1
@@ -717,12 +717,12 @@ recipe foo x:_elem -> y:_elem [
 +mem: storing 4 in location 1
 
 :(scenario specialize_with_literal_2)
-recipe main [
+def main [
   local-scope
   # permit literal to map to character
   1:character/raw <- foo 3
 ]
-recipe foo x:_elem -> y:_elem [
+def foo x:_elem -> y:_elem [
   local-scope
   load-ingredients
   y <- add x, 1
@@ -730,12 +730,12 @@ recipe foo x:_elem -> y:_elem [
 +mem: storing 4 in location 1
 
 :(scenario specialize_with_literal_3)
-recipe main [
+def main [
   local-scope
   # permit '0' to map to address to shape-shifting type-ingredient
   1:address:shared:character/raw <- foo 0
 ]
-recipe foo x:address:_elem -> y:address:_elem [
+def foo x:address:_elem -> y:address:_elem [
   local-scope
   load-ingredients
   y <- copy x
@@ -745,12 +745,12 @@ $error: 0
 
 :(scenario specialize_with_literal_4)
 % Hide_errors = true;
-recipe main [
+def main [
   local-scope
   # ambiguous call: what's the type of its ingredient?!
   foo 0
 ]
-recipe foo x:address:_elem -> y:address:_elem [
+def foo x:address:_elem -> y:address:_elem [
   local-scope
   load-ingredients
   y <- copy x
@@ -759,10 +759,10 @@ recipe foo x:address:_elem -> y:address:_elem [
 +error: foo: failed to map a type to y
 
 :(scenario specialize_with_literal_5)
-recipe main [
+def main [
   foo 3, 4  # recipe mapping two variables to literals
 ]
-recipe foo x:_elem, y:_elem [
+def foo x:_elem, y:_elem [
   local-scope
   load-ingredients
   1:number/raw <- add x, y
@@ -771,22 +771,22 @@ recipe foo x:_elem, y:_elem [
 
 :(scenario multiple_shape_shifting_variants)
 # try to call two different shape-shifting recipes with the same name
-recipe main [
+def main [
   e1:d1:number <- merge 3
   e2:d2:number <- merge 4, 5
   1:number/raw <- foo e1
   2:number/raw <- foo e2
 ]
 # the two shape-shifting definitions
-recipe foo a:d1:_elem -> b:number [
+def foo a:d1:_elem -> b:number [
   local-scope
   load-ingredients
-  reply 34
+  return 34
 ]
-recipe foo a:d2:_elem -> b:number [
+def foo a:d2:_elem -> b:number [
   local-scope
   load-ingredients
-  reply 35
+  return 35
 ]
 # the shape-shifting containers they use
 container d1:_elem [
@@ -801,21 +801,21 @@ container d2:_elem [
 
 :(scenario multiple_shape_shifting_variants_2)
 # static dispatch between shape-shifting variants, _including pointer lookups_
-recipe main [
+def main [
   e1:d1:number <- merge 3
   e2:address:shared:d2:number <- new {(d2 number): type}
   1:number/raw <- foo e1
   2:number/raw <- foo *e2  # different from previous scenario
 ]
-recipe foo a:d1:_elem -> b:number [
+def foo a:d1:_elem -> b:number [
   local-scope
   load-ingredients
-  reply 34
+  return 34
 ]
-recipe foo a:d2:_elem -> b:number [
+def foo a:d2:_elem -> b:number [
   local-scope
   load-ingredients
-  reply 35
+  return 35
 ]
 container d1:_elem [
   x:_elem
@@ -829,15 +829,15 @@ container d2:_elem [
 
 :(scenario missing_type_in_shape_shifting_recipe)
 % Hide_errors = true;
-recipe main [
+def main [
   a:d1:number <- merge 3
   foo a
 ]
-recipe foo a:d1:_elem -> b:number [
+def foo a:d1:_elem -> b:number [
   local-scope
   load-ingredients
   copy e  # no such variable
-  reply 34
+  return 34
 ]
 container d1:_elem [
   x:_elem
@@ -848,15 +848,15 @@ container d1:_elem [
 
 :(scenario missing_type_in_shape_shifting_recipe_2)
 % Hide_errors = true;
-recipe main [
+def main [
   a:d1:number <- merge 3
   foo a
 ]
-recipe foo a:d1:_elem -> b:number [
+def foo a:d1:_elem -> b:number [
   local-scope
   load-ingredients
   get e, x:offset  # unknown variable in a 'get', which does some extra checking
-  reply 34
+  return 34
 ]
 container d1:_elem [
   x:_elem
@@ -867,108 +867,108 @@ container d1:_elem [
 
 :(scenarios transform)
 :(scenario specialize_recursive_shape_shifting_recipe)
-recipe main [
+def main [
   1:number <- copy 34
   2:number <- foo 1:number
 ]
-recipe foo x:_elem -> y:number [
+def foo x:_elem -> y:number [
   local-scope
   load-ingredients
   {
     break
     y:number <- foo x
   }
-  reply y
+  return y
 ]
 +transform: new specialization: foo_2
 # transform terminates
 
 :(scenarios run)
 :(scenario specialize_most_similar_variant)
-recipe main [
+def main [
   1:address:shared:number <- new number:type
   2:number <- foo 1:address:shared:number
 ]
-recipe foo x:_elem -> y:number [
+def foo x:_elem -> y:number [
   local-scope
   load-ingredients
-  reply 34
+  return 34
 ]
-recipe foo x:address:shared:_elem -> y:number [
+def foo x:address:shared:_elem -> y:number [
   local-scope
   load-ingredients
-  reply 35
+  return 35
 ]
 +mem: storing 35 in location 2
 
 :(scenario specialize_most_similar_variant_2)
 # version with headers padded with lots of unrelated concrete types
-recipe main [
+def main [
   1:number <- copy 23
   2:address:shared:array:number <- copy 0
   3:number <- foo 2:address:shared:array:number, 1:number
 ]
 # variant with concrete type
-recipe foo dummy:address:shared:array:number, x:number -> y:number, dummy:address:shared:array:number [
+def foo dummy:address:shared:array:number, x:number -> y:number, dummy:address:shared:array:number [
   local-scope
   load-ingredients
-  reply 34
+  return 34
 ]
 # shape-shifting variant
-recipe foo dummy:address:shared:array:number, x:_elem -> y:number, dummy:address:shared:array:number [
+def foo dummy:address:shared:array:number, x:_elem -> y:number, dummy:address:shared:array:number [
   local-scope
   load-ingredients
-  reply 35
+  return 35
 ]
 # prefer the concrete variant
 +mem: storing 34 in location 3
 
 :(scenario specialize_most_similar_variant_3)
-recipe main [
+def main [
   1:address:shared:array:character <- new [abc]
   foo 1:address:shared:array:character
 ]
-recipe foo x:address:shared:array:character [
+def foo x:address:shared:array:character [
   2:number <- copy 34
 ]
-recipe foo x:address:_elem [
+def foo x:address:_elem [
   2:number <- copy 35
 ]
 # make sure the more precise version was used
 +mem: storing 34 in location 2
 
 :(scenario specialize_literal_as_number)
-recipe main [
+def main [
   1:number <- foo 23
 ]
-recipe foo x:_elem -> y:number [
+def foo x:_elem -> y:number [
   local-scope
   load-ingredients
-  reply 34
+  return 34
 ]
-recipe foo x:character -> y:number [
+def foo x:character -> y:number [
   local-scope
   load-ingredients
-  reply 35
+  return 35
 ]
 +mem: storing 34 in location 1
 
 :(scenario specialize_literal_as_number_2)
 # version calling with literal
-recipe main [
+def main [
   1:number <- foo 0
 ]
 # variant with concrete type
-recipe foo x:number -> y:number [
+def foo x:number -> y:number [
   local-scope
   load-ingredients
-  reply 34
+  return 34
 ]
 # shape-shifting variant
-recipe foo x:address:shared:_elem -> y:number [
+def foo x:address:shared:_elem -> y:number [
   local-scope
   load-ingredients
-  reply 35
+  return 35
 ]
 # prefer the concrete variant, ignore concrete types in scoring the shape-shifting variant
 +mem: storing 34 in location 1
diff --git a/060immutable.cc b/060immutable.cc
index 3017a6d0..5d56622f 100644
--- a/060immutable.cc
+++ b/060immutable.cc
@@ -4,12 +4,12 @@
 //: One hole for now: variables in surrounding spaces are implicitly mutable.
 
 :(scenario can_modify_value_ingredients)
-recipe main [
+def main [
   local-scope
   p:address:shared:point <- new point:type
   foo *p
 ]
-recipe foo p:point [
+def foo p:point [
   local-scope
   load-ingredients
   x:address:number <- get-address p, x:offset
@@ -18,12 +18,12 @@ recipe foo p:point [
 $error: 0
 
 :(scenario can_modify_ingredients_that_are_also_products)
-recipe main [
+def main [
   local-scope
   p:address:shared:point <- new point:type
   p <- foo p
 ]
-recipe foo p:address:shared:point -> p:address:shared:point [
+def foo p:address:shared:point -> p:address:shared:point [
   local-scope
   load-ingredients
   x:address:number <- get-address *p, x:offset
@@ -32,12 +32,12 @@ recipe foo p:address:shared:point -> p:address:shared:point [
 $error: 0
 
 :(scenario ignore_literal_ingredients_for_immutability_checks)
-recipe main [
+def main [
   local-scope
   p:address:shared:d1 <- new d1:type
   q:number <- foo p
 ]
-recipe foo p:address:shared:d1 -> q:number [
+def foo p:address:shared:d1 -> q:number [
   local-scope
   load-ingredients
   x:address:shared:d1 <- new d1:type
@@ -52,12 +52,12 @@ $error: 0
 
 :(scenario cannot_modify_immutable_ingredients)
 % Hide_errors = true;
-recipe main [
+def main [
   local-scope
   x:address:shared:number <- new number:type
   foo x
 ]
-recipe foo x:address:shared:number [
+def foo x:address:shared:number [
   local-scope
   load-ingredients
   *x <- copy 34
@@ -66,12 +66,12 @@ recipe foo x:address:shared:number [
 
 :(scenario cannot_take_address_inside_immutable_ingredients)
 % Hide_errors = true;
-recipe main [
+def main [
   local-scope
   p:address:shared:point <- new point:type
   foo p
 ]
-recipe foo p:address:shared:point [
+def foo p:address:shared:point [
   local-scope
   load-ingredients
   x:address:number <- get-address *p, x:offset
@@ -81,17 +81,17 @@ recipe foo p:address:shared:point [
 
 :(scenario cannot_call_mutating_recipes_on_immutable_ingredients)
 % Hide_errors = true;
-recipe main [
+def main [
   local-scope
   p:address:shared:point <- new point:type
   foo p
 ]
-recipe foo p:address:shared:point [
+def foo p:address:shared:point [
   local-scope
   load-ingredients
   bar p
 ]
-recipe bar p:address:shared:point -> p:address:shared:point [
+def bar p:address:shared:point -> p:address:shared:point [
   local-scope
   load-ingredients
   x:address:number <- get-address *p, x:offset
@@ -101,12 +101,12 @@ recipe bar p:address:shared:point -> p:address:shared:point [
 
 :(scenario cannot_modify_copies_of_immutable_ingredients)
 % Hide_errors = true;
-recipe main [
+def main [
   local-scope
   p:address:shared:point <- new point:type
   foo p
 ]
-recipe foo p:address:shared:point [
+def foo p:address:shared:point [
   local-scope
   load-ingredients
   q:address:shared:point <- copy p
@@ -115,12 +115,12 @@ recipe foo p:address:shared:point [
 +error: foo: cannot modify q after instruction 'x:address:number <- get-address *q, x:offset' because that would modify ingredient p which is not also a product of foo
 
 :(scenario can_modify_copies_of_mutable_ingredients)
-recipe main [
+def main [
   local-scope
   p:address:shared:point <- new point:type
   foo p
 ]
-recipe foo p:address:shared:point -> p:address:shared:point [
+def foo p:address:shared:point -> p:address:shared:point [
   local-scope
   load-ingredients
   q:address:shared:point <- copy p
@@ -133,10 +133,10 @@ $error: 0
 container foo [
   x:address:shared:array:number  # contains an address
 ]
-recipe main [
+def main [
   # don't run anything
 ]
-recipe foo a:address:shared:foo [
+def foo a:address:shared:foo [
   local-scope
   load-ingredients
   x:address:shared:array:number <- get *a, x:offset  # just a regular get of the container
@@ -149,10 +149,10 @@ recipe foo a:address:shared:foo [
 container foo [
   x:address:shared:array:number  # contains an address
 ]
-recipe main [
+def main [
   # don't run anything
 ]
-recipe foo a:address:shared:foo [
+def foo a:address:shared:foo [
   local-scope
   load-ingredients
   b:foo <- merge 0  # completely unrelated to 'a'
@@ -167,10 +167,10 @@ $error: 0
 container foo [
   x:number
 ]
-recipe main [
+def main [
   # don't run anything
 ]
-recipe foo a:address:shared:array:address:number [
+def foo a:address:shared:array:address:number [
   local-scope
   load-ingredients
   x:address:number <- index *a, 0  # just a regular index of the array
@@ -183,10 +183,10 @@ recipe foo a:address:shared:array:address:number [
 container foo [
   x:address:shared:array:number  # contains an address
 ]
-recipe main [
+def main [
   # don't run anything
 ]
-recipe foo a:address:shared:array:address:number [
+def foo a:address:shared:array:address:number [
   local-scope
   load-ingredients
   b:address:shared:array:address:number <- new {(address number): type}, 3  # completely unrelated to 'a'
@@ -199,17 +199,17 @@ $error: 0
 container test-list [
   next:address:shared:test-list
 ]
-recipe main [
+def main [
   local-scope
   p:address:shared:test-list <- new test-list:type
   foo p
 ]
-recipe foo p:address:shared:test-list [
+def foo p:address:shared:test-list [
   local-scope
   load-ingredients
   p2:address:shared:test-list <- bar p
 ]
-recipe bar x:address:shared:test-list -> y:address:shared:test-list [
+def bar x:address:shared:test-list -> y:address:shared:test-list [
   local-scope
   load-ingredients
   y <- get *x, next:offset
@@ -217,18 +217,18 @@ recipe bar x:address:shared:test-list -> y:address:shared:test-list [
 $error: 0
 
 :(scenario handle_optional_ingredients_in_immutability_checks)
-recipe main [
+def main [
   k:address:shared:number <- new number:type
   test k
 ]
 # recipe taking an immutable address ingredient
-recipe test k:address:shared:number [
+def test k:address:shared:number [
   local-scope
   load-ingredients
   foo k
 ]
 # ..calling a recipe with an optional address ingredient
-recipe foo -> [
+def foo -> [
   local-scope
   load-ingredients
   k:address:shared:number, found?:boolean <- next-ingredient
@@ -237,17 +237,17 @@ $error: 0
 
 //: when checking for immutable ingredients, remember to take space into account
 :(scenario check_space_of_reagents_in_immutability_checks)
-recipe main [
+def main [
   a:address:shared:array:location <- new-closure
   b:address:shared:number <- new number:type
   run-closure b:address:shared:number, a:address:shared:array:location
 ]
-recipe new-closure [
+def new-closure [
   new-default-space
   x:address:shared:number <- new number:type
-  reply default-space
+  return default-space
 ]
-recipe run-closure x:address:shared:number, s:address:shared:array:location [
+def run-closure x:address:shared:number, s:address:shared:array:location [
   local-scope
   load-ingredients
   0:address:shared:array:location/names:new-closure <- copy s
@@ -336,18 +336,18 @@ set<long long int> scan_contained_in_product_indices(const instruction& inst, se
 container test-list [
   next:address:shared:test-list
 ]
-recipe main [
+def main [
   local-scope
   p:address:shared:test-list <- new test-list:type
   foo p
 ]
-recipe foo p:address:shared:test-list [  # p is immutable
+def foo p:address:shared:test-list [  # p is immutable
   local-scope
   load-ingredients
   p2:address:shared:test-list <- test-next p  # p2 is immutable
   p3:address:address:shared:test-list <- get-address *p2, next:offset  # signal modification of p2
 ]
-recipe test-next x:address:shared:test-list -> y:address:shared:test-list/contained-in:x [
+def test-next x:address:shared:test-list -> y:address:shared:test-list/contained-in:x [
   local-scope
   load-ingredients
   y <- get *x, next:offset
@@ -447,23 +447,23 @@ set<long long int> ingredient_indices(const instruction& inst, const set<reagent
 container test-list [
   next:address:shared:test-list
 ]
-recipe main [
+def main [
   local-scope
   p:address:shared:test-list <- new test-list:type
   foo p
 ]
-recipe foo p:address:shared:test-list -> p:address:shared:test-list [
+def foo p:address:shared:test-list -> p:address:shared:test-list [
   local-scope
   load-ingredients
   p2:address:shared:test-list <- test-next p
   p <- test-remove p2, p
 ]
-recipe test-next x:address:shared:test-list -> y:address:shared:test-list [
+def test-next x:address:shared:test-list -> y:address:shared:test-list [
   local-scope
   load-ingredients
   y <- get *x, next:offset
 ]
-recipe test-remove x:address:shared:test-list/contained-in:from, from:address:shared:test-list -> from:address:shared:test-list [
+def test-remove x:address:shared:test-list/contained-in:from, from:address:shared:test-list -> from:address:shared:test-list [
   local-scope
   load-ingredients
   x2:address:address:shared:test-list <- get-address *x, next:offset  # pretend modification
diff --git a/061recipe.cc b/061recipe.cc
index a173daac..dffd53a2 100644
--- a/061recipe.cc
+++ b/061recipe.cc
@@ -5,10 +5,10 @@
 //: todo: support storing shape-shifting recipes into recipe variables and calling them
 
 :(scenario call_literal_recipe)
-recipe main [
+def main [
   1:number <- call f, 34
 ]
-recipe f x:number -> y:number [
+def f x:number -> y:number [
   local-scope
   load-ingredients
   y <- copy x
@@ -16,11 +16,11 @@ recipe f x:number -> y:number [
 +mem: storing 34 in location 1
 
 :(scenario call_variable)
-recipe main [
+def main [
   {1: (recipe number -> number)} <- copy f
   2:number <- call {1: (recipe number -> number)}, 34
 ]
-recipe f x:number -> y:number [
+def f x:number -> y:number [
   local-scope
   load-ingredients
   y <- copy x
@@ -75,10 +75,10 @@ case CALL: {
 
 :(scenario call_check_literal_recipe)
 % Hide_errors = true;
-recipe main [
+def main [
   1:number <- call f, 34
 ]
-recipe f x:point -> y:point [
+def f x:point -> y:point [
   local-scope
   load-ingredients
   y <- copy x
@@ -88,11 +88,11 @@ recipe f x:point -> y:point [
 
 :(scenario call_check_variable_recipe)
 % Hide_errors = true;
-recipe main [
+def main [
   {1: (recipe point -> point)} <- copy f
   2:number <- call {1: (recipe point -> point)}, 34
 ]
-recipe f x:point -> y:point [
+def f x:point -> y:point [
   local-scope
   load-ingredients
   y <- copy x
@@ -153,12 +153,12 @@ bool is_mu_recipe(reagent r) {
 
 :(scenario copy_typecheck_recipe_variable)
 % Hide_errors = true;
-recipe main [
+def main [
   3:number <- copy 34  # abc def
   {1: (recipe number -> number)} <- copy f  # store literal in a matching variable
   {2: (recipe boolean -> boolean)} <- copy {1: (recipe number -> number)}  # mismatch between recipe variables
 ]
-recipe f x:number -> y:number [
+def f x:number -> y:number [
   local-scope
   load-ingredients
   y <- copy x
@@ -167,10 +167,10 @@ recipe f x:number -> y:number [
 
 :(scenario copy_typecheck_recipe_variable_2)
 % Hide_errors = true;
-recipe main [
+def main [
   {1: (recipe number -> number)} <- copy f  # mismatch with a recipe literal
 ]
-recipe f x:boolean -> y:boolean [
+def f x:boolean -> y:boolean [
   local-scope
   load-ingredients
   y <- copy x
diff --git a/062scheduler.cc b/062scheduler.cc
index 17e39c46..10a4d46a 100644
--- a/062scheduler.cc
+++ b/062scheduler.cc
@@ -2,14 +2,14 @@
 //: guarantees on how the operations in each are interleaved with each other.
 
 :(scenario scheduler)
-recipe f1 [
+def f1 [
   start-running f2
   # wait for f2 to run
   {
     jump-unless 1:number, -1
   }
 ]
-recipe f2 [
+def f2 [
   1:number <- copy 1
 ]
 +schedule: f1
@@ -181,7 +181,7 @@ case START_RUNNING: {
 
 :(scenario scheduler_runs_single_routine)
 % Scheduling_interval = 1;
-recipe f1 [
+def f1 [
   1:number <- copy 0
   2:number <- copy 0
 ]
@@ -192,12 +192,12 @@ recipe f1 [
 
 :(scenario scheduler_interleaves_routines)
 % Scheduling_interval = 1;
-recipe f1 [
+def f1 [
   start-running f2
   1:number <- copy 0
   2:number <- copy 0
 ]
-recipe f2 [
+def f2 [
   3:number <- copy 0
   4:number <- copy 0
 ]
@@ -213,24 +213,24 @@ recipe f2 [
 +run: 2:number <- copy 0
 
 :(scenario start_running_takes_ingredients)
-recipe f1 [
+def f1 [
   start-running f2, 3
   # wait for f2 to run
   {
     jump-unless 1:number, -1
   }
 ]
-recipe f2 [
+def f2 [
   1:number <- next-ingredient
   2:number <- add 1:number, 1
 ]
 +mem: storing 4 in location 2
 
 :(scenario start_running_returns_routine_id)
-recipe f1 [
+def f1 [
   1:number <- start-running f2
 ]
-recipe f2 [
+def f2 [
   12:number <- copy 44
 ]
 +mem: storing 2 in location 1
@@ -244,7 +244,7 @@ recipe f2 [
 % Routines.push_back(new routine(f2));
 % Routines.back()->state = COMPLETED;  // f2 not meant to run
 # must have at least one routine without escaping
-recipe f3 [
+def f3 [
   3:number <- copy 0
 ]
 # by interleaving '+' lines with '-' lines, we allow f1 and f3 to run in any order
@@ -258,7 +258,7 @@ recipe f3 [
 :(scenario scheduler_starts_at_middle_of_routines)
 % Routines.push_back(new routine(COPY));
 % Routines.back()->state = COMPLETED;
-recipe f1 [
+def f1 [
   1:number <- copy 0
   2:number <- copy 0
 ]
@@ -270,12 +270,12 @@ recipe f1 [
 :(scenario scheduler_terminates_routines_after_errors)
 % Hide_errors = true;
 % Scheduling_interval = 2;
-recipe f1 [
+def f1 [
   start-running f2
   1:number <- copy 0
   2:number <- copy 0
 ]
-recipe f2 [
+def f2 [
   # divide by 0 twice
   3:number <- divide-with-remainder 4, 0
   4:number <- divide-with-remainder 4, 0
@@ -292,11 +292,11 @@ recipe f2 [
 //:: Routines are marked completed when their parent completes.
 
 :(scenario scheduler_kills_orphans)
-recipe main [
+def main [
   start-running f1
   # f1 never actually runs because its parent completes without waiting for it
 ]
-recipe f1 [
+def f1 [
   1:number <- copy 0
 ]
 -schedule: f1
@@ -323,13 +323,13 @@ bool has_completed_parent(long long int routine_index) {
 
 :(scenario routine_state_test)
 % Scheduling_interval = 2;
-recipe f1 [
+def f1 [
   1:number/child-id <- start-running f2
   12:number <- copy 0  # race condition since we don't care about location 12
   # thanks to Scheduling_interval, f2's one instruction runs in between here and completes
   2:number/state <- routine-state 1:number/child-id
 ]
-recipe f2 [
+def f2 [
   12:number <- copy 0
   # trying to run a second instruction marks routine as completed
 ]
@@ -445,7 +445,7 @@ case _DUMP_ROUTINES: {
 
 :(scenario routine_discontinues_past_limit)
 % Scheduling_interval = 2;
-recipe f1 [
+def f1 [
   1:number/child-id <- start-running f2
   limit-time 1:number/child-id, 10
   # padding loop just to make sure f2 has time to completed
@@ -453,7 +453,7 @@ recipe f1 [
   2:number <- subtract 2:number, 1
   jump-if 2:number, -2:offset
 ]
-recipe f2 [
+def f2 [
   jump -1:offset  # run forever
   $print [should never get here], 10/newline
 ]
@@ -514,7 +514,7 @@ case LIMIT_TIME: {
 //:: make sure that each routine gets a different alloc to start
 
 :(scenario new_concurrent)
-recipe f1 [
+def f1 [
   start-running f2
   1:address:shared:number/raw <- new number:type
   # wait for f2 to complete
@@ -522,7 +522,7 @@ recipe f1 [
     loop-unless 4:number/raw
   }
 ]
-recipe f2 [
+def f2 [
   2:address:shared:number/raw <- new number:type
   # hack: assumes scheduler implementation
   3:boolean/raw <- equal 1:address:shared:number/raw, 2:address:shared:number/raw
diff --git a/063wait.cc b/063wait.cc
index c57f6b28..2d0e2d8d 100644
--- a/063wait.cc
+++ b/063wait.cc
@@ -4,14 +4,14 @@
 //: operate.
 
 :(scenario wait_for_location)
-recipe f1 [
+def f1 [
   1:number <- copy 0
   start-running f2
   wait-for-location 1:number
   # now wait for f2 to run and modify location 1 before using its value
   2:number <- copy 1:number
 ]
-recipe f2 [
+def f2 [
   1:number <- copy 34
 ]
 # if we got the synchronization wrong we'd be storing 0 in location 2
@@ -65,14 +65,14 @@ for (long long int i = 0; i < SIZE(Routines); ++i) {
 //: also allow waiting on a routine to stop running
 
 :(scenario wait_for_routine)
-recipe f1 [
+def f1 [
   1:number <- copy 0
   12:number/routine <- start-running f2
   wait-for-routine 12:number/routine
   # now wait for f2 to run and modify location 1 before using its value
   3:number <- copy 1:number
 ]
-recipe f2 [
+def f2 [
   1:number <- copy 34
 ]
 +schedule: f1
diff --git a/070text.mu b/070text.mu
index f6005f58..b69db18a 100644
--- a/070text.mu
+++ b/070text.mu
@@ -2,20 +2,20 @@
 
 # to-text-line gets called implicitly in various places
 # define it to be identical to 'to-text' by default
-recipe to-text-line x:_elem -> y:address:shared:array:character [
+def to-text-line x:_elem -> y:address:shared:array:character [
   local-scope
   load-ingredients
   y <- to-text x
 ]
 
 # to-text on text is just the identity function
-recipe to-text x:address:shared:array:character -> y:address:shared:array:character [
+def to-text x:address:shared:array:character -> y:address:shared:array:character [
   local-scope
   load-ingredients
-  reply x
+  return x
 ]
 
-recipe equal a:address:shared:array:character, b:address:shared:array:character -> result:boolean [
+def equal a:address:shared:array:character, b:address:shared:array:character -> result:boolean [
   local-scope
   load-ingredients
   a-len:number <- length *a
@@ -25,7 +25,7 @@ recipe equal a:address:shared:array:character, b:address:shared:array:character
     trace 99, [text-equal], [comparing lengths]
     length-equal?:boolean <- equal a-len, b-len
     break-if length-equal?
-    reply 0
+    return 0
   }
   # compare each corresponding character
   trace 99, [text-equal], [comparing characters]
@@ -38,12 +38,12 @@ recipe equal a:address:shared:array:character, b:address:shared:array:character
     {
       chars-match?:boolean <- equal a2, b2
       break-if chars-match?
-      reply 0
+      return 0
     }
     i <- add i, 1
     loop
   }
-  reply 1
+  return 1
 ]
 
 scenario text-equal-reflexive [
@@ -117,7 +117,7 @@ container buffer [
   data:address:shared:array:character
 ]
 
-recipe new-buffer capacity:number -> result:address:shared:buffer [
+def new-buffer capacity:number -> result:address:shared:buffer [
   local-scope
   load-ingredients
   result <- new buffer:type
@@ -125,10 +125,10 @@ recipe new-buffer capacity:number -> result:address:shared:buffer [
   *len:address:number <- copy 0
   s:address:address:shared:array:character <- get-address *result, data:offset
   *s <- new character:type, capacity
-  reply result
+  return result
 ]
 
-recipe grow-buffer in:address:shared:buffer -> in:address:shared:buffer [
+def grow-buffer in:address:shared:buffer -> in:address:shared:buffer [
   local-scope
   load-ingredients
   # double buffer size
@@ -150,7 +150,7 @@ recipe grow-buffer in:address:shared:buffer -> in:address:shared:buffer [
   }
 ]
 
-recipe buffer-full? in:address:shared:buffer -> result:boolean [
+def buffer-full? in:address:shared:buffer -> result:boolean [
   local-scope
   load-ingredients
   len:number <- get *in, length:offset
@@ -160,7 +160,7 @@ recipe buffer-full? in:address:shared:buffer -> result:boolean [
 ]
 
 # most broadly applicable definition of append to a buffer: just call to-text
-recipe append buf:address:shared:buffer, x:_elem -> buf:address:shared:buffer [
+def append buf:address:shared:buffer, x:_elem -> buf:address:shared:buffer [
   local-scope
   load-ingredients
   text:address:shared:array:character <- to-text x
@@ -176,7 +176,7 @@ recipe append buf:address:shared:buffer, x:_elem -> buf:address:shared:buffer [
   }
 ]
 
-recipe append in:address:shared:buffer, c:character -> in:address:shared:buffer [
+def append in:address:shared:buffer, c:character -> in:address:shared:buffer [
   local-scope
   load-ingredients
   len:address:number <- get-address *in, length:offset
@@ -185,9 +185,9 @@ recipe append in:address:shared:buffer, c:character -> in:address:shared:buffer
     backspace?:boolean <- equal c, 8/backspace
     break-unless backspace?
     empty?:boolean <- lesser-or-equal *len, 0
-    reply-if empty?
+    return-if empty?
     *len <- subtract *len, 1
-    reply
+    return
   }
   {
     # grow buffer if necessary
@@ -263,14 +263,14 @@ scenario buffer-append-handles-backspace [
   ]
 ]
 
-recipe to-text n:number -> result:address:shared:array:character [
+def to-text n:number -> result:address:shared:array:character [
   local-scope
   load-ingredients
   # is n zero?
   {
     break-if n
     result <- new [0]
-    reply
+    return
   }
   # save sign
   negate-result:boolean <- copy 0
@@ -317,27 +317,27 @@ recipe to-text n:number -> result:address:shared:array:character [
   }
 ]
 
-recipe to-text x:boolean -> result:address:shared:array:character [
+def to-text x:boolean -> result:address:shared:array:character [
   local-scope
   load-ingredients
   n:number <- copy x:boolean
   result <- to-text n
 ]
 
-recipe to-text x:address:_elem -> result:address:shared:array:character [
+def to-text x:address:_elem -> result:address:shared:array:character [
   local-scope
   load-ingredients
   n:number <- copy x
   result <- to-text n
 ]
 
-recipe buffer-to-array in:address:shared:buffer -> result:address:shared:array:character [
+def buffer-to-array in:address:shared:buffer -> result:address:shared:array:character [
   local-scope
   load-ingredients
   {
     # propagate null buffer
     break-if in
-    reply 0
+    return 0
   }
   len:number <- get *in, length:offset
   s:address:shared:array:character <- get *in, data:offset
@@ -387,7 +387,7 @@ scenario integer-to-decimal-digit-negative [
   ]
 ]
 
-recipe append a:address:shared:array:character, b:address:shared:array:character -> result:address:shared:array:character [
+def append a:address:shared:array:character, b:address:shared:array:character -> result:address:shared:array:character [
   local-scope
   load-ingredients
   # result = new character[a.length + b.length]
@@ -449,13 +449,13 @@ scenario replace-character-in-text [
   ]
 ]
 
-recipe replace s:address:shared:array:character, oldc:character, newc:character, from:number/optional -> s:address:shared:array:character [
+def replace s:address:shared:array:character, oldc:character, newc:character, from:number/optional -> s:address:shared:array:character [
   local-scope
   load-ingredients
   len:number <- length *s
   i:number <- find-next s, oldc, from
   done?:boolean <- greater-or-equal i, len
-  reply-if done?, s/same-as-ingredient:0
+  return-if done?, s/same-as-ingredient:0
   dest:address:character <- index-address *s, i
   *dest <- copy newc
   i <- add i, 1
@@ -507,7 +507,7 @@ scenario replace-all-characters [
 ]
 
 # replace underscores in first with remaining args
-recipe interpolate template:address:shared:array:character -> result:address:shared:array:character [
+def interpolate template:address:shared:array:character -> result:address:shared:array:character [
   local-scope
   load-ingredients  # consume just the template
   # compute result-len, space to allocate for result
@@ -621,68 +621,68 @@ scenario interpolate-at-end [
 ]
 
 # result:boolean <- space? c:character
-recipe space? c:character -> result:boolean [
+def space? c:character -> result:boolean [
   local-scope
   load-ingredients
   # most common case first
   result <- equal c, 32/space
-  reply-if result
+  return-if result
   result <- equal c, 10/newline
-  reply-if result
+  return-if result
   result <- equal c, 9/tab
-  reply-if result
+  return-if result
   result <- equal c, 13/carriage-return
-  reply-if result
+  return-if result
   # remaining uncommon cases in sorted order
   # http://unicode.org code-points in unicode-set Z and Pattern_White_Space
   result <- equal c, 11/ctrl-k
-  reply-if result
+  return-if result
   result <- equal c, 12/ctrl-l
-  reply-if result
+  return-if result
   result <- equal c, 133/ctrl-0085
-  reply-if result
+  return-if result
   result <- equal c, 160/no-break-space
-  reply-if result
+  return-if result
   result <- equal c, 5760/ogham-space-mark
-  reply-if result
+  return-if result
   result <- equal c, 8192/en-quad
-  reply-if result
+  return-if result
   result <- equal c, 8193/em-quad
-  reply-if result
+  return-if result
   result <- equal c, 8194/en-space
-  reply-if result
+  return-if result
   result <- equal c, 8195/em-space
-  reply-if result
+  return-if result
   result <- equal c, 8196/three-per-em-space
-  reply-if result
+  return-if result
   result <- equal c, 8197/four-per-em-space
-  reply-if result
+  return-if result
   result <- equal c, 8198/six-per-em-space
-  reply-if result
+  return-if result
   result <- equal c, 8199/figure-space
-  reply-if result
+  return-if result
   result <- equal c, 8200/punctuation-space
-  reply-if result
+  return-if result
   result <- equal c, 8201/thin-space
-  reply-if result
+  return-if result
   result <- equal c, 8202/hair-space
-  reply-if result
+  return-if result
   result <- equal c, 8206/left-to-right
-  reply-if result
+  return-if result
   result <- equal c, 8207/right-to-left
-  reply-if result
+  return-if result
   result <- equal c, 8232/line-separator
-  reply-if result
+  return-if result
   result <- equal c, 8233/paragraph-separator
-  reply-if result
+  return-if result
   result <- equal c, 8239/narrow-no-break-space
-  reply-if result
+  return-if result
   result <- equal c, 8287/medium-mathematical-space
-  reply-if result
+  return-if result
   result <- equal c, 12288/ideographic-space
 ]
 
-recipe trim s:address:shared:array:character -> result:address:shared:array:character [
+def trim s:address:shared:array:character -> result:address:shared:array:character [
   local-scope
   load-ingredients
   len:number <- length *s
@@ -693,7 +693,7 @@ recipe trim s:address:shared:array:character -> result:address:shared:array:char
       at-end?:boolean <- greater-or-equal start, len
       break-unless at-end?
       result <- new character:type, 0
-      reply
+      return
     }
     curr:character <- index *s, start
     whitespace?:boolean <- space? curr
@@ -788,7 +788,7 @@ scenario trim-newline-tab [
   ]
 ]
 
-recipe find-next text:address:shared:array:character, pattern:character, idx:number -> next-index:number [
+def find-next text:address:shared:array:character, pattern:character, idx:number -> next-index:number [
   local-scope
   load-ingredients
   len:number <- length *text
@@ -801,7 +801,7 @@ recipe find-next text:address:shared:array:character, pattern:character, idx:num
     idx <- add idx, 1
     loop
   }
-  reply idx
+  return idx
 ]
 
 scenario text-find-next [
@@ -886,7 +886,7 @@ scenario text-find-next-second [
 
 # search for a pattern of multiple characters
 # fairly dumb algorithm
-recipe find-next text:address:shared:array:character, pattern:address:shared:array:character, idx:number -> next-index:number [
+def find-next text:address:shared:array:character, pattern:address:shared:array:character, idx:number -> next-index:number [
   local-scope
   load-ingredients
   first:character <- index *pattern, 0
@@ -903,7 +903,7 @@ recipe find-next text:address:shared:array:character, pattern:address:shared:arr
     idx <- find-next text, first, idx
     loop
   }
-  reply idx
+  return idx
 ]
 
 scenario find-next-text-1 [
@@ -962,7 +962,7 @@ scenario find-next-suffix-match-2 [
 ]
 
 # checks if pattern matches at index 'idx'
-recipe match-at text:address:shared:array:character, pattern:address:shared:array:character, idx:number -> result:boolean [
+def match-at text:address:shared:array:character, pattern:address:shared:array:character, idx:number -> result:boolean [
   local-scope
   load-ingredients
   pattern-len:number <- length *pattern
@@ -972,7 +972,7 @@ recipe match-at text:address:shared:array:character, pattern:address:shared:arra
     x <- subtract x, pattern-len
     enough-room?:boolean <- lesser-or-equal idx, x
     break-if enough-room?
-    reply 0/not-found
+    return 0/not-found
   }
   # check each character of pattern
   pattern-idx:number <- copy 0
@@ -984,13 +984,13 @@ recipe match-at text:address:shared:array:character, pattern:address:shared:arra
     {
       match?:boolean <- equal c, exp
       break-if match?
-      reply 0/not-found
+      return 0/not-found
     }
     idx <- add idx, 1
     pattern-idx <- add pattern-idx, 1
     loop
   }
-  reply 1/found
+  return 1/found
 ]
 
 scenario match-at-checks-pattern-at-index [
@@ -1090,7 +1090,7 @@ scenario match-at-inside-bounds-2 [
   ]
 ]
 
-recipe split s:address:shared:array:character, delim:character -> result:address:shared:array:address:shared:array:character [
+def split s:address:shared:array:character, delim:character -> result:address:shared:array:address:shared:array:character [
   local-scope
   load-ingredients
   # empty text? return empty array
@@ -1099,7 +1099,7 @@ recipe split s:address:shared:array:character, delim:character -> result:address
     empty?:boolean <- equal len, 0
     break-unless empty?
     result <- new {(address shared array character): type}, 0
-    reply
+    return
   }
   # count #pieces we need room for
   count:number <- copy 1  # n delimiters = n+1 pieces
@@ -1217,7 +1217,7 @@ scenario text-split-empty-piece [
   ]
 ]
 
-recipe split-first text:address:shared:array:character, delim:character -> x:address:shared:array:character, y:address:shared:array:character [
+def split-first text:address:shared:array:character, delim:character -> x:address:shared:array:character, y:address:shared:array:character [
   local-scope
   load-ingredients
   # empty text? return empty texts
@@ -1227,7 +1227,7 @@ recipe split-first text:address:shared:array:character, delim:character -> x:add
     break-unless empty?
     x:address:shared:array:character <- new []
     y:address:shared:array:character <- new []
-    reply
+    return
   }
   idx:number <- find-next text, delim, 0
   x:address:shared:array:character <- copy-range text, 0, idx
@@ -1248,7 +1248,7 @@ scenario text-split-first [
   ]
 ]
 
-recipe copy-range buf:address:shared:array:character, start:number, end:number -> result:address:shared:array:character [
+def copy-range buf:address:shared:array:character, start:number, end:number -> result:address:shared:array:character [
   local-scope
   load-ingredients
   # if end is out of bounds, trim it
@@ -1305,24 +1305,24 @@ scenario text-copy-out-of-bounds-2 [
   ]
 ]
 
-recipe min x:number, y:number -> z:number [
+def min x:number, y:number -> z:number [
   local-scope
   load-ingredients
   {
     return-x?:boolean <- lesser-than x, y
     break-if return-x?
-    reply y
+    return y
   }
-  reply x
+  return x
 ]
 
-recipe max x:number, y:number -> z:number [
+def max x:number, y:number -> z:number [
   local-scope
   load-ingredients
   {
     return-x?:boolean <- greater-than x, y
     break-if return-x?
-    reply y
+    return y
   }
-  reply x
+  return x
 ]
diff --git a/071channel.mu b/071channel.mu
index 3cff3b7c..a9068603 100644
--- a/071channel.mu
+++ b/071channel.mu
@@ -31,7 +31,7 @@ container channel [
   data:address:shared:array:character
 ]
 
-recipe new-channel capacity:number -> result:address:shared:channel [
+def new-channel capacity:number -> result:address:shared:channel [
   local-scope
   load-ingredients
   result <- new channel:type
@@ -47,7 +47,7 @@ recipe new-channel capacity:number -> result:address:shared:channel [
   *dest <- new character:type, capacity
 ]
 
-recipe write chan:address:shared:channel, val:character -> chan:address:shared:channel [
+def write chan:address:shared:channel, val:character -> chan:address:shared:channel [
   local-scope
   load-ingredients
   {
@@ -73,7 +73,7 @@ recipe write chan:address:shared:channel, val:character -> chan:address:shared:c
   }
 ]
 
-recipe read chan:address:shared:channel -> result:character, chan:address:shared:channel [
+def read chan:address:shared:channel -> result:character, chan:address:shared:channel [
   local-scope
   load-ingredients
   {
@@ -98,7 +98,7 @@ recipe read chan:address:shared:channel -> result:character, chan:address:shared
   }
 ]
 
-recipe clear-channel chan:address:shared:channel -> chan:address:shared:channel [
+def clear-channel chan:address:shared:channel -> chan:address:shared:channel [
   local-scope
   load-ingredients
   {
@@ -175,7 +175,7 @@ scenario channel-wrap [
 ## helpers
 
 # An empty channel has first-empty and first-full both at the same value.
-recipe channel-empty? chan:address:shared:channel -> result:boolean [
+def channel-empty? chan:address:shared:channel -> result:boolean [
   local-scope
   load-ingredients
   # return chan.first-full == chan.first-free
@@ -186,7 +186,7 @@ recipe channel-empty? chan:address:shared:channel -> result:boolean [
 
 # A full channel has first-empty just before first-full, wasting one slot.
 # (Other alternatives: https://en.wikipedia.org/wiki/Circular_buffer#Full_.2F_Empty_Buffer_Distinction)
-recipe channel-full? chan:address:shared:channel -> result:boolean [
+def channel-full? chan:address:shared:channel -> result:boolean [
   local-scope
   load-ingredients
   # tmp = chan.first-free + 1
@@ -204,7 +204,7 @@ recipe channel-full? chan:address:shared:channel -> result:boolean [
   result <- equal full, tmp
 ]
 
-recipe channel-capacity chan:address:shared:channel -> result:number [
+def channel-capacity chan:address:shared:channel -> result:number [
   local-scope
   load-ingredients
   q:address:shared:array:character <- get *chan, data:offset
@@ -264,7 +264,7 @@ scenario channel-read-not-full [
 ]
 
 # helper for channels of characters in particular
-recipe buffer-lines in:address:shared:channel, out:address:shared:channel -> out:address:shared:channel, in:address:shared:channel [
+def buffer-lines in:address:shared:channel, out:address:shared:channel -> out:address:shared:channel, in:address:shared:channel [
   local-scope
   load-ingredients
   # repeat forever
diff --git a/072array.mu b/072array.mu
index 147ec0bf..fcd1fcb7 100644
--- a/072array.mu
+++ b/072array.mu
@@ -12,7 +12,7 @@ scenario array-from-args [
 ]
 
 # create an array out of a list of scalar args
-recipe new-array -> result:address:shared:array:character [
+def new-array -> result:address:shared:array:character [
   local-scope
   capacity:number <- copy 0
   {
@@ -36,5 +36,5 @@ recipe new-array -> result:address:shared:array:character [
     i <- add i, 1
     loop
   }
-  reply result
+  return result
 ]
diff --git a/073list.mu b/073list.mu
index 1dedf573..856c5e9c 100644
--- a/073list.mu
+++ b/073list.mu
@@ -8,7 +8,7 @@ container list:_elem [
   next:address:shared:list:_elem
 ]
 
-recipe push x:_elem, in:address:shared:list:_elem -> in:address:shared:list:_elem [
+def push x:_elem, in:address:shared:list:_elem -> in:address:shared:list:_elem [
   local-scope
   load-ingredients
   result:address:shared:list:_elem <- new {(list _elem): type}
@@ -16,16 +16,16 @@ recipe push x:_elem, in:address:shared:list:_elem -> in:address:shared:list:_ele
   *val <- copy x
   next:address:address:shared:list:_elem <- get-address *result, next:offset
   *next <- copy in
-  reply result  # needed explicitly because we need to replace 'in' with 'result'
+  return result  # needed explicitly because we need to replace 'in' with 'result'
 ]
 
-recipe first in:address:shared:list:_elem -> result:_elem [
+def first in:address:shared:list:_elem -> result:_elem [
   local-scope
   load-ingredients
   result <- get *in, value:offset
 ]
 
-recipe rest in:address:shared:list:_elem -> result:address:shared:list:_elem/contained-in:in [
+def rest in:address:shared:list:_elem -> result:address:shared:list:_elem/contained-in:in [
   local-scope
   load-ingredients
   result <- get *in, next:offset
@@ -51,7 +51,7 @@ scenario list-handling [
   ]
 ]
 
-recipe to-text in:address:shared:list:_elem -> result:address:shared:array:character [
+def to-text in:address:shared:list:_elem -> result:address:shared:array:character [
   local-scope
   load-ingredients
   buf:address:shared:buffer <- new-buffer 80
@@ -60,7 +60,7 @@ recipe to-text in:address:shared:list:_elem -> result:address:shared:array:chara
 ]
 
 # variant of 'to-text' which stops printing after a few elements (and so is robust to cycles)
-recipe to-text-line in:address:shared:list:_elem -> result:address:shared:array:character [
+def to-text-line in:address:shared:list:_elem -> result:address:shared:array:character [
   local-scope
   load-ingredients
   buf:address:shared:buffer <- new-buffer 80
@@ -68,13 +68,13 @@ recipe to-text-line in:address:shared:list:_elem -> result:address:shared:array:
   result <- buffer-to-array buf
 ]
 
-recipe to-buffer in:address:shared:list:_elem, buf:address:shared:buffer -> buf:address:shared:buffer [
+def to-buffer in:address:shared:list:_elem, buf:address:shared:buffer -> buf:address:shared:buffer [
   local-scope
   load-ingredients
   {
     break-if in
     buf <- append buf, 48/0
-    reply
+    return
   }
   # append in.value to buf
   val:_elem <- get *in, value:offset
@@ -82,7 +82,7 @@ recipe to-buffer in:address:shared:list:_elem, buf:address:shared:buffer -> buf:
   # now prepare next
   next:address:shared:list:_elem <- rest in
   nextn:number <- copy next
-  reply-unless next
+  return-unless next
   space:character <- copy 32/space
   buf <- append buf, space:character
   s:address:shared:array:character <- new [-> ]
@@ -94,14 +94,14 @@ recipe to-buffer in:address:shared:list:_elem, buf:address:shared:buffer -> buf:
     break-if optional-ingredient-found?
     # unlimited recursion
     buf <- to-buffer next, buf
-    reply
+    return
   }
   {
     break-unless remaining
     # limited recursion
     remaining <- subtract remaining, 1
     buf <- to-buffer next, buf, remaining
-    reply
+    return
   }
   # past recursion depth; insert ellipses and stop
   s:address:shared:array:character <- new [...]
diff --git a/074random.cc b/074random.cc
index 5c965d17..4be8f05b 100644
--- a/074random.cc
+++ b/074random.cc
@@ -53,7 +53,7 @@ case ROUND: {
 }
 
 :(scenario round_to_nearest_integer)
-recipe main [
+def main [
   1:number <- round 12.2
 ]
 +mem: storing 12 in location 1
diff --git a/075duplex_list.mu b/075duplex_list.mu
index c2f4d8ba..f4ff27cd 100644
--- a/075duplex_list.mu
+++ b/075duplex_list.mu
@@ -7,7 +7,7 @@ container duplex-list:_elem [
 ]
 
 # should I say in/contained-in:result, allow ingredients to refer to products?
-recipe push x:_elem, in:address:shared:duplex-list:_elem -> in:address:shared:duplex-list:_elem [
+def push x:_elem, in:address:shared:duplex-list:_elem -> in:address:shared:duplex-list:_elem [
   local-scope
   load-ingredients
   result:address:shared:duplex-list:_elem <- new {(duplex-list _elem): type}
@@ -20,29 +20,29 @@ recipe push x:_elem, in:address:shared:duplex-list:_elem -> in:address:shared:du
     prev:address:address:shared:duplex-list:_elem <- get-address *in, prev:offset
     *prev <- copy result
   }
-  reply result  # needed explicitly because we need to replace 'in' with 'result'
+  return result  # needed explicitly because we need to replace 'in' with 'result'
 ]
 
-recipe first in:address:shared:duplex-list:_elem -> result:_elem [
+def first in:address:shared:duplex-list:_elem -> result:_elem [
   local-scope
   load-ingredients
-  reply-unless in, 0
+  return-unless in, 0
   result <- get *in, value:offset
 ]
 
-recipe next in:address:shared:duplex-list:_elem -> result:address:shared:duplex-list:_elem/contained-in:in [
+def next in:address:shared:duplex-list:_elem -> result:address:shared:duplex-list:_elem/contained-in:in [
   local-scope
   load-ingredients
-  reply-unless in, 0
+  return-unless in, 0
   result <- get *in, next:offset
 ]
 
-recipe prev in:address:shared:duplex-list:_elem -> result:address:shared:duplex-list:_elem/contained-in:in [
+def prev in:address:shared:duplex-list:_elem -> result:address:shared:duplex-list:_elem/contained-in:in [
   local-scope
   load-ingredients
-  reply-unless in, 0
+  return-unless in, 0
   result <- get *in, prev:offset
-  reply result
+  return result
 ]
 
 scenario duplex-list-handling [
@@ -87,7 +87,7 @@ scenario duplex-list-handling [
 ]
 
 # insert 'x' after 'in'
-recipe insert x:_elem, in:address:shared:duplex-list:_elem -> in:address:shared:duplex-list:_elem [
+def insert x:_elem, in:address:shared:duplex-list:_elem -> in:address:shared:duplex-list:_elem [
   local-scope
   load-ingredients
   new-node:address:shared:duplex-list:_elem <- new {(duplex-list _elem): type}
@@ -104,7 +104,7 @@ recipe insert x:_elem, in:address:shared:duplex-list:_elem -> in:address:shared:
   y <- get-address *new-node, next:offset
   *y <- copy next-node
   # if next-node is not null
-  reply-unless next-node
+  return-unless next-node
   # next-node.prev = new-node
   y <- get-address *next-node, prev:offset
   *y <- copy new-node
@@ -222,11 +222,11 @@ scenario inserting-after-start-of-duplex-list [
 #
 # Returns null if and only if list is empty. Beware: in that case any other
 # pointers to the head are now invalid.
-recipe remove x:address:shared:duplex-list:_elem/contained-in:in, in:address:shared:duplex-list:_elem -> in:address:shared:duplex-list:_elem [
+def remove x:address:shared:duplex-list:_elem/contained-in:in, in:address:shared:duplex-list:_elem -> in:address:shared:duplex-list:_elem [
   local-scope
   load-ingredients
   # if 'x' is null, return
-  reply-unless x
+  return-unless x
   next-node:address:shared:duplex-list:_elem <- get *x, next:offset
   prev-node:address:shared:duplex-list:_elem <- get *x, prev:offset
   # null x's pointers
@@ -245,11 +245,11 @@ recipe remove x:address:shared:duplex-list:_elem/contained-in:in, in:address:sha
     break-unless prev-node
     tmp <- get-address *prev-node, next:offset
     *tmp <- copy next-node
-    reply
+    return
   }
   # if prev-node is null, then we removed the node at 'in'
   # return the new head rather than the old 'in'
-  reply next-node
+  return next-node
 ]
 
 scenario removing-from-duplex-list [
@@ -347,19 +347,19 @@ scenario removing-from-singleton-list [
 
 # remove values between 'start' and 'end' (both exclusive)
 # also clear pointers back out from start/end for hygiene
-recipe remove-between start:address:shared:duplex-list:_elem, end:address:shared:duplex-list:_elem/contained-in:start -> start:address:shared:duplex-list:_elem [
+def remove-between start:address:shared:duplex-list:_elem, end:address:shared:duplex-list:_elem/contained-in:start -> start:address:shared:duplex-list:_elem [
   local-scope
   load-ingredients
-  reply-unless start
+  return-unless start
   # start->next->prev = 0
   # start->next = end
   next:address:address:shared:duplex-list:_elem <- get-address *start, next:offset
   nothing-to-delete?:boolean <- equal *next, end
-  reply-if nothing-to-delete?
+  return-if nothing-to-delete?
   prev:address:address:shared:duplex-list:_elem <- get-address **next, prev:offset
   *prev <- copy 0
   *next <- copy end
-  reply-unless end
+  return-unless end
   # end->prev->next = 0
   # end->prev = start
   prev <- get-address *end, prev:offset
@@ -455,11 +455,11 @@ scenario remove-range-empty [
 ]
 
 # insert list beginning at 'new' after 'in'
-recipe insert-range in:address:shared:duplex-list:_elem, start:address:shared:duplex-list:_elem/contained-in:in -> in:address:shared:duplex-list:_elem [
+def insert-range in:address:shared:duplex-list:_elem, start:address:shared:duplex-list:_elem/contained-in:in -> in:address:shared:duplex-list:_elem [
   local-scope
   load-ingredients
-  reply-unless in
-  reply-unless start
+  return-unless in
+  return-unless start
   end:address:shared:duplex-list:_elem <- copy start
   {
     next:address:shared:duplex-list:_elem <- next end/insert-range
@@ -481,18 +481,18 @@ recipe insert-range in:address:shared:duplex-list:_elem, start:address:shared:du
   *dest <- copy in
 ]
 
-recipe append in:address:shared:duplex-list:_elem, new:address:shared:duplex-list:_elem/contained-in:in -> in:address:shared:duplex-list:_elem [
+def append in:address:shared:duplex-list:_elem, new:address:shared:duplex-list:_elem/contained-in:in -> in:address:shared:duplex-list:_elem [
   local-scope
   load-ingredients
   last:address:shared:duplex-list:_elem <- last in
   dest:address:address:shared:duplex-list:_elem <- get-address *last, next:offset
   *dest <- copy new
-  reply-unless new
+  return-unless new
   dest <- get-address *new, prev:offset
   *dest <- copy last
 ]
 
-recipe last in:address:shared:duplex-list:_elem -> result:address:shared:duplex-list:_elem [
+def last in:address:shared:duplex-list:_elem -> result:address:shared:duplex-list:_elem [
   local-scope
   load-ingredients
   result <- copy in
@@ -505,7 +505,7 @@ recipe last in:address:shared:duplex-list:_elem -> result:address:shared:duplex-
 ]
 
 # helper for debugging
-recipe dump-from x:address:shared:duplex-list:_elem [
+def dump-from x:address:shared:duplex-list:_elem [
   local-scope
   load-ingredients
   $print x, [: ]
diff --git a/076stream.mu b/076stream.mu
index aa11b773..c3af2ddf 100644
--- a/076stream.mu
+++ b/076stream.mu
@@ -4,7 +4,7 @@ container stream [
   data:address:shared:array:character
 ]
 
-recipe new-stream s:address:shared:array:character -> result:address:shared:stream [
+def new-stream s:address:shared:array:character -> result:address:shared:stream [
   local-scope
   load-ingredients
   result <- new stream:type
@@ -14,14 +14,14 @@ recipe new-stream s:address:shared:array:character -> result:address:shared:stre
   *d <- copy s
 ]
 
-recipe rewind-stream in:address:shared:stream -> in:address:shared:stream [
+def rewind-stream in:address:shared:stream -> in:address:shared:stream [
   local-scope
   load-ingredients
   x:address:number <- get-address *in, index:offset
   *x <- copy 0
 ]
 
-recipe read-line in:address:shared:stream -> result:address:shared:array:character, in:address:shared:stream [
+def read-line in:address:shared:stream -> result:address:shared:array:character, in:address:shared:stream [
   local-scope
   load-ingredients
   idx:address:number <- get-address *in, index:offset
@@ -31,7 +31,7 @@ recipe read-line in:address:shared:stream -> result:address:shared:array:charact
   *idx <- add next-idx, 1  # skip newline
 ]
 
-recipe end-of-stream? in:address:shared:stream -> result:boolean [
+def end-of-stream? in:address:shared:stream -> result:boolean [
   local-scope
   load-ingredients
   idx:number <- get *in, index:offset
diff --git a/077hash.cc b/077hash.cc
index 682232dd..62c02eca 100644
--- a/077hash.cc
+++ b/077hash.cc
@@ -143,13 +143,13 @@ container foo [
   x:number
   y:character
 ]
-recipe main [
+def main [
   1:foo <- merge 34, 97/a
   3:number <- hash 1:foo
-  reply-unless 3:number
+  return-unless 3:number
   4:foo <- merge 34, 98/a
   6:number <- hash 4:foo
-  reply-unless 6:number
+  return-unless 6:number
   7:boolean <- equal 3:number, 6:number
 ]
 # hash on containers includes all elements
@@ -164,13 +164,13 @@ container bar [
   a:number
   b:number
 ]
-recipe main [
+def main [
   1:foo <- merge 0/x, 34, 35
   4:number <- hash 1:foo
-  reply-unless 4:number
+  return-unless 4:number
   5:foo <- merge 0/x, 34, 36
   8:number <- hash 5:foo
-  reply-unless 8:number
+  return-unless 8:number
   9:boolean <- equal 4:number, 8:number
 ]
 # hash on containers includes all elements
@@ -181,13 +181,13 @@ container foo [
   x:number
   y:character/ignore-for-hash
 ]
-recipe main [
+def main [
   1:foo <- merge 34, 97/a
   3:number <- hash 1:foo
-  reply-unless 3:number
+  return-unless 3:number
   4:foo <- merge 34, 98/a
   6:number <- hash 4:foo
-  reply-unless 6:number
+  return-unless 6:number
   7:boolean <- equal 3:number, 6:number
 ]
 # hashes match even though y is different
@@ -197,7 +197,7 @@ recipe main [
 //: current implementation works like we think it does.
 
 :(scenario hash_of_zero_address)
-recipe main [
+def main [
   1:address:number <- copy 0
   2:number <- hash 1:address:number
 ]
@@ -206,7 +206,7 @@ recipe main [
 //: This is probably too aggressive, but we need some way to avoid depending
 //: on the precise bit pattern of a floating-point number.
 :(scenario hash_of_numbers_ignores_fractional_part)
-recipe main [
+def main [
   1:number <- hash 1.5
   2:number <- hash 1
   3:boolean <- equal 1:number, 2:number
@@ -214,22 +214,22 @@ recipe main [
 +mem: storing 1 in location 3
 
 :(scenario hash_of_array_same_as_string)
-recipe main [
+def main [
   10:number <- copy 3
   11:number <- copy 97
   12:number <- copy 98
   13:number <- copy 99
   2:number <- hash 10:array:number/unsafe
-  reply-unless 2:number
+  return-unless 2:number
   3:address:shared:array:character <- new [abc]
   4:number <- hash 3:address:shared:array:character
-  reply-unless 4:number
+  return-unless 4:number
   5:boolean <- equal 2:number, 4:number
 ]
 +mem: storing 1 in location 5
 
 :(scenario hash_ignores_address_value)
-recipe main [
+def main [
   1:address:shared:number <- new number:type
   *1:address:shared:number <- copy 34
   2:number <- hash 1:address:shared:number
@@ -242,15 +242,15 @@ recipe main [
 +mem: storing 1 in location 5
 
 :(scenario hash_ignores_address_refcount)
-recipe main [
+def main [
   1:address:shared:number <- new number:type
   *1:address:shared:number <- copy 34
   2:number <- hash 1:address:shared:number
-  reply-unless 2:number
+  return-unless 2:number
   # increment refcount
   3:address:shared:number <- copy 1:address:shared:number
   4:number <- hash 3:address:shared:number
-  reply-unless 4:number
+  return-unless 4:number
   5:boolean <- equal 2:number, 4:number
 ]
 # hash doesn't change when refcount changes
@@ -265,13 +265,13 @@ container bar [
   x:number
   y:character
 ]
-recipe main [
+def main [
   1:foo <- merge 34, 97/a
   3:number <- hash 1:foo
-  reply-unless 3:number
+  return-unless 3:number
   4:bar <- merge 34, 97/a
   6:number <- hash 4:bar
-  reply-unless 6:number
+  return-unless 6:number
   7:boolean <- equal 3:number, 6:number
 ]
 # containers with identical elements return identical hashes
@@ -283,17 +283,17 @@ container foo [
   y:character
   z:address:shared:number
 ]
-recipe main [
+def main [
   1:address:shared:number <- new number:type
   *1:address:shared:number <- copy 34
   2:foo <- merge 34, 97/a, 1:address:shared:number
   5:number <- hash 2:foo
-  reply-unless 5:number
+  return-unless 5:number
   6:address:shared:number <- new number:type
   *6:address:shared:number <- copy 34
   7:foo <- merge 34, 97/a, 6:address:shared:number
   10:number <- hash 7:foo
-  reply-unless 10:number
+  return-unless 10:number
   11:boolean <- equal 5:number, 10:number
 ]
 # containers with identical 'leaf' elements return identical hashes
@@ -309,13 +309,13 @@ container bar [
   x:number
   y:number
 ]
-recipe main [
+def main [
   1:foo <- merge 34, 97/a, 47, 48
   6:number <- hash 1:foo
-  reply-unless 6:number
+  return-unless 6:number
   7:foo <- merge 34, 97/a, 47, 48
   12:number <- hash 7:foo
-  reply-unless 12:number
+  return-unless 12:number
   13:boolean <- equal 6:number, 12:number
 ]
 # containers with identical 'leaf' elements return identical hashes
@@ -330,13 +330,13 @@ container bar [
   a:number
   b:number
 ]
-recipe main [
+def main [
   1:foo <- merge 0/x, 34, 35
   4:number <- hash 1:foo
-  reply-unless 4:number
+  return-unless 4:number
   5:bar <- merge 34, 35
   7:number <- hash 5:bar
-  reply-unless 7:number
+  return-unless 7:number
   8:boolean <- equal 4:number, 7:number
 ]
 # hash on containers includes all elements
@@ -347,7 +347,7 @@ recipe main [
 //: version around and check that the new one is consistent with it.
 
 :(scenario hash_matches_old_version)
-recipe main [
+def main [
   1:address:shared:array:character <- new [abc]
   2:number <- hash 1:address:shared:array:character
   3:number <- hash_old 1:address:shared:array:character
diff --git a/078table.mu b/078table.mu
index 4ab30d4a..56b7c9fd 100644
--- a/078table.mu
+++ b/078table.mu
@@ -36,7 +36,7 @@ container table_row:_key:_value [
   value:_value
 ]
 
-recipe new-table capacity:number -> result:address:shared:table:_key:_value [
+def new-table capacity:number -> result:address:shared:table:_key:_value [
   local-scope
   load-ingredients
   result <- new {(table _key _value): type}
@@ -46,7 +46,7 @@ recipe new-table capacity:number -> result:address:shared:table:_key:_value [
   *data <- new {(table_row _key _value): type}, capacity
 ]
 
-recipe put table:address:shared:table:_key:_value, key:_key, value:_value -> table:address:shared:table:_key:_value [
+def put table:address:shared:table:_key:_value, key:_key, value:_value -> table:address:shared:table:_key:_value [
   local-scope
   load-ingredients
   hash:number <- hash key
@@ -62,15 +62,15 @@ recipe put table:address:shared:table:_key:_value, key:_key, value:_value -> tab
   *x <- merge 1/true, key, value
 ]
 
-recipe abs n:number -> result:number [
+def abs n:number -> result:number [
   local-scope
   load-ingredients
   positive?:boolean <- greater-or-equal n, 0
-  reply-if positive?, n
+  return-if positive?, n
   result <- multiply n, -1
 ]
 
-recipe index table:address:shared:table:_key:_value, key:_key -> result:_value [
+def index table:address:shared:table:_key:_value, key:_key -> result:_value [
   local-scope
   load-ingredients
   hash:number <- hash key
diff --git a/081print.mu b/081print.mu
index 8f61504e..9b7e146a 100644
--- a/081print.mu
+++ b/081print.mu
@@ -14,7 +14,7 @@ container screen-cell [
   color:number
 ]
 
-recipe new-fake-screen w:number, h:number -> result:address:shared:screen [
+def new-fake-screen w:number, h:number -> result:address:shared:screen [
   local-scope
   load-ingredients
   result <- new screen:type
@@ -32,7 +32,7 @@ recipe new-fake-screen w:number, h:number -> result:address:shared:screen [
   result <- clear-screen result
 ]
 
-recipe clear-screen screen:address:shared:screen -> screen:address:shared:screen [
+def clear-screen screen:address:shared:screen -> screen:address:shared:screen [
   local-scope
   load-ingredients
   # if x exists
@@ -58,13 +58,13 @@ recipe clear-screen screen:address:shared:screen -> screen:address:shared:screen
     *x <- copy 0
     x <- get-address *screen, cursor-column:offset
     *x <- copy 0
-    reply
+    return
   }
   # otherwise, real screen
   clear-display
 ]
 
-recipe sync-screen screen:address:shared:screen -> screen:address:shared:screen [
+def sync-screen screen:address:shared:screen -> screen:address:shared:screen [
   local-scope
   load-ingredients
   {
@@ -74,10 +74,10 @@ recipe sync-screen screen:address:shared:screen -> screen:address:shared:screen
   # do nothing for fake screens
 ]
 
-recipe fake-screen-is-empty? screen:address:shared:screen -> result:boolean [
+def fake-screen-is-empty? screen:address:shared:screen -> result:boolean [
   local-scope
   load-ingredients
-  reply-unless screen, 1/true
+  return-unless screen, 1/true
   buf:address:shared:array:screen-cell <- get *screen, data:offset
   i:number <- copy 0
   len:number <- length *buf
@@ -89,12 +89,12 @@ recipe fake-screen-is-empty? screen:address:shared:screen -> result:boolean [
     i <- add i, 1
     loop-unless curr-contents
     # not 0
-    reply 0/false
+    return 0/false
   }
-  reply 1/true
+  return 1/true
 ]
 
-recipe print screen:address:shared:screen, c:character -> screen:address:shared:screen [
+def print screen:address:shared:screen, c:character -> screen:address:shared:screen [
   local-scope
   load-ingredients
   color:number, color-found?:boolean <- next-ingredient
@@ -119,14 +119,14 @@ recipe print screen:address:shared:screen, c:character -> screen:address:shared:
     # if cursor is out of bounds, silently exit
     row:address:number <- get-address *screen, cursor-row:offset
     legal?:boolean <- greater-or-equal *row, 0
-    reply-unless legal?
+    return-unless legal?
     legal? <- lesser-than *row, height
-    reply-unless legal?
+    return-unless legal?
     column:address:number <- get-address *screen, cursor-column:offset
     legal? <- greater-or-equal *column, 0
-    reply-unless legal?
+    return-unless legal?
     legal? <- lesser-than *column, width
-    reply-unless legal?
+    return-unless legal?
 #?     $print [print-character (], *row, [, ], *column, [): ], c, 10/newline
     # special-case: newline
     {
@@ -141,7 +141,7 @@ recipe print screen:address:shared:screen, c:character -> screen:address:shared:
         *column <- copy 0
         *row <- add *row, 1
       }
-      reply
+      return
     }
     # save character in fake screen
     index:number <- multiply *row, width
@@ -165,7 +165,7 @@ recipe print screen:address:shared:screen, c:character -> screen:address:shared:
         cursor-color:address:number <- get-address *cursor, color:offset
         *cursor-color <- copy 7/white
       }
-      reply
+      return
     }
     cursor:address:screen-cell <- index-address *buf, index
     cursor-contents:address:character <- get-address *cursor, contents:offset
@@ -179,7 +179,7 @@ recipe print screen:address:shared:screen, c:character -> screen:address:shared:
       break-if at-right?
       *column <- add *column, 1
     }
-    reply
+    return
   }
   # otherwise, real screen
   print-character-to-display c, color, bg-color
@@ -356,7 +356,7 @@ scenario print-character-at-bottom-right [
   ]
 ]
 
-recipe clear-line screen:address:shared:screen -> screen:address:shared:screen [
+def clear-line screen:address:shared:screen -> screen:address:shared:screen [
   local-scope
   load-ingredients
   space:character <- copy 0/nul
@@ -376,13 +376,13 @@ recipe clear-line screen:address:shared:screen -> screen:address:shared:screen [
     }
     # now back to where the cursor was
     *column <- copy original-column
-    reply
+    return
   }
   # otherwise, real screen
   clear-line-on-display
 ]
 
-recipe cursor-position screen:address:shared:screen -> row:number, column:number [
+def cursor-position screen:address:shared:screen -> row:number, column:number [
   local-scope
   load-ingredients
   # if x exists, lookup cursor in fake screen
@@ -390,12 +390,12 @@ recipe cursor-position screen:address:shared:screen -> row:number, column:number
     break-unless screen
     row:number <- get *screen, cursor-row:offset
     column:number <- get *screen, cursor-column:offset
-    reply
+    return
   }
   row, column <- cursor-position-on-display
 ]
 
-recipe move-cursor screen:address:shared:screen, new-row:number, new-column:number -> screen:address:shared:screen [
+def move-cursor screen:address:shared:screen, new-row:number, new-column:number -> screen:address:shared:screen [
   local-scope
   load-ingredients
   # if x exists, move cursor in fake screen
@@ -405,7 +405,7 @@ recipe move-cursor screen:address:shared:screen, new-row:number, new-column:numb
     *row <- copy new-row
     column:address:number <- get-address *screen, cursor-column:offset
     *column <- copy new-column
-    reply
+    return
   }
   # otherwise, real screen
   move-cursor-on-display new-row, new-column
@@ -442,7 +442,7 @@ scenario clear-line-erases-printed-characters [
   ]
 ]
 
-recipe cursor-down screen:address:shared:screen -> screen:address:shared:screen [
+def cursor-down screen:address:shared:screen -> screen:address:shared:screen [
   local-scope
   load-ingredients
   # if x exists, move cursor in fake screen
@@ -457,13 +457,13 @@ recipe cursor-down screen:address:shared:screen -> screen:address:shared:screen
       break-if at-bottom?
       *row <- add *row, 1
     }
-    reply
+    return
   }
   # otherwise, real screen
   move-cursor-down-on-display
 ]
 
-recipe cursor-up screen:address:shared:screen -> screen:address:shared:screen [
+def cursor-up screen:address:shared:screen -> screen:address:shared:screen [
   local-scope
   load-ingredients
   # if x exists, move cursor in fake screen
@@ -476,13 +476,13 @@ recipe cursor-up screen:address:shared:screen -> screen:address:shared:screen [
       break-if at-top?
       *row <- subtract *row, 1
     }
-    reply
+    return
   }
   # otherwise, real screen
   move-cursor-up-on-display
 ]
 
-recipe cursor-right screen:address:shared:screen -> screen:address:shared:screen [
+def cursor-right screen:address:shared:screen -> screen:address:shared:screen [
   local-scope
   load-ingredients
   # if x exists, move cursor in fake screen
@@ -497,13 +497,13 @@ recipe cursor-right screen:address:shared:screen -> screen:address:shared:screen
       break-if at-bottom?
       *column <- add *column, 1
     }
-    reply
+    return
   }
   # otherwise, real screen
   move-cursor-right-on-display
 ]
 
-recipe cursor-left screen:address:shared:screen -> screen:address:shared:screen [
+def cursor-left screen:address:shared:screen -> screen:address:shared:screen [
   local-scope
   load-ingredients
   # if x exists, move cursor in fake screen
@@ -516,13 +516,13 @@ recipe cursor-left screen:address:shared:screen -> screen:address:shared:screen
       break-if at-top?
       *column <- subtract *column, 1
     }
-    reply
+    return
   }
   # otherwise, real screen
   move-cursor-left-on-display
 ]
 
-recipe cursor-to-start-of-line screen:address:shared:screen -> screen:address:shared:screen [
+def cursor-to-start-of-line screen:address:shared:screen -> screen:address:shared:screen [
   local-scope
   load-ingredients
   row:number <- cursor-position screen
@@ -530,90 +530,90 @@ recipe cursor-to-start-of-line screen:address:shared:screen -> screen:address:sh
   screen <- move-cursor screen, row, column
 ]
 
-recipe cursor-to-next-line screen:address:shared:screen -> screen:address:shared:screen [
+def cursor-to-next-line screen:address:shared:screen -> screen:address:shared:screen [
   local-scope
   load-ingredients
   screen <- cursor-down screen
   screen <- cursor-to-start-of-line screen
 ]
 
-recipe screen-width screen:address:shared:screen -> width:number [
+def screen-width screen:address:shared:screen -> width:number [
   local-scope
   load-ingredients
   # if x exists, move cursor in fake screen
   {
     break-unless screen
     width <- get *screen, num-columns:offset
-    reply
+    return
   }
   # otherwise, real screen
   width <- display-width
 ]
 
-recipe screen-height screen:address:shared:screen -> height:number [
+def screen-height screen:address:shared:screen -> height:number [
   local-scope
   load-ingredients
   # if x exists, move cursor in fake screen
   {
     break-unless screen
     height <- get *screen, num-rows:offset
-    reply
+    return
   }
   # otherwise, real screen
   height <- display-height
 ]
 
-recipe hide-cursor screen:address:shared:screen -> screen:address:shared:screen [
+def hide-cursor screen:address:shared:screen -> screen:address:shared:screen [
   local-scope
   load-ingredients
   # if x exists (not real display), do nothing
   {
     break-unless screen
-    reply
+    return
   }
   # otherwise, real screen
   hide-cursor-on-display
 ]
 
-recipe show-cursor screen:address:shared:screen -> screen:address:shared:screen [
+def show-cursor screen:address:shared:screen -> screen:address:shared:screen [
   local-scope
   load-ingredients
   # if x exists (not real display), do nothing
   {
     break-unless screen
-    reply
+    return
   }
   # otherwise, real screen
   show-cursor-on-display
 ]
 
-recipe hide-screen screen:address:shared:screen -> screen:address:shared:screen [
+def hide-screen screen:address:shared:screen -> screen:address:shared:screen [
   local-scope
   load-ingredients
   # if x exists (not real display), do nothing
   # todo: help test this
   {
     break-unless screen
-    reply
+    return
   }
   # otherwise, real screen
   hide-display
 ]
 
-recipe show-screen screen:address:shared:screen -> screen:address:shared:screen [
+def show-screen screen:address:shared:screen -> screen:address:shared:screen [
   local-scope
   load-ingredients
   # if x exists (not real display), do nothing
   # todo: help test this
   {
     break-unless screen
-    reply
+    return
   }
   # otherwise, real screen
   show-display
 ]
 
-recipe print screen:address:shared:screen, s:address:shared:array:character -> screen:address:shared:screen [
+def print screen:address:shared:screen, s:address:shared:array:character -> screen:address:shared:screen [
   local-scope
   load-ingredients
   color:number, color-found?:boolean <- next-ingredient
@@ -660,7 +660,7 @@ scenario print-text-stops-at-right-margin [
   ]
 ]
 
-recipe print-integer screen:address:shared:screen, n:number -> screen:address:shared:screen [
+def print-integer screen:address:shared:screen, n:number -> screen:address:shared:screen [
   local-scope
   load-ingredients
   color:number, color-found?:boolean <- next-ingredient
@@ -681,7 +681,7 @@ recipe print-integer screen:address:shared:screen, n:number -> screen:address:sh
 ]
 
 # for now, we can only print integers
-recipe print screen:address:shared:screen, n:number -> screen:address:shared:screen [
+def print screen:address:shared:screen, n:number -> screen:address:shared:screen [
   local-scope
   load-ingredients
   color:number, color-found?:boolean <- next-ingredient
@@ -700,7 +700,7 @@ recipe print screen:address:shared:screen, n:number -> screen:address:shared:scr
 ]
 
 # addresses
-recipe print screen:address:shared:screen, n:address:_elem -> screen:address:shared:screen [
+def print screen:address:shared:screen, n:address:_elem -> screen:address:shared:screen [
   local-scope
   load-ingredients
   color:number, color-found?:boolean <- next-ingredient
diff --git a/082scenario_screen.cc b/082scenario_screen.cc
index 9da18cd1..579d9b9a 100644
--- a/082scenario_screen.cc
+++ b/082scenario_screen.cc
@@ -115,7 +115,7 @@ if (s == "screen") return true;
 :(scenarios run)
 :(scenario convert_names_does_not_fail_when_mixing_special_names_and_numeric_locations)
 % Scenario_testing_scenario = true;
-recipe main [
+def main [
   screen:number <- copy 1:number
 ]
 -error: mixing variable names and numeric addresses in main
diff --git a/084console.mu b/084console.mu
index 5adb5a36..83fb2f1d 100644
--- a/084console.mu
+++ b/084console.mu
@@ -25,7 +25,7 @@ container console [
   events:address:shared:array:event
 ]
 
-recipe new-fake-console events:address:shared:array:event -> result:address:shared:console [
+def new-fake-console events:address:shared:array:event -> result:address:shared:console [
   local-scope
   load-ingredients
   result:address:shared:console <- new console:type
@@ -35,7 +35,7 @@ recipe new-fake-console events:address:shared:array:event -> result:address:shar
   *idx <- copy 0
 ]
 
-recipe read-event console:address:shared:console -> result:event, console:address:shared:console, found?:boolean, quit?:boolean [
+def read-event console:address:shared:console -> result:event, console:address:shared:console, found?:boolean, quit?:boolean [
   local-scope
   load-ingredients
   {
@@ -47,32 +47,32 @@ recipe read-event console:address:shared:console -> result:event, console:addres
       done?:boolean <- greater-or-equal *current-event-index, max
       break-unless done?
       dummy:address:shared:event <- new event:type
-      reply *dummy, console/same-as-ingredient:0, 1/found, 1/quit
+      return *dummy, console/same-as-ingredient:0, 1/found, 1/quit
     }
     result <- index *buf, *current-event-index
     *current-event-index <- add *current-event-index, 1
-    reply result, console/same-as-ingredient:0, 1/found, 0/quit
+    return result, console/same-as-ingredient:0, 1/found, 0/quit
   }
   switch  # real event source is infrequent; avoid polling it too much
   result:event, found?:boolean <- check-for-interaction
-  reply result, console/same-as-ingredient:0, found?, 0/quit
+  return result, console/same-as-ingredient:0, found?, 0/quit
 ]
 
 # variant of read-event for just keyboard events. Discards everything that
 # isn't unicode, so no arrow keys, page-up/page-down, etc. But you still get
 # newlines, tabs, ctrl-d..
-recipe read-key console:address:shared:console -> result:character, console:address:shared:console, found?:boolean, quit?:boolean [
+def read-key console:address:shared:console -> result:character, console:address:shared:console, found?:boolean, quit?:boolean [
   local-scope
   load-ingredients
   x:event, console, found?:boolean, quit?:boolean <- read-event console
-  reply-if quit?, 0, console/same-as-ingredient:0, found?, quit?
-  reply-unless found?, 0, console/same-as-ingredient:0, found?, quit?
+  return-if quit?, 0, console/same-as-ingredient:0, found?, quit?
+  return-unless found?, 0, console/same-as-ingredient:0, found?, quit?
   c:address:character <- maybe-convert x, text:variant
-  reply-unless c, 0, console/same-as-ingredient:0, 0/found, 0/quit
-  reply *c, console/same-as-ingredient:0, 1/found, 0/quit
+  return-unless c, 0, console/same-as-ingredient:0, 0/found, 0/quit
+  return *c, console/same-as-ingredient:0, 1/found, 0/quit
 ]
 
-recipe send-keys-to-channel console:address:shared:console, chan:address:shared:channel, screen:address:shared:screen -> console:address:shared:console, chan:address:shared:channel, screen:address:shared:screen [
+def send-keys-to-channel console:address:shared:console, chan:address:shared:channel, screen:address:shared:screen -> console:address:shared:console, chan:address:shared:channel, screen:address:shared:screen [
   local-scope
   load-ingredients
   {
@@ -86,7 +86,7 @@ recipe send-keys-to-channel console:address:shared:console, chan:address:shared:
   }
 ]
 
-recipe wait-for-event console:address:shared:console -> console:address:shared:console [
+def wait-for-event console:address:shared:console -> console:address:shared:console [
   local-scope
   load-ingredients
   {
@@ -96,13 +96,13 @@ recipe wait-for-event console:address:shared:console -> console:address:shared:c
 ]
 
 # use this helper to skip rendering if there's lots of other events queued up
-recipe has-more-events? console:address:shared:console -> result:boolean [
+def has-more-events? console:address:shared:console -> result:boolean [
   local-scope
   load-ingredients
   {
     break-unless console
     # fake consoles should be plenty fast; never skip
-    reply 0/false
+    return 0/false
   }
   result <- interactions-left?
 ]
diff --git a/091run_interactive.cc b/091run_interactive.cc
index 0cdfb8dc..6bebfd31 100644
--- a/091run_interactive.cc
+++ b/091run_interactive.cc
@@ -2,7 +2,7 @@
 //: return some result in string form.
 
 :(scenario run_interactive_code)
-recipe main [
+def main [
   1:number/raw <- copy 0
   2:address:shared:array:character <- new [1:number/raw <- copy 34]
   run-interactive 2:address:shared:array:character
@@ -11,7 +11,7 @@ recipe main [
 +mem: storing 34 in location 3
 
 :(scenario run_interactive_empty)
-recipe main [
+def main [
   1:address:shared:array:character <- copy 0/unsafe
   2:address:shared:array:character <- run-interactive 1:address:shared:array:character
 ]
@@ -92,7 +92,7 @@ bool run_interactive(long long int address) {
           "$start-tracking-products\n" +
           command + "\n" +
           "$stop-tracking-products\n" +
-          "reply screen\n" +
+          "return screen\n" +
        "]\n");
   transform_all();
   Current_routine = save_current_routine;
@@ -159,7 +159,7 @@ load(string(
   "errors:address:shared:array:character <- save-errors\n" +
   "stashes:address:shared:array:character <- save-app-trace\n" +
   "$cleanup-run-interactive\n" +
-  "reply output, errors, screen, stashes, completed?\n" +
+  "return output, errors, screen, stashes, completed?\n" +
 "]\n");
 transform_all();
 Recently_added_recipes.clear();
@@ -169,7 +169,7 @@ Recently_added_recipes.clear();
   if (s == "interactive") return "";
 
 :(scenario run_interactive_comments)
-recipe main [
+def main [
   1:address:shared:array:character <- new [# ab
 add 2, 2]
   2:address:shared:array:character <- run-interactive 1:address:shared:array:character
@@ -265,7 +265,7 @@ case _CLEANUP_RUN_INTERACTIVE: {
 }
 
 :(scenario "run_interactive_converts_result_to_text")
-recipe main [
+def main [
   # try to interactively add 2 and 2
   1:address:shared:array:character <- new [add 2, 2]
   2:address:shared:array:character <- run-interactive 1:address:shared:array:character
@@ -275,7 +275,7 @@ recipe main [
 +mem: storing 52 in location 11
 
 :(scenario "run_interactive_returns_text")
-recipe main [
+def main [
   # try to interactively add 2 and 2
   1:address:shared:array:character <- new [
     x:address:shared:array:character <- new [a]
@@ -290,7 +290,7 @@ recipe main [
 +mem: storing 98 in location 12
 
 :(scenario "run_interactive_returns_errors")
-recipe main [
+def main [
   # run a command that generates an error
   1:address:shared:array:character <- new [x:number <- copy 34
 get x:number, foo:offset]
@@ -305,7 +305,7 @@ get x:number, foo:offset]
 # ...
 
 :(scenario run_interactive_with_comment)
-recipe main [
+def main [
   # 2 instructions, with a comment after the first
   1:address:shared:array:number <- new [a:number <- copy 0  # abc
 b:number <- copy 0
@@ -320,7 +320,7 @@ void test_run_interactive_cleans_up_any_created_specializations() {
   // define a generic recipe
   assert(!contains_key(Recipe_ordinal, "foo"));
   load("recipe foo x:_elem -> n:number [\n"
-       "  reply 34\n"
+       "  return 34\n"
        "]\n");
   assert(SIZE(Recently_added_recipes) == 1);  // foo
   assert(variant_count("foo") == 1);
@@ -494,7 +494,7 @@ case RELOAD: {
 }
 
 :(scenario reload_continues_past_error)
-recipe main [
+def main [
   local-scope
   x:address:shared:array:character <- new [recipe foo [
   get 1234:number, foo:offset
@@ -515,7 +515,7 @@ void test_reload_cleans_up_any_created_specializations() {
       "  x:address:shared:array:character <- new [recipe foo x:_elem -> n:number [\n"
       "local-scope\n"
       "load-ingredients\n"
-      "reply 34\n"
+      "return 34\n"
       "]\n"
       "recipe main2 [\n"
       "local-scope\n"
diff --git a/999spaces.cc b/999spaces.cc
index 34017add..f379d3c5 100644
--- a/999spaces.cc
+++ b/999spaces.cc
@@ -43,7 +43,7 @@ assert(Max_callstack_depth == 9989);
 //:
 //:   begin instruction modifying transforms
 //:     56.2 check header ingredients
-//:      ↳ 56.4 fill in reply ingredients
+//:      ↳ 56.4 fill in return ingredients
 //:     48 check or set types by name
 //:
 //:     begin type modifying transforms
@@ -68,9 +68,9 @@ assert(Max_callstack_depth == 9989);
 //:     ↳ 56 check calls against header
 //:     ↳ 43 transform 'new' to 'allocate'
 //:     30 check merge calls
-//:     36 check types of reply instructions
+//:     36 check types of return instructions
 //:     43 check default space
-//:     56 check reply instructions against header
+//:     56 check return instructions against header
 //:   end checks
 //: end transforms
 
diff --git a/Readme.md b/Readme.md
index d27d1015..97885f11 100644
--- a/Readme.md
+++ b/Readme.md
@@ -210,7 +210,7 @@ Running Mu will always recompile it if necessary:
 As a sneak peek, here's how you perform some simple arithmetic:
 
   ```nim
-  recipe example1 [
+  def example1 [
     a:number <- add 2, 2
     a <- multiply a, 3
   ]
@@ -218,10 +218,10 @@ As a sneak peek, here's how you perform some simple arithmetic:
 
 But it's easier to read in color:
 
-<img alt='code example' src='html/example1.png' width='188px'>
+<img alt='code example' src='html/example1.png'>
 
-Mu functions or 'recipes' are lists of instructions, one to a line. Each
-instruction operates on some *ingredients* and returns some *products*.
+Mu functions are lists of instructions, one to a line. Each instruction
+operates on some *ingredients* and returns some *products*.
 
   ```
   [products] <- instruction [ingredients]
@@ -255,31 +255,31 @@ Try out the program now:
   ```
 
 Not much to see yet, since it doesn't print anything. To print the result, try
-adding the instruction `$print a` to the recipe.
+adding the instruction `$print a` to the function.
 
 ---
 
-Here's a second example, of a recipe that can take ingredients:
+Here's a second example, of a function that can take ingredients:
 
-<img alt='fahrenheit to celsius' src='html/f2c-1.png' width='426px'>
+<img alt='fahrenheit to celsius' src='html/f2c-1.png'>
 
 Recipes can specify headers showing their expected ingredients and products,
 separated by `->` (unlike the `<-` in *calls*).
 
 Since Mu is a low-level VM language, it provides extra control at the cost of
 verbosity. Using `local-scope`, you have explicit control over stack frames to
-isolate your recipes (in a type-safe manner; more on that below). One
+isolate your functions (in a type-safe manner; more on that below). One
 consequence: you have to explicitly `load-ingredients` after you set up the
 stack.
 
 An alternative syntax is what the above example is converted to internally:
 
-<img alt='fahrenheit to celsius desugared' src='html/f2c-2.png' width='426px'>
+<img alt='fahrenheit to celsius desugared' src='html/f2c-2.png'>
 
 The header gets dropped after checking types at call-sites, and after
 replacing `load-ingredients` with explicit instructions to load each
 ingredient separately, and to explicitly return products to the caller. After
-this translation recipes are once again just lists of instructions.
+this translation functions are once again just lists of instructions.
 
 This alternative syntax isn't just an implementation detail. I've actually
 found it easier to teach functions to non-programmers by starting with this
@@ -290,7 +290,7 @@ names of variables gradually get translated through the pipe.
 
 A third example, this time illustrating conditionals:
 
-<img alt='factorial example' src='html/factorial.png' width='330px'>
+<img alt='factorial example' src='html/factorial.png'>
 
 In spite of how it looks, this is still just a list of instructions.
 Internally, the instructions `break` and `loop` get converted to `jump`
@@ -311,7 +311,7 @@ You can also run its unit tests:
 
 Here's what one of the tests inside `factorial.mu` looks like:
 
-<img alt='test example' src='html/factorial-test.png' width='250px'>
+<img alt='test example' src='html/factorial-test.png'>
 
 Every test conceptually spins up a really lightweight virtual machine, so you
 can do things like check the value of specific locations in memory. You can
@@ -319,7 +319,7 @@ also print to screen and check that the screen contains what you expect at the
 end of a test. For example, `chessboard.mu` checks the initial position of a
 game of chess (delimiting the edges of the screen with periods):
 
-<img alt='screen test' src='html/chessboard-test.png' width='320px'>
+<img alt='screen test' src='html/chessboard-test.png'>
 
 Similarly you can fake the keyboard to pretend someone typed something:
 
@@ -348,11 +348,11 @@ might turn into this:
 
 You shouldn't rely on the specific address Mu chooses for a variable, but it
 will be unique (other variables won't clobber it) and consistent (all mentions
-of the name will map to the same address inside a recipe).
+of the name will map to the same address inside a function).
 
-Things get more complicated when your recipes call other recipes. Mu
-doesn't preserve uniqueness of addresses across recipes, so you need to
-organize your names into spaces. At the start of each recipe (like
+Things get more complicated when your functions call other functions. Mu
+doesn't preserve uniqueness of addresses across functions, so you need to
+organize your names into spaces. At the start of each function (like
 `factorial` above), set its *default space*:
 
   ```nim
@@ -371,10 +371,10 @@ or
   default-space:address:array:location <- new location:type, 30/capacity
   ```
 
-Without one of these lines, all variables in the recipe will be *global*,
+Without one of these lines, all variables in the function will be *global*,
 something you rarely want. (Luckily, this is also the sort of mistake that
 will be easily caught by tests.) *With* this line, all addresses in your
-recipe will by default refer to one of the (30, in the final case) slots
+function will by default refer to one of the (30, in the final case) slots
 inside this local space. (If you choose the last, most explicit option and
 need more than 30 slots, Mu will complain asking you to increase capacity.)
 
@@ -444,7 +444,7 @@ An alternative way to define factorial is by inserting *labels* and later
 inserting code at them.
 
   ```nim
-  recipe factorial [
+  def factorial [
     local-scope
     n:number <- next-ingredient
     {
@@ -457,7 +457,7 @@ inserting code at them.
     # if n=0 return 1
     zero?:boolean <- equal n, 0
     break-unless zero?
-    reply 1
+    return 1
   ]
 
   after <recursive-case> [
@@ -465,7 +465,7 @@ inserting code at them.
     x:number <- subtract n, 1
     subresult:number <- factorial x
     result:number <- multiply subresult, n
-    reply result
+    return result
   ]
   ```
 
@@ -473,7 +473,7 @@ inserting code at them.
 
 Any instruction without ingredients or products that starts with a
 non-alphanumeric character is a label. By convention we use '+' to indicate
-recipe-local label names you can jump to, and surround in '<>' global label
+function-local label names you can jump to, and surround in '<>' global label
 names for inserting code at.
 
 ---
@@ -481,7 +481,7 @@ names for inserting code at.
 Another example, this time with concurrency.
 
   ```
-  recipe main [
+  def main [
     start-running thread2
     {
       $print 34
@@ -489,7 +489,7 @@ Another example, this time with concurrency.
     }
   ]
 
-  recipe thread2 [
+  def thread2 [
     {
       $print 35
       loop
@@ -569,9 +569,9 @@ d) Try out the programming environment:
 
 Screenshot:
 
-<img alt='programming environment' src='html/edit.png' width='720px'>
+<img alt='programming environment' src='html/edit.png'>
 
-You write recipes on the left and try them out in *sandboxes* on the right.
+You write functions on the left and try them out in *sandboxes* on the right.
 Hit F4 to rerun all sandboxes with the latest version of the code. More
 details: http://akkartik.name/post/mu. Beware, it won't save your edits by
 default. But if you create a sub-directory called `lesson/` under `mu/` it
@@ -580,12 +580,12 @@ back up each version you try out.
 
 Once you have a sandbox you can click on its result to mark it as expected:
 
-<img alt='expected result' src='html/expected-result.png' width='180px'>
+<img alt='expected result' src='html/expected-result.png'>
 
 Later if the result changes it'll be flagged in red to draw your attention to
 it. Thus, manually tested sandboxes become reproducible automated tests.
 
-<img alt='unexpected result' src='html/unexpected-result.png' width='180px'>
+<img alt='unexpected result' src='html/unexpected-result.png'>
 
 Another feature: Clicking on the code in a sandbox expands its trace for you
 to browse. To add to the trace, use `stash`. For example:
diff --git a/channel.mu b/channel.mu
index 54486957..6e948da0 100644
--- a/channel.mu
+++ b/channel.mu
@@ -1,6 +1,6 @@
 # example program: communicating between routines using channels
 
-recipe producer chan:address:shared:channel -> chan:address:shared:channel [
+def producer chan:address:shared:channel -> chan:address:shared:channel [
   # produce characters 1 to 5 on a channel
   local-scope
   load-ingredients
@@ -18,7 +18,7 @@ recipe producer chan:address:shared:channel -> chan:address:shared:channel [
   }
 ]
 
-recipe consumer chan:address:shared:channel -> chan:address:shared:channel [
+def consumer chan:address:shared:channel -> chan:address:shared:channel [
   # consume and print integers from a channel
   local-scope
   load-ingredients
@@ -32,7 +32,7 @@ recipe consumer chan:address:shared:channel -> chan:address:shared:channel [
   }
 ]
 
-recipe main [
+def main [
   local-scope
   chan:address:shared:channel <- new-channel 3
   # create two background 'routines' that communicate by a channel
diff --git a/chessboard.mu b/chessboard.mu
index d7cce788..fcaea5a7 100644
--- a/chessboard.mu
+++ b/chessboard.mu
@@ -2,7 +2,7 @@
 # display the position after each move.
 
 # recipes are mu's names for functions
-recipe main [
+def main [
   open-console  # take control of screen, keyboard and mouse
 
   # The chessboard recipe takes keyboard and screen objects as 'ingredients'.
@@ -66,7 +66,7 @@ scenario print-board-and-read-move [
 
 ## Here's how 'chessboard' is implemented.
 
-recipe chessboard screen:address:shared:screen, console:address:shared:console -> screen:address:shared:screen, console:address:shared:console [
+def chessboard screen:address:shared:screen, console:address:shared:console -> screen:address:shared:screen, console:address:shared:console [
   local-scope
   load-ingredients
   board:address:shared:array:address:shared:array:character <- initial-position
@@ -109,7 +109,7 @@ recipe chessboard screen:address:shared:screen, console:address:shared:console -
 
 ## a board is an array of files, a file is an array of characters (squares)
 
-recipe new-board initial-position:address:shared:array:character -> board:address:shared:array:address:shared:array:character [
+def new-board initial-position:address:shared:array:character -> board:address:shared:array:address:shared:array:character [
   local-scope
   load-ingredients
   # assert(length(initial-position) == 64)
@@ -129,7 +129,7 @@ recipe new-board initial-position:address:shared:array:character -> board:addres
   }
 ]
 
-recipe new-file position:address:shared:array:character, index:number -> result:address:shared:array:character [
+def new-file position:address:shared:array:character, index:number -> result:address:shared:array:character [
   local-scope
   load-ingredients
   index <- multiply index, 8
@@ -146,7 +146,7 @@ recipe new-file position:address:shared:array:character, index:number -> result:
   }
 ]
 
-recipe print-board screen:address:shared:screen, board:address:shared:array:address:shared:array:character -> screen:address:shared:screen [
+def print-board screen:address:shared:screen, board:address:shared:array:address:shared:array:character -> screen:address:shared:screen [
   local-scope
   load-ingredients
   row:number <- copy 7  # start printing from the top of the board
@@ -185,7 +185,7 @@ recipe print-board screen:address:shared:screen, board:address:shared:array:addr
   screen <- cursor-to-next-line screen
 ]
 
-recipe initial-position -> board:address:shared:array:address:shared:array:character [
+def initial-position -> board:address:shared:array:address:shared:array:character [
   local-scope
   # layout in memory (in raster order):
   #   R P _ _ _ _ p r
@@ -242,61 +242,61 @@ container move [
 ]
 
 # prints only error messages to screen
-recipe read-move stdin:address:shared:channel, screen:address:shared:screen -> result:address:shared:move, quit?:boolean, error?:boolean, stdin:address:shared:channel, screen:address:shared:screen [
+def read-move stdin:address:shared:channel, screen:address:shared:screen -> result:address:shared:move, quit?:boolean, error?:boolean, stdin:address:shared:channel, screen:address:shared:screen [
   local-scope
   load-ingredients
   from-file:number, quit?:boolean, error?:boolean <- read-file stdin, screen
-  reply-if quit?, 0/dummy, quit?, error?
-  reply-if error?, 0/dummy, quit?, error?
+  return-if quit?, 0/dummy, quit?, error?
+  return-if error?, 0/dummy, quit?, error?
   # construct the move object
   result:address:shared:move <- new move:type
   x:address:number <- get-address *result, from-file:offset
   *x <- copy from-file
   x <- get-address *result, from-rank:offset
   *x, quit?, error? <- read-rank stdin, screen
-  reply-if quit?, 0/dummy, quit?, error?
-  reply-if error?, 0/dummy, quit?, error?
+  return-if quit?, 0/dummy, quit?, error?
+  return-if error?, 0/dummy, quit?, error?
   error? <- expect-from-channel stdin, 45/dash, screen
-  reply-if error?, 0/dummy, 0/quit, error?
+  return-if error?, 0/dummy, 0/quit, error?
   x <- get-address *result, to-file:offset
   *x, quit?, error? <- read-file stdin, screen
-  reply-if quit?:boolean, 0/dummy, quit?:boolean, error?:boolean
-  reply-if error?:boolean, 0/dummy, quit?:boolean, error?:boolean
+  return-if quit?:boolean, 0/dummy, quit?:boolean, error?:boolean
+  return-if error?:boolean, 0/dummy, quit?:boolean, error?:boolean
   x:address:number <- get-address *result, to-rank:offset
   *x, quit?, error? <- read-rank stdin, screen
-  reply-if quit?, 0/dummy, quit?, error?
-  reply-if error?, 0/dummy, quit?, error?
+  return-if quit?, 0/dummy, quit?, error?
+  return-if error?, 0/dummy, quit?, error?
   error? <- expect-from-channel stdin, 10/newline, screen
-  reply-if error?, 0/dummy, 0/quit, error?
-  reply result, quit?, error?
+  return-if error?, 0/dummy, 0/quit, error?
+  return result, quit?, error?
 ]
 
 # valid values for file: 0-7
-recipe read-file stdin:address:shared:channel, screen:address:shared:screen -> file:number, quit:boolean, error:boolean, stdin:address:shared:channel, screen:address:shared:screen [
+def read-file stdin:address:shared:channel, screen:address:shared:screen -> file:number, quit:boolean, error:boolean, stdin:address:shared:channel, screen:address:shared:screen [
   local-scope
   load-ingredients
   c:character, stdin <- read stdin
   {
     q-pressed?:boolean <- equal c, 81/Q
     break-unless q-pressed?
-    reply 0/dummy, 1/quit, 0/error
+    return 0/dummy, 1/quit, 0/error
   }
   {
     q-pressed? <- equal c, 113/q
     break-unless q-pressed?
-    reply 0/dummy, 1/quit, 0/error
+    return 0/dummy, 1/quit, 0/error
   }
   {
     empty-fake-keyboard?:boolean <- equal c, 0/eof
     break-unless empty-fake-keyboard?
-    reply 0/dummy, 1/quit, 0/error
+    return 0/dummy, 1/quit, 0/error
   }
   {
     newline?:boolean <- equal c, 10/newline
     break-unless newline?
     error-message:address:shared:array:character <- new [that's not enough]
     print screen, error-message
-    reply 0/dummy, 0/quit, 1/error
+    return 0/dummy, 0/quit, 1/error
   }
   file:number <- subtract c, 97/a
   # 'a' <= file <= 'h'
@@ -307,7 +307,7 @@ recipe read-file stdin:address:shared:channel, screen:address:shared:screen -> f
     print screen, error-message
     print screen, c
     cursor-to-next-line screen
-    reply 0/dummy, 0/quit, 1/error
+    return 0/dummy, 0/quit, 1/error
   }
   {
     below-max:boolean <- lesser-than file, 8
@@ -315,32 +315,32 @@ recipe read-file stdin:address:shared:channel, screen:address:shared:screen -> f
     error-message <- new [file too high: ]
     print screen, error-message
     print screen, c
-    reply 0/dummy, 0/quit, 1/error
+    return 0/dummy, 0/quit, 1/error
   }
-  reply file, 0/quit, 0/error
+  return file, 0/quit, 0/error
 ]
 
 # valid values: 0-7, -1 (quit), -2 (error)
-recipe read-rank stdin:address:shared:channel, screen:address:shared:screen -> rank:number, quit?:boolean, error?:boolean, stdin:address:shared:channel, screen:address:shared:screen [
+def read-rank stdin:address:shared:channel, screen:address:shared:screen -> rank:number, quit?:boolean, error?:boolean, stdin:address:shared:channel, screen:address:shared:screen [
   local-scope
   load-ingredients
   c:character, stdin <- read stdin
   {
     q-pressed?:boolean <- equal c, 8/Q
     break-unless q-pressed?
-    reply 0/dummy, 1/quit, 0/error
+    return 0/dummy, 1/quit, 0/error
   }
   {
     q-pressed? <- equal c, 113/q
     break-unless q-pressed?
-    reply 0/dummy, 1/quit, 0/error
+    return 0/dummy, 1/quit, 0/error
   }
   {
     newline?:boolean <- equal c, 10  # newline
     break-unless newline?
     error-message:address:shared:array:character <- new [that's not enough]
     print screen, error-message
-    reply 0/dummy, 0/quit, 1/error
+    return 0/dummy, 0/quit, 1/error
   }
   rank:number <- subtract c, 49/'1'
   # assert'1' <= rank <= '8'
@@ -350,7 +350,7 @@ recipe read-rank stdin:address:shared:channel, screen:address:shared:screen -> r
     error-message <- new [rank too low: ]
     print screen, error-message
     print screen, c
-    reply 0/dummy, 0/quit, 1/error
+    return 0/dummy, 0/quit, 1/error
   }
   {
     below-max:boolean <- lesser-or-equal rank, 7
@@ -358,14 +358,14 @@ recipe read-rank stdin:address:shared:channel, screen:address:shared:screen -> r
     error-message <- new [rank too high: ]
     print screen, error-message
     print screen, c
-    reply 0/dummy, 0/quit, 1/error
+    return 0/dummy, 0/quit, 1/error
   }
-  reply rank, 0/quit, 0/error
+  return rank, 0/quit, 0/error
 ]
 
 # read a character from the given channel and check that it's what we expect
 # return true on error
-recipe expect-from-channel stdin:address:shared:channel, expected:character, screen:address:shared:screen -> result:boolean, stdin:address:shared:channel, screen:address:shared:screen [
+def expect-from-channel stdin:address:shared:channel, expected:character, screen:address:shared:screen -> result:boolean, stdin:address:shared:channel, screen:address:shared:screen [
   local-scope
   load-ingredients
   c:character, stdin <- read stdin
@@ -542,7 +542,7 @@ F read-move-file: routine failed to pause after coming up (before any keys were
   ]
 ]
 
-recipe make-move board:address:shared:array:address:shared:array:character, m:address:shared:move -> board:address:shared:array:address:shared:array:character [
+def make-move board:address:shared:array:address:shared:array:character, m:address:shared:move -> board:address:shared:array:address:shared:array:character [
   local-scope
   load-ingredients
   from-file:number <- get *m, from-file:offset
diff --git a/console.mu b/console.mu
index 1b1d5654..8f7ee83c 100644
--- a/console.mu
+++ b/console.mu
@@ -2,7 +2,7 @@
 #
 # Keeps printing 'a' until you press a key or click on the mouse.
 
-recipe main [
+def main [
   local-scope
   open-console
   {
diff --git a/counters.mu b/counters.mu
index b69b2eee..d3566ce0 100644
--- a/counters.mu
+++ b/counters.mu
@@ -1,19 +1,19 @@
 # example program: maintain multiple counters with isolated lexical scopes
 # (spaces)
 
-recipe new-counter n:number -> default-space:address:shared:array:location [
+def new-counter n:number -> default-space:address:shared:array:location [
   default-space <- new location:type, 30
   load-ingredients
 ]
 
-recipe increment-counter outer:address:shared:array:location/names:new-counter, x:number -> n:number/space:1 [
+def increment-counter outer:address:shared:array:location/names:new-counter, x:number -> n:number/space:1 [
   local-scope
   load-ingredients
   0:address:shared:array:location/names:new-counter <- copy outer  # setup outer space; it *must* come from 'new-counter'
   n/space:1 <- add n/space:1, x
 ]
 
-recipe main [
+def main [
   local-scope
   # counter A
   a:address:shared:array:location <- new-counter 34
@@ -24,9 +24,7 @@ recipe main [
   b-value:number <- increment-counter b, 2
   a-value:number <- increment-counter a, 1
   # check results
-  $print [Contents of counters
-]
+  $print [Contents of counters], 10/newline
   # trailing space in next line is to help with syntax highlighting
-  $print [a: ], a-value, [ b: ], b-value, [ 
-]
+  $print [a: ], a-value, [ b: ], b-value,  10/newline
 ]
diff --git a/display.mu b/display.mu
index 057c7ed1..71aa391e 100644
--- a/display.mu
+++ b/display.mu
@@ -1,6 +1,6 @@
 # example program: managing the display
 
-recipe main [
+def main [
   open-console
   print-character-to-display 97, 1/red, 2/green
   1:number/raw, 2:number/raw <- cursor-position-on-display
diff --git a/edit/001-editor.mu b/edit/001-editor.mu
index d338b4bb..818f3520 100644
--- a/edit/001-editor.mu
+++ b/edit/001-editor.mu
@@ -2,7 +2,7 @@
 
 # temporary main for this layer: just render the given text at the given
 # screen dimensions, then stop
-recipe! main text:address:shared:array:character [
+def! main text:address:shared:array:character [
   local-scope
   load-ingredients
   open-console
@@ -48,7 +48,7 @@ container editor-data [
 # creates a new editor widget and renders its initial appearance to screen
 #   top/left/right constrain the screen area available to the new editor
 #   right is exclusive
-recipe new-editor s:address:shared:array:character, screen:address:shared:screen, left:number, right:number -> result:address:shared:editor-data, screen:address:shared:screen [
+def new-editor s:address:shared:array:character, screen:address:shared:screen, left:number, right:number -> result:address:shared:editor-data, screen:address:shared:screen [
   local-scope
   load-ingredients
   # no clipping of bounds
@@ -79,13 +79,13 @@ recipe new-editor s:address:shared:array:character, screen:address:shared:screen
   <editor-initialization>
 ]
 
-recipe insert-text editor:address:shared:editor-data, text:address:shared:array:character -> editor:address:shared:editor-data [
+def insert-text editor:address:shared:editor-data, text:address:shared:array:character -> editor:address:shared:editor-data [
   local-scope
   load-ingredients
   # early exit if text is empty
-  reply-unless text, editor/same-as-ingredient:0
+  return-unless text, editor/same-as-ingredient:0
   len:number <- length *text
-  reply-unless len, editor/same-as-ingredient:0
+  return-unless len, editor/same-as-ingredient:0
   idx:number <- copy 0
   # now we can start appending the rest, character by character
   curr:address:shared:duplex-list:character <- get *editor, data:offset
@@ -99,7 +99,7 @@ recipe insert-text editor:address:shared:editor-data, text:address:shared:array:
     idx <- add idx, 1
     loop
   }
-  reply editor/same-as-ingredient:0
+  return editor/same-as-ingredient:0
 ]
 
 scenario editor-initializes-without-data [
@@ -129,10 +129,10 @@ scenario editor-initializes-without-data [
 # Assumes cursor should be at coordinates (cursor-row, cursor-column) and
 # updates before-cursor to match. Might also move coordinates if they're
 # outside text.
-recipe render screen:address:shared:screen, editor:address:shared:editor-data -> last-row:number, last-column:number, screen:address:shared:screen, editor:address:shared:editor-data [
+def render screen:address:shared:screen, editor:address:shared:editor-data -> last-row:number, last-column:number, screen:address:shared:screen, editor:address:shared:editor-data [
   local-scope
   load-ingredients
-  reply-unless editor, 1/top, 0/left, screen/same-as-ingredient:0, editor/same-as-ingredient:1
+  return-unless editor, 1/top, 0/left, screen/same-as-ingredient:0, editor/same-as-ingredient:1
   left:number <- get *editor, left:offset
   screen-height:number <- screen-height screen
   right:number <- get *editor, right:offset
@@ -226,10 +226,10 @@ recipe render screen:address:shared:screen, editor:address:shared:editor-data ->
   }
   bottom:address:number <- get-address *editor, bottom:offset
   *bottom <- copy row
-  reply row, column, screen/same-as-ingredient:0, editor/same-as-ingredient:1
+  return row, column, screen/same-as-ingredient:0, editor/same-as-ingredient:1
 ]
 
-recipe clear-line-delimited screen:address:shared:screen, column:number, right:number -> screen:address:shared:screen [
+def clear-line-delimited screen:address:shared:screen, column:number, right:number -> screen:address:shared:screen [
   local-scope
   load-ingredients
   space:character <- copy 32/space
@@ -248,23 +248,23 @@ recipe clear-line-delimited screen:address:shared:screen, column:number, right:n
   }
 ]
 
-recipe clear-screen-from screen:address:shared:screen, row:number, column:number, left:number, right:number -> screen:address:shared:screen [
+def clear-screen-from screen:address:shared:screen, row:number, column:number, left:number, right:number -> screen:address:shared:screen [
   local-scope
   load-ingredients
   # if it's the real screen, use the optimized primitive
   {
     break-if screen
     clear-display-from row, column, left, right
-    reply screen/same-as-ingredient:0
+    return screen/same-as-ingredient:0
   }
   # if not, go the slower route
   screen <- move-cursor screen, row, column
   clear-line-delimited screen, column, right
   clear-rest-of-screen screen, row, left, right
-  reply screen/same-as-ingredient:0
+  return screen/same-as-ingredient:0
 ]
 
-recipe clear-rest-of-screen screen:address:shared:screen, row:number, left:number, right:number -> screen:address:shared:screen [
+def clear-rest-of-screen screen:address:shared:screen, row:number, left:number, right:number -> screen:address:shared:screen [
   local-scope
   load-ingredients
   row <- add row, 1
@@ -422,7 +422,7 @@ after <character-c-received> [
 ]
 
 # so far the previous color is all the information we need; that may change
-recipe get-color color:number, c:character -> color:number [
+def get-color color:number, c:character -> color:number [
   local-scope
   load-ingredients
   color-is-white?:boolean <- equal color, 7/white
@@ -464,7 +464,7 @@ recipe get-color color:number, c:character -> color:number [
   }
   # otherwise no change
   +exit
-  reply color
+  return color
 ]
 
 scenario render-colors-assignment [
diff --git a/edit/002-typing.mu b/edit/002-typing.mu
index f3f6b321..7a68bb64 100644
--- a/edit/002-typing.mu
+++ b/edit/002-typing.mu
@@ -2,7 +2,7 @@
 
 # temporary main: interactive editor
 # hit ctrl-c to exit
-recipe! main text:address:shared:array:character [
+def! main text:address:shared:array:character [
   local-scope
   load-ingredients
   open-console
@@ -11,7 +11,7 @@ recipe! main text:address:shared:array:character [
   close-console
 ]
 
-recipe editor-event-loop screen:address:shared:screen, console:address:shared:console, editor:address:shared:editor-data -> screen:address:shared:screen, console:address:shared:console, editor:address:shared:editor-data [
+def editor-event-loop screen:address:shared:screen, console:address:shared:console, editor:address:shared:editor-data -> screen:address:shared:screen, console:address:shared:console, editor:address:shared:editor-data [
   local-scope
   load-ingredients
   {
@@ -45,35 +45,35 @@ recipe editor-event-loop screen:address:shared:screen, console:address:shared:co
 ]
 
 # process click, return if it was on current editor
-recipe move-cursor-in-editor screen:address:shared:screen, editor:address:shared:editor-data, t:touch-event -> in-focus?:boolean, editor:address:shared:editor-data [
+def move-cursor-in-editor screen:address:shared:screen, editor:address:shared:editor-data, t:touch-event -> in-focus?:boolean, editor:address:shared:editor-data [
   local-scope
   load-ingredients
-  reply-unless editor, 0/false
+  return-unless editor, 0/false
   click-row:number <- get t, row:offset
-  reply-unless click-row, 0/false  # ignore clicks on 'menu'
+  return-unless click-row, 0/false  # ignore clicks on 'menu'
   click-column:number <- get t, column:offset
   left:number <- get *editor, left:offset
   too-far-left?:boolean <- lesser-than click-column, left
-  reply-if too-far-left?, 0/false
+  return-if too-far-left?, 0/false
   right:number <- get *editor, right:offset
   too-far-right?:boolean <- greater-than click-column, right
-  reply-if too-far-right?, 0/false
+  return-if too-far-right?, 0/false
   # position cursor
   <move-cursor-begin>
   editor <- snap-cursor screen, editor, click-row, click-column
   undo-coalesce-tag:number <- copy 0/never
   <move-cursor-end>
   # gain focus
-  reply 1/true
+  return 1/true
 ]
 
 # Variant of 'render' that only moves the cursor (coordinates and
 # before-cursor). If it's past the end of a line, it 'slides' it left. If it's
 # past the last line it positions at end of last line.
-recipe snap-cursor screen:address:shared:screen, editor:address:shared:editor-data, target-row:number, target-column:number -> editor:address:shared:editor-data [
+def snap-cursor screen:address:shared:screen, editor:address:shared:editor-data, target-row:number, target-column:number -> editor:address:shared:editor-data [
   local-scope
   load-ingredients
-  reply-unless editor
+  return-unless editor
   left:number <- get *editor, left:offset
   right:number <- get *editor, right:offset
   screen-height:number <- screen-height screen
@@ -155,11 +155,11 @@ recipe snap-cursor screen:address:shared:screen, editor:address:shared:editor-da
 
 # Process an event 'e' and try to minimally update the screen.
 # Set 'go-render?' to true to indicate the caller must perform a non-minimal update.
-recipe handle-keyboard-event screen:address:shared:screen, editor:address:shared:editor-data, e:event -> screen:address:shared:screen, editor:address:shared:editor-data, go-render?:boolean [
+def handle-keyboard-event screen:address:shared:screen, editor:address:shared:editor-data, e:event -> screen:address:shared:screen, editor:address:shared:editor-data, go-render?:boolean [
   local-scope
   load-ingredients
   go-render? <- copy 0/false
-  reply-unless editor
+  return-unless editor
   screen-width:number <- screen-width screen
   screen-height:number <- screen-height screen
   left:number <- get *editor, left:offset
@@ -179,12 +179,12 @@ recipe handle-keyboard-event screen:address:shared:screen, editor:address:shared
     # ignore any other special characters
     regular-character?:boolean <- greater-or-equal *c, 32/space
     go-render? <- copy 0/false
-    reply-unless regular-character?
+    return-unless regular-character?
     # otherwise type it in
     <insert-character-begin>
     editor, screen, go-render?:boolean <- insert-at-cursor editor, *c, screen
     <insert-character-end>
-    reply
+    return
   }
   # special key to modify the text or move the cursor
   k:address:number <- maybe-convert e:event, keycode:variant
@@ -192,10 +192,10 @@ recipe handle-keyboard-event screen:address:shared:screen, editor:address:shared
   # handlers for each special key will go here
   <handle-special-key>
   go-render? <- copy 1/true
-  reply
+  return
 ]
 
-recipe insert-at-cursor editor:address:shared:editor-data, c:character, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean [
+def insert-at-cursor editor:address:shared:editor-data, c:character, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean [
   local-scope
   load-ingredients
   before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
@@ -226,7 +226,7 @@ recipe insert-at-cursor editor:address:shared:editor-data, c:character, screen:a
     move-cursor screen, save-row, save-column
     print screen, c
     go-render? <- copy 0/false
-    reply
+    return
   }
   {
     # not at right margin? print the character and rest of line
@@ -240,7 +240,7 @@ recipe insert-at-cursor editor:address:shared:editor-data, c:character, screen:a
       # hit right margin? give up and let caller render
       go-render? <- copy 1/true
       at-right?:boolean <- greater-than curr-column, right
-      reply-if at-right?
+      return-if at-right?
       break-unless curr
       # newline? done.
       currc:character <- get *curr, value:offset
@@ -252,14 +252,14 @@ recipe insert-at-cursor editor:address:shared:editor-data, c:character, screen:a
       loop
     }
     go-render? <- copy 0/false
-    reply
+    return
   }
   go-render? <- copy 1/true
-  reply
+  return
 ]
 
 # helper for tests
-recipe editor-render screen:address:shared:screen, editor:address:shared:editor-data -> screen:address:shared:screen, editor:address:shared:editor-data [
+def editor-render screen:address:shared:screen, editor:address:shared:editor-data -> screen:address:shared:screen, editor:address:shared:editor-data [
   local-scope
   load-ingredients
   left:number <- get *editor, left:offset
@@ -697,7 +697,7 @@ after <insert-character-special-case> [
       <scroll-down>
     }
     go-render? <- copy 1/true
-    reply
+    return
   }
 ]
 
@@ -818,11 +818,11 @@ after <handle-special-character> [
     editor <- insert-new-line-and-indent editor, screen
     <insert-enter-end>
     go-render? <- copy 1/true
-    reply
+    return
   }
 ]
 
-recipe insert-new-line-and-indent editor:address:shared:editor-data, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean [
+def insert-new-line-and-indent editor:address:shared:editor-data, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean [
   local-scope
   load-ingredients
   cursor-row:address:number <- get-address *editor, cursor-row:offset
@@ -846,7 +846,7 @@ recipe insert-new-line-and-indent editor:address:shared:editor-data, screen:addr
   }
   # indent if necessary
   indent?:boolean <- get *editor, indent?:offset
-  reply-unless indent?
+  return-unless indent?
   d:address:shared:duplex-list:character <- get *editor, data:offset
   end-of-previous-line:address:shared:duplex-list:character <- prev *before-cursor
   indent:number <- line-indent end-of-previous-line, d
@@ -862,13 +862,13 @@ recipe insert-new-line-and-indent editor:address:shared:editor-data, screen:addr
 
 # takes a pointer 'curr' into the doubly-linked list and its sentinel, counts
 # the number of spaces at the start of the line containing 'curr'.
-recipe line-indent curr:address:shared:duplex-list:character, start:address:shared:duplex-list:character -> result:number [
+def line-indent curr:address:shared:duplex-list:character, start:address:shared:duplex-list:character -> result:number [
   local-scope
   load-ingredients
   result:number <- copy 0
-  reply-unless curr
+  return-unless curr
   at-start?:boolean <- equal curr, start
-  reply-if at-start?
+  return-if at-start?
   {
     curr <- prev curr
     break-unless curr
@@ -995,7 +995,7 @@ after <handle-special-key> [
     indent?:address:boolean <- get-address *editor, indent?:offset
     *indent? <- copy 0/false
     go-render? <- copy 1/true
-    reply
+    return
   }
 ]
 
@@ -1006,13 +1006,13 @@ after <handle-special-key> [
     indent?:address:boolean <- get-address *editor, indent?:offset
     *indent? <- copy 1/true
     go-render? <- copy 1/true
-    reply
+    return
   }
 ]
 
 ## helpers
 
-recipe draw-horizontal screen:address:shared:screen, row:number, x:number, right:number -> screen:address:shared:screen [
+def draw-horizontal screen:address:shared:screen, row:number, x:number, right:number -> screen:address:shared:screen [
   local-scope
   load-ingredients
   style:character, style-found?:boolean <- next-ingredient
diff --git a/edit/003-shortcuts.mu b/edit/003-shortcuts.mu
index f6c762a6..c09c3441 100644
--- a/edit/003-shortcuts.mu
+++ b/edit/003-shortcuts.mu
@@ -32,7 +32,7 @@ after <handle-special-character> [
     editor, screen, go-render?:boolean <- insert-at-cursor editor, 32/space, screen
     <insert-character-end>
     go-render? <- copy 1/true
-    reply
+    return
   }
 ]
 
@@ -73,14 +73,14 @@ after <handle-special-character> [
     <backspace-character-begin>
     editor, screen, go-render?:boolean, backspaced-cell:address:shared:duplex-list:character <- delete-before-cursor editor, screen
     <backspace-character-end>
-    reply
+    return
   }
 ]
 
 # return values:
 #   go-render? - whether caller needs to update the screen
 #   backspaced-cell - value deleted (or 0 if nothing was deleted) so we can save it for undo, etc.
-recipe delete-before-cursor editor:address:shared:editor-data, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean, backspaced-cell:address:shared:duplex-list:character [
+def delete-before-cursor editor:address:shared:editor-data, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean, backspaced-cell:address:shared:duplex-list:character [
   local-scope
   load-ingredients
   before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
@@ -88,7 +88,7 @@ recipe delete-before-cursor editor:address:shared:editor-data, screen:address:sh
   # if at start of text (before-cursor at § sentinel), return
   prev:address:shared:duplex-list:character <- prev *before-cursor
   go-render?, backspaced-cell <- copy 0/no-more-render, 0/nothing-deleted
-  reply-unless prev
+  return-unless prev
   trace 10, [app], [delete-before-cursor]
   original-row:number <- get *editor, cursor-row:offset
   editor, scroll?:boolean <- move-cursor-coordinates-left editor
@@ -96,14 +96,14 @@ recipe delete-before-cursor editor:address:shared:editor-data, screen:address:sh
   data <- remove *before-cursor, data  # will also neatly trim next/prev pointers in backspaced-cell/*before-cursor
   *before-cursor <- copy prev
   go-render? <- copy 1/true
-  reply-if scroll?
+  return-if scroll?
   screen-width:number <- screen-width screen
   cursor-row:number <- get *editor, cursor-row:offset
   cursor-column:number <- get *editor, cursor-column:offset
   # did we just backspace over a newline?
   same-row?:boolean <- equal cursor-row, original-row
   go-render? <- copy 1/true
-  reply-unless same-row?
+  return-unless same-row?
   left:number <- get *editor, left:offset
   right:number <- get *editor, right:offset
   curr:address:shared:duplex-list:character <- next *before-cursor
@@ -113,7 +113,7 @@ recipe delete-before-cursor editor:address:shared:editor-data, screen:address:sh
     # hit right margin? give up and let caller render
     at-right?:boolean <- greater-or-equal curr-column, right
     go-render? <- copy 1/true
-    reply-if at-right?
+    return-if at-right?
     break-unless curr
     # newline? done.
     currc:character <- get *curr, value:offset
@@ -130,7 +130,7 @@ recipe delete-before-cursor editor:address:shared:editor-data, screen:address:sh
   go-render? <- copy 0/false
 ]
 
-recipe move-cursor-coordinates-left editor:address:shared:editor-data -> editor:address:shared:editor-data, go-render?:boolean [
+def move-cursor-coordinates-left editor:address:shared:editor-data -> editor:address:shared:editor-data, go-render?:boolean [
   local-scope
   load-ingredients
   before-cursor:address:shared:duplex-list:character <- get *editor, before-cursor:offset
@@ -144,7 +144,7 @@ recipe move-cursor-coordinates-left editor:address:shared:editor-data -> editor:
     trace 10, [app], [decrementing cursor column]
     *cursor-column <- subtract *cursor-column, 1
     go-render? <- copy 0/false
-    reply
+    return
   }
   # if at left margin, we must move to previous row:
   top-of-screen?:boolean <- equal *cursor-row, 1  # exclude menu bar
@@ -179,7 +179,7 @@ recipe move-cursor-coordinates-left editor:address:shared:editor-data -> editor:
       break-if wrap?
       *cursor-column <- add left, end-of-line
     }
-    reply
+    return
   }
   # case 2: if previous-character was not newline, we're just at a wrapped line
   trace 10, [app], [wrapping to previous line]
@@ -189,13 +189,13 @@ recipe move-cursor-coordinates-left editor:address:shared:editor-data -> editor:
 
 # takes a pointer 'curr' into the doubly-linked list and its sentinel, counts
 # the length of the previous line before the 'curr' pointer.
-recipe previous-line-length curr:address:shared:duplex-list:character, start:address:shared:duplex-list:character -> result:number [
+def previous-line-length curr:address:shared:duplex-list:character, start:address:shared:duplex-list:character -> result:number [
   local-scope
   load-ingredients
   result:number <- copy 0
-  reply-unless curr
+  return-unless curr
   at-start?:boolean <- equal curr, start
-  reply-if at-start?
+  return-if at-start?
   {
     curr <- prev curr
     break-unless curr
@@ -338,23 +338,23 @@ after <handle-special-key> [
     <delete-character-begin>
     editor, screen, go-render?:boolean, deleted-cell:address:shared:duplex-list:character <- delete-at-cursor editor, screen
     <delete-character-end>
-    reply
+    return
   }
 ]
 
-recipe delete-at-cursor editor:address:shared:editor-data, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean, deleted-cell:address:shared:duplex-list:character [
+def delete-at-cursor editor:address:shared:editor-data, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean, deleted-cell:address:shared:duplex-list:character [
   local-scope
   load-ingredients
   before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
   data:address:shared:duplex-list:character <- get *editor, data:offset
   deleted-cell:address:shared:duplex-list:character <- next *before-cursor
   go-render? <- copy 0/false
-  reply-unless deleted-cell
+  return-unless deleted-cell
   currc:character <- get *deleted-cell, value:offset
   data <- remove deleted-cell, data
   deleted-newline?:boolean <- equal currc, 10/newline
   go-render? <- copy 1/true
-  reply-if deleted-newline?
+  return-if deleted-newline?
   # wasn't a newline? render rest of line
   curr:address:shared:duplex-list:character <- next *before-cursor  # refresh after remove above
   cursor-row:address:number <- get-address *editor, cursor-row:offset
@@ -366,7 +366,7 @@ recipe delete-at-cursor editor:address:shared:editor-data, screen:address:shared
     # hit right margin? give up and let caller render
     at-right?:boolean <- greater-or-equal curr-column, screen-width
     go-render? <- copy 1/true
-    reply-if at-right?
+    return-if at-right?
     break-unless curr
     # newline? done.
     currc:character <- get *curr, value:offset
@@ -421,11 +421,11 @@ after <handle-special-key> [
     screen <- move-cursor screen, *cursor-row, *cursor-column
     undo-coalesce-tag:number <- copy 2/right-arrow
     <move-cursor-end>
-    reply
+    return
   }
 ]
 
-recipe move-cursor-coordinates-right editor:address:shared:editor-data, screen-height:number -> editor:address:shared:editor-data, go-render?:boolean [
+def move-cursor-coordinates-right editor:address:shared:editor-data, screen-height:number -> editor:address:shared:editor-data, go-render?:boolean [
   local-scope
   load-ingredients
   before-cursor:address:shared:duplex-list:character <- get *editor before-cursor:offset
@@ -442,11 +442,11 @@ recipe move-cursor-coordinates-right editor:address:shared:editor-data, screen-h
     *cursor-column <- copy left
     below-screen?:boolean <- greater-or-equal *cursor-row, screen-height  # must be equal
     go-render? <- copy 0/false
-    reply-unless below-screen?
+    return-unless below-screen?
     <scroll-down>
     *cursor-row <- subtract *cursor-row, 1  # bring back into screen range
     go-render? <- copy 1/true
-    reply
+    return
   }
   # if the line wraps, move cursor to start of next row
   {
@@ -463,11 +463,11 @@ recipe move-cursor-coordinates-right editor:address:shared:editor-data, screen-h
     *cursor-row <- add *cursor-row, 1
     *cursor-column <- copy left
     below-screen?:boolean <- greater-or-equal *cursor-row, screen-height  # must be equal
-    reply-unless below-screen?, editor/same-as-ingredient:0, 0/no-more-render
+    return-unless below-screen?, editor/same-as-ingredient:0, 0/no-more-render
     <scroll-down>
     *cursor-row <- subtract *cursor-row, 1  # bring back into screen range
     go-render? <- copy 1/true
-    reply
+    return
   }
   # otherwise move cursor one character right
   *cursor-column <- add *cursor-column, 1
@@ -691,13 +691,13 @@ after <handle-special-key> [
     # if not at start of text (before-cursor at § sentinel)
     prev:address:shared:duplex-list:character <- prev *before-cursor
     go-render? <- copy 0/false
-    reply-unless prev
+    return-unless prev
     <move-cursor-begin>
     editor, go-render? <- move-cursor-coordinates-left editor
     *before-cursor <- copy prev
     undo-coalesce-tag:number <- copy 1/left-arrow
     <move-cursor-end>
-    reply
+    return
   }
 ]
 
@@ -954,11 +954,11 @@ after <handle-special-key> [
     editor, go-render? <- move-to-previous-line editor
     undo-coalesce-tag:number <- copy 3/up-arrow
     <move-cursor-end>
-    reply
+    return
   }
 ]
 
-recipe move-to-previous-line editor:address:shared:editor-data -> editor:address:shared:editor-data, go-render?:boolean [
+def move-to-previous-line editor:address:shared:editor-data -> editor:address:shared:editor-data, go-render?:boolean [
   local-scope
   load-ingredients
   cursor-row:address:number <- get-address *editor, cursor-row:offset
@@ -982,14 +982,14 @@ recipe move-to-previous-line editor:address:shared:editor-data -> editor:address
       curr:address:shared:duplex-list:character <- before-previous-line curr, editor
       no-motion?:boolean <- equal curr, old
       go-render? <- copy 0/false
-      reply-if no-motion?
+      return-if no-motion?
     }
     {
       old <- copy curr
       curr <- before-previous-line curr, editor
       no-motion?:boolean <- equal curr, old
       go-render? <- copy 0/false
-      reply-if no-motion?
+      return-if no-motion?
     }
     *before-cursor <- copy curr
     *cursor-row <- subtract *cursor-row, 1
@@ -1010,14 +1010,14 @@ recipe move-to-previous-line editor:address:shared:editor-data -> editor:address
       loop
     }
     go-render? <- copy 0/false
-    reply
+    return
   }
   {
     # if cursor already at top, scroll up
     break-unless already-at-top?
     <scroll-up>
     go-render? <- copy 1/true
-    reply
+    return
   }
 ]
 
@@ -1179,11 +1179,11 @@ after <handle-special-key> [
     editor, go-render? <- move-to-next-line editor, screen-height
     undo-coalesce-tag:number <- copy 4/down-arrow
     <move-cursor-end>
-    reply
+    return
   }
 ]
 
-recipe move-to-next-line editor:address:shared:editor-data, screen-height:number -> editor:address:shared:editor-data, go-render?:boolean [
+def move-to-next-line editor:address:shared:editor-data, screen-height:number -> editor:address:shared:editor-data, go-render?:boolean [
   local-scope
   load-ingredients
   cursor-row:address:number <- get-address *editor, cursor-row:offset
@@ -1207,7 +1207,7 @@ recipe move-to-next-line editor:address:shared:editor-data, screen-height:number
       scroll?:boolean <- greater-than *cursor-row, 1
       break-if scroll?, +try-to-scroll:label
       go-render? <- copy 0/false
-      reply
+      return
     }
     *cursor-row <- add *cursor-row, 1
     *before-cursor <- copy next-line
@@ -1227,7 +1227,7 @@ recipe move-to-next-line editor:address:shared:editor-data, screen-height:number
       loop
     }
     go-render? <- copy 0/false
-    reply
+    return
   }
   +try-to-scroll
   <scroll-down>
@@ -1306,7 +1306,7 @@ after <handle-special-character> [
     undo-coalesce-tag:number <- copy 0/never
     <move-cursor-end>
     go-render? <- copy 0/false
-    reply
+    return
   }
 ]
 
@@ -1319,11 +1319,11 @@ after <handle-special-key> [
     undo-coalesce-tag:number <- copy 0/never
     <move-cursor-end>
     go-render? <- copy 0/false
-    reply
+    return
   }
 ]
 
-recipe move-to-start-of-line editor:address:shared:editor-data -> editor:address:shared:editor-data [
+def move-to-start-of-line editor:address:shared:editor-data -> editor:address:shared:editor-data [
   local-scope
   load-ingredients
   # update cursor column
@@ -1477,7 +1477,7 @@ after <handle-special-character> [
     undo-coalesce-tag:number <- copy 0/never
     <move-cursor-end>
     go-render? <- copy 0/false
-    reply
+    return
   }
 ]
 
@@ -1490,11 +1490,11 @@ after <handle-special-key> [
     undo-coalesce-tag:number <- copy 0/never
     <move-cursor-end>
     go-render? <- copy 0/false
-    reply
+    return
   }
 ]
 
-recipe move-to-end-of-line editor:address:shared:editor-data -> editor:address:shared:editor-data [
+def move-to-end-of-line editor:address:shared:editor-data -> editor:address:shared:editor-data [
   local-scope
   load-ingredients
   before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
@@ -1620,11 +1620,11 @@ after <handle-special-character> [
     deleted-cells:address:shared:duplex-list:character <- delete-to-start-of-line editor
     <delete-to-start-of-line-end>
     go-render? <- copy 1/true
-    reply
+    return
   }
 ]
 
-recipe delete-to-start-of-line editor:address:shared:editor-data -> result:address:shared:duplex-list:character, editor:address:shared:editor-data [
+def delete-to-start-of-line editor:address:shared:editor-data -> result:address:shared:duplex-list:character, editor:address:shared:editor-data [
   local-scope
   load-ingredients
   # compute range to delete
@@ -1754,11 +1754,11 @@ after <handle-special-character> [
     deleted-cells:address:shared:duplex-list:character <- delete-to-end-of-line editor
     <delete-to-end-of-line-end>
     go-render? <- copy 1/true
-    reply
+    return
   }
 ]
 
-recipe delete-to-end-of-line editor:address:shared:editor-data -> result:address:shared:duplex-list:character, editor:address:shared:editor-data [
+def delete-to-end-of-line editor:address:shared:editor-data -> result:address:shared:duplex-list:character, editor:address:shared:editor-data [
   local-scope
   load-ingredients
   # compute range to delete
@@ -1937,13 +1937,13 @@ after <scroll-down> [
   *top-of-screen <- before-start-of-next-line *top-of-screen, max
   no-movement?:boolean <- equal old-top, *top-of-screen
   go-render? <- copy 0/false
-  reply-if no-movement?
+  return-if no-movement?
 ]
 
 # takes a pointer into the doubly-linked list, scans ahead at most 'max'
 # positions until the next newline
 # beware: never return null pointer.
-recipe before-start-of-next-line original:address:shared:duplex-list:character, max:number -> curr:address:shared:duplex-list:character [
+def before-start-of-next-line original:address:shared:duplex-list:character, max:number -> curr:address:shared:duplex-list:character [
   local-scope
   load-ingredients
   count:number <- copy 0
@@ -1957,7 +1957,7 @@ recipe before-start-of-next-line original:address:shared:duplex-list:character,
     count <- add count, 1
   }
   {
-    reply-unless curr, original
+    return-unless curr, original
     done?:boolean <- greater-or-equal count, max
     break-if done?
     c:character <- get *curr, value:offset
@@ -1967,8 +1967,8 @@ recipe before-start-of-next-line original:address:shared:duplex-list:character,
     count <- add count, 1
     loop
   }
-  reply-unless curr, original
-  reply curr
+  return-unless curr, original
+  return curr
 ]
 
 scenario editor-scrolls-down-past-wrapped-line-using-arrow-keys [
@@ -2304,13 +2304,13 @@ after <scroll-up> [
   *top-of-screen <- before-previous-line *top-of-screen, editor
   no-movement?:boolean <- equal old-top, *top-of-screen
   go-render? <- copy 0/false
-  reply-if no-movement?
+  return-if no-movement?
 ]
 
 # takes a pointer into the doubly-linked list, scans back to before start of
 # previous *wrapped* line
 # beware: never return null pointer
-recipe before-previous-line in:address:shared:duplex-list:character, editor:address:shared:editor-data -> out:address:shared:duplex-list:character [
+def before-previous-line in:address:shared:duplex-list:character, editor:address:shared:editor-data -> out:address:shared:duplex-list:character [
   local-scope
   load-ingredients
   curr:address:shared:duplex-list:character <- copy in
@@ -2327,8 +2327,8 @@ recipe before-previous-line in:address:shared:duplex-list:character, editor:addr
     break-if len
     # empty line; just skip this newline
     prev:address:shared:duplex-list:character <- prev curr
-    reply-unless prev, curr
-    reply prev
+    return-unless prev, curr
+    return prev
   }
   _, max:number <- divide-with-remainder len, max-line-length
   # remainder 0 => scan one width-worth
@@ -2348,7 +2348,7 @@ recipe before-previous-line in:address:shared:duplex-list:character, editor:addr
     count <- add count, 1
     loop
   }
-  reply curr
+  return curr
 ]
 
 scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys [
@@ -2698,7 +2698,7 @@ after <handle-special-character> [
     <move-cursor-end>
     no-movement?:boolean <- equal *top-of-screen, old-top
     go-render? <- not no-movement?
-    reply
+    return
   }
 ]
 
@@ -2714,18 +2714,18 @@ after <handle-special-key> [
     <move-cursor-end>
     no-movement?:boolean <- equal *top-of-screen, old-top
     go-render? <- not no-movement?
-    reply
+    return
   }
 ]
 
 # page-down skips entire wrapped lines, so it can't scroll past lines
 # taking up the entire screen
-recipe page-down editor:address:shared:editor-data -> editor:address:shared:editor-data [
+def page-down editor:address:shared:editor-data -> editor:address:shared:editor-data [
   local-scope
   load-ingredients
   # if editor contents don't overflow screen, do nothing
   bottom-of-screen:address:shared:duplex-list:character <- get *editor, bottom-of-screen:offset
-  reply-unless bottom-of-screen
+  return-unless bottom-of-screen
   # if not, position cursor at final character
   before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
   *before-cursor <- prev bottom-of-screen
@@ -2890,7 +2890,7 @@ after <handle-special-character> [
     <move-cursor-end>
     no-movement?:boolean <- equal *top-of-screen, old-top
     go-render? <- not no-movement?
-    reply
+    return
   }
 ]
 
@@ -2907,11 +2907,11 @@ after <handle-special-key> [
     no-movement?:boolean <- equal *top-of-screen, old-top
     # don't bother re-rendering if nothing changed. todo: test this
     go-render? <- not no-movement?
-    reply
+    return
   }
 ]
 
-recipe page-up editor:address:shared:editor-data, screen-height:number -> editor:address:shared:editor-data [
+def page-up editor:address:shared:editor-data, screen-height:number -> editor:address:shared:editor-data [
   local-scope
   load-ingredients
   max:number <- subtract screen-height, 1/menu-bar, 1/overlapping-line
diff --git a/edit/004-programming-environment.mu b/edit/004-programming-environment.mu
index 75d14245..e8ff90d8 100644
--- a/edit/004-programming-environment.mu
+++ b/edit/004-programming-environment.mu
@@ -3,7 +3,7 @@
 # Consists of one editor on the left for recipes and one on the right for the
 # sandbox.
 
-recipe! main [
+def! main [
   local-scope
   open-console
   initial-recipe:address:shared:array:character <- restore [recipes.mu]
@@ -21,7 +21,7 @@ container programming-environment-data [
   sandbox-in-focus?:boolean  # false => cursor in recipes; true => cursor in current-sandbox
 ]
 
-recipe new-programming-environment screen:address:shared:screen, initial-recipe-contents:address:shared:array:character, initial-sandbox-contents:address:shared:array:character -> result:address:shared:programming-environment-data, screen:address:shared:screen [
+def new-programming-environment screen:address:shared:screen, initial-recipe-contents:address:shared:array:character, initial-sandbox-contents:address:shared:array:character -> result:address:shared:programming-environment-data, screen:address:shared:screen [
   local-scope
   load-ingredients
   width:number <- screen-width screen
@@ -48,7 +48,7 @@ recipe new-programming-environment screen:address:shared:screen, initial-recipe-
   <programming-environment-initialization>
 ]
 
-recipe event-loop screen:address:shared:screen, console:address:shared:console, env:address:shared:programming-environment-data -> screen:address:shared:screen, console:address:shared:console, env:address:shared:programming-environment-data [
+def event-loop screen:address:shared:screen, console:address:shared:console, env:address:shared:programming-environment-data -> screen:address:shared:screen, console:address:shared:console, env:address:shared:programming-environment-data [
   local-scope
   load-ingredients
   recipes:address:shared:editor-data <- get *env, recipes:offset
@@ -180,7 +180,7 @@ recipe event-loop screen:address:shared:screen, console:address:shared:console,
   }
 ]
 
-recipe resize screen:address:shared:screen, env:address:shared:programming-environment-data -> env:address:shared:programming-environment-data, screen:address:shared:screen [
+def resize screen:address:shared:screen, env:address:shared:programming-environment-data -> env:address:shared:programming-environment-data, screen:address:shared:screen [
   local-scope
   load-ingredients
   clear-screen screen  # update screen dimensions
@@ -372,7 +372,7 @@ def]
   ]
 ]
 
-recipe render-all screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen, env:address:shared:programming-environment-data [
+def render-all screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen, env:address:shared:programming-environment-data [
   local-scope
   load-ingredients
   trace 10, [app], [render all]
@@ -405,7 +405,7 @@ recipe render-all screen:address:shared:screen, env:address:shared:programming-e
   show-screen screen
 ]
 
-recipe render-recipes screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen, env:address:shared:programming-environment-data [
+def render-recipes screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen, env:address:shared:programming-environment-data [
   local-scope
   load-ingredients
   trace 11, [app], [render recipes]
@@ -424,7 +424,7 @@ recipe render-recipes screen:address:shared:screen, env:address:shared:programmi
 ]
 
 # replaced in a later layer
-recipe render-sandbox-side screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen, env:address:shared:programming-environment-data [
+def render-sandbox-side screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen, env:address:shared:programming-environment-data [
   local-scope
   load-ingredients
   current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
@@ -439,7 +439,7 @@ recipe render-sandbox-side screen:address:shared:screen, env:address:shared:prog
   clear-screen-from screen, row, left, left, right
 ]
 
-recipe update-cursor screen:address:shared:screen, recipes:address:shared:editor-data, current-sandbox:address:shared:editor-data, sandbox-in-focus?:boolean, env:address:shared:programming-environment-data -> screen:address:shared:screen [
+def update-cursor screen:address:shared:screen, recipes:address:shared:editor-data, current-sandbox:address:shared:editor-data, sandbox-in-focus?:boolean, env:address:shared:programming-environment-data -> screen:address:shared:screen [
   local-scope
   load-ingredients
   <update-cursor-special-cases>
@@ -458,10 +458,10 @@ recipe update-cursor screen:address:shared:screen, recipes:address:shared:editor
 
 # print a text 's' to 'editor' in 'color' starting at 'row'
 # clear rest of last line, move cursor to next line
-recipe render screen:address:shared:screen, s:address:shared:array:character, left:number, right:number, color:number, row:number -> row:number, screen:address:shared:screen [
+def render screen:address:shared:screen, s:address:shared:array:character, left:number, right:number, color:number, row:number -> row:number, screen:address:shared:screen [
   local-scope
   load-ingredients
-  reply-unless s
+  return-unless s
   column:number <- copy left
   screen <- move-cursor screen, row, column
   screen-height:number <- screen-height screen
@@ -519,10 +519,10 @@ recipe render screen:address:shared:screen, s:address:shared:array:character, le
 ]
 
 # like 'render' for texts, but with colorization for comments like in the editor
-recipe render-code screen:address:shared:screen, s:address:shared:array:character, left:number, right:number, row:number -> row:number, screen:address:shared:screen [
+def render-code screen:address:shared:screen, s:address:shared:array:character, left:number, right:number, row:number -> row:number, screen:address:shared:screen [
   local-scope
   load-ingredients
-  reply-unless s
+  return-unless s
   color:number <- copy 7/white
   column:number <- copy left
   screen <- move-cursor screen, row, column
@@ -608,7 +608,7 @@ after <global-type> [
 
 ## helpers
 
-recipe draw-vertical screen:address:shared:screen, col:number, y:number, bottom:number -> screen:address:shared:screen [
+def draw-vertical screen:address:shared:screen, col:number, y:number, bottom:number -> screen:address:shared:screen [
   local-scope
   load-ingredients
   style:character, style-found?:boolean <- next-ingredient
diff --git a/edit/005-sandbox.mu b/edit/005-sandbox.mu
index 4f96e55e..361a346f 100644
--- a/edit/005-sandbox.mu
+++ b/edit/005-sandbox.mu
@@ -4,7 +4,7 @@
 # (non-editable) sandboxes below the editor, showing the result and a maybe
 # few other things.
 
-recipe! main [
+def! main [
   local-scope
   open-console
   initial-recipe:address:shared:array:character <- restore [recipes.mu]
@@ -142,11 +142,11 @@ after <global-keypress> [
   }
 ]
 
-recipe run-sandboxes env:address:shared:programming-environment-data, screen:address:shared:screen -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
+def run-sandboxes env:address:shared:programming-environment-data, screen:address:shared:screen -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
   local-scope
   load-ingredients
   errors-found?:boolean, env, screen <- update-recipes env, screen
-  reply-if errors-found?
+  return-if errors-found?
   # check contents of right editor (sandbox)
   <run-sandboxes-begin>
   current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
@@ -189,7 +189,7 @@ recipe run-sandboxes env:address:shared:programming-environment-data, screen:add
 
 # copy code from recipe editor, persist, load into mu
 # replaced in a later layer (whereupon errors-found? will actually be set)
-recipe update-recipes env:address:shared:programming-environment-data, screen:address:shared:screen -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
+def update-recipes env:address:shared:programming-environment-data, screen:address:shared:screen -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
   local-scope
   load-ingredients
   recipes:address:shared:editor-data <- get *env, recipes:offset
@@ -200,7 +200,7 @@ recipe update-recipes env:address:shared:programming-environment-data, screen:ad
 ]
 
 # replaced in a later layer
-recipe! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data, idx:number -> sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data [
+def! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data, idx:number -> sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data [
   local-scope
   load-ingredients
   data:address:shared:array:character <- get *sandbox, data:offset
@@ -209,14 +209,14 @@ recipe! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:p
   *response, _, *fake-screen <- run-interactive data
 ]
 
-recipe update-status screen:address:shared:screen, msg:address:shared:array:character, color:number -> screen:address:shared:screen [
+def update-status screen:address:shared:screen, msg:address:shared:array:character, color:number -> screen:address:shared:screen [
   local-scope
   load-ingredients
   screen <- move-cursor screen, 0, 2
   screen <- print screen, msg, color, 238/grey/background
 ]
 
-recipe save-sandboxes env:address:shared:programming-environment-data [
+def save-sandboxes env:address:shared:programming-environment-data [
   local-scope
   load-ingredients
   current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
@@ -237,7 +237,7 @@ recipe save-sandboxes env:address:shared:programming-environment-data [
   }
 ]
 
-recipe! render-sandbox-side screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen, env:address:shared:programming-environment-data [
+def! render-sandbox-side screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen, env:address:shared:programming-environment-data [
   local-scope
   load-ingredients
   trace 11, [app], [render sandbox side]
@@ -261,13 +261,13 @@ recipe! render-sandbox-side screen:address:shared:screen, env:address:shared:pro
   clear-rest-of-screen screen, row, left, right
 ]
 
-recipe render-sandboxes screen:address:shared:screen, sandbox:address:shared:sandbox-data, left:number, right:number, row:number, render-from:number, idx:number -> row:number, screen:address:shared:screen, sandbox:address:shared:sandbox-data [
+def render-sandboxes screen:address:shared:screen, sandbox:address:shared:sandbox-data, left:number, right:number, row:number, render-from:number, idx:number -> row:number, screen:address:shared:screen, sandbox:address:shared:sandbox-data [
   local-scope
   load-ingredients
-  reply-unless sandbox
+  return-unless sandbox
   screen-height:number <- screen-height screen
   at-bottom?:boolean <- greater-or-equal row, screen-height
-  reply-if at-bottom?:boolean
+  return-if at-bottom?:boolean
   hidden?:boolean <- lesser-than idx, render-from
   {
     break-if hidden?
@@ -304,7 +304,7 @@ recipe render-sandboxes screen:address:shared:screen, sandbox:address:shared:san
     }
     +render-sandbox-end
     at-bottom?:boolean <- greater-or-equal row, screen-height
-    reply-if at-bottom?
+    return-if at-bottom?
     # draw solid line after sandbox
     draw-horizontal screen, row, left, right, 9473/horizontal-double
   }
@@ -324,7 +324,7 @@ recipe render-sandboxes screen:address:shared:screen, sandbox:address:shared:san
 ]
 
 # assumes programming environment has no sandboxes; restores them from previous session
-recipe restore-sandboxes env:address:shared:programming-environment-data -> env:address:shared:programming-environment-data [
+def restore-sandboxes env:address:shared:programming-environment-data -> env:address:shared:programming-environment-data [
   local-scope
   load-ingredients
   # read all scenarios, pushing them to end of a list of scenarios
@@ -358,10 +358,10 @@ recipe restore-sandboxes env:address:shared:programming-environment-data -> env:
 
 # print the fake sandbox screen to 'screen' with appropriate delimiters
 # leave cursor at start of next line
-recipe render-screen screen:address:shared:screen, sandbox-screen:address:shared:screen, left:number, right:number, row:number -> row:number, screen:address:shared:screen [
+def render-screen screen:address:shared:screen, sandbox-screen:address:shared:screen, left:number, right:number, row:number -> row:number, screen:address:shared:screen [
   local-scope
   load-ingredients
-  reply-unless sandbox-screen
+  return-unless sandbox-screen
   # print 'screen:'
   header:address:shared:array:character <- new [screen:]
   row <- render screen, header, left, right, 245/grey, row
@@ -510,7 +510,7 @@ scenario run-instruction-manages-screen-per-sandbox [
   ]
 ]
 
-recipe editor-contents editor:address:shared:editor-data -> result:address:shared:array:character [
+def editor-contents editor:address:shared:editor-data -> result:address:shared:array:character [
   local-scope
   load-ingredients
   buf:address:shared:buffer <- new-buffer 80
@@ -518,7 +518,7 @@ recipe editor-contents editor:address:shared:editor-data -> result:address:share
   # skip § sentinel
   assert curr, [editor without data is illegal; must have at least a sentinel]
   curr <- next curr
-  reply-unless curr, 0
+  return-unless curr, 0
   {
     break-unless curr
     c:character <- get *curr, value:offset
@@ -655,7 +655,7 @@ after <update-cursor-special-cases> [
     break-unless scrolling?
     cursor-column:number <- get *current-sandbox, left:offset
     screen <- move-cursor screen, 2/row, cursor-column  # highlighted sandbox will always start at row 2
-    reply
+    return
   }
 ]
 
@@ -678,21 +678,21 @@ after <global-keypress> [
 
 # sandbox belonging to 'env' whose next-sandbox is 'in'
 # return 0 if there's no such sandbox, either because 'in' doesn't exist in 'env', or because it's the first sandbox
-recipe previous-sandbox env:address:shared:programming-environment-data, in:address:shared:sandbox-data -> out:address:shared:sandbox-data [
+def previous-sandbox env:address:shared:programming-environment-data, in:address:shared:sandbox-data -> out:address:shared:sandbox-data [
   local-scope
   load-ingredients
   curr:address:shared:sandbox-data <- get *env, sandbox:offset
-  reply-unless curr, 0/nil
+  return-unless curr, 0/nil
   next:address:shared:sandbox-data <- get *curr, next-sandbox:offset
   {
-    reply-unless next, 0/nil
+    return-unless next, 0/nil
     found?:boolean <- equal next, in
     break-if found?
     curr <- copy next
     next <- get *curr, next-sandbox:offset
     loop
   }
-  reply curr
+  return curr
 ]
 
 scenario scrolling-down-on-recipe-side [
diff --git a/edit/006-sandbox-edit.mu b/edit/006-sandbox-edit.mu
index de4be675..7354d60b 100644
--- a/edit/006-sandbox-edit.mu
+++ b/edit/006-sandbox-edit.mu
@@ -92,7 +92,7 @@ after <global-touch> [
   }
 ]
 
-recipe empty-editor? editor:address:shared:editor-data -> result:boolean [
+def empty-editor? editor:address:shared:editor-data -> result:boolean [
   local-scope
   load-ingredients
   head:address:shared:duplex-list:character <- get *editor, data:offset
@@ -100,13 +100,13 @@ recipe empty-editor? editor:address:shared:editor-data -> result:boolean [
   result <- not first
 ]
 
-recipe extract-sandbox env:address:shared:programming-environment-data, click-row:number -> result:address:shared:sandbox-data, env:address:shared:programming-environment-data [
+def extract-sandbox env:address:shared:programming-environment-data, click-row:number -> result:address:shared:sandbox-data, env:address:shared:programming-environment-data [
   local-scope
   load-ingredients
   sandbox:address:address:shared:sandbox-data <- get-address *env, sandbox:offset
   start:number <- get **sandbox, starting-row-on-screen:offset
   in-editor?:boolean <- lesser-than click-row, start
-  reply-if in-editor?, 0
+  return-if in-editor?, 0
   {
     next-sandbox:address:shared:sandbox-data <- get **sandbox, next-sandbox:offset
     break-unless next-sandbox
diff --git a/edit/007-sandbox-delete.mu b/edit/007-sandbox-delete.mu
index 3d6d2d12..567e3cd6 100644
--- a/edit/007-sandbox-delete.mu
+++ b/edit/007-sandbox-delete.mu
@@ -77,14 +77,14 @@ after <global-touch> [
   }
 ]
 
-recipe delete-sandbox t:touch-event, env:address:shared:programming-environment-data -> was-delete?:boolean, env:address:shared:programming-environment-data [
+def delete-sandbox t:touch-event, env:address:shared:programming-environment-data -> was-delete?:boolean, env:address:shared:programming-environment-data [
   local-scope
   load-ingredients
   click-column:number <- get t, column:offset
   current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
   right:number <- get *current-sandbox, right:offset
   at-right?:boolean <- equal click-column, right
-  reply-unless at-right?, 0/false
+  return-unless at-right?, 0/false
   click-row:number <- get t, row:offset
   prev:address:address:shared:sandbox-data <- get-address *env, sandbox:offset
   curr:address:shared:sandbox-data <- get *env, sandbox:offset
@@ -108,13 +108,13 @@ recipe delete-sandbox t:touch-event, env:address:shared:programming-environment-
         break-unless reset-scroll?
         *render-from <- copy -1
       }
-      reply 1/true  # force rerender
+      return 1/true  # force rerender
     }
     prev <- get-address *curr, next-sandbox:offset
     curr <- get *curr, next-sandbox:offset
     loop
   }
-  reply 0/false
+  return 0/false
 ]
 
 scenario deleting-sandbox-after-scroll [
diff --git a/edit/008-sandbox-test.mu b/edit/008-sandbox-test.mu
index 5fa4c70c..a3311891 100644
--- a/edit/008-sandbox-test.mu
+++ b/edit/008-sandbox-test.mu
@@ -132,7 +132,7 @@ after <global-touch> [
   }
 ]
 
-recipe find-click-in-sandbox-output env:address:shared:programming-environment-data, click-row:number -> sandbox:address:shared:sandbox-data [
+def find-click-in-sandbox-output env:address:shared:programming-environment-data, click-row:number -> sandbox:address:shared:sandbox-data [
   local-scope
   load-ingredients
   # assert click-row >= sandbox.starting-row-on-screen
@@ -152,13 +152,13 @@ recipe find-click-in-sandbox-output env:address:shared:programming-environment-d
   }
   # return sandbox if click is in its output region
   response-starting-row:number <- get *sandbox, response-starting-row-on-screen:offset
-  reply-unless response-starting-row, 0/no-click-in-sandbox-output
+  return-unless response-starting-row, 0/no-click-in-sandbox-output
   click-in-response?:boolean <- greater-or-equal click-row, response-starting-row
-  reply-unless click-in-response?, 0/no-click-in-sandbox-output
-  reply sandbox
+  return-unless click-in-response?, 0/no-click-in-sandbox-output
+  return sandbox
 ]
 
-recipe toggle-expected-response sandbox:address:shared:sandbox-data -> sandbox:address:shared:sandbox-data [
+def toggle-expected-response sandbox:address:shared:sandbox-data -> sandbox:address:shared:sandbox-data [
   local-scope
   load-ingredients
   expected-response:address:address:shared:array:character <- get-address *sandbox, expected-response:offset
@@ -166,7 +166,7 @@ recipe toggle-expected-response sandbox:address:shared:sandbox-data -> sandbox:a
     # if expected-response is set, reset
     break-unless *expected-response
     *expected-response <- copy 0
-    reply sandbox/same-as-ingredient:0
+    return sandbox/same-as-ingredient:0
   }
   # if not, current response is the expected response
   response:address:shared:array:character <- get *sandbox, response:offset
diff --git a/edit/009-sandbox-trace.mu b/edit/009-sandbox-trace.mu
index d95350bc..0ac17120 100644
--- a/edit/009-sandbox-trace.mu
+++ b/edit/009-sandbox-trace.mu
@@ -81,7 +81,7 @@ scenario sandbox-shows-app-trace-and-result [
   1:address:shared:array:character <- new [ 
 recipe foo [
   stash [abc]
-  reply 4 
+  reply 4
 ]]
   # run it
   2:address:shared:array:character <- new [foo]
@@ -127,7 +127,7 @@ container sandbox-data [
 ]
 
 # replaced in a later layer
-recipe! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data, idx:number -> sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data [
+def! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data, idx:number -> sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data [
   local-scope
   load-ingredients
   data:address:shared:array:character <- get *sandbox, data:offset
@@ -166,7 +166,7 @@ after <global-touch> [
   }
 ]
 
-recipe find-click-in-sandbox-code env:address:shared:programming-environment-data, click-row:number -> sandbox:address:shared:sandbox-data [
+def find-click-in-sandbox-code env:address:shared:programming-environment-data, click-row:number -> sandbox:address:shared:sandbox-data [
   local-scope
   load-ingredients
   # assert click-row >= sandbox.starting-row-on-screen
@@ -192,9 +192,9 @@ recipe find-click-in-sandbox-code env:address:shared:programming-environment-dat
   click-on-sandbox-code?:boolean <- and click-above-response?, click-below-menu?
   {
     break-if click-on-sandbox-code?
-    reply 0/no-click-in-sandbox-output
+    return 0/no-click-in-sandbox-output
   }
-  reply sandbox
+  return sandbox
 ]
 
 # when rendering a sandbox, dump its trace before response/warning if display-trace? property is set
diff --git a/edit/010-errors.mu b/edit/010-errors.mu
index 32dff4fa..aa4283e1 100644
--- a/edit/010-errors.mu
+++ b/edit/010-errors.mu
@@ -5,7 +5,7 @@ container programming-environment-data [
 ]
 
 # copy code from recipe editor, persist, load into mu, save any errors
-recipe! update-recipes env:address:shared:programming-environment-data, screen:address:shared:screen -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
+def! update-recipes env:address:shared:programming-environment-data, screen:address:shared:screen -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
   local-scope
   load-ingredients
   recipes:address:shared:editor-data <- get *env, recipes:offset
@@ -19,7 +19,7 @@ recipe! update-recipes env:address:shared:programming-environment-data, screen:a
     status:address:shared:array:character <- new [errors found     ]
     update-status screen, status, 1/red
     errors-found? <- copy 1/true
-    reply
+    return
   }
   errors-found? <- copy 0/false
 ]
@@ -81,7 +81,7 @@ container sandbox-data [
   errors:address:shared:array:character
 ]
 
-recipe! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data, idx:number -> sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data [
+def! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data, idx:number -> sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data [
   local-scope
   load-ingredients
   data:address:shared:array:character <- get *sandbox, data:offset
diff --git a/edit/011-editor-undo.mu b/edit/011-editor-undo.mu
index d79e056c..5866fb52 100644
--- a/edit/011-editor-undo.mu
+++ b/edit/011-editor-undo.mu
@@ -72,7 +72,7 @@ after <handle-special-character> [
     redo:address:address:shared:list:address:shared:operation <- get-address *editor, redo:offset
     *redo <- push op, *redo
     <handle-undo>
-    reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render
+    return screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render
   }
 ]
 
@@ -88,7 +88,7 @@ after <handle-special-character> [
     undo:address:address:shared:list:address:shared:operation <- get-address *editor, undo:offset
     *undo <- push op, *undo
     <handle-redo>
-    reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render
+    return screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render
   }
 ]
 
@@ -189,14 +189,14 @@ before <insert-enter-end> [
 # redo stack, because it's now obsolete.
 # Beware: since we're counting cursor moves as operations, this means just
 # moving the cursor can lose work on the undo stack.
-recipe add-operation editor:address:shared:editor-data, op:address:shared:operation -> editor:address:shared:editor-data [
+def add-operation editor:address:shared:editor-data, op:address:shared:operation -> editor:address:shared:editor-data [
   local-scope
   load-ingredients
   undo:address:address:shared:list:address:shared:operation <- get-address *editor, undo:offset
   *undo <- push op *undo
   redo:address:address:shared:list:address:shared:operation <- get-address *editor, redo:offset
   *redo <- copy 0
-  reply editor/same-as-ingredient:0
+  return editor/same-as-ingredient:0
 ]
 
 after <handle-undo> [
diff --git a/example1.mu b/example1.mu
index 29610604..00897776 100644
--- a/example1.mu
+++ b/example1.mu
@@ -1,4 +1,4 @@
-recipe example1 [
+def example1 [
   local-scope
   a:number <- add 2, 2
   a <- multiply a, 3
diff --git a/factorial.mu b/factorial.mu
index 02a4e2b0..14e85140 100644
--- a/factorial.mu
+++ b/factorial.mu
@@ -1,20 +1,20 @@
 # example program: compute the factorial of 5
 
-recipe main [
+def main [
   local-scope
   x:number <- factorial 5
   $print [result: ], x, [ 
 ]
 ]
 
-recipe factorial n:number -> result:number [
+def factorial n:number -> result:number [
   local-scope
   load-ingredients
   {
     # if n=0 return 1
     zero?:boolean <- equal n, 0
     break-unless zero?
-    reply 1
+    return 1
   }
   # return n * factorial(n-1)
   x:number <- subtract n, 1
diff --git a/fork.mu b/fork.mu
index 3aa37227..af414cf2 100644
--- a/fork.mu
+++ b/fork.mu
@@ -1,6 +1,6 @@
 # example program: running multiple routines
 
-recipe main [
+def main [
   start-running thread2
   {
     $print 34
@@ -8,7 +8,7 @@ recipe main [
   }
 ]
 
-recipe thread2 [
+def thread2 [
   {
     $print 35
     loop
diff --git a/global.mu b/global.mu
index b78ba47b..7f117c0c 100644
--- a/global.mu
+++ b/global.mu
@@ -1,6 +1,6 @@
 # example program: creating and using global variables
 
-recipe main [
+def main [
   # allocate 5 locations for globals
   global-space:address:shared:array:location <- new location:type, 5
   # read to globals by using /space:global
@@ -8,7 +8,7 @@ recipe main [
   foo
 ]
 
-recipe foo [
+def foo [
   # ditto for writing to globals
   $print 1:number/space:global, 10/newline
 ]
diff --git a/html/chessboard-test.png b/html/chessboard-test.png
index 1dc5a4fa..5f9af84e 100644
--- a/html/chessboard-test.png
+++ b/html/chessboard-test.png
Binary files differdiff --git a/html/edit.png b/html/edit.png
index 2cd2445b..04099cf8 100644
--- a/html/edit.png
+++ b/html/edit.png
Binary files differdiff --git a/html/example1.png b/html/example1.png
index 980d4a08..de90c925 100644
--- a/html/example1.png
+++ b/html/example1.png
Binary files differdiff --git a/html/expected-result.png b/html/expected-result.png
index bf741431..7f35fdec 100644
--- a/html/expected-result.png
+++ b/html/expected-result.png
Binary files differdiff --git a/html/f2c-1.png b/html/f2c-1.png
index 745eb0f3..044b4d71 100644
--- a/html/f2c-1.png
+++ b/html/f2c-1.png
Binary files differdiff --git a/html/f2c-2.png b/html/f2c-2.png
index 250d6158..c7a84cb2 100644
--- a/html/f2c-2.png
+++ b/html/f2c-2.png
Binary files differdiff --git a/html/factorial-test.png b/html/factorial-test.png
index 024c2995..f6e5696d 100644
--- a/html/factorial-test.png
+++ b/html/factorial-test.png
Binary files differdiff --git a/html/factorial.png b/html/factorial.png
index 5474f7ae..d3a57aa7 100644
--- a/html/factorial.png
+++ b/html/factorial.png
Binary files differdiff --git a/html/unexpected-result.png b/html/unexpected-result.png
index b7b75e09..37bff0f2 100644
--- a/html/unexpected-result.png
+++ b/html/unexpected-result.png
Binary files differdiff --git a/mu.vim b/mu.vim
index 90d130e3..613c04fb 100644
--- a/mu.vim
+++ b/mu.vim
@@ -58,9 +58,9 @@ syntax keyword muKeyword default-space global-space new-default-space local-scop
 syntax match muDelimiter "[{}]" | highlight link muDelimiter Delimiter
 syntax match muAssign " <- \|\<raw\>" | highlight link muAssign SpecialChar
 syntax match muGlobal %[^ ]\+:global/\?[^ ,]*% | highlight link muGlobal SpecialChar
-syntax keyword muControl reply reply-if reply-unless jump jump-if jump-unless loop loop-if loop-unless break break-if break-unless current-continuation continue-from create-delimited-continuation reply-delimited-continuation | highlight muControl ctermfg=3
+syntax keyword muControl reply reply-if reply-unless return return-if return-unless jump jump-if jump-unless loop loop-if loop-unless break break-if break-unless current-continuation continue-from create-delimited-continuation reply-delimited-continuation | highlight muControl ctermfg=3
 " common keywords
-syntax keyword muRecipe recipe recipe! before after | highlight muRecipe ctermfg=208
+syntax keyword muRecipe recipe recipe! def def! before after | highlight muRecipe ctermfg=208
 syntax match muRecipe " -> "
 syntax keyword muScenario scenario | highlight muScenario ctermfg=34
 syntax keyword muData container exclusive-container | highlight muData ctermfg=226
diff --git a/sandbox/001-editor.mu b/sandbox/001-editor.mu
index d338b4bb..818f3520 100644
--- a/sandbox/001-editor.mu
+++ b/sandbox/001-editor.mu
@@ -2,7 +2,7 @@
 
 # temporary main for this layer: just render the given text at the given
 # screen dimensions, then stop
-recipe! main text:address:shared:array:character [
+def! main text:address:shared:array:character [
   local-scope
   load-ingredients
   open-console
@@ -48,7 +48,7 @@ container editor-data [
 # creates a new editor widget and renders its initial appearance to screen
 #   top/left/right constrain the screen area available to the new editor
 #   right is exclusive
-recipe new-editor s:address:shared:array:character, screen:address:shared:screen, left:number, right:number -> result:address:shared:editor-data, screen:address:shared:screen [
+def new-editor s:address:shared:array:character, screen:address:shared:screen, left:number, right:number -> result:address:shared:editor-data, screen:address:shared:screen [
   local-scope
   load-ingredients
   # no clipping of bounds
@@ -79,13 +79,13 @@ recipe new-editor s:address:shared:array:character, screen:address:shared:screen
   <editor-initialization>
 ]
 
-recipe insert-text editor:address:shared:editor-data, text:address:shared:array:character -> editor:address:shared:editor-data [
+def insert-text editor:address:shared:editor-data, text:address:shared:array:character -> editor:address:shared:editor-data [
   local-scope
   load-ingredients
   # early exit if text is empty
-  reply-unless text, editor/same-as-ingredient:0
+  return-unless text, editor/same-as-ingredient:0
   len:number <- length *text
-  reply-unless len, editor/same-as-ingredient:0
+  return-unless len, editor/same-as-ingredient:0
   idx:number <- copy 0
   # now we can start appending the rest, character by character
   curr:address:shared:duplex-list:character <- get *editor, data:offset
@@ -99,7 +99,7 @@ recipe insert-text editor:address:shared:editor-data, text:address:shared:array:
     idx <- add idx, 1
     loop
   }
-  reply editor/same-as-ingredient:0
+  return editor/same-as-ingredient:0
 ]
 
 scenario editor-initializes-without-data [
@@ -129,10 +129,10 @@ scenario editor-initializes-without-data [
 # Assumes cursor should be at coordinates (cursor-row, cursor-column) and
 # updates before-cursor to match. Might also move coordinates if they're
 # outside text.
-recipe render screen:address:shared:screen, editor:address:shared:editor-data -> last-row:number, last-column:number, screen:address:shared:screen, editor:address:shared:editor-data [
+def render screen:address:shared:screen, editor:address:shared:editor-data -> last-row:number, last-column:number, screen:address:shared:screen, editor:address:shared:editor-data [
   local-scope
   load-ingredients
-  reply-unless editor, 1/top, 0/left, screen/same-as-ingredient:0, editor/same-as-ingredient:1
+  return-unless editor, 1/top, 0/left, screen/same-as-ingredient:0, editor/same-as-ingredient:1
   left:number <- get *editor, left:offset
   screen-height:number <- screen-height screen
   right:number <- get *editor, right:offset
@@ -226,10 +226,10 @@ recipe render screen:address:shared:screen, editor:address:shared:editor-data ->
   }
   bottom:address:number <- get-address *editor, bottom:offset
   *bottom <- copy row
-  reply row, column, screen/same-as-ingredient:0, editor/same-as-ingredient:1
+  return row, column, screen/same-as-ingredient:0, editor/same-as-ingredient:1
 ]
 
-recipe clear-line-delimited screen:address:shared:screen, column:number, right:number -> screen:address:shared:screen [
+def clear-line-delimited screen:address:shared:screen, column:number, right:number -> screen:address:shared:screen [
   local-scope
   load-ingredients
   space:character <- copy 32/space
@@ -248,23 +248,23 @@ recipe clear-line-delimited screen:address:shared:screen, column:number, right:n
   }
 ]
 
-recipe clear-screen-from screen:address:shared:screen, row:number, column:number, left:number, right:number -> screen:address:shared:screen [
+def clear-screen-from screen:address:shared:screen, row:number, column:number, left:number, right:number -> screen:address:shared:screen [
   local-scope
   load-ingredients
   # if it's the real screen, use the optimized primitive
   {
     break-if screen
     clear-display-from row, column, left, right
-    reply screen/same-as-ingredient:0
+    return screen/same-as-ingredient:0
   }
   # if not, go the slower route
   screen <- move-cursor screen, row, column
   clear-line-delimited screen, column, right
   clear-rest-of-screen screen, row, left, right
-  reply screen/same-as-ingredient:0
+  return screen/same-as-ingredient:0
 ]
 
-recipe clear-rest-of-screen screen:address:shared:screen, row:number, left:number, right:number -> screen:address:shared:screen [
+def clear-rest-of-screen screen:address:shared:screen, row:number, left:number, right:number -> screen:address:shared:screen [
   local-scope
   load-ingredients
   row <- add row, 1
@@ -422,7 +422,7 @@ after <character-c-received> [
 ]
 
 # so far the previous color is all the information we need; that may change
-recipe get-color color:number, c:character -> color:number [
+def get-color color:number, c:character -> color:number [
   local-scope
   load-ingredients
   color-is-white?:boolean <- equal color, 7/white
@@ -464,7 +464,7 @@ recipe get-color color:number, c:character -> color:number [
   }
   # otherwise no change
   +exit
-  reply color
+  return color
 ]
 
 scenario render-colors-assignment [
diff --git a/sandbox/002-typing.mu b/sandbox/002-typing.mu
index f3f6b321..7a68bb64 100644
--- a/sandbox/002-typing.mu
+++ b/sandbox/002-typing.mu
@@ -2,7 +2,7 @@
 
 # temporary main: interactive editor
 # hit ctrl-c to exit
-recipe! main text:address:shared:array:character [
+def! main text:address:shared:array:character [
   local-scope
   load-ingredients
   open-console
@@ -11,7 +11,7 @@ recipe! main text:address:shared:array:character [
   close-console
 ]
 
-recipe editor-event-loop screen:address:shared:screen, console:address:shared:console, editor:address:shared:editor-data -> screen:address:shared:screen, console:address:shared:console, editor:address:shared:editor-data [
+def editor-event-loop screen:address:shared:screen, console:address:shared:console, editor:address:shared:editor-data -> screen:address:shared:screen, console:address:shared:console, editor:address:shared:editor-data [
   local-scope
   load-ingredients
   {
@@ -45,35 +45,35 @@ recipe editor-event-loop screen:address:shared:screen, console:address:shared:co
 ]
 
 # process click, return if it was on current editor
-recipe move-cursor-in-editor screen:address:shared:screen, editor:address:shared:editor-data, t:touch-event -> in-focus?:boolean, editor:address:shared:editor-data [
+def move-cursor-in-editor screen:address:shared:screen, editor:address:shared:editor-data, t:touch-event -> in-focus?:boolean, editor:address:shared:editor-data [
   local-scope
   load-ingredients
-  reply-unless editor, 0/false
+  return-unless editor, 0/false
   click-row:number <- get t, row:offset
-  reply-unless click-row, 0/false  # ignore clicks on 'menu'
+  return-unless click-row, 0/false  # ignore clicks on 'menu'
   click-column:number <- get t, column:offset
   left:number <- get *editor, left:offset
   too-far-left?:boolean <- lesser-than click-column, left
-  reply-if too-far-left?, 0/false
+  return-if too-far-left?, 0/false
   right:number <- get *editor, right:offset
   too-far-right?:boolean <- greater-than click-column, right
-  reply-if too-far-right?, 0/false
+  return-if too-far-right?, 0/false
   # position cursor
   <move-cursor-begin>
   editor <- snap-cursor screen, editor, click-row, click-column
   undo-coalesce-tag:number <- copy 0/never
   <move-cursor-end>
   # gain focus
-  reply 1/true
+  return 1/true
 ]
 
 # Variant of 'render' that only moves the cursor (coordinates and
 # before-cursor). If it's past the end of a line, it 'slides' it left. If it's
 # past the last line it positions at end of last line.
-recipe snap-cursor screen:address:shared:screen, editor:address:shared:editor-data, target-row:number, target-column:number -> editor:address:shared:editor-data [
+def snap-cursor screen:address:shared:screen, editor:address:shared:editor-data, target-row:number, target-column:number -> editor:address:shared:editor-data [
   local-scope
   load-ingredients
-  reply-unless editor
+  return-unless editor
   left:number <- get *editor, left:offset
   right:number <- get *editor, right:offset
   screen-height:number <- screen-height screen
@@ -155,11 +155,11 @@ recipe snap-cursor screen:address:shared:screen, editor:address:shared:editor-da
 
 # Process an event 'e' and try to minimally update the screen.
 # Set 'go-render?' to true to indicate the caller must perform a non-minimal update.
-recipe handle-keyboard-event screen:address:shared:screen, editor:address:shared:editor-data, e:event -> screen:address:shared:screen, editor:address:shared:editor-data, go-render?:boolean [
+def handle-keyboard-event screen:address:shared:screen, editor:address:shared:editor-data, e:event -> screen:address:shared:screen, editor:address:shared:editor-data, go-render?:boolean [
   local-scope
   load-ingredients
   go-render? <- copy 0/false
-  reply-unless editor
+  return-unless editor
   screen-width:number <- screen-width screen
   screen-height:number <- screen-height screen
   left:number <- get *editor, left:offset
@@ -179,12 +179,12 @@ recipe handle-keyboard-event screen:address:shared:screen, editor:address:shared
     # ignore any other special characters
     regular-character?:boolean <- greater-or-equal *c, 32/space
     go-render? <- copy 0/false
-    reply-unless regular-character?
+    return-unless regular-character?
     # otherwise type it in
     <insert-character-begin>
     editor, screen, go-render?:boolean <- insert-at-cursor editor, *c, screen
     <insert-character-end>
-    reply
+    return
   }
   # special key to modify the text or move the cursor
   k:address:number <- maybe-convert e:event, keycode:variant
@@ -192,10 +192,10 @@ recipe handle-keyboard-event screen:address:shared:screen, editor:address:shared
   # handlers for each special key will go here
   <handle-special-key>
   go-render? <- copy 1/true
-  reply
+  return
 ]
 
-recipe insert-at-cursor editor:address:shared:editor-data, c:character, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean [
+def insert-at-cursor editor:address:shared:editor-data, c:character, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean [
   local-scope
   load-ingredients
   before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
@@ -226,7 +226,7 @@ recipe insert-at-cursor editor:address:shared:editor-data, c:character, screen:a
     move-cursor screen, save-row, save-column
     print screen, c
     go-render? <- copy 0/false
-    reply
+    return
   }
   {
     # not at right margin? print the character and rest of line
@@ -240,7 +240,7 @@ recipe insert-at-cursor editor:address:shared:editor-data, c:character, screen:a
       # hit right margin? give up and let caller render
       go-render? <- copy 1/true
       at-right?:boolean <- greater-than curr-column, right
-      reply-if at-right?
+      return-if at-right?
       break-unless curr
       # newline? done.
       currc:character <- get *curr, value:offset
@@ -252,14 +252,14 @@ recipe insert-at-cursor editor:address:shared:editor-data, c:character, screen:a
       loop
     }
     go-render? <- copy 0/false
-    reply
+    return
   }
   go-render? <- copy 1/true
-  reply
+  return
 ]
 
 # helper for tests
-recipe editor-render screen:address:shared:screen, editor:address:shared:editor-data -> screen:address:shared:screen, editor:address:shared:editor-data [
+def editor-render screen:address:shared:screen, editor:address:shared:editor-data -> screen:address:shared:screen, editor:address:shared:editor-data [
   local-scope
   load-ingredients
   left:number <- get *editor, left:offset
@@ -697,7 +697,7 @@ after <insert-character-special-case> [
       <scroll-down>
     }
     go-render? <- copy 1/true
-    reply
+    return
   }
 ]
 
@@ -818,11 +818,11 @@ after <handle-special-character> [
     editor <- insert-new-line-and-indent editor, screen
     <insert-enter-end>
     go-render? <- copy 1/true
-    reply
+    return
   }
 ]
 
-recipe insert-new-line-and-indent editor:address:shared:editor-data, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean [
+def insert-new-line-and-indent editor:address:shared:editor-data, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean [
   local-scope
   load-ingredients
   cursor-row:address:number <- get-address *editor, cursor-row:offset
@@ -846,7 +846,7 @@ recipe insert-new-line-and-indent editor:address:shared:editor-data, screen:addr
   }
   # indent if necessary
   indent?:boolean <- get *editor, indent?:offset
-  reply-unless indent?
+  return-unless indent?
   d:address:shared:duplex-list:character <- get *editor, data:offset
   end-of-previous-line:address:shared:duplex-list:character <- prev *before-cursor
   indent:number <- line-indent end-of-previous-line, d
@@ -862,13 +862,13 @@ recipe insert-new-line-and-indent editor:address:shared:editor-data, screen:addr
 
 # takes a pointer 'curr' into the doubly-linked list and its sentinel, counts
 # the number of spaces at the start of the line containing 'curr'.
-recipe line-indent curr:address:shared:duplex-list:character, start:address:shared:duplex-list:character -> result:number [
+def line-indent curr:address:shared:duplex-list:character, start:address:shared:duplex-list:character -> result:number [
   local-scope
   load-ingredients
   result:number <- copy 0
-  reply-unless curr
+  return-unless curr
   at-start?:boolean <- equal curr, start
-  reply-if at-start?
+  return-if at-start?
   {
     curr <- prev curr
     break-unless curr
@@ -995,7 +995,7 @@ after <handle-special-key> [
     indent?:address:boolean <- get-address *editor, indent?:offset
     *indent? <- copy 0/false
     go-render? <- copy 1/true
-    reply
+    return
   }
 ]
 
@@ -1006,13 +1006,13 @@ after <handle-special-key> [
     indent?:address:boolean <- get-address *editor, indent?:offset
     *indent? <- copy 1/true
     go-render? <- copy 1/true
-    reply
+    return
   }
 ]
 
 ## helpers
 
-recipe draw-horizontal screen:address:shared:screen, row:number, x:number, right:number -> screen:address:shared:screen [
+def draw-horizontal screen:address:shared:screen, row:number, x:number, right:number -> screen:address:shared:screen [
   local-scope
   load-ingredients
   style:character, style-found?:boolean <- next-ingredient
diff --git a/sandbox/003-shortcuts.mu b/sandbox/003-shortcuts.mu
index f6c762a6..c09c3441 100644
--- a/sandbox/003-shortcuts.mu
+++ b/sandbox/003-shortcuts.mu
@@ -32,7 +32,7 @@ after <handle-special-character> [
     editor, screen, go-render?:boolean <- insert-at-cursor editor, 32/space, screen
     <insert-character-end>
     go-render? <- copy 1/true
-    reply
+    return
   }
 ]
 
@@ -73,14 +73,14 @@ after <handle-special-character> [
     <backspace-character-begin>
     editor, screen, go-render?:boolean, backspaced-cell:address:shared:duplex-list:character <- delete-before-cursor editor, screen
     <backspace-character-end>
-    reply
+    return
   }
 ]
 
 # return values:
 #   go-render? - whether caller needs to update the screen
 #   backspaced-cell - value deleted (or 0 if nothing was deleted) so we can save it for undo, etc.
-recipe delete-before-cursor editor:address:shared:editor-data, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean, backspaced-cell:address:shared:duplex-list:character [
+def delete-before-cursor editor:address:shared:editor-data, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean, backspaced-cell:address:shared:duplex-list:character [
   local-scope
   load-ingredients
   before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
@@ -88,7 +88,7 @@ recipe delete-before-cursor editor:address:shared:editor-data, screen:address:sh
   # if at start of text (before-cursor at § sentinel), return
   prev:address:shared:duplex-list:character <- prev *before-cursor
   go-render?, backspaced-cell <- copy 0/no-more-render, 0/nothing-deleted
-  reply-unless prev
+  return-unless prev
   trace 10, [app], [delete-before-cursor]
   original-row:number <- get *editor, cursor-row:offset
   editor, scroll?:boolean <- move-cursor-coordinates-left editor
@@ -96,14 +96,14 @@ recipe delete-before-cursor editor:address:shared:editor-data, screen:address:sh
   data <- remove *before-cursor, data  # will also neatly trim next/prev pointers in backspaced-cell/*before-cursor
   *before-cursor <- copy prev
   go-render? <- copy 1/true
-  reply-if scroll?
+  return-if scroll?
   screen-width:number <- screen-width screen
   cursor-row:number <- get *editor, cursor-row:offset
   cursor-column:number <- get *editor, cursor-column:offset
   # did we just backspace over a newline?
   same-row?:boolean <- equal cursor-row, original-row
   go-render? <- copy 1/true
-  reply-unless same-row?
+  return-unless same-row?
   left:number <- get *editor, left:offset
   right:number <- get *editor, right:offset
   curr:address:shared:duplex-list:character <- next *before-cursor
@@ -113,7 +113,7 @@ recipe delete-before-cursor editor:address:shared:editor-data, screen:address:sh
     # hit right margin? give up and let caller render
     at-right?:boolean <- greater-or-equal curr-column, right
     go-render? <- copy 1/true
-    reply-if at-right?
+    return-if at-right?
     break-unless curr
     # newline? done.
     currc:character <- get *curr, value:offset
@@ -130,7 +130,7 @@ recipe delete-before-cursor editor:address:shared:editor-data, screen:address:sh
   go-render? <- copy 0/false
 ]
 
-recipe move-cursor-coordinates-left editor:address:shared:editor-data -> editor:address:shared:editor-data, go-render?:boolean [
+def move-cursor-coordinates-left editor:address:shared:editor-data -> editor:address:shared:editor-data, go-render?:boolean [
   local-scope
   load-ingredients
   before-cursor:address:shared:duplex-list:character <- get *editor, before-cursor:offset
@@ -144,7 +144,7 @@ recipe move-cursor-coordinates-left editor:address:shared:editor-data -> editor:
     trace 10, [app], [decrementing cursor column]
     *cursor-column <- subtract *cursor-column, 1
     go-render? <- copy 0/false
-    reply
+    return
   }
   # if at left margin, we must move to previous row:
   top-of-screen?:boolean <- equal *cursor-row, 1  # exclude menu bar
@@ -179,7 +179,7 @@ recipe move-cursor-coordinates-left editor:address:shared:editor-data -> editor:
       break-if wrap?
       *cursor-column <- add left, end-of-line
     }
-    reply
+    return
   }
   # case 2: if previous-character was not newline, we're just at a wrapped line
   trace 10, [app], [wrapping to previous line]
@@ -189,13 +189,13 @@ recipe move-cursor-coordinates-left editor:address:shared:editor-data -> editor:
 
 # takes a pointer 'curr' into the doubly-linked list and its sentinel, counts
 # the length of the previous line before the 'curr' pointer.
-recipe previous-line-length curr:address:shared:duplex-list:character, start:address:shared:duplex-list:character -> result:number [
+def previous-line-length curr:address:shared:duplex-list:character, start:address:shared:duplex-list:character -> result:number [
   local-scope
   load-ingredients
   result:number <- copy 0
-  reply-unless curr
+  return-unless curr
   at-start?:boolean <- equal curr, start
-  reply-if at-start?
+  return-if at-start?
   {
     curr <- prev curr
     break-unless curr
@@ -338,23 +338,23 @@ after <handle-special-key> [
     <delete-character-begin>
     editor, screen, go-render?:boolean, deleted-cell:address:shared:duplex-list:character <- delete-at-cursor editor, screen
     <delete-character-end>
-    reply
+    return
   }
 ]
 
-recipe delete-at-cursor editor:address:shared:editor-data, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean, deleted-cell:address:shared:duplex-list:character [
+def delete-at-cursor editor:address:shared:editor-data, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean, deleted-cell:address:shared:duplex-list:character [
   local-scope
   load-ingredients
   before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
   data:address:shared:duplex-list:character <- get *editor, data:offset
   deleted-cell:address:shared:duplex-list:character <- next *before-cursor
   go-render? <- copy 0/false
-  reply-unless deleted-cell
+  return-unless deleted-cell
   currc:character <- get *deleted-cell, value:offset
   data <- remove deleted-cell, data
   deleted-newline?:boolean <- equal currc, 10/newline
   go-render? <- copy 1/true
-  reply-if deleted-newline?
+  return-if deleted-newline?
   # wasn't a newline? render rest of line
   curr:address:shared:duplex-list:character <- next *before-cursor  # refresh after remove above
   cursor-row:address:number <- get-address *editor, cursor-row:offset
@@ -366,7 +366,7 @@ recipe delete-at-cursor editor:address:shared:editor-data, screen:address:shared
     # hit right margin? give up and let caller render
     at-right?:boolean <- greater-or-equal curr-column, screen-width
     go-render? <- copy 1/true
-    reply-if at-right?
+    return-if at-right?
     break-unless curr
     # newline? done.
     currc:character <- get *curr, value:offset
@@ -421,11 +421,11 @@ after <handle-special-key> [
     screen <- move-cursor screen, *cursor-row, *cursor-column
     undo-coalesce-tag:number <- copy 2/right-arrow
     <move-cursor-end>
-    reply
+    return
   }
 ]
 
-recipe move-cursor-coordinates-right editor:address:shared:editor-data, screen-height:number -> editor:address:shared:editor-data, go-render?:boolean [
+def move-cursor-coordinates-right editor:address:shared:editor-data, screen-height:number -> editor:address:shared:editor-data, go-render?:boolean [
   local-scope
   load-ingredients
   before-cursor:address:shared:duplex-list:character <- get *editor before-cursor:offset
@@ -442,11 +442,11 @@ recipe move-cursor-coordinates-right editor:address:shared:editor-data, screen-h
     *cursor-column <- copy left
     below-screen?:boolean <- greater-or-equal *cursor-row, screen-height  # must be equal
     go-render? <- copy 0/false
-    reply-unless below-screen?
+    return-unless below-screen?
     <scroll-down>
     *cursor-row <- subtract *cursor-row, 1  # bring back into screen range
     go-render? <- copy 1/true
-    reply
+    return
   }
   # if the line wraps, move cursor to start of next row
   {
@@ -463,11 +463,11 @@ recipe move-cursor-coordinates-right editor:address:shared:editor-data, screen-h
     *cursor-row <- add *cursor-row, 1
     *cursor-column <- copy left
     below-screen?:boolean <- greater-or-equal *cursor-row, screen-height  # must be equal
-    reply-unless below-screen?, editor/same-as-ingredient:0, 0/no-more-render
+    return-unless below-screen?, editor/same-as-ingredient:0, 0/no-more-render
     <scroll-down>
     *cursor-row <- subtract *cursor-row, 1  # bring back into screen range
     go-render? <- copy 1/true
-    reply
+    return
   }
   # otherwise move cursor one character right
   *cursor-column <- add *cursor-column, 1
@@ -691,13 +691,13 @@ after <handle-special-key> [
     # if not at start of text (before-cursor at § sentinel)
     prev:address:shared:duplex-list:character <- prev *before-cursor
     go-render? <- copy 0/false
-    reply-unless prev
+    return-unless prev
     <move-cursor-begin>
     editor, go-render? <- move-cursor-coordinates-left editor
     *before-cursor <- copy prev
     undo-coalesce-tag:number <- copy 1/left-arrow
     <move-cursor-end>
-    reply
+    return
   }
 ]
 
@@ -954,11 +954,11 @@ after <handle-special-key> [
     editor, go-render? <- move-to-previous-line editor
     undo-coalesce-tag:number <- copy 3/up-arrow
     <move-cursor-end>
-    reply
+    return
   }
 ]
 
-recipe move-to-previous-line editor:address:shared:editor-data -> editor:address:shared:editor-data, go-render?:boolean [
+def move-to-previous-line editor:address:shared:editor-data -> editor:address:shared:editor-data, go-render?:boolean [
   local-scope
   load-ingredients
   cursor-row:address:number <- get-address *editor, cursor-row:offset
@@ -982,14 +982,14 @@ recipe move-to-previous-line editor:address:shared:editor-data -> editor:address
       curr:address:shared:duplex-list:character <- before-previous-line curr, editor
       no-motion?:boolean <- equal curr, old
       go-render? <- copy 0/false
-      reply-if no-motion?
+      return-if no-motion?
     }
     {
       old <- copy curr
       curr <- before-previous-line curr, editor
       no-motion?:boolean <- equal curr, old
       go-render? <- copy 0/false
-      reply-if no-motion?
+      return-if no-motion?
     }
     *before-cursor <- copy curr
     *cursor-row <- subtract *cursor-row, 1
@@ -1010,14 +1010,14 @@ recipe move-to-previous-line editor:address:shared:editor-data -> editor:address
       loop
     }
     go-render? <- copy 0/false
-    reply
+    return
   }
   {
     # if cursor already at top, scroll up
     break-unless already-at-top?
     <scroll-up>
     go-render? <- copy 1/true
-    reply
+    return
   }
 ]
 
@@ -1179,11 +1179,11 @@ after <handle-special-key> [
     editor, go-render? <- move-to-next-line editor, screen-height
     undo-coalesce-tag:number <- copy 4/down-arrow
     <move-cursor-end>
-    reply
+    return
   }
 ]
 
-recipe move-to-next-line editor:address:shared:editor-data, screen-height:number -> editor:address:shared:editor-data, go-render?:boolean [
+def move-to-next-line editor:address:shared:editor-data, screen-height:number -> editor:address:shared:editor-data, go-render?:boolean [
   local-scope
   load-ingredients
   cursor-row:address:number <- get-address *editor, cursor-row:offset
@@ -1207,7 +1207,7 @@ recipe move-to-next-line editor:address:shared:editor-data, screen-height:number
       scroll?:boolean <- greater-than *cursor-row, 1
       break-if scroll?, +try-to-scroll:label
       go-render? <- copy 0/false
-      reply
+      return
     }
     *cursor-row <- add *cursor-row, 1
     *before-cursor <- copy next-line
@@ -1227,7 +1227,7 @@ recipe move-to-next-line editor:address:shared:editor-data, screen-height:number
       loop
     }
     go-render? <- copy 0/false
-    reply
+    return
   }
   +try-to-scroll
   <scroll-down>
@@ -1306,7 +1306,7 @@ after <handle-special-character> [
     undo-coalesce-tag:number <- copy 0/never
     <move-cursor-end>
     go-render? <- copy 0/false
-    reply
+    return
   }
 ]
 
@@ -1319,11 +1319,11 @@ after <handle-special-key> [
     undo-coalesce-tag:number <- copy 0/never
     <move-cursor-end>
     go-render? <- copy 0/false
-    reply
+    return
   }
 ]
 
-recipe move-to-start-of-line editor:address:shared:editor-data -> editor:address:shared:editor-data [
+def move-to-start-of-line editor:address:shared:editor-data -> editor:address:shared:editor-data [
   local-scope
   load-ingredients
   # update cursor column
@@ -1477,7 +1477,7 @@ after <handle-special-character> [
     undo-coalesce-tag:number <- copy 0/never
     <move-cursor-end>
     go-render? <- copy 0/false
-    reply
+    return
   }
 ]
 
@@ -1490,11 +1490,11 @@ after <handle-special-key> [
     undo-coalesce-tag:number <- copy 0/never
     <move-cursor-end>
     go-render? <- copy 0/false
-    reply
+    return
   }
 ]
 
-recipe move-to-end-of-line editor:address:shared:editor-data -> editor:address:shared:editor-data [
+def move-to-end-of-line editor:address:shared:editor-data -> editor:address:shared:editor-data [
   local-scope
   load-ingredients
   before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
@@ -1620,11 +1620,11 @@ after <handle-special-character> [
     deleted-cells:address:shared:duplex-list:character <- delete-to-start-of-line editor
     <delete-to-start-of-line-end>
     go-render? <- copy 1/true
-    reply
+    return
   }
 ]
 
-recipe delete-to-start-of-line editor:address:shared:editor-data -> result:address:shared:duplex-list:character, editor:address:shared:editor-data [
+def delete-to-start-of-line editor:address:shared:editor-data -> result:address:shared:duplex-list:character, editor:address:shared:editor-data [
   local-scope
   load-ingredients
   # compute range to delete
@@ -1754,11 +1754,11 @@ after <handle-special-character> [
     deleted-cells:address:shared:duplex-list:character <- delete-to-end-of-line editor
     <delete-to-end-of-line-end>
     go-render? <- copy 1/true
-    reply
+    return
   }
 ]
 
-recipe delete-to-end-of-line editor:address:shared:editor-data -> result:address:shared:duplex-list:character, editor:address:shared:editor-data [
+def delete-to-end-of-line editor:address:shared:editor-data -> result:address:shared:duplex-list:character, editor:address:shared:editor-data [
   local-scope
   load-ingredients
   # compute range to delete
@@ -1937,13 +1937,13 @@ after <scroll-down> [
   *top-of-screen <- before-start-of-next-line *top-of-screen, max
   no-movement?:boolean <- equal old-top, *top-of-screen
   go-render? <- copy 0/false
-  reply-if no-movement?
+  return-if no-movement?
 ]
 
 # takes a pointer into the doubly-linked list, scans ahead at most 'max'
 # positions until the next newline
 # beware: never return null pointer.
-recipe before-start-of-next-line original:address:shared:duplex-list:character, max:number -> curr:address:shared:duplex-list:character [
+def before-start-of-next-line original:address:shared:duplex-list:character, max:number -> curr:address:shared:duplex-list:character [
   local-scope
   load-ingredients
   count:number <- copy 0
@@ -1957,7 +1957,7 @@ recipe before-start-of-next-line original:address:shared:duplex-list:character,
     count <- add count, 1
   }
   {
-    reply-unless curr, original
+    return-unless curr, original
     done?:boolean <- greater-or-equal count, max
     break-if done?
     c:character <- get *curr, value:offset
@@ -1967,8 +1967,8 @@ recipe before-start-of-next-line original:address:shared:duplex-list:character,
     count <- add count, 1
     loop
   }
-  reply-unless curr, original
-  reply curr
+  return-unless curr, original
+  return curr
 ]
 
 scenario editor-scrolls-down-past-wrapped-line-using-arrow-keys [
@@ -2304,13 +2304,13 @@ after <scroll-up> [
   *top-of-screen <- before-previous-line *top-of-screen, editor
   no-movement?:boolean <- equal old-top, *top-of-screen
   go-render? <- copy 0/false
-  reply-if no-movement?
+  return-if no-movement?
 ]
 
 # takes a pointer into the doubly-linked list, scans back to before start of
 # previous *wrapped* line
 # beware: never return null pointer
-recipe before-previous-line in:address:shared:duplex-list:character, editor:address:shared:editor-data -> out:address:shared:duplex-list:character [
+def before-previous-line in:address:shared:duplex-list:character, editor:address:shared:editor-data -> out:address:shared:duplex-list:character [
   local-scope
   load-ingredients
   curr:address:shared:duplex-list:character <- copy in
@@ -2327,8 +2327,8 @@ recipe before-previous-line in:address:shared:duplex-list:character, editor:addr
     break-if len
     # empty line; just skip this newline
     prev:address:shared:duplex-list:character <- prev curr
-    reply-unless prev, curr
-    reply prev
+    return-unless prev, curr
+    return prev
   }
   _, max:number <- divide-with-remainder len, max-line-length
   # remainder 0 => scan one width-worth
@@ -2348,7 +2348,7 @@ recipe before-previous-line in:address:shared:duplex-list:character, editor:addr
     count <- add count, 1
     loop
   }
-  reply curr
+  return curr
 ]
 
 scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys [
@@ -2698,7 +2698,7 @@ after <handle-special-character> [
     <move-cursor-end>
     no-movement?:boolean <- equal *top-of-screen, old-top
     go-render? <- not no-movement?
-    reply
+    return
   }
 ]
 
@@ -2714,18 +2714,18 @@ after <handle-special-key> [
     <move-cursor-end>
     no-movement?:boolean <- equal *top-of-screen, old-top
     go-render? <- not no-movement?
-    reply
+    return
   }
 ]
 
 # page-down skips entire wrapped lines, so it can't scroll past lines
 # taking up the entire screen
-recipe page-down editor:address:shared:editor-data -> editor:address:shared:editor-data [
+def page-down editor:address:shared:editor-data -> editor:address:shared:editor-data [
   local-scope
   load-ingredients
   # if editor contents don't overflow screen, do nothing
   bottom-of-screen:address:shared:duplex-list:character <- get *editor, bottom-of-screen:offset
-  reply-unless bottom-of-screen
+  return-unless bottom-of-screen
   # if not, position cursor at final character
   before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
   *before-cursor <- prev bottom-of-screen
@@ -2890,7 +2890,7 @@ after <handle-special-character> [
     <move-cursor-end>
     no-movement?:boolean <- equal *top-of-screen, old-top
     go-render? <- not no-movement?
-    reply
+    return
   }
 ]
 
@@ -2907,11 +2907,11 @@ after <handle-special-key> [
     no-movement?:boolean <- equal *top-of-screen, old-top
     # don't bother re-rendering if nothing changed. todo: test this
     go-render? <- not no-movement?
-    reply
+    return
   }
 ]
 
-recipe page-up editor:address:shared:editor-data, screen-height:number -> editor:address:shared:editor-data [
+def page-up editor:address:shared:editor-data, screen-height:number -> editor:address:shared:editor-data [
   local-scope
   load-ingredients
   max:number <- subtract screen-height, 1/menu-bar, 1/overlapping-line
diff --git a/sandbox/004-programming-environment.mu b/sandbox/004-programming-environment.mu
index 78aca5ae..8c6e58cb 100644
--- a/sandbox/004-programming-environment.mu
+++ b/sandbox/004-programming-environment.mu
@@ -1,6 +1,6 @@
 ## putting the environment together out of editors
 
-recipe! main [
+def! main [
   local-scope
   open-console
   initial-sandbox:address:shared:array:character <- new []
@@ -19,7 +19,7 @@ container programming-environment-data [
   current-sandbox:address:shared:editor-data
 ]
 
-recipe new-programming-environment screen:address:shared:screen, initial-sandbox-contents:address:shared:array:character -> result:address:shared:programming-environment-data, screen:address:shared:screen [
+def new-programming-environment screen:address:shared:screen, initial-sandbox-contents:address:shared:array:character -> result:address:shared:programming-environment-data, screen:address:shared:screen [
   local-scope
   load-ingredients
   width:number <- screen-width screen
@@ -39,7 +39,7 @@ recipe new-programming-environment screen:address:shared:screen, initial-sandbox
   <programming-environment-initialization>
 ]
 
-recipe event-loop screen:address:shared:screen, console:address:shared:console, env:address:shared:programming-environment-data -> screen:address:shared:screen, console:address:shared:console, env:address:shared:programming-environment-data [
+def event-loop screen:address:shared:screen, console:address:shared:console, env:address:shared:programming-environment-data -> screen:address:shared:screen, console:address:shared:console, env:address:shared:programming-environment-data [
   local-scope
   load-ingredients
   current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
@@ -136,7 +136,7 @@ recipe event-loop screen:address:shared:screen, console:address:shared:console,
   }
 ]
 
-recipe resize screen:address:shared:screen, env:address:shared:programming-environment-data -> env:address:shared:programming-environment-data, screen:address:shared:screen [
+def resize screen:address:shared:screen, env:address:shared:programming-environment-data -> env:address:shared:programming-environment-data, screen:address:shared:screen [
   local-scope
   load-ingredients
   clear-screen screen  # update screen dimensions
@@ -152,7 +152,7 @@ recipe resize screen:address:shared:screen, env:address:shared:programming-envir
   *cursor-column <- copy 0
 ]
 
-recipe render-all screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen [
+def render-all screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen, env:address:shared:programming-environment-data [
   local-scope
   load-ingredients
   trace 10, [app], [render all]
@@ -178,7 +178,7 @@ recipe render-all screen:address:shared:screen, env:address:shared:programming-e
 ]
 
 # replaced in a later layer
-recipe render-sandbox-side screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen [
+def render-sandbox-side screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen, env:address:shared:programming-environment-data [
   local-scope
   load-ingredients
   current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
@@ -193,7 +193,7 @@ recipe render-sandbox-side screen:address:shared:screen, env:address:shared:prog
   clear-screen-from screen, row, left, left, right
 ]
 
-recipe update-cursor screen:address:shared:screen, current-sandbox:address:shared:editor-data, env:address:shared:programming-environment-data -> screen:address:shared:screen [
+def update-cursor screen:address:shared:screen, current-sandbox:address:shared:editor-data, env:address:shared:programming-environment-data -> screen:address:shared:screen [
   local-scope
   load-ingredients
   <update-cursor-special-cases>
@@ -204,10 +204,10 @@ recipe update-cursor screen:address:shared:screen, current-sandbox:address:share
 
 # print a text 's' to 'editor' in 'color' starting at 'row'
 # clear rest of last line, move cursor to next line
-recipe render screen:address:shared:screen, s:address:shared:array:character, left:number, right:number, color:number, row:number -> row:number, screen:address:shared:screen [
+def render screen:address:shared:screen, s:address:shared:array:character, left:number, right:number, color:number, row:number -> row:number, screen:address:shared:screen [
   local-scope
   load-ingredients
-  reply-unless s
+  return-unless s
   column:number <- copy left
   screen <- move-cursor screen, row, column
   screen-height:number <- screen-height screen
@@ -265,10 +265,10 @@ recipe render screen:address:shared:screen, s:address:shared:array:character, le
 ]
 
 # like 'render' for texts, but with colorization for comments like in the editor
-recipe render-code screen:address:shared:screen, s:address:shared:array:character, left:number, right:number, row:number -> row:number, screen:address:shared:screen [
+def render-code screen:address:shared:screen, s:address:shared:array:character, left:number, right:number, row:number -> row:number, screen:address:shared:screen [
   local-scope
   load-ingredients
-  reply-unless s
+  return-unless s
   color:number <- copy 7/white
   column:number <- copy left
   screen <- move-cursor screen, row, column
@@ -340,6 +340,6 @@ after <global-type> [
 ]
 
 # dummy
-recipe restore-sandboxes env:address:shared:programming-environment-data -> env:address:shared:programming-environment-data [
+def restore-sandboxes env:address:shared:programming-environment-data -> env:address:shared:programming-environment-data [
   # do nothing; redefined later
 ]
diff --git a/sandbox/005-sandbox.mu b/sandbox/005-sandbox.mu
index 31032eb3..a9c07e5e 100644
--- a/sandbox/005-sandbox.mu
+++ b/sandbox/005-sandbox.mu
@@ -129,7 +129,7 @@ after <global-keypress> [
   }
 ]
 
-recipe run-sandboxes env:address:shared:programming-environment-data, screen:address:shared:screen, test-recipes:address:shared:array:character -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
+def run-sandboxes env:address:shared:programming-environment-data, screen:address:shared:screen, test-recipes:address:shared:array:character -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
   local-scope
   load-ingredients
   errors-found?:boolean, env, screen <- update-recipes env, screen, test-recipes
@@ -175,7 +175,7 @@ recipe run-sandboxes env:address:shared:programming-environment-data, screen:add
 
 # load code from recipes.mu, or from test-recipes in tests
 # replaced in a later layer (whereupon errors-found? will actually be set)
-recipe update-recipes env:address:shared:programming-environment-data, screen:address:shared:screen, test-recipes:address:shared:array:character -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
+def update-recipes env:address:shared:programming-environment-data, screen:address:shared:screen, test-recipes:address:shared:array:character -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
   local-scope
   load-ingredients
   {
@@ -191,7 +191,7 @@ recipe update-recipes env:address:shared:programming-environment-data, screen:ad
 ]
 
 # replaced in a later layer
-recipe! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data, idx:number -> sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data [
+def! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data, idx:number -> sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data [
   local-scope
   load-ingredients
   data:address:shared:array:character <- get *sandbox, data:offset
@@ -200,14 +200,14 @@ recipe! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:p
   *response, _, *fake-screen <- run-interactive data
 ]
 
-recipe update-status screen:address:shared:screen, msg:address:shared:array:character, color:number -> screen:address:shared:screen [
+def update-status screen:address:shared:screen, msg:address:shared:array:character, color:number -> screen:address:shared:screen [
   local-scope
   load-ingredients
   screen <- move-cursor screen, 0, 2
   screen <- print screen, msg, color, 238/grey/background
 ]
 
-recipe save-sandboxes env:address:shared:programming-environment-data [
+def save-sandboxes env:address:shared:programming-environment-data [
   local-scope
   load-ingredients
   current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
@@ -228,7 +228,7 @@ recipe save-sandboxes env:address:shared:programming-environment-data [
   }
 ]
 
-recipe! render-sandbox-side screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen [
+def! render-sandbox-side screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen, env:address:shared:programming-environment-data [
   local-scope
   load-ingredients
   trace 11, [app], [render sandbox side]
@@ -252,14 +252,14 @@ recipe! render-sandbox-side screen:address:shared:screen, env:address:shared:pro
   clear-rest-of-screen screen, row, left, right
 ]
 
-recipe render-sandboxes screen:address:shared:screen, sandbox:address:shared:sandbox-data, left:number, right:number, row:number, render-from:number, idx:number -> row:number, screen:address:shared:screen, sandbox:address:shared:sandbox-data [
+def render-sandboxes screen:address:shared:screen, sandbox:address:shared:sandbox-data, left:number, right:number, row:number, render-from:number, idx:number -> row:number, screen:address:shared:screen, sandbox:address:shared:sandbox-data [
   local-scope
   load-ingredients
   env:address:shared:programming-environment-data, _/optional <- next-ingredient
-  reply-unless sandbox
+  return-unless sandbox
   screen-height:number <- screen-height screen
   at-bottom?:boolean <- greater-or-equal row, screen-height
-  reply-if at-bottom?:boolean
+  return-if at-bottom?:boolean
   hidden?:boolean <- lesser-than idx, render-from
   {
     break-if hidden?
@@ -296,7 +296,7 @@ recipe render-sandboxes screen:address:shared:screen, sandbox:address:shared:san
     }
     +render-sandbox-end
     at-bottom?:boolean <- greater-or-equal row, screen-height
-    reply-if at-bottom?
+    return-if at-bottom?
     # draw solid line after sandbox
     draw-horizontal screen, row, left, right, 9473/horizontal-double
   }
@@ -316,7 +316,7 @@ recipe render-sandboxes screen:address:shared:screen, sandbox:address:shared:san
 ]
 
 # assumes programming environment has no sandboxes; restores them from previous session
-recipe! restore-sandboxes env:address:shared:programming-environment-data -> env:address:shared:programming-environment-data [
+def! restore-sandboxes env:address:shared:programming-environment-data -> env:address:shared:programming-environment-data [
   local-scope
   load-ingredients
   # read all scenarios, pushing them to end of a list of scenarios
@@ -350,10 +350,10 @@ recipe! restore-sandboxes env:address:shared:programming-environment-data -> env
 
 # print the fake sandbox screen to 'screen' with appropriate delimiters
 # leave cursor at start of next line
-recipe render-screen screen:address:shared:screen, sandbox-screen:address:shared:screen, left:number, right:number, row:number -> row:number, screen:address:shared:screen [
+def render-screen screen:address:shared:screen, sandbox-screen:address:shared:screen, left:number, right:number, row:number -> row:number, screen:address:shared:screen [
   local-scope
   load-ingredients
-  reply-unless sandbox-screen
+  return-unless sandbox-screen
   # print 'screen:'
   header:address:shared:array:character <- new [screen:]
   row <- render screen, header, left, right, 245/grey, row
@@ -421,10 +421,10 @@ scenario run-updates-results [
   assume-screen 50/width, 12/height
   # define a recipe (no indent for the 'add' line below so column numbers are more obvious)
   1:address:shared:array:character <- new [ 
-recipe foo [
+def foo [
 local-scope
 z:number <- add 2, 2
-reply z
+return z
 ]]
   # sandbox editor contains an instruction without storing outputs
   2:address:shared:array:character <- new [foo]
@@ -446,10 +446,10 @@ reply z
   ]
   # make a change (incrementing one of the args to 'add'), then rerun
   1:address:shared:array:character <- new [ 
-recipe foo [
+def foo [
 local-scope
 z:number <- add 2, 3
-reply z
+return z
 ]]
   assume-console [
     press F4
@@ -501,7 +501,7 @@ scenario run-instruction-manages-screen-per-sandbox [
   ]
 ]
 
-recipe editor-contents editor:address:shared:editor-data -> result:address:shared:array:character [
+def editor-contents editor:address:shared:editor-data -> result:address:shared:array:character [
   local-scope
   load-ingredients
   buf:address:shared:buffer <- new-buffer 80
@@ -509,7 +509,7 @@ recipe editor-contents editor:address:shared:editor-data -> result:address:share
   # skip § sentinel
   assert curr, [editor without data is illegal; must have at least a sentinel]
   curr <- next curr
-  reply-unless curr, 0
+  return-unless curr, 0
   {
     break-unless curr
     c:character <- get *curr, value:offset
@@ -646,7 +646,7 @@ after <update-cursor-special-cases> [
     break-unless scrolling?
     cursor-column:number <- get *current-sandbox, left:offset
     screen <- move-cursor screen, 2/row, cursor-column  # highlighted sandbox will always start at row 2
-    reply
+    return
   }
 ]
 
@@ -668,21 +668,21 @@ after <global-keypress> [
 
 # sandbox belonging to 'env' whose next-sandbox is 'in'
 # return 0 if there's no such sandbox, either because 'in' doesn't exist in 'env', or because it's the first sandbox
-recipe previous-sandbox env:address:shared:programming-environment-data, in:address:shared:sandbox-data -> out:address:shared:sandbox-data [
+def previous-sandbox env:address:shared:programming-environment-data, in:address:shared:sandbox-data -> out:address:shared:sandbox-data [
   local-scope
   load-ingredients
   curr:address:shared:sandbox-data <- get *env, sandbox:offset
-  reply-unless curr, 0/nil
+  return-unless curr, 0/nil
   next:address:shared:sandbox-data <- get *curr, next-sandbox:offset
   {
-    reply-unless next, 0/nil
+    return-unless next, 0/nil
     found?:boolean <- equal next, in
     break-if found?
     curr <- copy next
     next <- get *curr, next-sandbox:offset
     loop
   }
-  reply curr
+  return curr
 ]
 
 scenario scrolling-through-multiple-sandboxes [
diff --git a/sandbox/006-sandbox-edit.mu b/sandbox/006-sandbox-edit.mu
index e974034a..d39ec118 100644
--- a/sandbox/006-sandbox-edit.mu
+++ b/sandbox/006-sandbox-edit.mu
@@ -93,7 +93,7 @@ after <global-touch> [
   }
 ]
 
-recipe empty-editor? editor:address:shared:editor-data -> result:boolean [
+def empty-editor? editor:address:shared:editor-data -> result:boolean [
   local-scope
   load-ingredients
   head:address:shared:duplex-list:character <- get *editor, data:offset
@@ -101,13 +101,13 @@ recipe empty-editor? editor:address:shared:editor-data -> result:boolean [
   result <- not first
 ]
 
-recipe extract-sandbox env:address:shared:programming-environment-data, click-row:number -> result:address:shared:sandbox-data, env:address:shared:programming-environment-data [
+def extract-sandbox env:address:shared:programming-environment-data, click-row:number -> result:address:shared:sandbox-data, env:address:shared:programming-environment-data [
   local-scope
   load-ingredients
   sandbox:address:address:shared:sandbox-data <- get-address *env, sandbox:offset
   start:number <- get **sandbox, starting-row-on-screen:offset
   in-editor?:boolean <- lesser-than click-row, start
-  reply-if in-editor?, 0
+  return-if in-editor?, 0
   {
     next-sandbox:address:shared:sandbox-data <- get **sandbox, next-sandbox:offset
     break-unless next-sandbox
diff --git a/sandbox/007-sandbox-delete.mu b/sandbox/007-sandbox-delete.mu
index 35cf47cb..dbf5d70c 100644
--- a/sandbox/007-sandbox-delete.mu
+++ b/sandbox/007-sandbox-delete.mu
@@ -76,14 +76,14 @@ after <global-touch> [
   }
 ]
 
-recipe delete-sandbox t:touch-event, env:address:shared:programming-environment-data -> was-delete?:boolean, env:address:shared:programming-environment-data [
+def delete-sandbox t:touch-event, env:address:shared:programming-environment-data -> was-delete?:boolean, env:address:shared:programming-environment-data [
   local-scope
   load-ingredients
   click-column:number <- get t, column:offset
   current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
   right:number <- get *current-sandbox, right:offset
   at-right?:boolean <- equal click-column, right
-  reply-unless at-right?, 0/false
+  return-unless at-right?, 0/false
   click-row:number <- get t, row:offset
   prev:address:address:shared:sandbox-data <- get-address *env, sandbox:offset
   curr:address:shared:sandbox-data <- get *env, sandbox:offset
@@ -107,13 +107,13 @@ recipe delete-sandbox t:touch-event, env:address:shared:programming-environment-
         break-unless reset-scroll?
         *render-from <- copy -1
       }
-      reply 1/true  # force rerender
+      return 1/true  # force rerender
     }
     prev <- get-address *curr, next-sandbox:offset
     curr <- get *curr, next-sandbox:offset
     loop
   }
-  reply 0/false
+  return 0/false
 ]
 
 scenario deleting-sandbox-after-scroll [
diff --git a/sandbox/008-sandbox-test.mu b/sandbox/008-sandbox-test.mu
index b299f704..a7010190 100644
--- a/sandbox/008-sandbox-test.mu
+++ b/sandbox/008-sandbox-test.mu
@@ -5,8 +5,8 @@ scenario sandbox-click-on-result-toggles-color-to-green [
   assume-screen 50/width, 20/height
   # basic recipe
   1:address:shared:array:character <- new [ 
-recipe foo [
-  reply 4
+def foo [
+  return 4
 ]]
   # run it
   2:address:shared:array:character <- new [foo]
@@ -59,8 +59,8 @@ recipe foo [
   ]
   # now change the result
   1:address:shared:array:character <- new [ 
-recipe foo [
-  reply 3
+def foo [
+  return 3
 ]]
   # then rerun
   assume-console [
@@ -131,7 +131,7 @@ after <global-touch> [
   }
 ]
 
-recipe find-click-in-sandbox-output env:address:shared:programming-environment-data, click-row:number -> sandbox:address:shared:sandbox-data [
+def find-click-in-sandbox-output env:address:shared:programming-environment-data, click-row:number -> sandbox:address:shared:sandbox-data [
   local-scope
   load-ingredients
   # assert click-row >= sandbox.starting-row-on-screen
@@ -151,13 +151,13 @@ recipe find-click-in-sandbox-output env:address:shared:programming-environment-d
   }
   # return sandbox if click is in its output region
   response-starting-row:number <- get *sandbox, response-starting-row-on-screen:offset
-  reply-unless response-starting-row, 0/no-click-in-sandbox-output
+  return-unless response-starting-row, 0/no-click-in-sandbox-output
   click-in-response?:boolean <- greater-or-equal click-row, response-starting-row
-  reply-unless click-in-response?, 0/no-click-in-sandbox-output
-  reply sandbox
+  return-unless click-in-response?, 0/no-click-in-sandbox-output
+  return sandbox
 ]
 
-recipe toggle-expected-response sandbox:address:shared:sandbox-data -> sandbox:address:shared:sandbox-data [
+def toggle-expected-response sandbox:address:shared:sandbox-data -> sandbox:address:shared:sandbox-data [
   local-scope
   load-ingredients
   expected-response:address:address:shared:array:character <- get-address *sandbox, expected-response:offset
@@ -165,7 +165,7 @@ recipe toggle-expected-response sandbox:address:shared:sandbox-data -> sandbox:a
     # if expected-response is set, reset
     break-unless *expected-response
     *expected-response <- copy 0
-    reply sandbox/same-as-ingredient:0
+    return sandbox/same-as-ingredient:0
   }
   # if not, current response is the expected response
   response:address:shared:array:character <- get *sandbox, response:offset
diff --git a/sandbox/009-sandbox-trace.mu b/sandbox/009-sandbox-trace.mu
index c59ecbbf..feecf010 100644
--- a/sandbox/009-sandbox-trace.mu
+++ b/sandbox/009-sandbox-trace.mu
@@ -119,7 +119,7 @@ container sandbox-data [
 ]
 
 # replaced in a later layer
-recipe! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data, idx:number -> sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data [
+def! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data, idx:number -> sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data [
   local-scope
   load-ingredients
   data:address:shared:array:character <- get *sandbox, data:offset
@@ -158,7 +158,7 @@ after <global-touch> [
   }
 ]
 
-recipe find-click-in-sandbox-code env:address:shared:programming-environment-data, click-row:number -> sandbox:address:shared:sandbox-data [
+def find-click-in-sandbox-code env:address:shared:programming-environment-data, click-row:number -> sandbox:address:shared:sandbox-data [
   local-scope
   load-ingredients
   # assert click-row >= sandbox.starting-row-on-screen
@@ -184,9 +184,9 @@ recipe find-click-in-sandbox-code env:address:shared:programming-environment-dat
   click-on-sandbox-code?:boolean <- and click-above-response?, click-below-menu?
   {
     break-if click-on-sandbox-code?
-    reply 0/no-click-in-sandbox-output
+    return 0/no-click-in-sandbox-output
   }
-  reply sandbox
+  return sandbox
 ]
 
 # when rendering a sandbox, dump its trace before response/warning if display-trace? property is set
diff --git a/sandbox/010-errors.mu b/sandbox/010-errors.mu
index 6794271d..ab2fb98b 100644
--- a/sandbox/010-errors.mu
+++ b/sandbox/010-errors.mu
@@ -6,7 +6,7 @@ container programming-environment-data [
 
 # copy code from recipe editor, persist, load into mu, save any errors
 # test-recipes is a hook for testing
-recipe! update-recipes env:address:shared:programming-environment-data, screen:address:shared:screen, test-recipes:address:shared:array:character -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
+def! update-recipes env:address:shared:programming-environment-data, screen:address:shared:screen, test-recipes:address:shared:array:character -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
   local-scope
   load-ingredients
   recipe-errors:address:address:shared:array:character <- get-address *env, recipe-errors:offset
@@ -25,7 +25,7 @@ recipe! update-recipes env:address:shared:programming-environment-data, screen:a
     status:address:shared:array:character <- new [errors found     ]
     update-status screen, status, 1/red
     errors-found? <- copy 1/true
-    reply
+    return
   }
   errors-found? <- copy 0/false
 ]
@@ -79,7 +79,7 @@ container sandbox-data [
   errors:address:shared:array:character
 ]
 
-recipe! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data, idx:number -> sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data [
+def! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data, idx:number -> sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data [
   local-scope
   load-ingredients
   data:address:shared:array:character <- get *sandbox, data:offset
@@ -91,7 +91,7 @@ recipe! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:p
   {
     break-unless recipe-errors
     *errors <- copy recipe-errors
-    reply
+    return
   }
   *response, *errors, *fake-screen, *trace, completed?:boolean <- run-interactive data
   {
@@ -131,7 +131,7 @@ scenario run-shows-errors-in-get [
   trace-until 100/app  # trace too long
   assume-screen 50/width, 20/height
   1:address:shared:array:character <- new [ 
-recipe foo [
+def foo [
   get 123:number, foo:offset
 ]]
   2:address:shared:array:character <- new [foo]
@@ -379,7 +379,7 @@ scenario run-shows-missing-type-errors [
   trace-until 100/app  # trace too long
   assume-screen 50/width, 20/height
   1:address:shared:array:character <- new [ 
-recipe foo [
+def foo [
   x <- copy 0
 ]]
   2:address:shared:array:character <- new [foo]
@@ -410,7 +410,7 @@ scenario run-shows-unbalanced-bracket-errors [
   assume-screen 50/width, 20/height
   # recipe is incomplete (unbalanced '[')
   1:address:shared:array:character <- new [ 
-recipe foo «
+def foo «
   x <- copy 0
 ]
   replace 1:address:shared:array:character, 171/«, 91  # '['
@@ -439,7 +439,7 @@ scenario run-shows-get-on-non-container-errors [
   trace-until 100/app  # trace too long
   assume-screen 50/width, 20/height
   1:address:shared:array:character <- new [ 
-recipe foo [
+def foo [
   local-scope
   x:address:shared:point <- new point:type
   get x:address:shared:point, 1:offset
@@ -467,7 +467,7 @@ scenario run-shows-non-literal-get-argument-errors [
   trace-until 100/app  # trace too long
   assume-screen 50/width, 20/height
   1:address:shared:array:character <- new [ 
-recipe foo [
+def foo [
   local-scope
   x:number <- copy 0
   y:address:shared:point <- new point:type
@@ -497,7 +497,7 @@ scenario run-shows-errors-everytime [
   assume-screen 50/width, 20/height
   # try to run a file with an error
   1:address:shared:array:character <- new [ 
-recipe foo [
+def foo [
   local-scope
   x:number <- copy y:number
 ]]
@@ -635,7 +635,7 @@ a:number <- next-ingredient
 b:number <- next-ingredient
 stash [dividing by], b
 _, c:number <- divide-with-remainder a, b
-reply b
+return b
 ]]
   2:address:shared:array:character <- new [foo 4, 0]
   3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 2:address:shared:array:character
diff --git a/sandbox/011-editor-undo.mu b/sandbox/011-editor-undo.mu
index d79e056c..5866fb52 100644
--- a/sandbox/011-editor-undo.mu
+++ b/sandbox/011-editor-undo.mu
@@ -72,7 +72,7 @@ after <handle-special-character> [
     redo:address:address:shared:list:address:shared:operation <- get-address *editor, redo:offset
     *redo <- push op, *redo
     <handle-undo>
-    reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render
+    return screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render
   }
 ]
 
@@ -88,7 +88,7 @@ after <handle-special-character> [
     undo:address:address:shared:list:address:shared:operation <- get-address *editor, undo:offset
     *undo <- push op, *undo
     <handle-redo>
-    reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render
+    return screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render
   }
 ]
 
@@ -189,14 +189,14 @@ before <insert-enter-end> [
 # redo stack, because it's now obsolete.
 # Beware: since we're counting cursor moves as operations, this means just
 # moving the cursor can lose work on the undo stack.
-recipe add-operation editor:address:shared:editor-data, op:address:shared:operation -> editor:address:shared:editor-data [
+def add-operation editor:address:shared:editor-data, op:address:shared:operation -> editor:address:shared:editor-data [
   local-scope
   load-ingredients
   undo:address:address:shared:list:address:shared:operation <- get-address *editor, undo:offset
   *undo <- push op *undo
   redo:address:address:shared:list:address:shared:operation <- get-address *editor, redo:offset
   *redo <- copy 0
-  reply editor/same-as-ingredient:0
+  return editor/same-as-ingredient:0
 ]
 
 after <handle-undo> [
diff --git a/screen.mu b/screen.mu
index 99efc9ce..89782489 100644
--- a/screen.mu
+++ b/screen.mu
@@ -3,7 +3,7 @@
 # The zero screen below means 'use the real screen'. Tests can also use fake
 # screens.
 
-recipe main [
+def main [
   open-console
   10:character <- copy 97/a
   print 0/screen, 10:character/a, 2/red
diff --git a/static_dispatch.mu b/static_dispatch.mu
index 00160a2a..9ef3e33c 100644
--- a/static_dispatch.mu
+++ b/static_dispatch.mu
@@ -1,16 +1,16 @@
-recipe test a:number -> b:number [
+def test a:number -> b:number [
   local-scope
   load-ingredients
   b <- add a, 1
 ]
 
-recipe test a:number, b:number -> c:number [
+def test a:number, b:number -> c:number [
   local-scope
   load-ingredients
   c <- add a, b
 ]
 
-recipe main [
+def main [
   local-scope
   a:number <- test 3  # selects single-ingredient version
   $print a, 10/newline
diff --git a/tangle.mu b/tangle.mu
index 8b989957..6d8d0e27 100644
--- a/tangle.mu
+++ b/tangle.mu
@@ -6,7 +6,7 @@
 # This isn't a very tasteful example, just a simple demonstration of
 # possibilities.
 
-recipe factorial n:number -> result:number [
+def factorial n:number -> result:number [
   local-scope
   load-ingredients
   {
@@ -19,7 +19,7 @@ after <base-case> [
   # if n=0 return 1
   zero?:boolean <- equal n, 0
   break-unless zero?
-  reply 1
+  return 1
 ]
 
 after <recursive-case> [
@@ -29,7 +29,7 @@ after <recursive-case> [
   result <- multiply subresult, n
 ]
 
-recipe main [
+def main [
   1:number <- factorial 5
   $print [result: ], 1:number, [
 ]
diff --git a/x.mu b/x.mu
index 8771381b..500ceae7 100644
--- a/x.mu
+++ b/x.mu
@@ -1,6 +1,6 @@
 # example program: add two numbers
 
-recipe main [
+def main [
   11:number <- copy 1
   12:number <- copy 3
   13:number <- add 11:number, 12:number