diff --git a/cmd/root.go b/cmd/root.go
index fa60984f49025557280c1bdb90a5466eca9c1cd8..d149d1a046c32e9c9f8fde138f9d2d5c15937d39 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -1,13 +1,16 @@
 package cmd
 
 import (
-	"encoding/json"
 	goflag "flag"
+	"fmt"
 	"path/filepath"
 
 	"github.com/golang/glog"
 	"github.com/spf13/cobra"
 	jsonnet "github.com/strickyak/jsonnet_cgo"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+	"github.com/bitnami/kubecfg/utils"
 )
 
 func init() {
@@ -40,30 +43,27 @@ func JsonnetVM(cmd *cobra.Command) (*jsonnet.VM, error) {
 		return nil, err
 	}
 	for _, p := range filepath.SplitList(jpath) {
-		glog.V(2).Infoln("Adding jsonnet path", p)
+		glog.V(2).Infoln("Adding jsonnet search path", p)
 		vm.JpathAdd(p)
 	}
 
 	return vm, nil
 }
 
-func evalFile(vm *jsonnet.VM, file string) (interface{}, error) {
-	var err error
-	jsonstr := ""
-	if file != "" {
-		jsonstr, err = vm.EvaluateFile(file)
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	glog.V(4).Infof("jsonnet result is: %s\n", jsonstr)
-
-	var jsobj interface{}
-	err = json.Unmarshal([]byte(jsonstr), &jsobj)
+func readObjs(cmd *cobra.Command, paths []string) ([]metav1.Object, error) {
+	vm, err := JsonnetVM(cmd)
 	if err != nil {
 		return nil, err
 	}
+	defer vm.Destroy()
 
-	return jsobj, nil
+	res := []metav1.Object{}
+	for _, path := range paths {
+		objs, err := utils.Read(vm, path)
+		if err != nil {
+			return nil, fmt.Errorf("Error reading %s: %v", path, err)
+		}
+		res = append(res, utils.FlattenToV1(objs)...)
+	}
+	return res, nil
 }
diff --git a/cmd/show.go b/cmd/show.go
index 82f8c0efafa2b9de502cf2b4ad8ca92f2e2cf176..9735cb418584a2e4d71057cd8538718c1faeda2b 100644
--- a/cmd/show.go
+++ b/cmd/show.go
@@ -10,8 +10,6 @@ import (
 
 func init() {
 	RootCmd.AddCommand(showCmd)
-	showCmd.PersistentFlags().StringP("file", "f", "", "Input jsonnet file")
-	showCmd.MarkFlagFilename("file", "jsonnet", "libsonnet")
 	showCmd.PersistentFlags().StringP("format", "o", "yaml", "Output format.  Supported values are: json, yaml")
 }
 
@@ -28,11 +26,7 @@ var showCmd = &cobra.Command{
 		}
 		defer vm.Destroy()
 
-		file, err := flags.GetString("file")
-		if err != nil {
-			return err
-		}
-		jsobj, err := evalFile(vm, file)
+		objs, err := readObjs(cmd, args)
 		if err != nil {
 			return err
 		}
@@ -43,16 +37,36 @@ var showCmd = &cobra.Command{
 		}
 		switch format {
 		case "yaml":
-			buf, err := yaml.Marshal(jsobj)
-			if err != nil {
-				return err
+			for _, obj := range objs {
+				fmt.Fprintln(out, "---")
+				// Urgh.  Go via json because we need
+				// to trigger the custom scheme
+				// encoding.
+				buf, err := json.Marshal(obj)
+				if err != nil {
+					return err
+				}
+				o := map[string]interface{}{}
+				if err := json.Unmarshal(buf, &o); err != nil {
+					return err
+				}
+				buf, err = yaml.Marshal(o)
+				if err != nil {
+					return err
+				}
+				out.Write(buf)
 			}
-			out.Write(buf)
 		case "json":
 			enc := json.NewEncoder(out)
 			enc.SetIndent("", "  ")
-			if err := enc.Encode(&jsobj); err != nil {
-				return err
+			for _, obj := range objs {
+				// TODO: this is not valid framing for JSON
+				if len(objs) > 1 {
+					fmt.Fprintln(out, "---")
+				}
+				if err := enc.Encode(obj); err != nil {
+					return err
+				}
 			}
 		default:
 			return fmt.Errorf("Unknown --format: %s", format)
diff --git a/cmd/show_test.go b/cmd/show_test.go
index 7ce55fb797bf1e01db49d4f9d29af34dccacb394..55017a7b20aa090d040cb1f183379597b9ace21c 100644
--- a/cmd/show_test.go
+++ b/cmd/show_test.go
@@ -39,6 +39,8 @@ func TestShow(t *testing.T) {
 	// Use the fact that JSON is also valid YAML ..
 	expected := `
 {
+  "apiVersion": "v0alpha1",
+  "kind": "TestObject",
   "nil": null,
   "bool": true,
   "number": 42,
@@ -56,8 +58,8 @@ func TestShow(t *testing.T) {
 
 		output := cmdOutput(t, []string{"show",
 			"-J", filepath.FromSlash("../testdata/lib"),
-			"-f", filepath.FromSlash("../testdata/test.jsonnet"),
 			"-o", format,
+			filepath.FromSlash("../testdata/test.jsonnet"),
 		})
 
 		t.Log("output is", output)
diff --git a/main.go b/main.go
index 2ce6712d345ee928a5a62a1eff1015d1cef9e159..c0677115f10f2d7d5272a55e40080ed283853358 100644
--- a/main.go
+++ b/main.go
@@ -14,7 +14,6 @@ func main() {
 	cmd.Version = version
 
 	if err := cmd.RootCmd.Execute(); err != nil {
-		fmt.Println("got error")
 		fmt.Println("Error:", err)
 		os.Exit(1)
 	}
diff --git a/testdata/lib/test.libsonnet b/testdata/lib/test.libsonnet
index 6dd03fe6d7eed62380793daf5dc9bd6d3c6c5e2f..50e063e1685ab35738d53add0f8036e475e3cd73 100644
--- a/testdata/lib/test.libsonnet
+++ b/testdata/lib/test.libsonnet
@@ -1,4 +1,7 @@
 {
+  apiVersion: "v0alpha1",
+  kind: "TestObject",
+
   nil: null,
   bool: true,
   number: 42,
diff --git a/testdata/simple.json b/testdata/simple.json
new file mode 100644
index 0000000000000000000000000000000000000000..6416b9bef50b9b8367ca6a21188beaf45dbb333c
--- /dev/null
+++ b/testdata/simple.json
@@ -0,0 +1,5 @@
+{
+  apiVersion: "v0alpha1",
+  kind: "JsonObject"
+  foo: "bar",
+}
diff --git a/testdata/test.jsonnet b/testdata/test.jsonnet
index 935c6df126dd4087df1250b3d3e23f0d4d68c828..f98a72df860010eb46154039ddc12ada117579e2 100644
--- a/testdata/test.jsonnet
+++ b/testdata/test.jsonnet
@@ -1,5 +1,11 @@
 local test = import "test.libsonnet";
 
-test {
-  string: "bar",
+{
+  apiVersion: "v1",
+  kind: "List",
+  items: [
+    test {
+      string: "bar",
+    }
+  ],
 }
diff --git a/testdata/test.yaml b/testdata/test.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c30e1838534d0d20079f4c0b08914e5787417499
--- /dev/null
+++ b/testdata/test.yaml
@@ -0,0 +1,3 @@
+apiVersion: v0alpha0
+kind: YamlObject
+foo: bar
diff --git a/utils/acquire.go b/utils/acquire.go
new file mode 100644
index 0000000000000000000000000000000000000000..01731a45b9329dbb26ca9be6bc0fbabf530fd33f
--- /dev/null
+++ b/utils/acquire.go
@@ -0,0 +1,110 @@
+package utils
+
+import (
+	"fmt"
+	"io"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"github.com/golang/glog"
+	jsonnet "github.com/strickyak/jsonnet_cgo"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	unstructuredv1 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+	"k8s.io/apimachinery/pkg/util/yaml"
+	"k8s.io/apimachinery/pkg/runtime"
+)
+
+// Read fetches and decodes K8s objects by path.
+// TODO: Replace this with something supporting more sophisticated
+// content negotiation.
+func Read(vm *jsonnet.VM, path string) ([]runtime.Unstructured, error) {
+	ext := filepath.Ext(path)
+	if ext == ".json" {
+		f, err := os.Open(path)
+		if err != nil {
+			return nil, err
+		}
+		defer f.Close()
+		return jsonReader(f)
+	} else if ext == ".yaml" {
+		f, err := os.Open(path)
+		if err != nil {
+			return nil, err
+		}
+		defer f.Close()
+		return yamlReader(f)
+	} else if ext == ".jsonnet" {
+		return jsonnetReader(vm, path)
+	}
+
+	return nil, fmt.Errorf("Unknown file extension: %s", path)
+}
+
+func jsonReader(r io.Reader) ([]runtime.Unstructured, error) {
+	data, err := ioutil.ReadAll(r)
+	if err != nil {
+		return nil, err
+	}
+	obj, _, err := unstructuredv1.UnstructuredJSONScheme.Decode(data, nil, nil)
+	if err != nil {
+		return nil, err
+	}
+	return []runtime.Unstructured{obj.(runtime.Unstructured)}, nil
+}
+
+func yamlReader(r io.ReadCloser) ([]runtime.Unstructured, error) {
+	decoder := yaml.NewDocumentDecoder(r)
+	ret := []runtime.Unstructured{}
+	buf := []byte{}
+	for {
+		_, err := decoder.Read(buf)
+		if err == io.EOF {
+			break
+		} else if err != nil {
+			return nil, err
+		}
+		jsondata, err := yaml.ToJSON(buf)
+		if err != nil {
+			return nil, err
+		}
+		obj, _, err := unstructuredv1.UnstructuredJSONScheme.Decode(jsondata, nil, nil)
+		if err != nil {
+			return nil, err
+		}
+		ret = append(ret, obj.(runtime.Unstructured))
+	}
+	return ret, nil
+}
+
+func jsonnetReader(vm *jsonnet.VM, path string) ([]runtime.Unstructured, error) {
+	jsonstr, err := vm.EvaluateFile(path)
+	if err != nil {
+		return nil, err
+	}
+
+	glog.V(4).Infof("jsonnet result is: %s\n", jsonstr)
+
+	return jsonReader(strings.NewReader(jsonstr))
+}
+
+// FlattenToV1 expands any List-type objects into their members, and
+// cooerces everything to metav1.Objects.  Panics if coercion
+// encounters an unexpected object type.
+func FlattenToV1(objs []runtime.Unstructured) []metav1.Object {
+	ret := make([]metav1.Object, 0, len(objs))
+	for _, obj := range objs {
+		switch o := obj.(type) {
+		case *unstructuredv1.UnstructuredList:
+			for _, item := range o.Items {
+				ret = append(ret, &item)
+			}
+		case *unstructuredv1.Unstructured:
+			ret = append(ret, o)
+		default:
+			panic("Unexpected unstructured object type")
+		}
+	}
+	return ret
+}