cue: introduce colon-separated labels

- parser: parse old and new style.
- format: format new style
- update generated examples and tutorial

Issue #60

Change-Id: I52e0d64932cc850281c96d6ad8d1eafca59f50b0
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/3550
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cmd/cue/cmd/script_test.go b/cmd/cue/cmd/script_test.go
index 13f23ea..e3bae80 100644
--- a/cmd/cue/cmd/script_test.go
+++ b/cmd/cue/cmd/script_test.go
@@ -1,12 +1,56 @@
 package cmd
 
 import (
+	"bytes"
+	"fmt"
 	"os"
+	"path"
+	"path/filepath"
+	"strings"
 	"testing"
 
+	"cuelang.org/go/cue/errors"
+	"cuelang.org/go/cue/parser"
 	"github.com/rogpeppe/testscript"
+	"github.com/rogpeppe/testscript/txtar"
 )
 
+// TestLatest checks that the examples match the latest language standard,
+// even if still valid in backwards compatibility mode.
+func TestLatest(t *testing.T) {
+	filepath.Walk("testdata/script", func(fullpath string, info os.FileInfo, err error) error {
+		if !strings.HasSuffix(fullpath, ".txt") {
+			return nil
+		}
+
+		a, err := txtar.ParseFile(fullpath)
+		if err != nil {
+			t.Error(err)
+			return nil
+		}
+		if bytes.HasPrefix(a.Comment, []byte("!")) {
+			return nil
+		}
+
+		for _, f := range a.Files {
+			t.Run(path.Join(fullpath, f.Name), func(t *testing.T) {
+				if !strings.HasSuffix(f.Name, ".cue") {
+					return
+				}
+				v := parser.FromVersion(parser.Latest)
+				_, err := parser.ParseFile(f.Name, f.Data, v)
+				if err != nil {
+					w := &bytes.Buffer{}
+					fmt.Fprintf(w, "\n%s:\n", fullpath)
+					errors.Print(w, err, nil)
+					t.Error(w.String())
+				}
+			})
+		}
+		return nil
+	})
+}
+
 func TestScript(t *testing.T) {
 	testscript.Run(t, testscript.Params{
 		Dir:           "testdata/script",
diff --git a/cmd/cue/cmd/testdata/script/cmd_baddisplay.txt b/cmd/cue/cmd/testdata/script/cmd_baddisplay.txt
index 3302f7e..a41547b 100644
--- a/cmd/cue/cmd/testdata/script/cmd_baddisplay.txt
+++ b/cmd/cue/cmd/testdata/script/cmd_baddisplay.txt
@@ -13,8 +13,8 @@
 -- task_tool.cue --
 package home
 
-command baddisplay: {
-	task display: {
+command: baddisplay: {
+	task: display: {
 		kind: "print"
 		text: 42
 	}
diff --git a/cmd/cue/cmd/testdata/script/cmd_echo.txt b/cmd/cue/cmd/testdata/script/cmd_echo.txt
index 9f76b2e..a626358 100644
--- a/cmd/cue/cmd/testdata/script/cmd_echo.txt
+++ b/cmd/cue/cmd/testdata/script/cmd_echo.txt
@@ -12,14 +12,14 @@
 -- hello_tool.cue --
 package hello
 
-command echo: {
-    task echo: {
+command: echo: {
+    task: echo: {
         kind:   "exec"
         cmd:    "echo \(message)"
         stdout: string
     }
 
-    task display: {
+    task: display: {
         kind: "print"
         text: task.echo.stdout
     }
diff --git a/cmd/cue/cmd/testdata/script/cmd_errcode.txt b/cmd/cue/cmd/testdata/script/cmd_errcode.txt
index e8ff6d1..633f94b 100644
--- a/cmd/cue/cmd/testdata/script/cmd_errcode.txt
+++ b/cmd/cue/cmd/testdata/script/cmd_errcode.txt
@@ -9,8 +9,8 @@
 -- task_tool.cue --
 package home
 
-command errcode: {
-	task bad: exec.Run & {
+command: errcode: {
+	task: bad: exec.Run & {
 		kind:   "exec"
 		cmd:    "ls --badflags"
 		stderr: string // suppress error message
diff --git a/cmd/cue/cmd/testdata/script/cmd_http.txt b/cmd/cue/cmd/testdata/script/cmd_http.txt
index 2ce28ee..4c240b1 100644
--- a/cmd/cue/cmd/testdata/script/cmd_http.txt
+++ b/cmd/cue/cmd/testdata/script/cmd_http.txt
@@ -7,20 +7,20 @@
 
 package home
 
-command http: {
-	task testserver: {
+command: http: {
+	task: testserver: {
 		kind: "testserver"
 		url:  string
 	}
-	task http: {
+	task: http: {
 		kind:   "http"
 		method: "POST"
 		url:    task.testserver.url
 
-		request body:  "I'll be back!"
-		response body: string // TODO: allow this to be a struct, parsing the body.
+		request: body:  "I'll be back!"
+		response: body: string // TODO: allow this to be a struct, parsing the body.
 	}
-	task print: {
+	task: print: {
 		kind: "print"
 		text: task.http.response.body
 	}
diff --git a/cmd/cue/cmd/testdata/script/cmd_print.txt b/cmd/cue/cmd/testdata/script/cmd_print.txt
index 5ebf1c0..a42de26 100644
--- a/cmd/cue/cmd/testdata/script/cmd_print.txt
+++ b/cmd/cue/cmd/testdata/script/cmd_print.txt
@@ -13,7 +13,7 @@
 	"strings"
 )
 
-command print: {
+command: print: {
 	task: {
 		t1: exec.Run & {
 			cmd: ["sh", "-c", "sleep 1; echo t1"]
diff --git a/cmd/cue/cmd/testdata/script/cmd_run.txt b/cmd/cue/cmd/testdata/script/cmd_run.txt
index 1da20f1..821fcf6 100644
--- a/cmd/cue/cmd/testdata/script/cmd_run.txt
+++ b/cmd/cue/cmd/testdata/script/cmd_run.txt
@@ -8,8 +8,8 @@
 -- task_tool.cue --
 package home
 
-command run: runBase & {
-	task echo cmd: "echo \(message)"
+command: run: runBase & {
+	task: echo: cmd: "echo \(message)"
 }
 
 -- base_tool.cue --
@@ -18,12 +18,12 @@
 // deliberately put in another file to test resolving top-level identifiers
 // in different files.
 runBase: {
-	task echo: {
+	task: echo: {
 		kind:   "exec"
 		stdout: string
 	}
 
-	task display: {
+	task: display: {
 		kind: "print"
 		text: task.echo.stdout
 	}
diff --git a/cmd/cue/cmd/testdata/script/cmd_run_list.txt b/cmd/cue/cmd/testdata/script/cmd_run_list.txt
index 16a5b1c..4fbbfed 100644
--- a/cmd/cue/cmd/testdata/script/cmd_run_list.txt
+++ b/cmd/cue/cmd/testdata/script/cmd_run_list.txt
@@ -8,8 +8,8 @@
 -- task_tool.cue --
 package home
 
-command run_list: runBase & {
-	task echo cmd: ["echo", message]
+command: run_list: runBase & {
+	task: echo: cmd: ["echo", message]
 }
 
 -- base_tool.cue --
@@ -18,12 +18,12 @@
 // deliberately put in another file to test resolving top-level identifiers
 // in different files.
 runBase: {
-	task echo: {
+	task: echo: {
 		kind:   "exec"
 		stdout: string
 	}
 
-	task display: {
+	task: display: {
 		kind: "print"
 		text: task.echo.stdout
 	}
diff --git a/cmd/cue/cmd/testdata/script/eval_expr.txt b/cmd/cue/cmd/testdata/script/eval_expr.txt
index 4d7b08e..69a60f4 100644
--- a/cmd/cue/cmd/testdata/script/eval_expr.txt
+++ b/cmd/cue/cmd/testdata/script/eval_expr.txt
@@ -20,7 +20,7 @@
 	idx: a[str] // should resolve to top-level `a`
 	str: string
 }
-b a b: 4
+b: a: b: 4
 a: {
 	b: 3
 	c: 4
diff --git a/cmd/cue/cmd/testdata/script/eval_tool.txt b/cmd/cue/cmd/testdata/script/eval_tool.txt
index 43aa9d6..e8a06e4 100644
--- a/cmd/cue/cmd/testdata/script/eval_tool.txt
+++ b/cmd/cue/cmd/testdata/script/eval_tool.txt
@@ -10,6 +10,6 @@
 -- task_tool.cue --
 package home
 
-command run_list: runBase & {
-	task echo cmd: ["echo", message]
+command: run_list: runBase & {
+	task: echo: cmd: ["echo", message]
 }
diff --git a/cmd/cue/cmd/testdata/script/import_hoiststr.txt b/cmd/cue/cmd/testdata/script/import_hoiststr.txt
index e821f07..e8fda16 100644
--- a/cmd/cue/cmd/testdata/script/import_hoiststr.txt
+++ b/cmd/cue/cmd/testdata/script/import_hoiststr.txt
@@ -18,7 +18,7 @@
 		_cue_json = [1, 2]
 	}]
 }
-deployment booster: [{
+deployment: booster: [{
 	kind:     "Deployment"
 	name:     "booster"
 	replicas: 1
diff --git a/cmd/cue/cmd/testdata/script/import_path.txt b/cmd/cue/cmd/testdata/script/import_path.txt
index 80618e2..64a4f32 100644
--- a/cmd/cue/cmd/testdata/script/import_path.txt
+++ b/cmd/cue/cmd/testdata/script/import_path.txt
@@ -2,16 +2,16 @@
 cmp stdout expect-stdout
 -- expect-stdout --
 
-service booster: {
+service: booster: {
 	kind: "Service"
 	name: "booster"
 }
-deployment booster: {
+deployment: booster: {
 	kind:     "Deployment"
 	name:     "booster"
 	replicas: 1
 }
-service "supplement\nfoo": {
+service: "supplement\nfoo": {
 	kind: "Service"
 	name: """
 		supplement
diff --git a/cmd/cue/cmd/testdata/script/toolonly.txt b/cmd/cue/cmd/testdata/script/toolonly.txt
index be535bc..735de03 100644
--- a/cmd/cue/cmd/testdata/script/toolonly.txt
+++ b/cmd/cue/cmd/testdata/script/toolonly.txt
@@ -8,7 +8,7 @@
 
 import "tool/cli"
 
-command foo task: {
+command: foo: task: {
 	foo: cli.Print & {
 		text: "foo"
 	}
diff --git a/cmd/cue/cmd/testdata/script/trim.txt b/cmd/cue/cmd/testdata/script/trim.txt
index b437ddf..df4bd4f 100644
--- a/cmd/cue/cmd/testdata/script/trim.txt
+++ b/cmd/cue/cmd/testdata/script/trim.txt
@@ -3,7 +3,7 @@
 -- expect-stdout --
 package trim
 
-foo <Name>: {
+foo: <Name>: {
 	_value: string
 
 	a: 4
@@ -21,12 +21,12 @@
 	rList: [{a: "a"}]
 	rcList: [{a: "a", c: b}]
 
-	t <Name>: {
+	t: <Name>: {
 		x: >=0 & <=5
 	}
 }
 
-foo bar: {
+foo: bar: {
 	_value: "here"
 	b:      "foo"
 	c:      45
@@ -34,33 +34,33 @@
 	sList: [{b: "foo"}, {}]
 }
 
-foo baz: {}
+foo: baz: {}
 
-foo multipath: {
-	t <Name>: {
+foo: multipath: {
+	t: <Name>: {
 		// Combined with the other template, we know the value must be 5 and
 		// thus the entry below can be eliminated.
 		x: >=5 & <=8
 	}
 
-	t u: {
+	t: u: {
 	}
 }
 
 // TODO: top-level fields are currently not removed.
 group: {
 	for k, v in foo {
-		comp "\(k)": v
+		comp: "\(k)": v
 	}
 
-	comp bar: {
+	comp: bar: {
 		aa: 8 // new value
 	}
 }
 -- trim/trim.cue --
 package trim
 
-foo <Name>: {
+foo: <Name>: {
 	_value: string
 
 	a: 4
@@ -78,12 +78,12 @@
 	rList: [{a: "a"}]
 	rcList: [{a: "a", c: b}]
 
-	t <Name>: {
+	t: <Name>: {
 		x: >=0 & <=5
 	}
 }
 
-foo bar: {
+foo: bar: {
 	_value: "here"
 	b:      "foo"
 	c:      45
@@ -91,26 +91,26 @@
 	sList: [{b: "foo"}, {}]
 }
 
-foo baz: {}
+foo: baz: {}
 
-foo multipath: {
-	t <Name>: {
+foo: multipath: {
+	t: <Name>: {
 		// Combined with the other template, we know the value must be 5 and
 		// thus the entry below can be eliminated.
 		x: >=5 & <=8
 	}
 
-	t u: {
+	t: u: {
 	}
 }
 
 // TODO: top-level fields are currently not removed.
 group: {
 	for k, v in foo {
-		comp "\(k)": v
+		comp: "\(k)": v
 	}
 
-	comp bar: {
+	comp: bar: {
 		aa: 8 // new value
 	}
 }
diff --git a/cmd/cue/cmd/testdata/script/vet_concrete.txt b/cmd/cue/cmd/testdata/script/vet_concrete.txt
index 2aa0108..aefae51 100644
--- a/cmd/cue/cmd/testdata/script/vet_concrete.txt
+++ b/cmd/cue/cmd/testdata/script/vet_concrete.txt
@@ -18,7 +18,7 @@
 	idx: a[str] // should resolve to top-level `a`
 	str: string
 }
-b a b: 4
+b: a: b: 4
 a: {
 	b: 3
 	c: 4
diff --git a/cmd/cue/cmd/testdata/script/vet_file.txt b/cmd/cue/cmd/testdata/script/vet_file.txt
index b000daf..672192b 100644
--- a/cmd/cue/cmd/testdata/script/vet_file.txt
+++ b/cmd/cue/cmd/testdata/script/vet_file.txt
@@ -3,13 +3,13 @@
 
 -- expect-stderr --
 translations.hello.lang: incomplete value (string):
-    ./vet.cue:2:24
+    ./vet.cue:2:26
 translations.hello.lang: conflicting values false and string (mismatched types bool and string):
     ./data.yaml:13:11
-    ./vet.cue:2:24
+    ./vet.cue:2:26
 -- vet.cue --
 
-translations <_> lang: string
+translations: <_>: lang: string
 
 File :: {
 	translations: {...}
diff --git a/cue/ast/astutil/apply_test.go b/cue/ast/astutil/apply_test.go
index 7c981bf..57b15c4 100644
--- a/cue/ast/astutil/apply_test.go
+++ b/cue/ast/astutil/apply_test.go
@@ -140,12 +140,12 @@
 		name: "templates",
 		in: `
 				foo: {
-					a <b> c: 3
+					a: <b>: c: 3
 				}
 				`,
 		out: `
 foo: {
-	a <b>: {
+	a: <b>: {
 		c:   3
 		iam: new
 	}
diff --git a/cue/export_test.go b/cue/export_test.go
index 3bf8181..a42f84e 100644
--- a/cue/export_test.go
+++ b/cue/export_test.go
@@ -160,7 +160,7 @@
 		in:  `{ a: { b: [] }, c: a.b, d: a["b"] }`,
 		out: unindent(`
 			{
-				a b: []
+				a: b: []
 				c: a.b
 				d: a["b"]
 			}`),
@@ -288,10 +288,10 @@
 			A = a
 			b: {
 				idx: A[str]
-				a b: 4
+				a: b: 4
 				str: string
 			}
-			a b: 3
+			a: b: 3
 		}`),
 	}, {
 		raw:   true,
@@ -355,7 +355,7 @@
 		{
 			emb :: {
 				a: 1
-				sub f: 3
+				sub: f: 3
 			}
 			f :: {
 				a: 10
@@ -391,26 +391,26 @@
 		{
 			reg: {
 				foo: 1
-				bar baz: 3
+				bar: baz: 3
 			}
 			def :: {
 				a: 1
 				sub: {
 					foo: 1
-					bar baz: 3
+					bar: baz: 3
 				}
 			}
 			val: {
 				a: 1
 				sub: {
 					foo: 1
-					bar baz: 3
+					bar: baz: 3
 				}
 			}
 			def2 :: {
-				a b: int
+				a: b: int
 			}
-			val2 a b: int
+			val2: a: b: int
 		}`),
 	}, {
 		raw:  true,
@@ -501,7 +501,7 @@
 				And :: {
 					"Fn::And": []
 				}
-				Ands "Fn::And": [3 | And]
+				Ands: "Fn::And": [3 | And]
 			}`),
 	}, {
 		raw:   true,
@@ -664,7 +664,7 @@
 		import "strings"
 
 		STRINGS = strings
-		a strings: STRINGS.ContainsAny("c")`),
+		a: strings: STRINGS.ContainsAny("c")`),
 	}, {
 		in: `
 			a: b - 100
@@ -745,7 +745,7 @@
 		{
 			reg: {
 				foo: 1
-				bar baz: 3
+				bar: baz: 3
 			}
 			def :: {
 				a: 1
@@ -762,7 +762,7 @@
 				a: 1
 				sub: {
 					foo: 1
-					bar baz: 3
+					bar: baz: 3
 				}
 			})
 		}`),
@@ -808,7 +808,7 @@
 			X :: {
 				x: int64
 			}
-			x x: int64
+			x: x: int64
 		}`),
 	}, {
 		eval: true,
@@ -829,7 +829,7 @@
 			{
 				reg: {
 					foo: 1
-					bar baz: 3
+					bar: baz: 3
 				}
 				def :: {
 					a: 1
@@ -846,11 +846,11 @@
 					a: 1
 					sub: {
 						foo: 1
-						bar baz: 3
+						bar: baz: 3
 					}
 				})
 				def2 :: {
-					a b: int
+					a: b: int
 				}
 				val2: close({
 					a: close({
diff --git a/cue/format/format.go b/cue/format/format.go
index e83a98c..6b2c6e2 100644
--- a/cue/format/format.go
+++ b/cue/format/format.go
@@ -179,6 +179,7 @@
 
 type labelEntry struct {
 	label    ast.Label
+	typ      token.Token
 	optional bool
 }
 
diff --git a/cue/format/format_test.go b/cue/format/format_test.go
index d3de3fe..0bd6104 100644
--- a/cue/format/format_test.go
+++ b/cue/format/format_test.go
@@ -18,7 +18,6 @@
 
 import (
 	"bytes"
-	"errors"
 	"flag"
 	"fmt"
 	"io/ioutil"
@@ -27,6 +26,7 @@
 	"time"
 
 	"cuelang.org/go/cue/ast"
+	"cuelang.org/go/cue/errors"
 	"cuelang.org/go/cue/parser"
 	"cuelang.org/go/cue/token"
 )
@@ -71,7 +71,8 @@
 
 	// make sure formatted output is syntactically correct
 	if _, err := parser.ParseFile("", res, parser.AllErrors); err != nil {
-		return nil, fmt.Errorf("re-parse: %s\n%s", err, res)
+		return nil, errors.Append(err.(errors.Error),
+			errors.Newf(token.NoPos, "re-parse failed: %s", res))
 	}
 
 	return res, nil
@@ -127,7 +128,9 @@
 
 	res, err := format(src, mode)
 	if err != nil {
-		t.Error(err)
+		b := &bytes.Buffer{}
+		errors.Print(b, err, nil)
+		t.Error(b.String())
 		return
 	}
 
diff --git a/cue/format/node.go b/cue/format/node.go
index 44c6fe9..8524431 100644
--- a/cue/format/node.go
+++ b/cue/format/node.go
@@ -138,11 +138,11 @@
 		lastSize := len(f.labelBuf)
 		f.labelBuf = f.labelBuf[:0]
 		regular := isRegularField(n.Token)
-		first, opt := n.Label, n.Optional != token.NoPos
+		first, typ, opt := n.Label, n.Token, n.Optional != token.NoPos
 
 		// If the label has a valid position, we assume that an unspecified
 		// Lbrace signals the intend to collapse fields.
-		for (n.Label.Pos().IsValid() || f.printer.cfg.simplify) && regular {
+		for n.Label.Pos().IsValid() || (f.printer.cfg.simplify && regular) {
 			obj, ok := n.Value.(*ast.StructLit)
 			if !ok || len(obj.Elts) != 1 || (obj.Lbrace.IsValid() && !f.printer.cfg.simplify) || len(n.Attrs) > 0 {
 				break
@@ -164,10 +164,7 @@
 			if !ok || len(mem.Attrs) > 0 {
 				break
 			}
-			if !isRegularField(mem.Token) {
-				break
-			}
-			entry := labelEntry{mem.Label, mem.Optional != token.NoPos}
+			entry := labelEntry{mem.Label, mem.Token, mem.Optional != token.NoPos}
 			f.labelBuf = append(f.labelBuf, entry)
 			n = mem
 		}
@@ -175,15 +172,18 @@
 		if lastSize != len(f.labelBuf) {
 			f.print(formfeed)
 		}
-		if !regular && first.Pos().RelPos() < token.Newline && len(f.output) > 0 {
-			f.print(newline, nooverride)
-		}
 
 		f.before(nil)
 		f.label(first, opt)
 		for _, x := range f.labelBuf {
+			if isRegularField(typ) {
+				f.print(n.TokenPos, token.COLON)
+			} else {
+				f.print(blank, nooverride, typ)
+			}
 			f.print(blank, nooverride)
 			f.label(x.label, x.optional)
+			typ = x.typ
 		}
 		f.after(nil)
 
diff --git a/cue/format/node_test.go b/cue/format/node_test.go
index ae358b6..6a5fe3e 100644
--- a/cue/format/node_test.go
+++ b/cue/format/node_test.go
@@ -15,7 +15,6 @@
 package format
 
 import (
-	"strings"
 	"testing"
 
 	"cuelang.org/go/cue/ast"
@@ -42,9 +41,8 @@
 			}},
 		}},
 		// Force a new struct.
-		out: `foo: {
-	bar :: {
-	}
+		out: `
+foo: bar :: {
 }`,
 	}}
 	for _, tc := range testCases {
@@ -54,7 +52,7 @@
 				t.Fatal(err)
 			}
 			got := string(b)
-			want := strings.TrimSpace(tc.out)
+			want := tc.out
 			if got != want {
 				t.Errorf("\ngot  %v;\nwant %v", got, want)
 			}
diff --git a/cue/format/testdata/expressions.golden b/cue/format/testdata/expressions.golden
index ae7d8bd..cbd4ab3 100644
--- a/cue/format/testdata/expressions.golden
+++ b/cue/format/testdata/expressions.golden
@@ -6,9 +6,9 @@
 
 	b: 3
 
-	c b a:       4
-	c? bb? aaa?: 5
-	c b <Name> a: int
+	c: b: a:       4
+	c?: bb?: aaa?: 5
+	c: b: <Name>: a: int
 	alias = 3.14
 	"g\("en")"?: 4
 
diff --git a/cue/format/testdata/simplify.golden b/cue/format/testdata/simplify.golden
index edb8b27..c6682e0 100644
--- a/cue/format/testdata/simplify.golden
+++ b/cue/format/testdata/simplify.golden
@@ -1,6 +1,6 @@
 
-foo bar: "str"
+foo: bar: "str"
 
-a B: 42
+a: B: 42
 
-"a.b" "foo-" cc_dd: x
+"a.b": "foo-": cc_dd: x
diff --git a/cue/parser/parser.go b/cue/parser/parser.go
index 894e2a7..46e2344 100644
--- a/cue/parser/parser.go
+++ b/cue/parser/parser.go
@@ -757,7 +757,8 @@
 	for i := 0; ; i++ {
 		tok := p.tok
 
-		expr, ok := p.parseLabel(m)
+		label, expr, ok := p.parseLabel(false)
+		m.Label = label
 
 		if !ok {
 			if expr == nil {
@@ -805,6 +806,7 @@
 
 		switch p.tok {
 		case token.IDENT, token.STRING, token.LSS, token.INTERPOLATION, token.LBRACK:
+			p.assertV0(0, 12, "space-separated labels")
 			field := &ast.Field{}
 			m.Value = &ast.StructLit{Elts: []ast.Decl{field}}
 			m = field
@@ -835,7 +837,38 @@
 		p.errorExpected(pos, "':' or '::'")
 	}
 	p.next() // : or ::
-	m.Value = p.parseRHS()
+
+	for {
+		tok := p.tok
+		label, expr, ok := p.parseLabel(true)
+		if !ok || (p.tok != token.COLON && p.tok != token.ISA && p.tok != token.OPTION) {
+			if expr == nil {
+				expr = p.parseRHS()
+			}
+			m.Value = expr
+			break
+		}
+		field := &ast.Field{Label: label}
+		m.Value = &ast.StructLit{Elts: []ast.Decl{field}}
+		m = field
+
+		if tok != token.LSS && p.tok == token.OPTION {
+			m.Optional = p.pos
+			p.next()
+		}
+
+		m.TokenPos = p.pos
+		m.Token = p.tok
+		if p.tok != token.COLON && p.tok != token.ISA {
+			if p.tok.IsLiteral() {
+				p.errf(p.pos, "expected ':' or '::'; found %s", p.lit)
+			} else {
+				p.errf(p.pos, "expected ':' or '::'; found %s", p.tok)
+			}
+			break
+		}
+		p.next()
+	}
 
 	if attrs := p.parseAttributes(); attrs != nil {
 		allowComprehension = false
@@ -894,7 +927,7 @@
 	return attrs
 }
 
-func (p *parser) parseLabel(f *ast.Field) (expr ast.Expr, ok bool) {
+func (p *parser) parseLabel(rhs bool) (label ast.Label, expr ast.Expr, ok bool) {
 	tok := p.tok
 	switch tok {
 	case token.IDENT, token.STRING, token.INTERPOLATION,
@@ -911,16 +944,16 @@
 				// generating good errors: any keyword can only appear on the RHS of a
 				// field (after a ':'), whereas labels always appear on the LHS.
 
-				f.Label, ok = x, true
+				label, ok = x, true
 			}
 
 		case ast.Label:
-			f.Label, ok = x, true
+			label, ok = x, true
 		}
 
 	case token.IF, token.FOR, token.IN, token.LET:
 		// Keywords representing clauses.
-		f.Label = &ast.Ident{
+		label = &ast.Ident{
 			NamePos: p.pos,
 			Name:    p.lit,
 		}
@@ -928,20 +961,69 @@
 		ok = true
 
 	case token.LSS:
+		p.openList()
+		defer p.closeList()
+
 		pos := p.pos
 		c := p.openComments()
 		p.next()
-		ident := p.parseIdent()
-		gtr := p.pos
-		if p.tok != token.GTR {
-			p.expect(token.GTR)
+		var ident *ast.Ident
+		var gtr token.Pos
+		switch {
+		case rhs:
+			// TODO: remove this code once the <X> notation is out.
+			if p.tok != token.IDENT {
+				// parse RHS and continue binary Expression
+				expr = p.parseUnaryExpr()
+				expr = &ast.UnaryExpr{OpPos: pos, Op: token.LSS, X: expr}
+				expr = c.closeExpr(p, expr)
+				return nil, p.parseBinaryExprTail(false, token.LowestPrec+1, expr), false
+			}
+
+			ident = p.parseIdent()
+			if p.tok != token.GTR {
+				expr = p.parsePrimaryExprTail(ident)
+				expr = &ast.UnaryExpr{OpPos: pos, Op: token.LSS, X: expr}
+				expr = c.closeExpr(p, expr)
+				return nil, p.parseBinaryExprTail(false, token.LowestPrec+1, expr), false
+			}
+			gtr = p.pos
+			p.next()
+
+			// NOTE: at this point, even if there still a syntactically valid
+			// expression, it will always yield bottom, as '>' does not take
+			// boolean arguments.
+			// This code does not allow for `<X>[string]:` and so on. So a
+			// new way to alias labels should be introduced at the time
+			// such constructs are introduced. For instance `(X,Y)=[string]:`.
+			if p.tok != token.COLON && p.tok != token.ISA {
+				expr = &ast.UnaryExpr{OpPos: pos, Op: token.LSS, X: ident}
+				expr = c.closeExpr(p, expr)
+				c := p.openComments()
+				prec := token.GTR.Precedence()
+				expr = c.closeExpr(p, &ast.BinaryExpr{
+					X:     expr,
+					OpPos: gtr,
+					Op:    token.GTR,
+					Y:     p.checkExpr(p.parseBinaryExpr(false, prec)),
+				})
+				return nil, expr, false
+			}
+
+		default:
+			ident = p.parseIdent()
+			gtr = p.pos
+			if p.tok != token.GTR {
+				p.expect(token.GTR)
+			}
+			p.next()
 		}
-		p.next()
-		label := &ast.TemplateLabel{Langle: pos, Ident: ident, Rangle: gtr}
+
+		label = &ast.TemplateLabel{Langle: pos, Ident: ident, Rangle: gtr}
 		c.closeNode(p, label)
-		f.Label, ok = label, true
+		ok = true
 	}
-	return expr, ok
+	return label, expr, ok
 }
 
 func (p *parser) parseStruct() (expr ast.Expr) {
@@ -1177,8 +1259,11 @@
 		defer un(trace(p, "PrimaryExpr"))
 	}
 
-	x := p.parseOperand()
+	return p.parsePrimaryExprTail(p.parseOperand())
+}
 
+func (p *parser) parsePrimaryExprTail(operand ast.Expr) ast.Expr {
+	x := operand
 L:
 	for {
 		switch p.tok {
@@ -1261,12 +1346,15 @@
 	p.openList()
 	defer p.closeList()
 
-	x := p.parseUnaryExpr()
+	return p.parseBinaryExprTail(lhs, prec1, p.parseUnaryExpr())
+}
 
+func (p *parser) parseBinaryExprTail(lhs bool, prec1 int, x ast.Expr) ast.Expr {
 	for {
 		op, prec := p.tokPrec()
 		if lhs && op == token.LSS {
 			// Eagerly interpret this as a template label.
+			// TODO: remove once <X> is deprecated.
 			if _, ok := x.(ast.Label); ok {
 				return x
 			}
diff --git a/cue/parser/parser_test.go b/cue/parser/parser_test.go
index 85e56c9..51821d9 100644
--- a/cue/parser/parser_test.go
+++ b/cue/parser/parser_test.go
@@ -146,11 +146,12 @@
 		`package k8s, import a "foo", import "bar/baz"`,
 	}, {
 		"collapsed fields",
-		`a b c: 1
+		`a: b:: c?: <Name>: d: 1
+		"g\("en")"?: 4
 		 // job foo { bar: 1 } // TODO error after foo
-		 job "foo": { bar: 1 }
+		 job "foo" <X>: { bar: 1 }
 		`,
-		`a: {b: {c: 1}}, job: {"foo": {bar: 1}}`,
+		`a: {b :: {c?: {<Name>: {d: 1}}}}, "g\("en")"?: 4, job: {"foo": {<X>: {bar: 1}}}`,
 	}, {
 		"identifiers",
 		`// 	$_: 1,
@@ -412,6 +413,8 @@
 	testCases := []struct{ desc, in string }{
 		{"block comments",
 			`a: 1 /* a */`},
+		{"space separator",
+			`a b c: 2`},
 	}
 	for _, tc := range testCases {
 		t.Run(tc.desc, func(t *testing.T) {
@@ -572,7 +575,7 @@
 func TestX(t *testing.T) {
 	t.Skip()
 
-	f, err := ParseFile("input", ``)
+	f, err := ParseFile("input", `a: b:: c?: <Name>: d: 1`)
 	if err != nil {
 		t.Errorf("unexpected error: %v", err)
 	}
diff --git a/doc/tutorial/basics/0_intro/55_fold.txt b/doc/tutorial/basics/0_intro/55_fold.txt
index a6bd0a9..fc950e1 100644
--- a/doc/tutorial/basics/0_intro/55_fold.txt
+++ b/doc/tutorial/basics/0_intro/55_fold.txt
@@ -23,11 +23,11 @@
 
 -- fold.cue --
 // path-value pairs
-outer middle1 inner: 3
-outer middle2 inner: 7
+outer: middle1: inner: 3
+outer: middle2: inner: 7
 
 // collection-constraint pair
-outer <Any> inner: int
+outer: <Any>: inner: int
 
 -- expect-stdout-cue --
 {
diff --git a/doc/tutorial/basics/2_types/05_types.txt b/doc/tutorial/basics/2_types/05_types.txt
index ef85665..c56e99f 100644
--- a/doc/tutorial/basics/2_types/05_types.txt
+++ b/doc/tutorial/basics/2_types/05_types.txt
@@ -43,10 +43,10 @@
 }
 
 xaxis: point
-xaxis x: 0
+xaxis: x: 0
 
 yaxis: point
-yaxis y: 0
+yaxis: y: 0
 
 origin: xaxis & yaxis
 
diff --git a/doc/tutorial/basics/2_types/90_templates.txt b/doc/tutorial/basics/2_types/90_templates.txt
index 779854b..b08f49b 100644
--- a/doc/tutorial/basics/2_types/90_templates.txt
+++ b/doc/tutorial/basics/2_types/90_templates.txt
@@ -18,15 +18,15 @@
 -- templates.cue --
 // The following struct is unified with all elements in job.
 // The name of each element is bound to Name and visible in the struct.
-job <Name>: {
+job: <Name>: {
     name:     Name
     replicas: uint | *1
     command:  string
 }
 
-job list command: "ls"
+job: list: command: "ls"
 
-job nginx: {
+job: nginx: {
     command:  "nginx"
     replicas: 2
 }
diff --git a/doc/tutorial/kubernetes/quick/services/frontend/bartender/kube.cue b/doc/tutorial/kubernetes/quick/services/frontend/bartender/kube.cue
index 24164fc..8570398 100644
--- a/doc/tutorial/kubernetes/quick/services/frontend/bartender/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/frontend/bartender/kube.cue
@@ -1,6 +1,6 @@
 package kube
 
-deployment bartender spec template spec containers: [{
+deployment: bartender: spec: template: spec: containers: [{
 	image: "gcr.io/myproj/bartender:v0.1.34"
 	args: [
 	]
diff --git a/doc/tutorial/kubernetes/quick/services/frontend/breaddispatcher/kube.cue b/doc/tutorial/kubernetes/quick/services/frontend/breaddispatcher/kube.cue
index 16af218..6e06a6a 100644
--- a/doc/tutorial/kubernetes/quick/services/frontend/breaddispatcher/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/frontend/breaddispatcher/kube.cue
@@ -1,6 +1,6 @@
 package kube
 
-deployment breaddispatcher spec template spec containers: [{
+deployment: breaddispatcher: spec: template: spec: containers: [{
 	image: "gcr.io/myproj/breaddispatcher:v0.3.24"
 	args: [
 		"-etcd=etcd:2379",
diff --git a/doc/tutorial/kubernetes/quick/services/frontend/host/kube.cue b/doc/tutorial/kubernetes/quick/services/frontend/host/kube.cue
index 97f1fe6..e58c822 100644
--- a/doc/tutorial/kubernetes/quick/services/frontend/host/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/frontend/host/kube.cue
@@ -1,8 +1,8 @@
 package kube
 
-deployment host spec: {
+deployment: host: spec: {
 	replicas: 2
-	template spec containers: [{
+	template: spec: containers: [{
 		image: "gcr.io/myproj/host:v0.1.10"
 		args: [
 		]
diff --git a/doc/tutorial/kubernetes/quick/services/frontend/kube.cue b/doc/tutorial/kubernetes/quick/services/frontend/kube.cue
index b2a3007..d896430 100644
--- a/doc/tutorial/kubernetes/quick/services/frontend/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/frontend/kube.cue
@@ -2,12 +2,12 @@
 
 Component :: "frontend"
 
-deployment <X> spec template: {
-	metadata annotations: {
+deployment: <X>: spec: template: {
+	metadata: annotations: {
 		"prometheus.io.scrape": "true"
 		"prometheus.io.port":   "\(spec.containers[0].ports[0].containerPort)"
 	}
-	spec containers: [{
+	spec: containers: [{
 		ports: [{containerPort: *7080 | int}] // 7080 is the default
 	}]
 }
diff --git a/doc/tutorial/kubernetes/quick/services/frontend/maitred/kube.cue b/doc/tutorial/kubernetes/quick/services/frontend/maitred/kube.cue
index 00a213c..4829e95 100644
--- a/doc/tutorial/kubernetes/quick/services/frontend/maitred/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/frontend/maitred/kube.cue
@@ -1,6 +1,6 @@
 package kube
 
-deployment maitred spec template spec containers: [{
+deployment: maitred: spec: template: spec: containers: [{
 	image: "gcr.io/myproj/maitred:v0.0.4"
 	args: [
 	]
diff --git a/doc/tutorial/kubernetes/quick/services/frontend/valeter/kube.cue b/doc/tutorial/kubernetes/quick/services/frontend/valeter/kube.cue
index da37ea9..3f0963e 100644
--- a/doc/tutorial/kubernetes/quick/services/frontend/valeter/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/frontend/valeter/kube.cue
@@ -1,9 +1,9 @@
 package kube
 
-service valeter spec ports: [{
+service: valeter: spec: ports: [{
 	name: "http"
 }]
-deployment valeter spec template spec containers: [{
+deployment: valeter: spec: template: spec: containers: [{
 	image: "gcr.io/myproj/valeter:v0.0.4"
 	ports: [{
 		containerPort: 8080
diff --git a/doc/tutorial/kubernetes/quick/services/frontend/waiter/kube.cue b/doc/tutorial/kubernetes/quick/services/frontend/waiter/kube.cue
index 3fcda5b..7a2c1de 100644
--- a/doc/tutorial/kubernetes/quick/services/frontend/waiter/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/frontend/waiter/kube.cue
@@ -1,8 +1,8 @@
 package kube
 
-deployment waiter spec: {
+deployment: waiter: spec: {
 	replicas: 5
-	template spec containers: [{
+	template: spec: containers: [{
 		image: "gcr.io/myproj/waiter:v0.3.0"
 	}]
 }
diff --git a/doc/tutorial/kubernetes/quick/services/frontend/waterdispatcher/kube.cue b/doc/tutorial/kubernetes/quick/services/frontend/waterdispatcher/kube.cue
index 66e9e56..058f185 100644
--- a/doc/tutorial/kubernetes/quick/services/frontend/waterdispatcher/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/frontend/waterdispatcher/kube.cue
@@ -1,9 +1,9 @@
 package kube
 
-service waterdispatcher spec ports: [{
+service: waterdispatcher: spec: ports: [{
 	name: "http"
 }]
-deployment waterdispatcher spec template spec containers: [{
+deployment: waterdispatcher: spec: template: spec: containers: [{
 	image: "gcr.io/myproj/waterdispatcher:v0.0.48"
 	args: [
 		"-http=:8080",
diff --git a/doc/tutorial/kubernetes/quick/services/infra/download/kube.cue b/doc/tutorial/kubernetes/quick/services/infra/download/kube.cue
index 7a56c6f..a7860ae 100644
--- a/doc/tutorial/kubernetes/quick/services/infra/download/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/infra/download/kube.cue
@@ -1,6 +1,6 @@
 package kube
 
-deployment download spec template spec containers: [{
+deployment: download: spec: template: spec: containers: [{
 	image: "gcr.io/myproj/download:v0.0.2"
 	ports: [{
 		containerPort: 7080
diff --git a/doc/tutorial/kubernetes/quick/services/infra/etcd/kube.cue b/doc/tutorial/kubernetes/quick/services/infra/etcd/kube.cue
index 7a0e915..ae2f756 100644
--- a/doc/tutorial/kubernetes/quick/services/infra/etcd/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/infra/etcd/kube.cue
@@ -1,23 +1,23 @@
 package kube
 
-service etcd spec: {
+service: etcd: spec: {
 	clusterIP: "None"
 	ports: [{
 	}, {
 		name: "peer"
 	}]
 }
-statefulSet etcd spec: {
+statefulSet: etcd: spec: {
 	serviceName: "etcd"
 	replicas:    3
 	template: {
-		metadata annotations: {
+		metadata: annotations: {
 			"prometheus.io.scrape": "true"
 			"prometheus.io.port":   "2379"
 		}
 		spec: {
-			affinity podAntiAffinity requiredDuringSchedulingIgnoredDuringExecution: [{
-				labelSelector matchExpressions: [{
+			affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: [{
+				labelSelector: matchExpressions: [{
 					key:      "app"
 					operator: "In"
 					values: [
@@ -55,10 +55,10 @@
 					value: "4"
 				}, {
 					name: "NAME"
-					valueFrom fieldRef fieldPath: "metadata.name"
+					valueFrom: fieldRef: fieldPath: "metadata.name"
 				}, {
 					name: "IP"
-					valueFrom fieldRef fieldPath: "status.podIP"
+					valueFrom: fieldRef: fieldPath: "status.podIP"
 				}]
 				command: ["/usr/local/bin/etcd"]
 				args: [
@@ -86,11 +86,11 @@
 	volumeClaimTemplates: [{
 		metadata: {
 			name: "etcd3"
-			annotations "volume.alpha.kubernetes.io/storage-class": "default"
+			annotations: "volume.alpha.kubernetes.io/storage-class": "default"
 		}
 		spec: {
 			accessModes: ["ReadWriteOnce"]
-			resources requests storage: "10Gi"
+			resources: requests: storage: "10Gi"
 		}
 	}]
 }
diff --git a/doc/tutorial/kubernetes/quick/services/infra/events/kube.cue b/doc/tutorial/kubernetes/quick/services/infra/events/kube.cue
index 5bfb6a3..d55ceb7 100644
--- a/doc/tutorial/kubernetes/quick/services/infra/events/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/infra/events/kube.cue
@@ -1,18 +1,18 @@
 package kube
 
-service events spec ports: [{
+service: events: spec: ports: [{
 	name: "grpc"
 }]
-deployment events spec: {
+deployment: events: spec: {
 	replicas: 2
 	template: {
-		metadata annotations: {
+		metadata: annotations: {
 			"prometheus.io.scrape": "true"
 			"prometheus.io.port":   "7080"
 		}
 		spec: {
-			affinity podAntiAffinity requiredDuringSchedulingIgnoredDuringExecution: [{
-				labelSelector matchExpressions: [{
+			affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: [{
+				labelSelector: matchExpressions: [{
 					key:      "app"
 					operator: "In"
 					values: [
@@ -23,7 +23,7 @@
 			}]
 			volumes: [{
 				name: "secret-volume"
-				secret secretName: "biz-secrets"
+				secret: secretName: "biz-secrets"
 			}]
 			containers: [{
 				image: "gcr.io/myproj/events:v0.1.31"
@@ -47,4 +47,4 @@
 	}
 }
 
-deployment events spec template spec containers: [{ports: [{_export: false}, _]}]
+deployment: events: spec: template: spec: containers: [{ports: [{_export: false}, _]}]
diff --git a/doc/tutorial/kubernetes/quick/services/infra/tasks/kube.cue b/doc/tutorial/kubernetes/quick/services/infra/tasks/kube.cue
index d478917..7181560 100644
--- a/doc/tutorial/kubernetes/quick/services/infra/tasks/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/infra/tasks/kube.cue
@@ -1,17 +1,17 @@
 package kube
 
-deployment tasks spec: {
+deployment: tasks: spec: {
 	// podTemplate defines the 'cookie cutter' used for creating
 	// new pods when necessary
 	template: {
-		metadata annotations: {
+		metadata: annotations: {
 			"prometheus.io.scrape": "true"
 			"prometheus.io.port":   "7080"
 		}
 		spec: {
 			volumes: [{
 				name: "secret-volume"
-				secret secretName: "star-example-com-secrets"
+				secret: secretName: "star-example-com-secrets"
 			}]
 			containers: [{
 				image: "gcr.io/myproj/tasks:v0.2.6"
@@ -29,4 +29,4 @@
 	}
 }
 
-deployment tasks spec template spec containers: [{ports: [{_export: false}, _]}]
+deployment: tasks: spec: template: spec: containers: [{ports: [{_export: false}, _]}]
diff --git a/doc/tutorial/kubernetes/quick/services/infra/tasks/service.cue b/doc/tutorial/kubernetes/quick/services/infra/tasks/service.cue
index 4cab0f4..ce4b3b3 100644
--- a/doc/tutorial/kubernetes/quick/services/infra/tasks/service.cue
+++ b/doc/tutorial/kubernetes/quick/services/infra/tasks/service.cue
@@ -1,6 +1,6 @@
 package kube
 
-service tasks spec: {
+service: tasks: spec: {
 	type:           "LoadBalancer"
 	loadBalancerIP: "1.2.3.4" // static ip
 	ports: [{
diff --git a/doc/tutorial/kubernetes/quick/services/infra/updater/kube.cue b/doc/tutorial/kubernetes/quick/services/infra/updater/kube.cue
index 480d013..ca7b848 100644
--- a/doc/tutorial/kubernetes/quick/services/infra/updater/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/infra/updater/kube.cue
@@ -1,9 +1,9 @@
 package kube
 
-deployment updater spec template spec: {
+deployment: updater: spec: template: spec: {
 	volumes: [{
 		name: "secret-updater"
-		secret secretName: "updater-secrets"
+		secret: secretName: "updater-secrets"
 	}]
 	containers: [{
 		image: "gcr.io/myproj/updater:v0.1.0"
diff --git a/doc/tutorial/kubernetes/quick/services/infra/watcher/kube.cue b/doc/tutorial/kubernetes/quick/services/infra/watcher/kube.cue
index 951b967..516a5cc 100644
--- a/doc/tutorial/kubernetes/quick/services/infra/watcher/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/infra/watcher/kube.cue
@@ -1,12 +1,12 @@
 package kube
 
-deployment watcher spec: {
+deployment: watcher: spec: {
 	// podTemplate defines the 'cookie cutter' used for creating
 	// new pods when necessary
-	template spec: {
+	template: spec: {
 		volumes: [{
 			name: "secret-volume"
-			secret secretName: "star-example-com-secrets"
+			secret: secretName: "star-example-com-secrets"
 		}]
 		containers: [{
 			image: "gcr.io/myproj/watcher:v0.1.0"
@@ -23,4 +23,4 @@
 	}
 }
 
-deployment watcher spec template spec containers: [{ports: [{_export: false}, _]}]
+deployment: watcher: spec: template: spec: containers: [{ports: [{_export: false}, _]}]
diff --git a/doc/tutorial/kubernetes/quick/services/infra/watcher/service.cue b/doc/tutorial/kubernetes/quick/services/infra/watcher/service.cue
index 0b8b6d9..3d0e60a 100644
--- a/doc/tutorial/kubernetes/quick/services/infra/watcher/service.cue
+++ b/doc/tutorial/kubernetes/quick/services/infra/watcher/service.cue
@@ -1,6 +1,6 @@
 package kube
 
-service watcher spec: {
+service: watcher: spec: {
 	type:           "LoadBalancer"
 	loadBalancerIP: "1.2.3.4." // static ip
 	ports: [{
diff --git a/doc/tutorial/kubernetes/quick/services/kitchen/caller/kube.cue b/doc/tutorial/kubernetes/quick/services/kitchen/caller/kube.cue
index 6315001..ddd728b 100644
--- a/doc/tutorial/kubernetes/quick/services/kitchen/caller/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/kitchen/caller/kube.cue
@@ -1,8 +1,8 @@
 package kube
 
-deployment caller spec: {
+deployment: caller: spec: {
 	replicas: 3
-	template spec: {
+	template: spec: {
 		volumes: [{
 			name: "ssd-caller"
 			gcePersistentDisk: {
@@ -12,7 +12,7 @@
 		}, {
 		}, {
 			name: "secret-ssh-key"
-			secret secretName: "secrets"
+			secret: secretName: "secrets"
 		}]
 		containers: [{
 			image: "gcr.io/myproj/caller:v0.20.14"
diff --git a/doc/tutorial/kubernetes/quick/services/kitchen/dishwasher/kube.cue b/doc/tutorial/kubernetes/quick/services/kitchen/dishwasher/kube.cue
index fe2019d..49430a4 100644
--- a/doc/tutorial/kubernetes/quick/services/kitchen/dishwasher/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/kitchen/dishwasher/kube.cue
@@ -1,13 +1,13 @@
 package kube
 
-deployment dishwasher spec: {
+deployment: dishwasher: spec: {
 	replicas: 5
-	template spec: {
+	template: spec: {
 		volumes: [{
 		}, {
 		}, {
 			name: "secret-ssh-key"
-			secret secretName: "dishwasher-secrets"
+			secret: secretName: "dishwasher-secrets"
 		}]
 		containers: [{
 			image: "gcr.io/myproj/dishwasher:v0.2.13"
diff --git a/doc/tutorial/kubernetes/quick/services/kitchen/expiditer/kube.cue b/doc/tutorial/kubernetes/quick/services/kitchen/expiditer/kube.cue
index 8370582..c152000 100644
--- a/doc/tutorial/kubernetes/quick/services/kitchen/expiditer/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/kitchen/expiditer/kube.cue
@@ -1,6 +1,6 @@
 package kube
 
-deployment expiditer spec template spec containers: [{
+deployment: expiditer: spec: template: spec: containers: [{
 	image: "gcr.io/myproj/expiditer:v0.5.34"
 	args: [
 		"-env=prod",
diff --git a/doc/tutorial/kubernetes/quick/services/kitchen/headchef/kube.cue b/doc/tutorial/kubernetes/quick/services/kitchen/headchef/kube.cue
index 68657ea..983d689 100644
--- a/doc/tutorial/kubernetes/quick/services/kitchen/headchef/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/kitchen/headchef/kube.cue
@@ -1,6 +1,6 @@
 package kube
 
-deployment headchef spec template spec containers: [{
+deployment: headchef: spec: template: spec: containers: [{
 	image: "gcr.io/myproj/headchef:v0.2.16"
 	volumeMounts: [{
 	}, {
diff --git a/doc/tutorial/kubernetes/quick/services/kitchen/kube.cue b/doc/tutorial/kubernetes/quick/services/kitchen/kube.cue
index 71450a1..02fa1f9 100644
--- a/doc/tutorial/kubernetes/quick/services/kitchen/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/kitchen/kube.cue
@@ -2,9 +2,9 @@
 
 Component :: "kitchen"
 
-deployment <Name> spec template: {
-	metadata annotations "prometheus.io.scrape": "true"
-	spec containers: [{
+deployment: <Name>: spec: template: {
+	metadata: annotations: "prometheus.io.scrape": "true"
+	spec: containers: [{
 		ports: [{
 			containerPort: 8080
 		}]
@@ -19,18 +19,18 @@
 	}]
 }
 
-deployment <ID> spec template spec: {
+deployment: <ID>: spec: template: spec: {
 	hasDisks :: *true | bool
 
 	// field comprehension using just "if"
 	if hasDisks {
 		volumes: [{
 			name: *"\(ID)-disk" | string
-			gcePersistentDisk pdName: *"\(ID)-disk" | string
-			gcePersistentDisk fsType: "ext4"
+			gcePersistentDisk: pdName: *"\(ID)-disk" | string
+			gcePersistentDisk: fsType: "ext4"
 		}, {
 			name: *"secret-\(ID)" | string
-			secret secretName: *"\(ID)-secrets" | string
+			secret: secretName: *"\(ID)-secrets" | string
 		}, ...]
 
 		containers: [{
diff --git a/doc/tutorial/kubernetes/quick/services/kitchen/linecook/kube.cue b/doc/tutorial/kubernetes/quick/services/kitchen/linecook/kube.cue
index fbe3a2e..179b993 100644
--- a/doc/tutorial/kubernetes/quick/services/kitchen/linecook/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/kitchen/linecook/kube.cue
@@ -1,10 +1,10 @@
 package kube
 
-deployment linecook spec template spec: {
+deployment: linecook: spec: template: spec: {
 	volumes: [{
 	}, {
 		name: "secret-kitchen"
-		secret secretName: "secrets"
+		secret: secretName: "secrets"
 	}]
 	containers: [{
 		image: "gcr.io/myproj/linecook:v0.1.42"
diff --git a/doc/tutorial/kubernetes/quick/services/kitchen/pastrychef/kube.cue b/doc/tutorial/kubernetes/quick/services/kitchen/pastrychef/kube.cue
index f8ac1a4..3810eda 100644
--- a/doc/tutorial/kubernetes/quick/services/kitchen/pastrychef/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/kitchen/pastrychef/kube.cue
@@ -1,10 +1,10 @@
 package kube
 
-deployment pastrychef spec template spec: {
+deployment: pastrychef: spec: template: spec: {
 	volumes: [{
 	}, {
 		name: "secret-ssh-key"
-		secret secretName: "secrets"
+		secret: secretName: "secrets"
 	}]
 	containers: [{
 		image: "gcr.io/myproj/pastrychef:v0.1.15"
diff --git a/doc/tutorial/kubernetes/quick/services/kitchen/souschef/kube.cue b/doc/tutorial/kubernetes/quick/services/kitchen/souschef/kube.cue
index 82e6533..11d9a94 100644
--- a/doc/tutorial/kubernetes/quick/services/kitchen/souschef/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/kitchen/souschef/kube.cue
@@ -1,9 +1,7 @@
 package kube
 
-deployment souschef spec template spec containers: [{
+deployment: souschef: spec: template: spec: containers: [{
 	image: "gcr.io/myproj/souschef:v0.5.3"
 }]
 
-deployment souschef spec template spec: {
-	hasDisks :: false
-}
+deployment : souschef : spec : template : spec : hasDisks :: false
diff --git a/doc/tutorial/kubernetes/quick/services/kube.cue b/doc/tutorial/kubernetes/quick/services/kube.cue
index 90c0e93..40aa035 100644
--- a/doc/tutorial/kubernetes/quick/services/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/kube.cue
@@ -1,6 +1,6 @@
 package kube
 
-service <ID>: {
+service: <ID>: {
 	apiVersion: "v1"
 	kind:       "Service"
 	metadata: {
@@ -22,79 +22,79 @@
 	}
 }
 
-deployment <ID>: {
+deployment: <ID>: {
 	apiVersion: "extensions/v1beta1"
 	kind:       "Deployment"
-	metadata name: ID
+	metadata: name: ID
 	spec: {
 		// 1 is the default, but we allow any number
 		replicas: *1 | int
 		template: {
-			metadata labels: {
+			metadata: labels: {
 				app:       ID
 				domain:    "prod"
 				component: Component
 			}
 			// we always have one namesake container
-			spec containers: [{name: ID}]
+			spec: containers: [{name: ID}]
 		}
 	}
 }
 
 Component :: string
 
-daemonSet <ID>: _spec & {
+daemonSet: <ID>: _spec & {
 	apiVersion: "extensions/v1beta1"
 	kind:       "DaemonSet"
 	Name ::     ID
 }
 
-statefulSet <ID>: _spec & {
+statefulSet: <ID>: _spec & {
 	apiVersion: "apps/v1beta1"
 	kind:       "StatefulSet"
 	Name ::     ID
 }
 
-deployment <ID>: _spec & {
+deployment: <ID>: _spec & {
 	apiVersion: "extensions/v1beta1"
 	kind:       "Deployment"
 	Name ::     ID
-	spec replicas: *1 | int
+	spec: replicas: *1 | int
 }
 
-configMap <ID>: {
-	metadata name: ID
-	metadata labels component: Component
+configMap: <ID>: {
+	metadata: name: ID
+	metadata: labels: component: Component
 }
 
 _spec: {
 	Name :: string
 
-	metadata name: Name
-	metadata labels component: Component
-	spec template: {
-		metadata labels: {
+	metadata: name: Name
+	metadata: labels: component: Component
+	spec: template: {
+		metadata: labels: {
 			app:       Name
 			component: Component
 			domain:    "prod"
 		}
-		spec containers: [{name: Name}]
+		spec: containers: [{name: Name}]
 	}
 }
 
 // Define the _export option and set the default to true
 // for all ports defined in all containers.
-_spec spec template spec containers: [...{
+_spec: spec: template: spec: containers: [...{
 	ports: [...{
 		_export: *true | false // include the port in the service
 	}]
 }]
 
 for x in [deployment, daemonSet, statefulSet] for k, v in x {
-	service "\(k)": {
-		spec selector: v.spec.template.metadata.labels
+	service: "\(k)": {
+		spec: selector: v.spec.template.metadata.labels
 
-		spec ports: [ {
+		spec: ports: [ {
 			Port = p.containerPort // Port is an alias
 			port:       *Port | int
 			targetPort: *Port | int
diff --git a/doc/tutorial/kubernetes/quick/services/mon/alertmanager/configmap.cue b/doc/tutorial/kubernetes/quick/services/mon/alertmanager/configmap.cue
index e641eed..ad04bc9 100644
--- a/doc/tutorial/kubernetes/quick/services/mon/alertmanager/configmap.cue
+++ b/doc/tutorial/kubernetes/quick/services/mon/alertmanager/configmap.cue
@@ -2,7 +2,7 @@
 
 import yaml656e63 "encoding/yaml"
 
-configMap alertmanager: {
+configMap: alertmanager: {
 	apiVersion: "v1"
 	kind:       "ConfigMap"
 	data: {
diff --git a/doc/tutorial/kubernetes/quick/services/mon/alertmanager/kube.cue b/doc/tutorial/kubernetes/quick/services/mon/alertmanager/kube.cue
index 76d2a8f..3af8c40 100644
--- a/doc/tutorial/kubernetes/quick/services/mon/alertmanager/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/mon/alertmanager/kube.cue
@@ -1,12 +1,12 @@
 package kube
 
-service alertmanager: {
+service: alertmanager: {
 	metadata: {
 		annotations: {
 			"prometheus.io/scrape": "true"
 			"prometheus.io/path":   "/metrics"
 		}
-		labels name: "alertmanager"
+		labels: name: "alertmanager"
 	}
 	spec: {
 		// type: ClusterIP
@@ -15,10 +15,10 @@
 		}]
 	}
 }
-deployment alertmanager spec: {
-	selector matchLabels app: "alertmanager"
+deployment: alertmanager: spec: {
+	selector: matchLabels: app: "alertmanager"
 	template: {
-		metadata name: "alertmanager"
+		metadata: name: "alertmanager"
 		spec: {
 			containers: [{
 				image: "prom/alertmanager:v0.15.2"
@@ -41,7 +41,7 @@
 			}]
 			volumes: [{
 				name: "config-volume"
-				configMap name: "alertmanager"
+				configMap: name: "alertmanager"
 			}, {
 				name: "alertmanager"
 				emptyDir: {}
diff --git a/doc/tutorial/kubernetes/quick/services/mon/grafana/kube.cue b/doc/tutorial/kubernetes/quick/services/mon/grafana/kube.cue
index 6efff35..dd8463c 100644
--- a/doc/tutorial/kubernetes/quick/services/mon/grafana/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/mon/grafana/kube.cue
@@ -1,8 +1,8 @@
 package kube
 
-deployment grafana: {
-	metadata labels app: "grafana"
-	spec template spec: {
+deployment: grafana: {
+	metadata: labels: app: "grafana"
+	spec: template: spec: {
 		volumes: [{
 			name: "grafana-volume"
 			gcePersistentDisk: {
@@ -49,7 +49,7 @@
 		}]
 	}
 }
-service grafana spec ports: [{
+service: grafana: spec: ports: [{
 	name:       "grafana"
 	port:       3000
 	targetPort: 3000
diff --git a/doc/tutorial/kubernetes/quick/services/mon/nodeexporter/kube.cue b/doc/tutorial/kubernetes/quick/services/mon/nodeexporter/kube.cue
index 8c46401..4ac3b8c 100644
--- a/doc/tutorial/kubernetes/quick/services/mon/nodeexporter/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/mon/nodeexporter/kube.cue
@@ -1,7 +1,7 @@
 package kube
 
-service "node-exporter": {
-	metadata annotations "prometheus.io/scrape": "true"
+service: "node-exporter": {
+	metadata: annotations: "prometheus.io/scrape": "true"
 	spec: {
 		type:      "ClusterIP"
 		clusterIP: "None"
@@ -10,8 +10,8 @@
 		}]
 	}
 }
-daemonSet "node-exporter" spec template: {
-	metadata name: "node-exporter"
+daemonSet: "node-exporter": spec: template: {
+	metadata: name: "node-exporter"
 	spec: {
 		hostNetwork: true
 		hostPID:     true
@@ -48,10 +48,10 @@
 		}]
 		volumes: [{
 			name: "proc"
-			hostPath path: "/proc"
+			hostPath: path: "/proc"
 		}, {
 			name: "sys"
-			hostPath path: "/sys"
+			hostPath: path: "/sys"
 		}]
 	}
 }
diff --git a/doc/tutorial/kubernetes/quick/services/mon/prometheus/configmap.cue b/doc/tutorial/kubernetes/quick/services/mon/prometheus/configmap.cue
index c73acf7..7c58f18 100644
--- a/doc/tutorial/kubernetes/quick/services/mon/prometheus/configmap.cue
+++ b/doc/tutorial/kubernetes/quick/services/mon/prometheus/configmap.cue
@@ -2,7 +2,7 @@
 
 import yaml656e63 "encoding/yaml"
 
-configMap prometheus: {
+configMap: prometheus: {
 	apiVersion: "v1"
 	kind:       "ConfigMap"
 	data: {
@@ -14,7 +14,7 @@
 					alert: "InstanceDown"
 					expr:  "up == 0"
 					for:   "30s"
-					labels severity: "page"
+					labels: severity: "page"
 					annotations: {
 						description: "{{$labels.app}} of job {{ $labels.job }} has been down for more than 30 seconds."
 
@@ -24,7 +24,7 @@
 					alert: "InsufficientPeers"
 					expr:  "count(up{job=\"etcd\"} == 0) > (count(up{job=\"etcd\"}) / 2 - 1)"
 					for:   "3m"
-					labels severity: "page"
+					labels: severity: "page"
 					annotations: {
 						description: "If one more etcd peer goes down the cluster will be unavailable"
 						summary:     "etcd cluster small"
@@ -33,13 +33,13 @@
 					alert: "EtcdNoMaster"
 					expr:  "sum(etcd_server_has_leader{app=\"etcd\"}) == 0"
 					for:   "1s"
-					labels severity:     "page"
-					annotations summary: "No ETCD master elected."
+					labels: severity:     "page"
+					annotations: summary: "No ETCD master elected."
 				}, {
 					alert: "PodRestart"
 					expr:  "(max_over_time(pod_container_status_restarts_total[5m]) - min_over_time(pod_container_status_restarts_total[5m])) > 2"
 					for:   "1m"
-					labels severity: "page"
+					labels: severity: "page"
 					annotations: {
 						description: "{{$labels.app}} {{ $labels.container }} resturted {{ $value }} times in 5m."
 						summary:     "Pod for {{$labels.container}} restarts too often"
@@ -50,11 +50,11 @@
 
 		"prometheus.yml": yaml656e63.Marshal(_cue_prometheus_yml)
 		_cue_prometheus_yml = {
-			global scrape_interval: "15s"
+			global: scrape_interval: "15s"
 			rule_files: [
 				"/etc/prometheus/alert.rules",
 			]
-			alerting alertmanagers: [{
+			alerting: alertmanagers: [{
 				scheme: "http"
 				static_configs: [{
 					targets: [
@@ -79,7 +79,7 @@
 				// Prometheus. The discovery auth config is automatic if Prometheus runs inside
 				// the cluster. Otherwise, more config options have to be provided within the
 				// <kubernetes_sd_config>.
-				tls_config ca_file: "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
+				tls_config: ca_file: "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
 				// If your node certificates are self-signed or use a different CA to the
 				// master CA, then disable certificate verification below. Note that
 				// certificate verification is an integral part of a secure infrastructure
@@ -116,7 +116,7 @@
 				// Prometheus. The discovery auth config is automatic if Prometheus runs inside
 				// the cluster. Otherwise, more config options have to be provided within the
 				// <kubernetes_sd_config>.
-				tls_config ca_file: "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
+				tls_config: ca_file: "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
 				bearer_token_file: "/var/run/secrets/kubernetes.io/serviceaccount/token"
 
 				kubernetes_sd_configs: [{
@@ -162,7 +162,7 @@
 				// Prometheus. The discovery auth config is automatic if Prometheus runs inside
 				// the cluster. Otherwise, more config options have to be provided within the
 				// <kubernetes_sd_config>.
-				tls_config ca_file: "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
+				tls_config: ca_file: "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
 				bearer_token_file: "/var/run/secrets/kubernetes.io/serviceaccount/token"
 
 				kubernetes_sd_configs: [{
@@ -241,7 +241,7 @@
 				job_name: "kubernetes-services"
 
 				metrics_path: "/probe"
-				params module: ["http_2xx"]
+				params: module: ["http_2xx"]
 
 				kubernetes_sd_configs: [{
 					role: "service"
@@ -280,7 +280,7 @@
 				job_name: "kubernetes-ingresses"
 
 				metrics_path: "/probe"
-				params module: ["http_2xx"]
+				params: module: ["http_2xx"]
 
 				kubernetes_sd_configs: [{
 					role: "ingress"
diff --git a/doc/tutorial/kubernetes/quick/services/mon/prometheus/kube.cue b/doc/tutorial/kubernetes/quick/services/mon/prometheus/kube.cue
index c24e39c..096a89d 100644
--- a/doc/tutorial/kubernetes/quick/services/mon/prometheus/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/mon/prometheus/kube.cue
@@ -1,9 +1,9 @@
 package kube
 
-service prometheus: {
+service: prometheus: {
 	metadata: {
-		annotations "prometheus.io/scrape": "true"
-		labels name:                        "prometheus"
+		annotations: "prometheus.io/scrape": "true"
+		labels: name:                        "prometheus"
 	}
 	spec: {
 		type: "NodePort"
@@ -13,7 +13,7 @@
 		}]
 	}
 }
-deployment prometheus spec: {
+deployment: prometheus: spec: {
 	strategy: {
 		rollingUpdate: {
 			maxSurge:       0
@@ -21,11 +21,11 @@
 		}
 		type: "RollingUpdate"
 	}
-	selector matchLabels app: "prometheus"
+	selector: matchLabels: app: "prometheus"
 	template: {
 		metadata: {
 			name: "prometheus"
-			annotations "prometheus.io.scrape": "true"
+			annotations: "prometheus.io.scrape": "true"
 		}
 		spec: {
 			containers: [{
@@ -45,7 +45,7 @@
 			}]
 			volumes: [{
 				name: "config-volume"
-				configMap name: "prometheus"
+				configMap: name: "prometheus"
 			}]
 		}
 	}
diff --git a/doc/tutorial/kubernetes/quick/services/proxy/authproxy/configmap.cue b/doc/tutorial/kubernetes/quick/services/proxy/authproxy/configmap.cue
index c38c6e3..f105c88 100644
--- a/doc/tutorial/kubernetes/quick/services/proxy/authproxy/configmap.cue
+++ b/doc/tutorial/kubernetes/quick/services/proxy/authproxy/configmap.cue
@@ -1,6 +1,6 @@
 package kube
 
-configMap authproxy: {
+configMap: authproxy: {
 	// To update run:
 	// kubectl apply -f configmap.yaml
 	// kubectl scale --replicas=0 deployment/proxy
@@ -8,7 +8,7 @@
 
 	apiVersion: "v1"
 	kind:       "ConfigMap"
-	data "authproxy.cfg": """
+	data: "authproxy.cfg": """
 		# Google Auth Proxy Config File
 		## https://github.com/bitly/google_auth_proxy
 
diff --git a/doc/tutorial/kubernetes/quick/services/proxy/authproxy/kube.cue b/doc/tutorial/kubernetes/quick/services/proxy/authproxy/kube.cue
index 487f005..7f2556c 100644
--- a/doc/tutorial/kubernetes/quick/services/proxy/authproxy/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/proxy/authproxy/kube.cue
@@ -1,9 +1,9 @@
 package kube
 
-deployment authproxy spec: {
+deployment: authproxy: spec: {
 	// podTemplate defines the 'cookie cutter' used for creating
 	// new pods when necessary
-	template spec: {
+	template: spec: {
 		containers: [{
 			image: "skippy/oauth2_proxy:2.0.1"
 			ports: [{
@@ -20,7 +20,7 @@
 		}]
 		volumes: [{
 			name: "config-volume"
-			configMap name: "authproxy"
+			configMap: name: "authproxy"
 		}]
 	}
 }
diff --git a/doc/tutorial/kubernetes/quick/services/proxy/goget/kube.cue b/doc/tutorial/kubernetes/quick/services/proxy/goget/kube.cue
index 33bc990..bdbbdcc 100644
--- a/doc/tutorial/kubernetes/quick/services/proxy/goget/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/proxy/goget/kube.cue
@@ -1,12 +1,12 @@
 package kube
 
-deployment goget spec: {
+deployment: goget: spec: {
 	// podTemplate defines the 'cookie cutter' used for creating
 	// new pods when necessary
-	template spec: {
+	template: spec: {
 		volumes: [{
 			name: "secret-volume"
-			secret secretName: "goget-secrets"
+			secret: secretName: "goget-secrets"
 		}]
 		containers: [{
 			image: "gcr.io/myproj/goget:v0.5.1"
diff --git a/doc/tutorial/kubernetes/quick/services/proxy/goget/service.cue b/doc/tutorial/kubernetes/quick/services/proxy/goget/service.cue
index 15465d2..70529cf 100644
--- a/doc/tutorial/kubernetes/quick/services/proxy/goget/service.cue
+++ b/doc/tutorial/kubernetes/quick/services/proxy/goget/service.cue
@@ -1,6 +1,6 @@
 package kube
 
-service goget spec: {
+service: goget: spec: {
 	type:           "LoadBalancer"
 	loadBalancerIP: "1.3.5.7" // static ip
 	ports: [{
diff --git a/doc/tutorial/kubernetes/quick/services/proxy/nginx/configmap.cue b/doc/tutorial/kubernetes/quick/services/proxy/nginx/configmap.cue
index a35ec2b..661ec92 100644
--- a/doc/tutorial/kubernetes/quick/services/proxy/nginx/configmap.cue
+++ b/doc/tutorial/kubernetes/quick/services/proxy/nginx/configmap.cue
@@ -1,9 +1,9 @@
 package kube
 
-configMap nginx: {
+configMap: nginx: {
 	apiVersion: "v1"
 	kind:       "ConfigMap"
-	data "nginx.conf": """
+	data: "nginx.conf": """
 		events {
 		    worker_connections 768;
 		}
diff --git a/doc/tutorial/kubernetes/quick/services/proxy/nginx/kube.cue b/doc/tutorial/kubernetes/quick/services/proxy/nginx/kube.cue
index 3486fef..fd1a1f6 100644
--- a/doc/tutorial/kubernetes/quick/services/proxy/nginx/kube.cue
+++ b/doc/tutorial/kubernetes/quick/services/proxy/nginx/kube.cue
@@ -1,15 +1,15 @@
 package kube
 
-deployment nginx spec: {
+deployment: nginx: spec: {
 	// podTemplate defines the 'cookie cutter' used for creating
 	// new pods when necessary
-	template spec: {
+	template: spec: {
 		volumes: [{
 			name: "secret-volume"
-			secret secretName: "proxy-secrets"
+			secret: secretName: "proxy-secrets"
 		}, {
 			name: "config-volume"
-			configMap name: "nginx"
+			configMap: name: "nginx"
 		}]
 		containers: [{
 			image: "nginx:1.11.10-alpine"
diff --git a/doc/tutorial/kubernetes/quick/services/proxy/nginx/service.cue b/doc/tutorial/kubernetes/quick/services/proxy/nginx/service.cue
index 7c715e5..b310cb9 100644
--- a/doc/tutorial/kubernetes/quick/services/proxy/nginx/service.cue
+++ b/doc/tutorial/kubernetes/quick/services/proxy/nginx/service.cue
@@ -1,6 +1,6 @@
 package kube
 
-service nginx spec: {
+service: nginx: spec: {
 	type:           "LoadBalancer"
 	loadBalancerIP: "1.3.4.5"
 	ports: [{
diff --git a/encoding/protobuf/testdata/client_config.proto.out.cue b/encoding/protobuf/testdata/client_config.proto.out.cue
index 3f9cb25..b9c5c3a 100644
--- a/encoding/protobuf/testdata/client_config.proto.out.cue
+++ b/encoding/protobuf/testdata/client_config.proto.out.cue
@@ -47,7 +47,7 @@
 	// service.
 	"FAIL_OPEN"
 
-NetworkFailPolicy_FailPolicy_value FAIL_OPEN: 0
+NetworkFailPolicy_FailPolicy_value: FAIL_OPEN: 0
 
 // Defines the per-service client configuration.
 ServiceConfig: {
diff --git a/encoding/protobuf/testdata/gateway.proto.out.cue b/encoding/protobuf/testdata/gateway.proto.out.cue
index f3503d2..1a7ed21 100644
--- a/encoding/protobuf/testdata/gateway.proto.out.cue
+++ b/encoding/protobuf/testdata/gateway.proto.out.cue
@@ -216,7 +216,7 @@
 	selector?: {
 		<_>: string
 	} @protobuf(2,type=map<string,string>)
-	selector? <name>: name
+	selector?: <name>: name
 }
 
 // `Server` describes the properties of the proxy on a given load balancer
diff --git a/encoding/protobuf/testdata/istio.io/api/mixer/v1/config/client/client_config_proto_gen.cue b/encoding/protobuf/testdata/istio.io/api/mixer/v1/config/client/client_config_proto_gen.cue
index 1397a5a..4762234 100644
--- a/encoding/protobuf/testdata/istio.io/api/mixer/v1/config/client/client_config_proto_gen.cue
+++ b/encoding/protobuf/testdata/istio.io/api/mixer/v1/config/client/client_config_proto_gen.cue
@@ -46,7 +46,7 @@
 	// service.
 	"FAIL_OPEN"
 
-NetworkFailPolicy_FailPolicy_value "FAIL_OPEN": 0
+NetworkFailPolicy_FailPolicy_value: "FAIL_OPEN": 0
 
 // Defines the per-service client configuration.
 ServiceConfig: {