feat: add docs command

It opens the documentation you request in a browser.

aspect docs -> open docs.bazel.build
aspect docs query-how-to -> https://docs.bazel.build/versions/main/query-how-to.html
aspect docs rules_nodejs -> https://docs.aspect.dev/rules_nodejs
diff --git a/cmd/aspect/docs/BUILD.bazel b/cmd/aspect/docs/BUILD.bazel
new file mode 100644
index 0000000..4fb7e40
--- /dev/null
+++ b/cmd/aspect/docs/BUILD.bazel
@@ -0,0 +1,13 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+    name = "docs",
+    srcs = ["docs.go"],
+    importpath = "aspect.build/cli/cmd/aspect/docs",
+    visibility = ["//visibility:public"],
+    deps = [
+        "//pkg/aspect/docs",
+        "//pkg/ioutils",
+        "@com_github_spf13_cobra//:cobra",
+    ],
+)
diff --git a/cmd/aspect/docs/docs.go b/cmd/aspect/docs/docs.go
new file mode 100644
index 0000000..91612ca
--- /dev/null
+++ b/cmd/aspect/docs/docs.go
@@ -0,0 +1,33 @@
+/*
+Copyright © 2021 Aspect Build Systems
+
+Not licensed for re-use
+*/
+
+package docs
+
+import (
+	"github.com/spf13/cobra"
+
+	"aspect.build/cli/pkg/aspect/docs"
+	"aspect.build/cli/pkg/ioutils"
+)
+
+func NewDefaultDocsCmd() *cobra.Command {
+	return NewDocsCmd(ioutils.DefaultStreams)
+}
+
+func NewDocsCmd(streams ioutils.Streams) *cobra.Command {
+	v := docs.New(streams)
+
+	cmd := &cobra.Command{
+		Use:   "docs",
+		Short: "Open documentation in the browser",
+		Long: `Given a selected topic, open the relevant API docs in a browser window.
+		The mechanism of choosing the browser to open is documented at https://github.com/pkg/browser
+		By default, opens docs.bazel.build`,
+		RunE: v.Run,
+	}
+
+	return cmd
+}
diff --git a/cmd/aspect/root/BUILD.bazel b/cmd/aspect/root/BUILD.bazel
index 762e55d..683cf6f 100644
--- a/cmd/aspect/root/BUILD.bazel
+++ b/cmd/aspect/root/BUILD.bazel
@@ -6,6 +6,7 @@
     importpath = "aspect.build/cli/cmd/aspect/root",
     visibility = ["//visibility:public"],
     deps = [
+        "//cmd/aspect/docs",
         "//cmd/aspect/version",
         "//docs/help/topics",
         "//pkg/ioutils",
diff --git a/cmd/aspect/root/root.go b/cmd/aspect/root/root.go
index 1f90641..c621794 100644
--- a/cmd/aspect/root/root.go
+++ b/cmd/aspect/root/root.go
@@ -15,6 +15,7 @@
 	"github.com/spf13/cobra"
 	"github.com/spf13/viper"
 
+	"aspect.build/cli/cmd/aspect/docs"
 	"aspect.build/cli/cmd/aspect/version"
 	"aspect.build/cli/docs/help/topics"
 	"aspect.build/cli/pkg/ioutils"
@@ -64,6 +65,7 @@
 	// ### Child commands
 	// IMPORTANT: when adding a new command, also update the _DOCS list in /docs/BUILD.bazel
 	cmd.AddCommand(version.NewDefaultVersionCmd())
+	cmd.AddCommand(docs.NewDefaultDocsCmd())
 
 	// ### "Additional help topic commands" which are not runnable
 	// https://pkg.go.dev/github.com/spf13/cobra#Command.IsAdditionalHelpTopicCommand
diff --git a/docs/BUILD.bazel b/docs/BUILD.bazel
index 8454806..d4cbfd4 100644
--- a/docs/BUILD.bazel
+++ b/docs/BUILD.bazel
@@ -4,6 +4,7 @@
 # This list must be updated when we add a new command
 _DOCS = [
     "aspect.md",
+    "aspect_docs.md",
     "aspect_version.md",
 ]
 
diff --git a/docs/aspect.md b/docs/aspect.md
index 8043d67..c305917 100644
--- a/docs/aspect.md
+++ b/docs/aspect.md
@@ -16,6 +16,7 @@
 
 ### SEE ALSO
 
+* [aspect docs](aspect_docs.md)	 - Open documentation in the browser
 * [aspect version](aspect_version.md)	 - Print the version of aspect CLI as well as tools it invokes
 
 ###### Auto generated by spf13/cobra
diff --git a/docs/aspect_docs.md b/docs/aspect_docs.md
new file mode 100644
index 0000000..8533a3e
--- /dev/null
+++ b/docs/aspect_docs.md
@@ -0,0 +1,32 @@
+## aspect docs
+
+Open documentation in the browser
+
+### Synopsis
+
+Given a selected topic, open the relevant API docs in a browser window.
+		The mechanism of choosing the browser to open is documented at https://github.com/pkg/browser
+		By default, opens docs.bazel.build
+
+```
+aspect docs [flags]
+```
+
+### Options
+
+```
+  -h, --help   help for docs
+```
+
+### Options inherited from parent commands
+
+```
+      --config string   config file (default is $HOME/.aspect.yaml)
+      --interactive     Interactive mode (e.g. prompts for user input)
+```
+
+### SEE ALSO
+
+* [aspect](aspect.md)	 - Aspect.build bazel wrapper
+
+###### Auto generated by spf13/cobra
diff --git a/go.bzl b/go.bzl
index 7dcb515..728a58f 100644
--- a/go.bzl
+++ b/go.bzl
@@ -624,6 +624,13 @@
         version = "v1.9.2",
     )
     go_repository(
+        name = "com_github_pkg_browser",
+        importpath = "github.com/pkg/browser",
+        sum = "h1:TdFv+3Gr3GaghJ/o80aulO4ian7GHGWMdLBXoLZH1Is=",
+        version = "v0.0.0-20210904010418-6d279e18f982",
+    )
+
+    go_repository(
         name = "com_github_pkg_errors",
         importpath = "github.com/pkg/errors",
         sum = "h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=",
@@ -1010,8 +1017,8 @@
     go_repository(
         name = "org_golang_x_sys",
         importpath = "golang.org/x/sys",
-        sum = "h1:faDu4veV+8pcThn4fewv6TVlNCezafGoC1gM/mxQLbQ=",
-        version = "v0.0.0-20210611083646-a4fc73990273",
+        sum = "h1:X/2sJAybVknnUnV7AD2HdT6rm2p5BP6eH2j+igduWgk=",
+        version = "v0.0.0-20210616045830-e2b7044e8c71",
     )
     go_repository(
         name = "org_golang_x_term",
@@ -1033,10 +1040,10 @@
     )
     go_repository(
         name = "org_golang_x_tools",
+        build_directives = ["gazelle:exclude **/testdata/**/*"],
         importpath = "golang.org/x/tools",
         sum = "h1:4nW4NLDYnU28ojHaHO8OVxFHk/aQ33U01a9cjED+pzE=",
         version = "v0.0.0-20201224043029-2b0845dc783e",
-        build_directives = ["gazelle:exclude **/testdata/**/*"],
     )
     go_repository(
         name = "org_golang_x_xerrors",
diff --git a/go.mod b/go.mod
index b32cf0c..96ca1e4 100644
--- a/go.mod
+++ b/go.mod
@@ -4,6 +4,7 @@
 
 require (
 	github.com/bazelbuild/bazelisk v1.10.1
+	github.com/bazelbuild/rules_go v0.28.0
 	github.com/fatih/color v1.12.0
 	github.com/magiconair/properties v1.8.5 // indirect
 	github.com/mattn/go-isatty v0.0.13
@@ -11,11 +12,11 @@
 	github.com/mitchellh/mapstructure v1.4.1 // indirect
 	github.com/onsi/gomega v1.16.0
 	github.com/pelletier/go-toml v1.9.2 // indirect
+	github.com/pkg/browser v0.0.0-20210904010418-6d279e18f982
 	github.com/spf13/afero v1.6.0 // indirect
 	github.com/spf13/cast v1.3.1 // indirect
 	github.com/spf13/cobra v1.1.3
 	github.com/spf13/jwalterweatherman v1.1.0 // indirect
 	github.com/spf13/viper v1.7.1
-	golang.org/x/sys v0.0.0-20210611083646-a4fc73990273 // indirect
 	gopkg.in/ini.v1 v1.62.0 // indirect
 )
diff --git a/go.sum b/go.sum
index b962aee..4db7f4a 100644
--- a/go.sum
+++ b/go.sum
@@ -262,6 +262,8 @@
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 github.com/pelletier/go-toml v1.9.2 h1:7NiByeVF4jKSG1lDF3X8LTIkq2/bu+1uYbIm1eS5tzk=
 github.com/pelletier/go-toml v1.9.2/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
+github.com/pkg/browser v0.0.0-20210904010418-6d279e18f982 h1:TdFv+3Gr3GaghJ/o80aulO4ian7GHGWMdLBXoLZH1Is=
+github.com/pkg/browser v0.0.0-20210904010418-6d279e18f982/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -438,8 +440,8 @@
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210611083646-a4fc73990273 h1:faDu4veV+8pcThn4fewv6TVlNCezafGoC1gM/mxQLbQ=
-golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71 h1:X/2sJAybVknnUnV7AD2HdT6rm2p5BP6eH2j+igduWgk=
+golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
diff --git a/pkg/aspect/docs/BUILD.bazel b/pkg/aspect/docs/BUILD.bazel
new file mode 100644
index 0000000..61a5701
--- /dev/null
+++ b/pkg/aspect/docs/BUILD.bazel
@@ -0,0 +1,13 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+    name = "docs",
+    srcs = ["docs.go"],
+    importpath = "aspect.build/cli/pkg/aspect/docs",
+    visibility = ["//visibility:public"],
+    deps = [
+        "//pkg/ioutils",
+        "@com_github_pkg_browser//:browser",
+        "@com_github_spf13_cobra//:cobra",
+    ],
+)
diff --git a/pkg/aspect/docs/docs.go b/pkg/aspect/docs/docs.go
new file mode 100644
index 0000000..a35fec0
--- /dev/null
+++ b/pkg/aspect/docs/docs.go
@@ -0,0 +1,49 @@
+/*
+Copyright © 2021 Aspect Build Systems Inc
+
+Not licensed for re-use.
+*/
+
+package docs
+
+import (
+	"fmt"
+	"os"
+	"strings"
+
+	"aspect.build/cli/pkg/ioutils"
+	"github.com/pkg/browser"
+	"github.com/spf13/cobra"
+)
+
+type Docs struct {
+	ioutils.Streams
+}
+
+func New(streams ioutils.Streams) *Docs {
+	return &Docs{
+		Streams: streams,
+	}
+}
+
+func (v *Docs) Run(_ *cobra.Command, args []string) error {
+	// TODO: we should open the browser to the bazel version matching what is running
+	dest := "https://docs.bazel.build"
+
+	// Detect requests for docs on rules, which we host
+	if len(args) == 1 {
+		if strings.HasPrefix(args[0], "rules_") {
+			dest = fmt.Sprintf("https://docs.aspect.dev/%s", args[0])
+		} else {
+			dest = fmt.Sprintf("https://docs.bazel.build/versions/main/%s.html", args[0])
+		}
+	}
+	// TODO: a way to lookup whatever the user typed after "docs" using docs.aspect.dev search
+	// as far as I can tell, Algolia doesn't provide a way to render results on a dedicated search page
+	// so I can't find a way to hyperlink to a search result.
+	if err := browser.OpenURL(dest); err != nil {
+		fmt.Fprintf(os.Stderr, "Failed to open link in the browser: %v\n", err)
+	}
+
+	return nil
+}