diff --git a/.circleci/config.yml b/.circleci/config.yml
index 629b0e2473f2c25aa76e6da51de7e67ff17020ba..e062f42388526a2d0914409fe4ef9d98f5fb8153 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -37,8 +37,10 @@ jobs:
       - run: make test_integration_bosmarmot
       - store_artifacts:
           path: ./.gopath_bos/src/github.com/monax/bosmarmot/monax/tests/burrow.log
+          destination: burrow.log
       - store_artifacts:
           path: ./.gopath_bos/src/github.com/monax/bosmarmot/monax/tests/keys.log
+          destination: keys.log
 
   ensure_vendor:
     <<: *defaults
diff --git a/cmd/burrow/commands/configure.go b/cmd/burrow/commands/configure.go
index f1af9e0f878b70e6948a33b9a49c629b7aa08859..97c64432f120452f7db6e5c8004081e235687f7c 100644
--- a/cmd/burrow/commands/configure.go
+++ b/cmd/burrow/commands/configure.go
@@ -3,7 +3,6 @@ package commands
 import (
 	"fmt"
 	"io/ioutil"
-	"os"
 	"strings"
 
 	"github.com/hyperledger/burrow/config"
@@ -20,156 +19,158 @@ import (
 	"github.com/jawher/mow.cli"
 )
 
-func Configure(cmd *cli.Cmd) {
-	genesisSpecOpt := cmd.StringOpt("s genesis-spec", "",
-		"A GenesisSpec to use as a template for a GenesisDoc that will be created along with keys")
+func Configure(output Output) func(cmd *cli.Cmd) {
+	return func(cmd *cli.Cmd) {
+		genesisSpecOpt := cmd.StringOpt("s genesis-spec", "",
+			"A GenesisSpec to use as a template for a GenesisDoc that will be created along with keys")
 
-	jsonOutOpt := cmd.BoolOpt("j json", false, "Emit config in JSON rather than TOML "+
-		"suitable for further processing")
+		jsonOutOpt := cmd.BoolOpt("j json", false, "Emit config in JSON rather than TOML "+
+			"suitable for further processing")
 
-	keysUrlOpt := cmd.StringOpt("k keys-url", "", fmt.Sprintf("Provide keys URL, default: %s",
-		keys.DefaultKeysConfig().URL))
+		keysUrlOpt := cmd.StringOpt("k keys-url", "", fmt.Sprintf("Provide keys URL, default: %s",
+			keys.DefaultKeysConfig().URL))
 
-	configOpt := cmd.StringOpt("c base-config", "", "Use the a specified burrow config file as a base")
+		configOpt := cmd.StringOpt("c base-config", "", "Use the a specified burrow config file as a base")
 
-	genesisDocOpt := cmd.StringOpt("g genesis-doc", "", "GenesisDoc in JSON or TOML to embed in config")
+		genesisDocOpt := cmd.StringOpt("g genesis-doc", "", "GenesisDoc in JSON or TOML to embed in config")
 
-	generateKeysOpt := cmd.StringOpt("x generate-keys", "",
-		"File to output containing secret keys as JSON or according to a custom template (see --keys-template). "+
-			"Note that using this options means the keys will not be generated in the default keys instance")
+		generateKeysOpt := cmd.StringOpt("x generate-keys", "",
+			"File to output containing secret keys as JSON or according to a custom template (see --keys-template). "+
+				"Note that using this options means the keys will not be generated in the default keys instance")
 
-	keysTemplateOpt := cmd.StringOpt("z keys-template", deployment.DefaultDumpKeysFormat,
-		fmt.Sprintf("Go text/template template (left delim: %s right delim: %s) to generate secret keys "+
-			"file specified with --generate-keys.", deployment.LeftTemplateDelim, deployment.RightTemplateDelim))
+		keysTemplateOpt := cmd.StringOpt("z keys-template", deployment.DefaultDumpKeysFormat,
+			fmt.Sprintf("Go text/template template (left delim: %s right delim: %s) to generate secret keys "+
+				"file specified with --generate-keys.", deployment.LeftTemplateDelim, deployment.RightTemplateDelim))
 
-	separateGenesisDoc := cmd.StringOpt("w separate-genesis-doc", "", "Emit a separate genesis doc as JSON or TOML")
+		separateGenesisDoc := cmd.StringOpt("w separate-genesis-doc", "", "Emit a separate genesis doc as JSON or TOML")
 
-	loggingOpt := cmd.StringOpt("l logging", "",
-		"Comma separated list of logging instructions which form a 'program' which is a depth-first "+
-			"pre-order of instructions that will build the root logging sink. See 'burrow help' for more information.")
+		loggingOpt := cmd.StringOpt("l logging", "",
+			"Comma separated list of logging instructions which form a 'program' which is a depth-first "+
+				"pre-order of instructions that will build the root logging sink. See 'burrow help' for more information.")
 
-	describeLoggingOpt := cmd.BoolOpt("describe-logging", false,
-		"Print an exhaustive list of logging instructions available with the --logging option")
+		describeLoggingOpt := cmd.BoolOpt("describe-logging", false,
+			"Print an exhaustive list of logging instructions available with the --logging option")
 
-	debugOpt := cmd.BoolOpt("d debug", false, "Include maximal debug options in config "+
-		"including logging opcodes and dumping EVM tokens to disk these can be later pruned from the "+
-		"generated config.")
+		debugOpt := cmd.BoolOpt("d debug", false, "Include maximal debug options in config "+
+			"including logging opcodes and dumping EVM tokens to disk these can be later pruned from the "+
+			"generated config.")
 
-	chainNameOpt := cmd.StringOpt("n chain-name", "", "Default chain name")
+		chainNameOpt := cmd.StringOpt("n chain-name", "", "Default chain name")
 
-	cmd.Spec = "[--keys-url=<keys URL> | (--generate-keys=<secret keys files> [--keys-template=<text template for each key>])] " +
-		"[--genesis-spec=<GenesisSpec file> | --genesis-doc=<GenesisDoc file>] " +
-		"[--separate-genesis-doc=<genesis JSON file>] [--chain-name] [--json] " +
-		"[--logging=<logging program>] [--describe-logging] [--debug]"
+		cmd.Spec = "[--keys-url=<keys URL> | (--generate-keys=<secret keys files> [--keys-template=<text template for each key>])] " +
+			"[--genesis-spec=<GenesisSpec file> | --genesis-doc=<GenesisDoc file>] " +
+			"[--separate-genesis-doc=<genesis JSON file>] [--chain-name] [--json] " +
+			"[--logging=<logging program>] [--describe-logging] [--debug]"
 
-	cmd.Action = func() {
-		conf := config.DefaultBurrowConfig()
+		cmd.Action = func() {
+			conf := config.DefaultBurrowConfig()
 
-		if *configOpt != "" {
-			// If explicitly given a config file use it as a base:
-			err := source.FromFile(*configOpt, conf)
-			if err != nil {
-				fatalf("could not read base config file (as TOML): %v", err)
+			if *configOpt != "" {
+				// If explicitly given a config file use it as a base:
+				err := source.FromFile(*configOpt, conf)
+				if err != nil {
+					output.Fatalf("could not read base config file (as TOML): %v", err)
+				}
 			}
-		}
 
-		if *describeLoggingOpt {
-			fmt.Printf("Usage:\n  burrow configure -l INSTRUCTION[,...]\n\nBuilds a logging " +
-				"configuration by constructing a tree of logging sinks assembled from preset instructions " +
-				"that generate the tree while traversing it.\n\nLogging Instructions:\n")
-			for _, instruction := range presets.Instructons() {
-				fmt.Printf("  %-15s\t%s\n", instruction.Name(), instruction.Description())
+			if *describeLoggingOpt {
+				output.Logf("Usage:\n  burrow configure -l INSTRUCTION[,...]\n\nBuilds a logging " +
+					"configuration by constructing a tree of logging sinks assembled from preset instructions " +
+					"that generate the tree while traversing it.\n\nLogging Instructions:\n")
+				for _, instruction := range presets.Instructons() {
+					output.Logf("  %-15s\t%s\n", instruction.Name(), instruction.Description())
+				}
+				output.Logf("\nExample Usage:\n  burrow configure -l include-any,info,stderr\n")
+				return
 			}
-			fmt.Printf("\nExample Usage:\n  burrow configure -l include-any,info,stderr\n")
-			return
-		}
-
-		if *keysUrlOpt != "" {
-			conf.Keys.URL = *keysUrlOpt
-		}
 
-		// Genesis Spec
-		if *genesisSpecOpt != "" {
-			genesisSpec := new(spec.GenesisSpec)
-			err := source.FromFile(*genesisSpecOpt, genesisSpec)
-			if err != nil {
-				fatalf("Could not read GenesisSpec: %v", err)
+			if *keysUrlOpt != "" {
+				conf.Keys.URL = *keysUrlOpt
 			}
-			if *generateKeysOpt != "" {
-				keyClient := mock.NewKeyClient()
-				conf.GenesisDoc, err = genesisSpec.GenesisDoc(keyClient)
+
+			// Genesis Spec
+			if *genesisSpecOpt != "" {
+				genesisSpec := new(spec.GenesisSpec)
+				err := source.FromFile(*genesisSpecOpt, genesisSpec)
 				if err != nil {
-					fatalf("Could not generate GenesisDoc from GenesisSpec using MockKeyClient: %v", err)
+					output.Fatalf("Could not read GenesisSpec: %v", err)
+				}
+				if *generateKeysOpt != "" {
+					keyClient := mock.NewKeyClient()
+					conf.GenesisDoc, err = genesisSpec.GenesisDoc(keyClient)
+					if err != nil {
+						output.Fatalf("Could not generate GenesisDoc from GenesisSpec using MockKeyClient: %v", err)
+					}
+
+					pkg := deployment.Package{Keys: keyClient.Keys()}
+					secretKeysString, err := pkg.Dump(*keysTemplateOpt)
+					if err != nil {
+						output.Fatalf("Could not dump keys: %v", err)
+					}
+					err = ioutil.WriteFile(*generateKeysOpt, []byte(secretKeysString), 0700)
+					if err != nil {
+						output.Fatalf("Could not write secret keys: %v", err)
+					}
+				} else {
+					conf.GenesisDoc, err = genesisSpec.GenesisDoc(keys.NewKeyClient(conf.Keys.URL, logging.NewNoopLogger()))
 				}
-
-				pkg := deployment.Package{Keys: keyClient.Keys()}
-				secretKeysString, err := pkg.Dump(*keysTemplateOpt)
 				if err != nil {
-					fatalf("Could not dump keys: %v", err)
+					output.Fatalf("could not realise GenesisSpec: %v", err)
 				}
-				err = ioutil.WriteFile(*generateKeysOpt, []byte(secretKeysString), 0700)
+			} else if *genesisDocOpt != "" {
+				genesisDoc := new(genesis.GenesisDoc)
+				err := source.FromFile(*genesisSpecOpt, genesisDoc)
 				if err != nil {
-					fatalf("Could not write secret keys: %v", err)
+					output.Fatalf("could not read GenesisSpec: %v", err)
 				}
-			} else {
-				conf.GenesisDoc, err = genesisSpec.GenesisDoc(keys.NewKeyClient(conf.Keys.URL, logging.NewNoopLogger()))
-			}
-			if err != nil {
-				fatalf("could not realise GenesisSpec: %v", err)
+				conf.GenesisDoc = genesisDoc
 			}
-		} else if *genesisDocOpt != "" {
-			genesisDoc := new(genesis.GenesisDoc)
-			err := source.FromFile(*genesisSpecOpt, genesisDoc)
-			if err != nil {
-				fatalf("could not read GenesisSpec: %v", err)
-			}
-			conf.GenesisDoc = genesisDoc
-		}
 
-		// Logging
-		if *loggingOpt != "" {
-			ops := strings.Split(*loggingOpt, ",")
-			sinkConfig, err := presets.BuildSinkConfig(ops...)
-			if err != nil {
-				fatalf("could not build logging configuration: %v\n\nTo see possible logging "+
-					"instructions run:\n  burrow configure --describe-logging", err)
-			}
-			conf.Logging = &logging_config.LoggingConfig{
-				RootSink: sinkConfig,
+			// Logging
+			if *loggingOpt != "" {
+				ops := strings.Split(*loggingOpt, ",")
+				sinkConfig, err := presets.BuildSinkConfig(ops...)
+				if err != nil {
+					output.Fatalf("could not build logging configuration: %v\n\nTo see possible logging "+
+						"instructions run:\n  burrow configure --describe-logging", err)
+				}
+				conf.Logging = &logging_config.LoggingConfig{
+					RootSink: sinkConfig,
+				}
 			}
-		}
 
-		if *debugOpt {
-			conf.Execution = &execution.ExecutionConfig{
-				VMOptions: []execution.VMOption{execution.DumpTokens, execution.DebugOpcodes},
+			if *debugOpt {
+				conf.Execution = &execution.ExecutionConfig{
+					VMOptions: []execution.VMOption{execution.DumpTokens, execution.DebugOpcodes},
+				}
 			}
-		}
 
-		if *chainNameOpt != "" {
-			if conf.GenesisDoc == nil {
-				fatalf("Unable to set ChainName since no GenesisDoc/GenesisSpec provided.")
+			if *chainNameOpt != "" {
+				if conf.GenesisDoc == nil {
+					output.Fatalf("Unable to set ChainName since no GenesisDoc/GenesisSpec provided.")
+				}
+				conf.GenesisDoc.ChainName = *chainNameOpt
 			}
-			conf.GenesisDoc.ChainName = *chainNameOpt
-		}
 
-		if *separateGenesisDoc != "" {
-			if conf.GenesisDoc == nil {
-				fatalf("Cannot write separate genesis doc since no GenesisDoc/GenesisSpec provided.")
-			}
-			genesisDocJSON, err := conf.GenesisDoc.JSONBytes()
-			if err != nil {
-				fatalf("Could not form GenesisDoc JSON: %v", err)
+			if *separateGenesisDoc != "" {
+				if conf.GenesisDoc == nil {
+					output.Fatalf("Cannot write separate genesis doc since no GenesisDoc/GenesisSpec provided.")
+				}
+				genesisDocJSON, err := conf.GenesisDoc.JSONBytes()
+				if err != nil {
+					output.Fatalf("Could not form GenesisDoc JSON: %v", err)
+				}
+				err = ioutil.WriteFile(*separateGenesisDoc, genesisDocJSON, 0700)
+				if err != nil {
+					output.Fatalf("Could not write GenesisDoc JSON: %v", err)
+				}
+				conf.GenesisDoc = nil
 			}
-			err = ioutil.WriteFile(*separateGenesisDoc, genesisDocJSON, 0700)
-			if err != nil {
-				fatalf("Could not write GenesisDoc JSON: %v", err)
+			if *jsonOutOpt {
+				output.Printf(conf.JSONString())
+			} else {
+				output.Printf(conf.TOMLString())
 			}
-			conf.GenesisDoc = nil
-		}
-		if *jsonOutOpt {
-			os.Stdout.WriteString(conf.JSONString())
-		} else {
-			os.Stdout.WriteString(conf.TOMLString())
 		}
 	}
 }
diff --git a/cmd/burrow/commands/helpers.go b/cmd/burrow/commands/helpers.go
index a36ca827e80083c257a58f569c60f5f126cead58..6c2a1b211dc8b26a7d726342b9d213a74f02aa7f 100644
--- a/cmd/burrow/commands/helpers.go
+++ b/cmd/burrow/commands/helpers.go
@@ -2,21 +2,16 @@ package commands
 
 import (
 	"fmt"
-	"os"
 
 	"github.com/hyperledger/burrow/config"
 	"github.com/hyperledger/burrow/config/source"
 	"github.com/hyperledger/burrow/genesis"
 )
 
-// Print informational output to Stderr
-func printf(format string, args ...interface{}) {
-	fmt.Fprintf(os.Stderr, format+"\n", args...)
-}
-
-func fatalf(format string, args ...interface{}) {
-	fmt.Fprintf(os.Stderr, format+"\n", args...)
-	os.Exit(1)
+type Output interface {
+	Printf(format string, args ...interface{})
+	Logf(format string, args ...interface{})
+	Fatalf(format string, args ...interface{})
 }
 
 func burrowConfigProvider(configFile string) source.ConfigProvider {
diff --git a/cmd/burrow/commands/spec.go b/cmd/burrow/commands/spec.go
index 6a0d3334439947e279f94703d0035c2f79f46023..36fad65a7fcd53b66bd6385bc133f7b3e927db79 100644
--- a/cmd/burrow/commands/spec.go
+++ b/cmd/burrow/commands/spec.go
@@ -2,66 +2,66 @@ package commands
 
 import (
 	"fmt"
-	"os"
 
 	"github.com/hyperledger/burrow/config/source"
 	"github.com/hyperledger/burrow/genesis/spec"
 	"github.com/jawher/mow.cli"
 )
 
-func Spec(cmd *cli.Cmd) {
-	tomlOpt := cmd.BoolOpt("t toml", false, "Emit GenesisSpec as TOML rather than the "+
-		"default JSON")
+func Spec(output Output) func(cmd *cli.Cmd) {
+	return func(cmd *cli.Cmd) {
+		tomlOpt := cmd.BoolOpt("t toml", false, "Emit GenesisSpec as TOML rather than the "+
+			"default JSON")
 
-	baseSpecsArg := cmd.StringsArg("BASE", nil, "Provide a base GenesisSpecs on top of which any "+
-		"additional GenesisSpec presets specified by other flags will be merged. GenesisSpecs appearing "+
-		"later take precedent over those appearing early if multiple --base flags are provided")
+		baseSpecsArg := cmd.StringsArg("BASE", nil, "Provide a base GenesisSpecs on top of which any "+
+			"additional GenesisSpec presets specified by other flags will be merged. GenesisSpecs appearing "+
+			"later take precedent over those appearing early if multiple --base flags are provided")
 
-	accountNamePrefixOpt := cmd.StringOpt("x name-prefix", "", "Prefix added to the names of accounts in GenesisSpec")
-	fullOpt := cmd.IntOpt("f full-accounts", 0, "Number of preset Full type accounts")
-	validatorOpt := cmd.IntOpt("v validator-accounts", 0, "Number of preset Validator type accounts")
-	rootOpt := cmd.IntOpt("r root-accounts", 0, "Number of preset Root type accounts")
-	developerOpt := cmd.IntOpt("d developer-accounts", 0, "Number of preset Developer type accounts")
-	participantsOpt := cmd.IntOpt("p participant-accounts", 0, "Number of preset Participant type accounts")
-	chainNameOpt := cmd.StringOpt("n chain-name", "", "Default chain name")
+		accountNamePrefixOpt := cmd.StringOpt("x name-prefix", "", "Prefix added to the names of accounts in GenesisSpec")
+		fullOpt := cmd.IntOpt("f full-accounts", 0, "Number of preset Full type accounts")
+		validatorOpt := cmd.IntOpt("v validator-accounts", 0, "Number of preset Validator type accounts")
+		rootOpt := cmd.IntOpt("r root-accounts", 0, "Number of preset Root type accounts")
+		developerOpt := cmd.IntOpt("d developer-accounts", 0, "Number of preset Developer type accounts")
+		participantsOpt := cmd.IntOpt("p participant-accounts", 0, "Number of preset Participant type accounts")
+		chainNameOpt := cmd.StringOpt("n chain-name", "", "Default chain name")
 
-	cmd.Spec = "[--name-prexix=<prefix for account names>][--full-accounts] [--validator-accounts] [--root-accounts] " +
-		"[--developer-accounts] [--participant-accounts] [--chain-name] [--toml] [BASE...]"
+		cmd.Spec = "[--name-prefix=<prefix for account names>][--full-accounts] [--validator-accounts] [--root-accounts] " +
+			"[--developer-accounts] [--participant-accounts] [--chain-name] [--toml] [BASE...]"
 
-	cmd.Action = func() {
-		specs := make([]spec.GenesisSpec, 0, *participantsOpt+*fullOpt)
-		for _, baseSpec := range *baseSpecsArg {
-			genesisSpec := new(spec.GenesisSpec)
-			err := source.FromFile(baseSpec, genesisSpec)
-			if err != nil {
-				fatalf("could not read GenesisSpec: %v", err)
+		cmd.Action = func() {
+			specs := make([]spec.GenesisSpec, 0, *participantsOpt+*fullOpt)
+			for _, baseSpec := range *baseSpecsArg {
+				genesisSpec := new(spec.GenesisSpec)
+				err := source.FromFile(baseSpec, genesisSpec)
+				if err != nil {
+					output.Fatalf("could not read GenesisSpec: %v", err)
+				}
+				specs = append(specs, *genesisSpec)
+			}
+			for i := 0; i < *fullOpt; i++ {
+				specs = append(specs, spec.FullAccount(fmt.Sprintf("%sFull_%v", *accountNamePrefixOpt, i)))
+			}
+			for i := 0; i < *validatorOpt; i++ {
+				specs = append(specs, spec.ValidatorAccount(fmt.Sprintf("%sValidator_%v", *accountNamePrefixOpt, i)))
+			}
+			for i := 0; i < *rootOpt; i++ {
+				specs = append(specs, spec.RootAccount(fmt.Sprintf("%sRoot_%v", *accountNamePrefixOpt, i)))
+			}
+			for i := 0; i < *developerOpt; i++ {
+				specs = append(specs, spec.DeveloperAccount(fmt.Sprintf("%sDeveloper_%v", *accountNamePrefixOpt, i)))
+			}
+			for i := 0; i < *participantsOpt; i++ {
+				specs = append(specs, spec.ParticipantAccount(fmt.Sprintf("%sParticipant_%v", *accountNamePrefixOpt, i)))
+			}
+			genesisSpec := spec.MergeGenesisSpecs(specs...)
+			if *chainNameOpt != "" {
+				genesisSpec.ChainName = *chainNameOpt
+			}
+			if *tomlOpt {
+				output.Printf(source.TOMLString(genesisSpec))
+			} else {
+				output.Printf(source.JSONString(genesisSpec))
 			}
-			specs = append(specs, *genesisSpec)
-		}
-		for i := 0; i < *fullOpt; i++ {
-			specs = append(specs, spec.FullAccount(fmt.Sprintf("%sFull_%v", *accountNamePrefixOpt, i)))
-		}
-		for i := 0; i < *validatorOpt; i++ {
-			specs = append(specs, spec.ValidatorAccount(fmt.Sprintf("%sValidator_%v", *accountNamePrefixOpt, i)))
-		}
-		for i := 0; i < *rootOpt; i++ {
-			specs = append(specs, spec.RootAccount(fmt.Sprintf("%sRoot_%v", *accountNamePrefixOpt, i)))
-		}
-		for i := 0; i < *developerOpt; i++ {
-			specs = append(specs, spec.DeveloperAccount(fmt.Sprintf("%sDeveloper_%v", *accountNamePrefixOpt, i)))
-		}
-		for i := 0; i < *participantsOpt; i++ {
-			specs = append(specs, spec.ParticipantAccount(fmt.Sprintf("%sParticipant_%v", *accountNamePrefixOpt, i)))
-		}
-		genesisSpec := spec.MergeGenesisSpecs(specs...)
-		if *chainNameOpt != "" {
-			genesisSpec.ChainName = *chainNameOpt
-		}
-		if *tomlOpt {
-			os.Stdout.WriteString(source.TOMLString(genesisSpec))
-		} else {
-			os.Stdout.WriteString(source.JSONString(genesisSpec))
 		}
-		os.Stdout.WriteString("\n")
 	}
 }
diff --git a/cmd/burrow/commands/start.go b/cmd/burrow/commands/start.go
index 5efb282a6b8e8eed18b0bbe985df051fa3ecacd5..7d112ffb2f27e790826ae0ce0309a7166bb06116 100644
--- a/cmd/burrow/commands/start.go
+++ b/cmd/burrow/commands/start.go
@@ -10,104 +10,106 @@ import (
 	"github.com/jawher/mow.cli"
 )
 
-func Start(cmd *cli.Cmd) {
-	genesisOpt := cmd.StringOpt("g genesis", "",
-		"Use the specified genesis JSON file rather than a key in the main config, use - to read from STDIN")
-
-	configOpt := cmd.StringOpt("c config", "", "Use the a specified burrow config file")
-
-	validatorIndexOpt := cmd.Int(cli.IntOpt{
-		Name:   "v validator-index",
-		Desc:   "Validator index (in validators list - GenesisSpec or GenesisDoc) from which to set ValidatorAddress",
-		Value:  -1,
-		EnvVar: "BURROW_VALIDATOR_INDEX",
-	})
-
-	validatorAddressOpt := cmd.String(cli.StringOpt{
-		Name:   "a validator-address",
-		Desc:   "The address of the the signing key of this validator",
-		EnvVar: "BURROW_VALIDATOR_ADDRESS",
-	})
-
-	validatorPassphraseOpt := cmd.String(cli.StringOpt{
-		Name:   "p validator-passphrase",
-		Desc:   "The passphrase of the signing key of this validator (currently unimplemented but planned for future version of our KeyClient interface)",
-		EnvVar: "BURROW_VALIDATOR_PASSPHRASE",
-	})
-
-	validatorMonikerOpt := cmd.String(cli.StringOpt{
-		Name:   "m validator-moniker",
-		Desc:   "An optional human-readable moniker to identify this validator amongst Tendermint peers in logs and status queries",
-		EnvVar: "BURROW_VALIDATOR_MONIKER",
-	})
-
-	cmd.Spec = "[--config=<config file>] [--validator-moniker=<human readable moniker>] " +
-		"[--validator-index=<index of validator in GenesisDoc> | --validator-address=<address of validator signing key>] " +
-		"[--genesis=<genesis json file>]"
-
-	cmd.Action = func() {
-
-		// We need to reflect on whether this obscures where values are coming from
-		conf := config.DefaultBurrowConfig()
-		// We treat logging a little differently in that if anything is set for logging we will not
-		// set default outputs
-		conf.Logging = nil
-		err := source.EachOf(
-			burrowConfigProvider(*configOpt),
-			source.FirstOf(
-				genesisDocProvider(*genesisOpt, false),
-				// Try working directory
-				genesisDocProvider(config.DefaultGenesisDocJSONFileName, true)),
-		).Apply(conf)
-
-		// If no logging config was provided use the default
-		if conf.Logging == nil {
-			conf.Logging = logging_config.DefaultNodeLoggingConfig()
-		}
-		if err != nil {
-			fatalf("could not obtain config: %v", err)
-		}
-
-		// Which validator am I?
-		if *validatorAddressOpt != "" {
-			address, err := acm.AddressFromHexString(*validatorAddressOpt)
-			if err != nil {
-				fatalf("could not read address for validator in '%s'", *validatorAddressOpt)
+func Start(output Output) func(cmd *cli.Cmd) {
+	return func(cmd *cli.Cmd) {
+		genesisOpt := cmd.StringOpt("g genesis", "",
+			"Use the specified genesis JSON file rather than a key in the main config, use - to read from STDIN")
+
+		configOpt := cmd.StringOpt("c config", "", "Use the a specified burrow config file")
+
+		validatorIndexOpt := cmd.Int(cli.IntOpt{
+			Name:   "v validator-index",
+			Desc:   "Validator index (in validators list - GenesisSpec or GenesisDoc) from which to set ValidatorAddress",
+			Value:  -1,
+			EnvVar: "BURROW_VALIDATOR_INDEX",
+		})
+
+		validatorAddressOpt := cmd.String(cli.StringOpt{
+			Name:   "a validator-address",
+			Desc:   "The address of the the signing key of this validator",
+			EnvVar: "BURROW_VALIDATOR_ADDRESS",
+		})
+
+		validatorPassphraseOpt := cmd.String(cli.StringOpt{
+			Name:   "p validator-passphrase",
+			Desc:   "The passphrase of the signing key of this validator (currently unimplemented but planned for future version of our KeyClient interface)",
+			EnvVar: "BURROW_VALIDATOR_PASSPHRASE",
+		})
+
+		validatorMonikerOpt := cmd.String(cli.StringOpt{
+			Name:   "m validator-moniker",
+			Desc:   "An optional human-readable moniker to identify this validator amongst Tendermint peers in logs and status queries",
+			EnvVar: "BURROW_VALIDATOR_MONIKER",
+		})
+
+		cmd.Spec = "[--config=<config file>] [--validator-moniker=<human readable moniker>] " +
+			"[--validator-index=<index of validator in GenesisDoc> | --validator-address=<address of validator signing key>] " +
+			"[--genesis=<genesis json file>]"
+
+		cmd.Action = func() {
+
+			// We need to reflect on whether this obscures where values are coming from
+			conf := config.DefaultBurrowConfig()
+			// We treat logging a little differently in that if anything is set for logging we will not
+			// set default outputs
+			conf.Logging = nil
+			err := source.EachOf(
+				burrowConfigProvider(*configOpt),
+				source.FirstOf(
+					genesisDocProvider(*genesisOpt, false),
+					// Try working directory
+					genesisDocProvider(config.DefaultGenesisDocJSONFileName, true)),
+			).Apply(conf)
+
+			// If no logging config was provided use the default
+			if conf.Logging == nil {
+				conf.Logging = logging_config.DefaultNodeLoggingConfig()
 			}
-			conf.ValidatorAddress = &address
-		} else if *validatorIndexOpt > -1 {
-			if conf.GenesisDoc == nil {
-				fatalf("Unable to set ValidatorAddress from provided validator-index since no " +
-					"GenesisDoc/GenesisSpec provided.")
+			if err != nil {
+				output.Fatalf("could not obtain config: %v", err)
 			}
-			if *validatorIndexOpt >= len(conf.GenesisDoc.Validators) {
-				fatalf("validator-index of %v given but only %v validators specified in GenesisDoc",
-					*validatorIndexOpt, len(conf.GenesisDoc.Validators))
+
+			// Which validator am I?
+			if *validatorAddressOpt != "" {
+				address, err := acm.AddressFromHexString(*validatorAddressOpt)
+				if err != nil {
+					output.Fatalf("could not read address for validator in '%s'", *validatorAddressOpt)
+				}
+				conf.ValidatorAddress = &address
+			} else if *validatorIndexOpt > -1 {
+				if conf.GenesisDoc == nil {
+					output.Fatalf("Unable to set ValidatorAddress from provided validator-index since no " +
+						"GenesisDoc/GenesisSpec provided.")
+				}
+				if *validatorIndexOpt >= len(conf.GenesisDoc.Validators) {
+					output.Fatalf("validator-index of %v given but only %v validators specified in GenesisDoc",
+						*validatorIndexOpt, len(conf.GenesisDoc.Validators))
+				}
+				conf.ValidatorAddress = &conf.GenesisDoc.Validators[*validatorIndexOpt].Address
+				output.Logf("Using validator index %v (address: %s)", *validatorIndexOpt, *conf.ValidatorAddress)
 			}
-			conf.ValidatorAddress = &conf.GenesisDoc.Validators[*validatorIndexOpt].Address
-			printf("Using validator index %v (address: %s)", *validatorIndexOpt, *conf.ValidatorAddress)
-		}
 
-		if *validatorPassphraseOpt != "" {
-			conf.ValidatorPassphrase = validatorPassphraseOpt
-		}
+			if *validatorPassphraseOpt != "" {
+				conf.ValidatorPassphrase = validatorPassphraseOpt
+			}
 
-		if *validatorMonikerOpt != "" {
-			conf.Tendermint.Moniker = *validatorMonikerOpt
-		}
+			if *validatorMonikerOpt != "" {
+				conf.Tendermint.Moniker = *validatorMonikerOpt
+			}
 
-		ctx, cancel := context.WithCancel(context.Background())
-		defer cancel()
+			ctx, cancel := context.WithCancel(context.Background())
+			defer cancel()
 
-		kern, err := conf.Kernel(ctx)
-		if err != nil {
-			fatalf("could not create Burrow kernel: %v", err)
-		}
+			kern, err := conf.Kernel(ctx)
+			if err != nil {
+				output.Fatalf("could not create Burrow kernel: %v", err)
+			}
 
-		err = kern.Boot()
-		if err != nil {
-			fatalf("could not boot Burrow kernel: %v", err)
+			err = kern.Boot()
+			if err != nil {
+				output.Fatalf("could not boot Burrow kernel: %v", err)
+			}
+			kern.WaitForShutdown()
 		}
-		kern.WaitForShutdown()
 	}
 }
diff --git a/cmd/burrow/main.go b/cmd/burrow/main.go
index 6c57758674250090e19c3d0f386248942bf10cb4..cddf19edc8d799e63f726b197ee34357adb0a7df 100644
--- a/cmd/burrow/main.go
+++ b/cmd/burrow/main.go
@@ -10,10 +10,11 @@ import (
 )
 
 func main() {
-	burrow().Run(os.Args)
+	// Print informational output to Stderr
+	burrow(stdOutput()).Run(os.Args)
 }
 
-func burrow() *cli.Cli {
+func burrow(output commands.Output) *cli.Cli {
 	app := cli.App("burrow", "The EVM smart contract machine with Tendermint consensus")
 
 	versionOpt := app.BoolOpt("v version", false, "Print the Burrow version")
@@ -22,19 +23,51 @@ func burrow() *cli.Cli {
 	app.Action = func() {
 		if *versionOpt {
 			fmt.Println(project.FullVersion())
-			os.Exit(0)
 		}
 	}
 
 	app.Command("start", "Start a Burrow node",
-		commands.Start)
+		commands.Start(output))
 
 	app.Command("spec", "Build a GenesisSpec that acts as a template for a GenesisDoc and the configure command",
-		commands.Spec)
+		commands.Spec(output))
 
 	app.Command("configure",
 		"Create Burrow configuration by consuming a GenesisDoc or GenesisSpec, creating keys, and emitting the config",
-		commands.Configure)
+		commands.Configure(output))
 
 	return app
 }
+
+func stdOutput() *output {
+	return &output{
+		PrintfFunc: func(format string, args ...interface{}) {
+			fmt.Fprintf(os.Stdout, format+"\n", args...)
+		},
+		LogfFunc: func(format string, args ...interface{}) {
+			fmt.Fprintf(os.Stderr, format+"\n", args...)
+		},
+		FatalfFunc: func(format string, args ...interface{}) {
+			fmt.Fprintf(os.Stderr, format+"\n", args...)
+			os.Exit(1)
+		},
+	}
+}
+
+type output struct {
+	PrintfFunc func(format string, args ...interface{})
+	LogfFunc   func(format string, args ...interface{})
+	FatalfFunc func(format string, args ...interface{})
+}
+
+func (out *output) Printf(format string, args ...interface{}) {
+	out.PrintfFunc(format, args...)
+}
+
+func (out *output) Logf(format string, args ...interface{}) {
+	out.LogfFunc(format, args...)
+}
+
+func (out *output) Fatalf(format string, args ...interface{}) {
+	out.FatalfFunc(format, args...)
+}
diff --git a/cmd/burrow/main_test.go b/cmd/burrow/main_test.go
index c2690fd223643ab69953e63311694b2b99764e67..7a9b5c13e18ec2531d29f99ce4606498d091d3c3 100644
--- a/cmd/burrow/main_test.go
+++ b/cmd/burrow/main_test.go
@@ -1,12 +1,30 @@
 package main
 
-import "testing"
+import (
+	"fmt"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
 
 func TestBurrow(t *testing.T) {
-	app := burrow()
+	var outputCount int
+	out := &output{
+		PrintfFunc: func(format string, args ...interface{}) {
+			outputCount++
+		},
+		LogfFunc: func(format string, args ...interface{}) {
+			outputCount++
+		},
+		FatalfFunc: func(format string, args ...interface{}) {
+			t.Fatalf("fatalf called by burrow cmd: %s", fmt.Sprintf(format, args...))
+		},
+	}
+	app := burrow(out)
 	// Basic smoke test for cli config
-	app.Run([]string{"--version"})
-	app.Run([]string{"spec"})
-	app.Run([]string{"configure"})
-	app.Run([]string{"serve"})
+	assert.NoError(t, app.Run([]string{"burrow", "--version"}))
+	assert.NoError(t, app.Run([]string{"burrow", "spec", "--name-prefix", "foo", "-f1"}))
+	assert.NoError(t, app.Run([]string{"burrow", "configure"}))
+	assert.NoError(t, app.Run([]string{"burrow", "start", "-h"}))
+	assert.True(t, outputCount > 0)
 }