From ac701b262cbc7cb0070174869d42eab559cef29d Mon Sep 17 00:00:00 2001 From: simonfaltum Date: Mon, 8 Jun 2026 12:48:59 +0200 Subject: [PATCH 1/3] Add `databricks quickstart` command Introduce a top-level `databricks quickstart` command that prints a short introduction to the CLI: authentication, profile selection, building with Databricks Asset Bundles, and where to go next. It prints a human-friendly guide by default and a denser, agent-oriented version when run in a non-interactive terminal (for example, when invoked by a coding agent). The detection uses cmdio.IsPromptSupported and is intentionally simple for now, leaving room for smarter agent detection later. Co-authored-by: Isaac --- NEXT_CHANGELOG.md | 1 + acceptance/help/output.txt | 1 + acceptance/quickstart/out.test.toml | 3 + acceptance/quickstart/output.txt | 88 +++++++++++++++++++++++++++ acceptance/quickstart/script | 1 + cmd/cmd.go | 2 + cmd/quickstart/quickstart-agent.md | 93 +++++++++++++++++++++++++++++ cmd/quickstart/quickstart-human.md | 67 +++++++++++++++++++++ cmd/quickstart/quickstart.go | 74 +++++++++++++++++++++++ cmd/quickstart/quickstart_test.go | 58 ++++++++++++++++++ 10 files changed, 388 insertions(+) create mode 100644 acceptance/quickstart/out.test.toml create mode 100644 acceptance/quickstart/output.txt create mode 100644 acceptance/quickstart/script create mode 100644 cmd/quickstart/quickstart-agent.md create mode 100644 cmd/quickstart/quickstart-human.md create mode 100644 cmd/quickstart/quickstart.go create mode 100644 cmd/quickstart/quickstart_test.go diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index 90b65ec3e86..07b8a0c4981 100644 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -5,6 +5,7 @@ ### Notable Changes ### CLI +* Added the `databricks quickstart` command, a short introduction to the CLI that prints a human-friendly guide interactively and an agent-oriented version when run non-interactively. ### Bundles * Set the default `data_security_mode` to `DATA_SECURITY_MODE_AUTO` in bundle templates ([#5452](https://github.com/databricks/cli/pull/5452)). diff --git a/acceptance/help/output.txt b/acceptance/help/output.txt index b847152cc87..dd1063bc392 100644 --- a/acceptance/help/output.txt +++ b/acceptance/help/output.txt @@ -177,6 +177,7 @@ Additional Commands: configure Configure authentication help Help about any command labs Manage Databricks Labs installations + quickstart Print an introduction to the Databricks CLI version Retrieve information about the current version of this CLI Flags: diff --git a/acceptance/quickstart/out.test.toml b/acceptance/quickstart/out.test.toml new file mode 100644 index 00000000000..f784a183258 --- /dev/null +++ b/acceptance/quickstart/out.test.toml @@ -0,0 +1,3 @@ +Local = true +Cloud = false +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["terraform", "direct"] diff --git a/acceptance/quickstart/output.txt b/acceptance/quickstart/output.txt new file mode 100644 index 00000000000..8d9dd3ab43b --- /dev/null +++ b/acceptance/quickstart/output.txt @@ -0,0 +1,88 @@ +# Databricks Quickstart + +The `databricks` CLI wraps the public Databricks REST API — there's a command for essentially every API endpoint, so almost any Databricks task can be driven from here. If something looks unsupported, it's almost always a command you haven't found yet, not a real gap. The headline workflow: build durable resources as code with **Databricks Asset Bundles (DABs)** and ship them with `databricks bundle deploy` (see Build and deploy below). + +## Golden rules + +- **Reason, don't refuse.** Before telling the user something can't be done, run `databricks --help` and install the matching skill (below). Almost everything is reachable through the CLI. +- **Build with bundles.** For anything durable — jobs, pipelines, dashboards, apps — define it as code in a Databricks Asset Bundle (DABs) and ship with `databricks bundle deploy`, not one-off API calls. +- **Pick the profile deliberately.** Run `databricks auth profiles`. If only one profile exists, use it. If one is already set as the default (via `databricks auth switch`), assume that one — you can confirm if unsure. Otherwise, show the user the profiles with their workspace URLs and let them choose. Don't invent profile names. +- **Always pass `--profile `.** Each Bash command runs in its own shell, so a separate `export DATABRICKS_CONFIG_PROFILE=...` line does NOT persist. Use the flag, or chain with `&&`. +- **OAuth, never PAT.** Authenticate with `databricks auth login`, not personal access tokens. + +## Step 1 — Authenticate + +```bash +databricks auth profiles # already set up? lists profiles + validity +databricks auth login --profile # if not — opens login.databricks.com to pick a workspace +``` + +No host needed: without `--host`, login opens login.databricks.com and the user picks a workspace in the browser. Only pass `--host ` if the user already gave you a specific workspace URL. Always pass a descriptive `--profile ` (e.g. `dev-aws`, `prod-azure`) so you can target it reliably afterward — ask the user for the name rather than inventing one. + +## Step 2 — Verify + +```bash +databricks current-user me --profile +``` + +## Build and deploy with Asset Bundles (DABs) + +**DABs are the standard, recommended way to build on Databricks.** A bundle is a project with a `databricks.yml` that declares your resources (jobs, pipelines, dashboards, apps) and its targets (e.g. dev, prod) — one project, one deploy, every resource type: + +```bash +databricks bundle init # scaffold a project from a template +databricks bundle validate # check the config +databricks bundle deploy -t dev # deploy everything to a target (dev, prod, ...) +databricks bundle run -t dev # run a job or pipeline +``` + +Read the `databricks-dabs` skill for bundle structure, resource schemas, and multi-target setup. + +**Databricks Apps** (full-stack TypeScript + React via AppKit) build on bundles too, with a dedicated scaffolder — see `databricks-apps`: + +```bash +databricks apps init # scaffold an AppKit app (generates the bundle for you) +databricks apps deploy # deploy it to the workspace +databricks apps run-local # develop locally (or `dev-remote` against the workspace) +``` + +## Common commands + +```bash +databricks jobs list --profile +databricks pipelines list --profile +databricks apps list --profile +databricks warehouses list --profile + +# Unity Catalog data uses POSITIONAL args, NOT flags: +databricks catalogs list --profile +databricks schemas list --profile +databricks tables list --profile +``` + +Unsure of a command's shape? Run `databricks --help`. + +## Install skills for the task + +Skills give you Databricks-specific patterns so you build resources correctly instead of guessing. They install into your coding agent (auto-detected): + +```bash +databricks aitools install # stable skills +databricks aitools install --experimental # broader coverage: more areas, lower quality bar +databricks aitools list # available + installed skills — check this for the latest +``` + +The set evolves, so run `databricks aitools list` rather than relying on a fixed list. Common ones: `databricks-core` (CLI/auth), `databricks-jobs`, `databricks-pipelines`, `databricks-dabs` (deploy as code), `databricks-apps`. Experimental skills reach further (Unity Catalog, vector search, dashboards, AI functions, and more) — worth a look depending on the prompt. + +## Explore data + +Use the built-in tools instead of guessing SQL or navigating by hand: + +```bash +databricks experimental aitools tools discover-schema .. --profile +databricks experimental aitools tools query "SELECT * FROM
LIMIT 10" --profile +``` + +## When you get stuck + +Re-read `databricks --help`, install the matching skill, and check https://docs.databricks.com. If you truly can't do something yourself, tell the user how they can — don't tell them Databricks can't. diff --git a/acceptance/quickstart/script b/acceptance/quickstart/script new file mode 100644 index 00000000000..ffe8b163648 --- /dev/null +++ b/acceptance/quickstart/script @@ -0,0 +1 @@ +$CLI quickstart diff --git a/cmd/cmd.go b/cmd/cmd.go index 2c1a32caa50..6f2848e8712 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -19,6 +19,7 @@ import ( "github.com/databricks/cli/cmd/fs" "github.com/databricks/cli/cmd/labs" "github.com/databricks/cli/cmd/pipelines" + "github.com/databricks/cli/cmd/quickstart" "github.com/databricks/cli/cmd/root" "github.com/databricks/cli/cmd/selftest" "github.com/databricks/cli/cmd/sync" @@ -123,6 +124,7 @@ func New(ctx context.Context) *cobra.Command { cli.AddCommand(labs.New(ctx)) cli.AddCommand(sync.New()) cli.AddCommand(version.New()) + cli.AddCommand(quickstart.New()) cli.AddCommand(selftest.New()) cli.AddCommand(ssh.New()) diff --git a/cmd/quickstart/quickstart-agent.md b/cmd/quickstart/quickstart-agent.md new file mode 100644 index 00000000000..04a8d187e04 --- /dev/null +++ b/cmd/quickstart/quickstart-agent.md @@ -0,0 +1,93 @@ +--- +name: databricks-quickstart +description: First-contact orientation for the Databricks CLI when no Databricks skill is loaded. Covers OAuth auth, profile selection, command discovery, and installing the right skill for the task. Read this before attempting any Databricks work. +--- + +# Databricks Quickstart + +The `databricks` CLI wraps the public Databricks REST API — there's a command for essentially every API endpoint, so almost any Databricks task can be driven from here. If something looks unsupported, it's almost always a command you haven't found yet, not a real gap. The headline workflow: build durable resources as code with **Databricks Asset Bundles (DABs)** and ship them with `databricks bundle deploy` (see Build and deploy below). + +## Golden rules + +- **Reason, don't refuse.** Before telling the user something can't be done, run `databricks --help` and install the matching skill (below). Almost everything is reachable through the CLI. +- **Build with bundles.** For anything durable — jobs, pipelines, dashboards, apps — define it as code in a Databricks Asset Bundle (DABs) and ship with `databricks bundle deploy`, not one-off API calls. +- **Pick the profile deliberately.** Run `databricks auth profiles`. If only one profile exists, use it. If one is already set as the default (via `databricks auth switch`), assume that one — you can confirm if unsure. Otherwise, show the user the profiles with their workspace URLs and let them choose. Don't invent profile names. +- **Always pass `--profile `.** Each Bash command runs in its own shell, so a separate `export DATABRICKS_CONFIG_PROFILE=...` line does NOT persist. Use the flag, or chain with `&&`. +- **OAuth, never PAT.** Authenticate with `databricks auth login`, not personal access tokens. + +## Step 1 — Authenticate + +```bash +databricks auth profiles # already set up? lists profiles + validity +databricks auth login --profile # if not — opens login.databricks.com to pick a workspace +``` + +No host needed: without `--host`, login opens login.databricks.com and the user picks a workspace in the browser. Only pass `--host ` if the user already gave you a specific workspace URL. Always pass a descriptive `--profile ` (e.g. `dev-aws`, `prod-azure`) so you can target it reliably afterward — ask the user for the name rather than inventing one. + +## Step 2 — Verify + +```bash +databricks current-user me --profile +``` + +## Build and deploy with Asset Bundles (DABs) + +**DABs are the standard, recommended way to build on Databricks.** A bundle is a project with a `databricks.yml` that declares your resources (jobs, pipelines, dashboards, apps) and its targets (e.g. dev, prod) — one project, one deploy, every resource type: + +```bash +databricks bundle init # scaffold a project from a template +databricks bundle validate # check the config +databricks bundle deploy -t dev # deploy everything to a target (dev, prod, ...) +databricks bundle run -t dev # run a job or pipeline +``` + +Read the `databricks-dabs` skill for bundle structure, resource schemas, and multi-target setup. + +**Databricks Apps** (full-stack TypeScript + React via AppKit) build on bundles too, with a dedicated scaffolder — see `databricks-apps`: + +```bash +databricks apps init # scaffold an AppKit app (generates the bundle for you) +databricks apps deploy # deploy it to the workspace +databricks apps run-local # develop locally (or `dev-remote` against the workspace) +``` + +## Common commands + +```bash +databricks jobs list --profile +databricks pipelines list --profile +databricks apps list --profile +databricks warehouses list --profile + +# Unity Catalog data uses POSITIONAL args, NOT flags: +databricks catalogs list --profile +databricks schemas list --profile +databricks tables list --profile +``` + +Unsure of a command's shape? Run `databricks --help`. + +## Install skills for the task + +Skills give you Databricks-specific patterns so you build resources correctly instead of guessing. They install into your coding agent (auto-detected): + +```bash +databricks aitools install # stable skills +databricks aitools install --experimental # broader coverage: more areas, lower quality bar +databricks aitools list # available + installed skills — check this for the latest +``` + +The set evolves, so run `databricks aitools list` rather than relying on a fixed list. Common ones: `databricks-core` (CLI/auth), `databricks-jobs`, `databricks-pipelines`, `databricks-dabs` (deploy as code), `databricks-apps`. Experimental skills reach further (Unity Catalog, vector search, dashboards, AI functions, and more) — worth a look depending on the prompt. + +## Explore data + +Use the built-in tools instead of guessing SQL or navigating by hand: + +```bash +databricks experimental aitools tools discover-schema ..
--profile +databricks experimental aitools tools query "SELECT * FROM
LIMIT 10" --profile +``` + +## When you get stuck + +Re-read `databricks --help`, install the matching skill, and check https://docs.databricks.com. If you truly can't do something yourself, tell the user how they can — don't tell them Databricks can't. diff --git a/cmd/quickstart/quickstart-human.md b/cmd/quickstart/quickstart-human.md new file mode 100644 index 00000000000..bdd84819389 --- /dev/null +++ b/cmd/quickstart/quickstart-human.md @@ -0,0 +1,67 @@ +# Welcome to Databricks + +Databricks is one place for all your data and AI work: store and govern data, run SQL and notebooks, build pipelines and dashboards, train and serve models, and ship apps. No stitching together separate tools. + +This guide takes you from zero to your first command. + +## What you need + +A **workspace** — your Databricks home, at a URL like `https://your-company.cloud.databricks.com`. No access yet? Sign up for a free trial at https://www.databricks.com (Databricks Free Edition is great for learning). You've already got the CLI — it's how you're reading this. + +## A few concepts (the 30-second version) + +- **Workspace** — the environment you log into. Notebooks, jobs, dashboards, and data all live here. +- **Unity Catalog** — how Databricks governs your data. Tables are named in three parts: `catalog.schema.table` (think folder → subfolder → table). +- **Compute** — where your code runs. *SQL warehouses* run SQL; *clusters* and *serverless* run notebooks and jobs. +- **Profile** — a saved connection to a workspace on your machine, so you don't re-enter credentials each time. + +## Step 1 — Connect to your workspace + +```bash +databricks auth login +``` +This opens **login.databricks.com** in your browser. Sign in, pick the workspace you want, and you're connected — no URL to look up. The CLI saves the connection as a *profile*; if it's your only workspace, press Enter to accept the suggested name and every command will use it automatically. Run `databricks auth login` again any time to add another workspace. + +Already know your workspace URL? Go straight to it: `databricks auth login --host https://your-company.cloud.databricks.com --profile my-workspace`. + +## Step 2 — Try it out + +```bash +databricks current-user me # who am I? +databricks catalogs list # what data can I see? +databricks jobs list # my jobs +``` +To see everything a command can do, add `--help` — for example, `databricks jobs --help`. + +Got more than one workspace? Name each at login (`databricks auth login --profile prod`), then target it with `--profile`, e.g. `databricks jobs list --profile prod`. + +💡 **Tip:** turn on tab-completion so you can `Tab` through commands and flags: `databricks completion install`. + +## Step 3 — Build something + +The standard way to build on Databricks is **Databricks Asset Bundles (DABs)** — your jobs, pipelines, dashboards, and apps defined as code in one project, shipped with one command: + +```bash +databricks bundle init # start from a template +databricks bundle validate # check it +databricks bundle deploy -t dev # ship it to your workspace +databricks bundle run -t dev # run a job or pipeline +``` + +Want a **full-stack app**? AppKit scaffolds one in TypeScript + React: + +```bash +databricks apps init # scaffold the app +databricks apps deploy # deploy it to your workspace +databricks apps run-local # develop locally (or dev-remote) +``` + +## Where to go next + +- **Explore your data** — browse catalogs, schemas, and tables, or query them from the workspace UI. +- **More to build** — Lakeflow Jobs (orchestration), Lakeflow Pipelines (ETL), AI/BI Dashboards, and Model Serving. +- **Using an AI coding assistant?** Install the Databricks skills so it knows these patterns: `databricks aitools install`. + +📚 Full docs: https://docs.databricks.com • CLI reference: https://docs.databricks.com/dev-tools/cli + +Welcome aboard. diff --git a/cmd/quickstart/quickstart.go b/cmd/quickstart/quickstart.go new file mode 100644 index 00000000000..3c03935342d --- /dev/null +++ b/cmd/quickstart/quickstart.go @@ -0,0 +1,74 @@ +package quickstart + +import ( + _ "embed" + "fmt" + "strings" + + "github.com/databricks/cli/cmd/root" + "github.com/databricks/cli/libs/cmdio" + "github.com/spf13/cobra" +) + +// humanQuickstart is the friendly, default introduction shown to people. +// +//go:embed quickstart-human.md +var humanQuickstart string + +// agentQuickstart is the denser, agent-oriented version. It is also the +// `databricks-quickstart` skill, so it carries skill frontmatter that +// stripFrontmatter removes before printing. +// +//go:embed quickstart-agent.md +var agentQuickstart string + +func New() *cobra.Command { + cmd := &cobra.Command{ + Use: "quickstart", + Args: root.NoArgs, + Short: "Print an introduction to the Databricks CLI", + Long: `Print a short introduction to the Databricks CLI: authentication, profiles, +building with Databricks Asset Bundles, and where to go next. + +Prints a human-friendly guide by default. When stdout is not an interactive +terminal (for example, when a coding agent runs the command), it prints a +denser, agent-oriented version instead.`, + } + + cmd.RunE = func(cmd *cobra.Command, args []string) error { + content := quickstartFor(cmdio.IsPromptSupported(cmd.Context())) + _, err := fmt.Fprintln(cmd.OutOrStdout(), content) + return err + } + + return cmd +} + +// quickstartFor returns the quickstart text for the caller. Interactive +// terminals (people) get the friendly guide; non-interactive callers (coding +// agents, scripts, CI) get the agent-oriented version. The detection is +// intentionally simple for now and can grow more precise later. +func quickstartFor(interactive bool) string { + if interactive { + return strings.TrimRight(humanQuickstart, "\n") + } + return stripFrontmatter(agentQuickstart) +} + +// stripFrontmatter removes a leading YAML frontmatter block ("---\n...\n---\n") +// so the printed output starts at the document heading rather than the skill +// metadata. Input without frontmatter is returned unchanged (trailing newlines +// trimmed). Fprintln re-adds a single trailing newline. +func stripFrontmatter(s string) string { + const fence = "---\n" + if !strings.HasPrefix(s, fence) { + return strings.TrimRight(s, "\n") + } + rest := s[len(fence):] + end := strings.Index(rest, "\n"+fence) + if end == -1 { + return strings.TrimRight(s, "\n") + } + body := rest[end+len("\n"+fence):] + return strings.TrimRight(strings.TrimLeft(body, "\n"), "\n") +} diff --git a/cmd/quickstart/quickstart_test.go b/cmd/quickstart/quickstart_test.go new file mode 100644 index 00000000000..a2b8b83f434 --- /dev/null +++ b/cmd/quickstart/quickstart_test.go @@ -0,0 +1,58 @@ +package quickstart + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestQuickstartForInteractiveReturnsHumanGuide(t *testing.T) { + out := quickstartFor(true) + assert.Contains(t, out, "# Welcome to Databricks") + assert.NotContains(t, out, "## Golden rules") + assert.False(t, strings.HasSuffix(out, "\n"), "trailing newline should be trimmed; Fprintln re-adds one") +} + +func TestQuickstartForNonInteractiveReturnsAgentGuide(t *testing.T) { + out := quickstartFor(false) + assert.Contains(t, out, "# Databricks Quickstart") + assert.Contains(t, out, "## Golden rules") + // Frontmatter must be stripped so the output starts at the heading. + assert.True(t, strings.HasPrefix(out, "# Databricks Quickstart")) + assert.NotContains(t, out, "name: databricks-quickstart") +} + +func TestStripFrontmatter(t *testing.T) { + tests := []struct { + name string + in string + want string + }{ + { + name: "with frontmatter", + in: "---\nname: x\ndescription: y\n---\n\n# Title\n\nbody\n", + want: "# Title\n\nbody", + }, + { + name: "without frontmatter", + in: "# Title\n\nbody\n", + want: "# Title\n\nbody", + }, + { + name: "unterminated frontmatter is left intact", + in: "---\nname: x\n# Title", + want: "---\nname: x\n# Title", + }, + { + name: "empty", + in: "", + want: "", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, stripFrontmatter(tt.in)) + }) + } +} From b37764bf35522da7a4192ab4eb7fb710328ceb6d Mon Sep 17 00:00:00 2001 From: simonfaltum Date: Mon, 8 Jun 2026 12:50:13 +0200 Subject: [PATCH 2/3] Add PR link to NEXT_CHANGELOG entry Co-authored-by: Isaac --- NEXT_CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index 07b8a0c4981..b7061fcb305 100644 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -5,7 +5,7 @@ ### Notable Changes ### CLI -* Added the `databricks quickstart` command, a short introduction to the CLI that prints a human-friendly guide interactively and an agent-oriented version when run non-interactively. +* Added the `databricks quickstart` command, a short introduction to the CLI that prints a human-friendly guide interactively and an agent-oriented version when run non-interactively ([#5464](https://github.com/databricks/cli/pull/5464)). ### Bundles * Set the default `data_security_mode` to `DATA_SECURITY_MODE_AUTO` in bundle templates ([#5452](https://github.com/databricks/cli/pull/5452)). From b29c0018d66f0045c1a1445e6eff3777aacb18c4 Mon Sep 17 00:00:00 2001 From: simonfaltum Date: Tue, 9 Jun 2026 14:39:48 +0200 Subject: [PATCH 3/3] quickstart: keep embedded markdown LF so frontmatter strips on Windows On Windows the embedded quickstart markdown was checked out with CRLF, so stripFrontmatter (which matches an LF fence "---\n") left the skill frontmatter in the output. That broke the unit test and the acceptance golden on Windows only. Add a .gitattributes forcing eol=lf for these go:embed files so the embedded content is identical on every platform, matching the existing convention in acceptance/ and integration/. Also switch stripFrontmatter from strings.Index to strings.Cut to fix the failing modernize lint check. Co-authored-by: Isaac Signed-off-by: simonfaltum --- cmd/quickstart/.gitattributes | 6 ++++++ cmd/quickstart/quickstart.go | 5 ++--- 2 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 cmd/quickstart/.gitattributes diff --git a/cmd/quickstart/.gitattributes b/cmd/quickstart/.gitattributes new file mode 100644 index 00000000000..c2c839a7c6b --- /dev/null +++ b/cmd/quickstart/.gitattributes @@ -0,0 +1,6 @@ +# These markdown files are embedded into the binary with go:embed and their +# newlines are semantically important: stripFrontmatter matches an LF fence +# ("---\n"), so an extra \r on Windows would leave the frontmatter unstripped. +# Always check them out with \n so the embedded content is identical on every +# platform. +*.md text eol=lf diff --git a/cmd/quickstart/quickstart.go b/cmd/quickstart/quickstart.go index 3c03935342d..6628ee990b3 100644 --- a/cmd/quickstart/quickstart.go +++ b/cmd/quickstart/quickstart.go @@ -65,10 +65,9 @@ func stripFrontmatter(s string) string { return strings.TrimRight(s, "\n") } rest := s[len(fence):] - end := strings.Index(rest, "\n"+fence) - if end == -1 { + _, body, found := strings.Cut(rest, "\n"+fence) + if !found { return strings.TrimRight(s, "\n") } - body := rest[end+len("\n"+fence):] return strings.TrimRight(strings.TrimLeft(body, "\n"), "\n") }