From b3cd71815c52331f194fbe32ab6829f9fc336103 Mon Sep 17 00:00:00 2001 From: James Broadhead Date: Wed, 8 Apr 2026 13:40:31 +0000 Subject: [PATCH 1/8] Promote aitools from experimental to top-level command The aitools command is feature-complete after the 5-PR series (#4810-#4814) that added state tracking, install/update/uninstall/list/version commands, and project scope support. Move it to a top-level `databricks aitools` command so it is discoverable without knowing the `experimental` prefix. The old `databricks experimental aitools` path is preserved as a hidden deprecated alias for backward compatibility. Co-authored-by: Isaac --- cmd/cmd.go | 2 ++ cmd/experimental/experimental.go | 7 ++++++- experimental/aitools/cmd/aitools.go | 5 ++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/cmd/cmd.go b/cmd/cmd.go index 014471f763..54658f6639 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/databricks/cli/cmd/psql" + aitoolscmd "github.com/databricks/cli/experimental/aitools/cmd" ssh "github.com/databricks/cli/experimental/ssh/cmd" "github.com/databricks/cli/cmd/account" @@ -93,6 +94,7 @@ func New(ctx context.Context) *cobra.Command { } // Add other subcommands. + cli.AddCommand(aitoolscmd.NewAitoolsCmd()) cli.AddCommand(api.New()) cli.AddCommand(auth.New()) cli.AddCommand(completion.New()) diff --git a/cmd/experimental/experimental.go b/cmd/experimental/experimental.go index eb3b7814e1..51e869ff16 100644 --- a/cmd/experimental/experimental.go +++ b/cmd/experimental/experimental.go @@ -20,7 +20,12 @@ These commands provide early access to new features that are still under development. They may change or be removed in future versions without notice.`, } - cmd.AddCommand(aitoolscmd.NewAitoolsCmd()) + // Keep aitools under experimental as a hidden backward-compatibility alias. + // The primary command is now registered at the top level. + aitoolsAlias := aitoolscmd.NewAitoolsCmd() + aitoolsAlias.Hidden = true + aitoolsAlias.Deprecated = "use 'databricks aitools' instead" + cmd.AddCommand(aitoolsAlias) return cmd } diff --git a/experimental/aitools/cmd/aitools.go b/experimental/aitools/cmd/aitools.go index f037ac1a22..d110401c00 100644 --- a/experimental/aitools/cmd/aitools.go +++ b/experimental/aitools/cmd/aitools.go @@ -6,9 +6,8 @@ import ( func NewAitoolsCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "aitools", - Hidden: true, - Short: "Databricks AI Tools for coding agents", + Use: "aitools", + Short: "Databricks AI Tools for coding agents", Long: `Manage Databricks AI Tools. Provides commands to: From 802dee21e1559c1dd8c1289985e725ddd5035ef4 Mon Sep 17 00:00:00 2001 From: James Broadhead Date: Wed, 8 Apr 2026 14:40:46 +0000 Subject: [PATCH 2/8] Update help acceptance test snapshot for aitools command Add the new top-level aitools entry to the expected help output. Co-authored-by: Isaac --- acceptance/help/output.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/acceptance/help/output.txt b/acceptance/help/output.txt index dd59847c64..fdec5582b8 100644 --- a/acceptance/help/output.txt +++ b/acceptance/help/output.txt @@ -167,6 +167,7 @@ Developer Tools Additional Commands: account Databricks Account Commands + aitools Databricks AI Tools for coding agents api Perform Databricks API call auth Authentication related commands cache Local cache related commands From 4ff79340611bf36986d177a23591023e9f0bfd7a Mon Sep 17 00:00:00 2001 From: James Broadhead Date: Tue, 28 Apr 2026 16:45:00 +0000 Subject: [PATCH 3/8] fix(aitools): make deprecation visible on subcommands and update tips - cobra's Deprecated only fires on the executed leaf command, so running 'databricks experimental aitools install' or any other subcommand under the alias produced no warning. Set a PersistentPreRunE on the alias root that prints to stderr; that hook is inherited by every subcommand. - After promoting aitools to a top-level command, every user-facing tip ("Run 'databricks experimental aitools install' to get started", etc.) was steering people back to the deprecated path. Update version.go, installer.go, update.go, uninstall.go, recommend.go, the per-command Examples in discover_schema.go/query.go/get_default_warehouse.go, and the README to use the canonical 'databricks aitools' form. Update recommend_test.go and update_test.go assertions to match. Co-authored-by: Isaac --- cmd/experimental/experimental.go | 11 ++++++++++- experimental/aitools/README.md | 14 +++++++------- experimental/aitools/cmd/discover_schema.go | 4 ++-- experimental/aitools/cmd/get_default_warehouse.go | 4 ++-- experimental/aitools/cmd/query.go | 10 +++++----- experimental/aitools/cmd/version.go | 4 ++-- experimental/aitools/lib/agents/recommend.go | 2 +- experimental/aitools/lib/agents/recommend_test.go | 2 +- experimental/aitools/lib/installer/installer.go | 6 +++--- experimental/aitools/lib/installer/uninstall.go | 2 +- experimental/aitools/lib/installer/update.go | 4 ++-- experimental/aitools/lib/installer/update_test.go | 2 +- 12 files changed, 37 insertions(+), 28 deletions(-) diff --git a/cmd/experimental/experimental.go b/cmd/experimental/experimental.go index 51e869ff16..e1fa301685 100644 --- a/cmd/experimental/experimental.go +++ b/cmd/experimental/experimental.go @@ -1,6 +1,8 @@ package experimental import ( + "fmt" + aitoolscmd "github.com/databricks/cli/experimental/aitools/cmd" "github.com/spf13/cobra" ) @@ -21,10 +23,17 @@ development. They may change or be removed in future versions without notice.`, } // Keep aitools under experimental as a hidden backward-compatibility alias. - // The primary command is now registered at the top level. + // The primary command is now registered at the top level. Cobra's + // `Deprecated` field only fires for the specific command it's set on, so + // running 'databricks experimental aitools install' would skip the warning + // — use a PersistentPreRunE that runs for every subcommand below the alias. aitoolsAlias := aitoolscmd.NewAitoolsCmd() aitoolsAlias.Hidden = true aitoolsAlias.Deprecated = "use 'databricks aitools' instead" + aitoolsAlias.PersistentPreRunE = func(c *cobra.Command, _ []string) error { + fmt.Fprintln(c.ErrOrStderr(), "Warning: 'databricks experimental aitools' is deprecated; use 'databricks aitools' instead.") + return nil + } cmd.AddCommand(aitoolsAlias) return cmd diff --git a/experimental/aitools/README.md b/experimental/aitools/README.md index 571136538c..b02b2b994a 100644 --- a/experimental/aitools/README.md +++ b/experimental/aitools/README.md @@ -1,15 +1,15 @@ # Experimental AI Tools -`databricks experimental aitools` is the remaining experimental surface for coding-agent workflows. +`databricks aitools` is the remaining experimental surface for coding-agent workflows. Current commands: -- `databricks experimental aitools skills list` -- `databricks experimental aitools skills install [skill-name]` -- `databricks experimental aitools install [skill-name]` -- `databricks experimental aitools tools query` -- `databricks experimental aitools tools discover-schema` -- `databricks experimental aitools tools get-default-warehouse` +- `databricks aitools skills list` +- `databricks aitools skills install [skill-name]` +- `databricks aitools install [skill-name]` +- `databricks aitools tools query` +- `databricks aitools tools discover-schema` +- `databricks aitools tools get-default-warehouse` Current behavior: diff --git a/experimental/aitools/cmd/discover_schema.go b/experimental/aitools/cmd/discover_schema.go index f7e2775a52..a3f7f18173 100644 --- a/experimental/aitools/cmd/discover_schema.go +++ b/experimental/aitools/cmd/discover_schema.go @@ -29,8 +29,8 @@ For each table, returns: - Sample data (5 rows) - Null counts per column - Total row count`, - Example: ` databricks experimental aitools tools discover-schema samples.nyctaxi.trips - databricks experimental aitools tools discover-schema catalog.schema.table1 catalog.schema.table2`, + Example: ` databricks aitools tools discover-schema samples.nyctaxi.trips + databricks aitools tools discover-schema catalog.schema.table1 catalog.schema.table2`, Args: cobra.MinimumNArgs(1), PreRunE: root.MustWorkspaceClient, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/experimental/aitools/cmd/get_default_warehouse.go b/experimental/aitools/cmd/get_default_warehouse.go index 446541e9d9..56255864fd 100644 --- a/experimental/aitools/cmd/get_default_warehouse.go +++ b/experimental/aitools/cmd/get_default_warehouse.go @@ -26,11 +26,11 @@ The command auto-detects an available warehouse unless DATABRICKS_WAREHOUSE_ID i Returns warehouse ID of the default warehouse. Use --output json to get the full warehouse info including name and state.`, Example: ` # Get warehouse ID in text format (default) - databricks experimental aitools tools get-default-warehouse + databricks aitools tools get-default-warehouse # Output: abc123def456... # Get full warehouse info including name and state in JSON format - databricks experimental aitools tools get-default-warehouse --output json + databricks aitools tools get-default-warehouse --output json # Output: {"id":"abc123def456...","name":"My Warehouse","state":"RUNNING"}`, Args: cobra.NoArgs, PreRunE: root.MustWorkspaceClient, diff --git a/experimental/aitools/cmd/query.go b/experimental/aitools/cmd/query.go index 801727b983..5e2c9e246e 100644 --- a/experimental/aitools/cmd/query.go +++ b/experimental/aitools/cmd/query.go @@ -84,11 +84,11 @@ or the DATABRICKS_WAREHOUSE_ID environment variable is configured. Output is JSON in non-interactive contexts. In interactive terminals it renders tables, and large results open an interactive table browser.`, - Example: ` databricks experimental aitools tools query "SELECT * FROM samples.nyctaxi.trips LIMIT 5" - databricks experimental aitools tools query --warehouse abc123 "SELECT 1" - databricks experimental aitools tools query --file report.sql - databricks experimental aitools tools query report.sql - echo "SELECT 1" | databricks experimental aitools tools query`, + Example: ` databricks aitools tools query "SELECT * FROM samples.nyctaxi.trips LIMIT 5" + databricks aitools tools query --warehouse abc123 "SELECT 1" + databricks aitools tools query --file report.sql + databricks aitools tools query report.sql + echo "SELECT 1" | databricks aitools tools query`, Args: cobra.MaximumNArgs(1), PreRunE: root.MustWorkspaceClient, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/experimental/aitools/cmd/version.go b/experimental/aitools/cmd/version.go index 67c38fec42..3df97cbbab 100644 --- a/experimental/aitools/cmd/version.go +++ b/experimental/aitools/cmd/version.go @@ -40,7 +40,7 @@ func newVersionCmd() *cobra.Command { if globalState == nil && projectState == nil { cmdio.LogString(ctx, "No Databricks AI Tools components installed.") cmdio.LogString(ctx, "") - cmdio.LogString(ctx, "Run 'databricks experimental aitools install' to get started.") + cmdio.LogString(ctx, "Run 'databricks aitools install' to get started.") return nil } @@ -89,6 +89,6 @@ func printVersionLine(ctx context.Context, label string, state *installer.Instal cmdio.LogString(ctx, " Update available: v"+latestVersion) cmdio.LogString(ctx, " Last updated: "+state.LastUpdated.Format("2006-01-02")) cmdio.LogString(ctx, "") - cmdio.LogString(ctx, "Run 'databricks experimental aitools update' to update.") + cmdio.LogString(ctx, "Run 'databricks aitools update' to update.") } } diff --git a/experimental/aitools/lib/agents/recommend.go b/experimental/aitools/lib/agents/recommend.go index bf10c67bfd..30ca09f02d 100644 --- a/experimental/aitools/lib/agents/recommend.go +++ b/experimental/aitools/lib/agents/recommend.go @@ -15,7 +15,7 @@ func RecommendSkillsInstall(ctx context.Context, installFn func(context.Context) } if !cmdio.IsPromptSupported(ctx) { - cmdio.LogString(ctx, "Tip: coding agents detected without Databricks skills. Run 'databricks experimental aitools skills install' to install them.") + cmdio.LogString(ctx, "Tip: coding agents detected without Databricks skills. Run 'databricks aitools skills install' to install them.") return nil } diff --git a/experimental/aitools/lib/agents/recommend_test.go b/experimental/aitools/lib/agents/recommend_test.go index c2c2769921..faebba6e05 100644 --- a/experimental/aitools/lib/agents/recommend_test.go +++ b/experimental/aitools/lib/agents/recommend_test.go @@ -67,7 +67,7 @@ func TestRecommendSkillsInstallNonInteractive(t *testing.T) { ctx, stderr := cmdio.NewTestContextWithStderr(t.Context()) err := RecommendSkillsInstall(ctx, noopInstall) require.NoError(t, err) - assert.Contains(t, stderr.String(), "databricks experimental aitools skills install") + assert.Contains(t, stderr.String(), "databricks aitools skills install") } func TestRecommendSkillsInstallInteractiveDecline(t *testing.T) { diff --git a/experimental/aitools/lib/installer/installer.go b/experimental/aitools/lib/installer/installer.go index 82d1364b04..fd76b6e03a 100644 --- a/experimental/aitools/lib/installer/installer.go +++ b/experimental/aitools/lib/installer/installer.go @@ -142,7 +142,7 @@ func InstallSkillsForAgents(ctx context.Context, src ManifestSource, targetAgent if state == nil && scope == ScopeGlobal { isLegacy := checkLegacyInstall(ctx, baseDir) if isLegacy && len(opts.SpecificSkills) > 0 { - return errors.New("legacy install detected without state tracking; run 'databricks experimental aitools install' (without a skill name) first to rebuild state") + return errors.New("legacy install detected without state tracking; run 'databricks aitools install' (without a skill name) first to rebuild state") } } @@ -338,7 +338,7 @@ func printNoAgentsDetected(ctx context.Context) { // Returns true if a legacy install was detected. func checkLegacyInstall(ctx context.Context, globalDir string) bool { if hasSkillsOnDisk(globalDir) { - cmdio.LogString(ctx, "Found skills installed before state tracking was added. Run 'databricks experimental aitools install' to refresh.") + cmdio.LogString(ctx, "Found skills installed before state tracking was added. Run 'databricks aitools install' to refresh.") return true } homeDir, err := env.UserHomeDir(ctx) @@ -347,7 +347,7 @@ func checkLegacyInstall(ctx context.Context, globalDir string) bool { } legacyDir := filepath.Join(homeDir, ".databricks", "agent-skills") if hasSkillsOnDisk(legacyDir) { - cmdio.LogString(ctx, "Found skills installed before state tracking was added. Run 'databricks experimental aitools install' to refresh.") + cmdio.LogString(ctx, "Found skills installed before state tracking was added. Run 'databricks aitools install' to refresh.") return true } return false diff --git a/experimental/aitools/lib/installer/uninstall.go b/experimental/aitools/lib/installer/uninstall.go index 5dc695ef9e..225e72be8e 100644 --- a/experimental/aitools/lib/installer/uninstall.go +++ b/experimental/aitools/lib/installer/uninstall.go @@ -53,7 +53,7 @@ func UninstallSkillsOpts(ctx context.Context, opts UninstallOptions) error { if state == nil { if scope == ScopeGlobal && hasLegacyInstall(ctx, baseDir) { - return errors.New("found skills from a previous install without state tracking; run 'databricks experimental aitools install' first, then uninstall") + return errors.New("found skills from a previous install without state tracking; run 'databricks aitools install' first, then uninstall") } return errors.New("no skills installed") } diff --git a/experimental/aitools/lib/installer/update.go b/experimental/aitools/lib/installer/update.go index f92de2f6d3..875c1eea23 100644 --- a/experimental/aitools/lib/installer/update.go +++ b/experimental/aitools/lib/installer/update.go @@ -75,9 +75,9 @@ func UpdateSkills(ctx context.Context, src ManifestSource, targetAgents []*agent if state == nil { if scope == ScopeGlobal && hasLegacyInstall(ctx, baseDir) { - return nil, errors.New("found skills from a previous install without state tracking; run 'databricks experimental aitools install' to refresh before updating") + return nil, errors.New("found skills from a previous install without state tracking; run 'databricks aitools install' to refresh before updating") } - return nil, errors.New("no skills installed. Run 'databricks experimental aitools install' to install") + return nil, errors.New("no skills installed. Run 'databricks aitools install' to install") } latestTag := GetSkillsRef(ctx) diff --git a/experimental/aitools/lib/installer/update_test.go b/experimental/aitools/lib/installer/update_test.go index 97e3014be6..160cf67c11 100644 --- a/experimental/aitools/lib/installer/update_test.go +++ b/experimental/aitools/lib/installer/update_test.go @@ -24,7 +24,7 @@ func TestUpdateNoStateReturnsInstallHint(t *testing.T) { _, err := UpdateSkills(ctx, src, nil, UpdateOptions{}) require.Error(t, err) assert.Contains(t, err.Error(), "no skills installed") - assert.Contains(t, err.Error(), "databricks experimental aitools install") + assert.Contains(t, err.Error(), "databricks aitools install") } func TestUpdateLegacyInstallDetected(t *testing.T) { From 84eb39dd4f2b8e0b321c24c9151b0b6d7791cbe7 Mon Sep 17 00:00:00 2001 From: James Broadhead Date: Tue, 28 Apr 2026 17:27:08 +0000 Subject: [PATCH 4/8] fix(aitools/discover-schema): escape backticks in column names The null-count SQL interpolated DESCRIBE-reported column names directly into a backtick-quoted identifier. A column whose name contained a backtick (rare in real catalogs but legal under Spark's identifier syntax) could break out of the identifier and inject SQL when this command was run against an attacker-controllable schema. Extract the loop into buildNullCountExprs so it can be unit-tested, double every backtick before interpolation per Spark's identifier-quote escape rule, and add a regression test that covers plain, single-tick, and double-tick column names. Co-authored-by: Isaac --- experimental/aitools/cmd/discover_schema.go | 22 ++++++++++----- .../aitools/cmd/discover_schema_test.go | 27 +++++++++++++++++++ 2 files changed, 43 insertions(+), 6 deletions(-) create mode 100644 experimental/aitools/cmd/discover_schema_test.go diff --git a/experimental/aitools/cmd/discover_schema.go b/experimental/aitools/cmd/discover_schema.go index a3f7f18173..b4c3c730c0 100644 --- a/experimental/aitools/cmd/discover_schema.go +++ b/experimental/aitools/cmd/discover_schema.go @@ -117,13 +117,9 @@ func discoverTable(ctx context.Context, w *databricks.WorkspaceClient, warehouse sb.WriteString(formatTableData(sampleResp)) } - // 3. null counts per column - nullCountExprs := make([]string, len(columns)) - for i, col := range columns { - nullCountExprs[i] = fmt.Sprintf("SUM(CASE WHEN `%s` IS NULL THEN 1 ELSE 0 END) AS `%s_nulls`", col, col) - } + // 3. null counts per column. nullSQL := fmt.Sprintf("SELECT COUNT(*) AS total_rows, %s FROM %s", - strings.Join(nullCountExprs, ", "), table) + strings.Join(buildNullCountExprs(columns), ", "), table) nullResp, err := executeSQL(ctx, w, warehouseID, nullSQL) if err != nil { @@ -136,6 +132,20 @@ func discoverTable(ctx context.Context, w *databricks.WorkspaceClient, warehouse return sb.String(), nil } +// buildNullCountExprs renders one SUM(CASE WHEN ... IS NULL ...) per column. +// Spark SQL identifier quoting uses backticks and a literal backtick within +// an identifier is escaped by doubling it. Without escaping, a column whose +// DESCRIBE-reported name contains "`" would break out of the identifier and +// inject SQL. +func buildNullCountExprs(columns []string) []string { + exprs := make([]string, len(columns)) + for i, col := range columns { + escaped := strings.ReplaceAll(col, "`", "``") + exprs[i] = fmt.Sprintf("SUM(CASE WHEN `%s` IS NULL THEN 1 ELSE 0 END) AS `%s_nulls`", escaped, escaped) + } + return exprs +} + func executeSQL(ctx context.Context, w *databricks.WorkspaceClient, warehouseID, statement string) (*dbsql.StatementResponse, error) { resp, err := w.StatementExecution.ExecuteAndWait(ctx, dbsql.ExecuteStatementRequest{ WarehouseId: warehouseID, diff --git a/experimental/aitools/cmd/discover_schema_test.go b/experimental/aitools/cmd/discover_schema_test.go new file mode 100644 index 0000000000..6a624ffa4f --- /dev/null +++ b/experimental/aitools/cmd/discover_schema_test.go @@ -0,0 +1,27 @@ +package aitools + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBuildNullCountExprs_EscapesBackticksInColumnName(t *testing.T) { + got := buildNullCountExprs([]string{"plain", "with`tick", "two``ticks"}) + assert.Len(t, got, 3) + + assert.Equal(t, "SUM(CASE WHEN `plain` IS NULL THEN 1 ELSE 0 END) AS `plain_nulls`", got[0]) + assert.Equal(t, "SUM(CASE WHEN `with``tick` IS NULL THEN 1 ELSE 0 END) AS `with``tick_nulls`", got[1]) + assert.Equal(t, "SUM(CASE WHEN `two````ticks` IS NULL THEN 1 ELSE 0 END) AS `two````ticks_nulls`", got[2]) + + for _, expr := range got { + assert.Equal(t, 0, strings.Count(strings.ReplaceAll(expr, "``", ""), "`")%2, + "%q has unbalanced backticks", expr) + } +} + +func TestBuildNullCountExprs_EmptyColumns(t *testing.T) { + assert.Empty(t, buildNullCountExprs(nil)) + assert.Empty(t, buildNullCountExprs([]string{})) +} From eb574eeef18d58e19cbbd9da8d77b195e416270e Mon Sep 17 00:00:00 2001 From: James Broadhead Date: Tue, 28 Apr 2026 20:18:58 +0000 Subject: [PATCH 5/8] Move aitools out of experimental/ to top-level aitools/ Per Simon's review on #4917, the source files should live outside experimental/ now that aitools is a top-level command. Renames the directory from experimental/aitools/ to aitools/ and updates all import paths, examples, and tooling references (Makefile, OWNERS, testmask, pr-checklist). The experimental/aitools alias still routes to the same package via its new import path, so 'databricks experimental aitools' continues to work as a deprecated entry point. Co-authored-by: Isaac --- .agent/skills/pr-checklist/SKILL.md | 2 +- .github/OWNERS | 4 ++-- Makefile | 2 +- {experimental/aitools => aitools}/README.md | 16 ++++++++-------- {experimental/aitools => aitools}/cmd/aitools.go | 0 {experimental/aitools => aitools}/cmd/batch.go | 0 .../aitools => aitools}/cmd/batch_test.go | 0 .../aitools => aitools}/cmd/discover_schema.go | 4 ++-- .../cmd/discover_schema_test.go | 0 {experimental/aitools => aitools}/cmd/flags.go | 0 .../aitools => aitools}/cmd/flags_test.go | 0 .../cmd/get_default_warehouse.go | 4 ++-- {experimental/aitools => aitools}/cmd/install.go | 4 ++-- .../aitools => aitools}/cmd/install_test.go | 4 ++-- {experimental/aitools => aitools}/cmd/list.go | 2 +- .../aitools => aitools}/cmd/list_test.go | 0 {experimental/aitools => aitools}/cmd/query.go | 4 ++-- .../aitools => aitools}/cmd/query_test.go | 0 {experimental/aitools => aitools}/cmd/render.go | 0 .../aitools => aitools}/cmd/render_test.go | 0 {experimental/aitools => aitools}/cmd/scope.go | 6 +++--- .../aitools => aitools}/cmd/scope_test.go | 2 +- {experimental/aitools => aitools}/cmd/skills.go | 4 ++-- .../aitools => aitools}/cmd/statement.go | 0 .../aitools => aitools}/cmd/statement_cancel.go | 2 +- .../aitools => aitools}/cmd/statement_get.go | 2 +- .../aitools => aitools}/cmd/statement_status.go | 2 +- .../aitools => aitools}/cmd/statement_submit.go | 4 ++-- .../aitools => aitools}/cmd/statement_test.go | 0 {experimental/aitools => aitools}/cmd/tools.go | 0 .../aitools => aitools}/cmd/uninstall.go | 2 +- {experimental/aitools => aitools}/cmd/update.go | 4 ++-- {experimental/aitools => aitools}/cmd/version.go | 2 +- .../aitools => aitools}/cmd/version_test.go | 2 +- .../aitools => aitools}/lib/agents/agents.go | 0 .../aitools => aitools}/lib/agents/recommend.go | 0 .../lib/agents/recommend_test.go | 0 .../aitools => aitools}/lib/agents/skills.go | 0 .../lib/agents/skills_test.go | 0 .../lib/installer/SKILLS_VERSION | 0 .../lib/installer/installer.go | 2 +- .../lib/installer/installer_test.go | 2 +- .../aitools => aitools}/lib/installer/source.go | 0 .../aitools => aitools}/lib/installer/state.go | 0 .../lib/installer/state_test.go | 0 .../lib/installer/uninstall.go | 2 +- .../lib/installer/uninstall_test.go | 2 +- .../aitools => aitools}/lib/installer/update.go | 2 +- .../lib/installer/update_test.go | 2 +- .../aitools => aitools}/lib/installer/version.go | 0 .../lib/middlewares/databricks_client.go | 2 +- .../lib/middlewares/databricks_client_test.go | 0 .../lib/middlewares/warehouse.go | 2 +- .../aitools => aitools}/lib/session/session.go | 0 .../lib/session/session_test.go | 0 cmd/apps/init.go | 6 +++--- cmd/cmd.go | 2 +- cmd/experimental/experimental.go | 2 +- tools/testmask/targets.go | 2 +- 59 files changed, 53 insertions(+), 53 deletions(-) rename {experimental/aitools => aitools}/README.md (78%) rename {experimental/aitools => aitools}/cmd/aitools.go (100%) rename {experimental/aitools => aitools}/cmd/batch.go (100%) rename {experimental/aitools => aitools}/cmd/batch_test.go (100%) rename {experimental/aitools => aitools}/cmd/discover_schema.go (98%) rename {experimental/aitools => aitools}/cmd/discover_schema_test.go (100%) rename {experimental/aitools => aitools}/cmd/flags.go (100%) rename {experimental/aitools => aitools}/cmd/flags_test.go (100%) rename {experimental/aitools => aitools}/cmd/get_default_warehouse.go (93%) rename {experimental/aitools => aitools}/cmd/install.go (97%) rename {experimental/aitools => aitools}/cmd/install_test.go (99%) rename {experimental/aitools => aitools}/cmd/list.go (98%) rename {experimental/aitools => aitools}/cmd/list_test.go (100%) rename {experimental/aitools => aitools}/cmd/query.go (99%) rename {experimental/aitools => aitools}/cmd/query_test.go (100%) rename {experimental/aitools => aitools}/cmd/render.go (100%) rename {experimental/aitools => aitools}/cmd/render_test.go (100%) rename {experimental/aitools => aitools}/cmd/scope.go (97%) rename {experimental/aitools => aitools}/cmd/scope_test.go (99%) rename {experimental/aitools => aitools}/cmd/skills.go (95%) rename {experimental/aitools => aitools}/cmd/statement.go (100%) rename {experimental/aitools => aitools}/cmd/statement_cancel.go (95%) rename {experimental/aitools => aitools}/cmd/statement_get.go (97%) rename {experimental/aitools => aitools}/cmd/statement_status.go (94%) rename {experimental/aitools => aitools}/cmd/statement_submit.go (93%) rename {experimental/aitools => aitools}/cmd/statement_test.go (100%) rename {experimental/aitools => aitools}/cmd/tools.go (100%) rename {experimental/aitools => aitools}/cmd/uninstall.go (95%) rename {experimental/aitools => aitools}/cmd/update.go (94%) rename {experimental/aitools => aitools}/cmd/version.go (97%) rename {experimental/aitools => aitools}/cmd/version_test.go (97%) rename {experimental/aitools => aitools}/lib/agents/agents.go (100%) rename {experimental/aitools => aitools}/lib/agents/recommend.go (100%) rename {experimental/aitools => aitools}/lib/agents/recommend_test.go (100%) rename {experimental/aitools => aitools}/lib/agents/skills.go (100%) rename {experimental/aitools => aitools}/lib/agents/skills_test.go (100%) rename {experimental/aitools => aitools}/lib/installer/SKILLS_VERSION (100%) rename {experimental/aitools => aitools}/lib/installer/installer.go (99%) rename {experimental/aitools => aitools}/lib/installer/installer_test.go (99%) rename {experimental/aitools => aitools}/lib/installer/source.go (100%) rename {experimental/aitools => aitools}/lib/installer/state.go (100%) rename {experimental/aitools => aitools}/lib/installer/state_test.go (100%) rename {experimental/aitools => aitools}/lib/installer/uninstall.go (99%) rename {experimental/aitools => aitools}/lib/installer/uninstall_test.go (99%) rename {experimental/aitools => aitools}/lib/installer/update.go (99%) rename {experimental/aitools => aitools}/lib/installer/update_test.go (99%) rename {experimental/aitools => aitools}/lib/installer/version.go (100%) rename {experimental/aitools => aitools}/lib/middlewares/databricks_client.go (96%) rename {experimental/aitools => aitools}/lib/middlewares/databricks_client_test.go (100%) rename {experimental/aitools => aitools}/lib/middlewares/warehouse.go (98%) rename {experimental/aitools => aitools}/lib/session/session.go (100%) rename {experimental/aitools => aitools}/lib/session/session_test.go (100%) diff --git a/.agent/skills/pr-checklist/SKILL.md b/.agent/skills/pr-checklist/SKILL.md index 8f0fe485b2..ac86456427 100644 --- a/.agent/skills/pr-checklist/SKILL.md +++ b/.agent/skills/pr-checklist/SKILL.md @@ -22,7 +22,7 @@ make schema # 5. If you changed files in python/: cd python && make codegen && make test && make lint && make docs -# 6. If you changed experimental/aitools or experimental/ssh: +# 6. If you changed aitools or experimental/ssh: make test-exp-aitools # only if aitools code changed make test-exp-ssh # only if ssh code changed ``` diff --git a/.github/OWNERS b/.github/OWNERS index 7cae525465..592bd57e13 100644 --- a/.github/OWNERS +++ b/.github/OWNERS @@ -59,5 +59,5 @@ # Internal /internal/ team:platform -# Experimental -/experimental/aitools/ team:eng-apps-devex @lennartkats-db +# AI tools +/aitools/ team:eng-apps-devex @lennartkats-db diff --git a/Makefile b/Makefile index 1b6f058f26..b6a82516e3 100644 --- a/Makefile +++ b/Makefile @@ -243,7 +243,7 @@ bundle/direct/dresources/resources.generated.yml: ./bundle/direct/tools/generate .PHONY: test-exp-aitools test-exp-aitools: - make test TEST_PACKAGES="./experimental/aitools/..." ACCEPTANCE_TEST_FILTER="TestAccept/apps" + make test TEST_PACKAGES="./aitools/..." ACCEPTANCE_TEST_FILTER="TestAccept/apps" .PHONY: test-exp-ssh test-exp-ssh: diff --git a/experimental/aitools/README.md b/aitools/README.md similarity index 78% rename from experimental/aitools/README.md rename to aitools/README.md index e815eab9fd..59d2464140 100644 --- a/experimental/aitools/README.md +++ b/aitools/README.md @@ -1,6 +1,6 @@ -# Experimental AI Tools +# AI Tools -`databricks aitools` is the remaining experimental surface for coding-agent workflows. +`databricks aitools` exposes commands for coding-agent workflows. Current commands: @@ -26,7 +26,7 @@ Current behavior: with `--concurrency` (default 8). ```bash - databricks experimental aitools tools query \ + databricks aitools tools query \ --warehouse --output json \ "SELECT count(*) FROM samples.nyctaxi.trips" \ "SELECT min(tpep_pickup_datetime), max(tpep_pickup_datetime) FROM samples.nyctaxi.trips" \ @@ -40,14 +40,14 @@ Current behavior: server-side statement; use `cancel` for that. ```bash - SID=$(databricks experimental aitools tools statement submit \ + SID=$(databricks aitools tools statement submit \ --warehouse "SELECT pg_sleep(5)" | jq -r '.statement_id') - databricks experimental aitools tools statement status "$SID" - databricks experimental aitools tools statement get "$SID" + databricks aitools tools statement status "$SID" + databricks aitools tools statement get "$SID" ``` Removed behavior: -- there is no MCP server under `experimental aitools` +- there is no MCP server under `aitools` - the old `deploy` and `validate` flows were removed -- command names and behavior in this area are still experimental and may change +- command names and behavior in this area may still change diff --git a/experimental/aitools/cmd/aitools.go b/aitools/cmd/aitools.go similarity index 100% rename from experimental/aitools/cmd/aitools.go rename to aitools/cmd/aitools.go diff --git a/experimental/aitools/cmd/batch.go b/aitools/cmd/batch.go similarity index 100% rename from experimental/aitools/cmd/batch.go rename to aitools/cmd/batch.go diff --git a/experimental/aitools/cmd/batch_test.go b/aitools/cmd/batch_test.go similarity index 100% rename from experimental/aitools/cmd/batch_test.go rename to aitools/cmd/batch_test.go diff --git a/experimental/aitools/cmd/discover_schema.go b/aitools/cmd/discover_schema.go similarity index 98% rename from experimental/aitools/cmd/discover_schema.go rename to aitools/cmd/discover_schema.go index b364a43a02..a127b02682 100644 --- a/experimental/aitools/cmd/discover_schema.go +++ b/aitools/cmd/discover_schema.go @@ -12,9 +12,9 @@ import ( "sync" "syscall" + "github.com/databricks/cli/aitools/lib/middlewares" + "github.com/databricks/cli/aitools/lib/session" "github.com/databricks/cli/cmd/root" - "github.com/databricks/cli/experimental/aitools/lib/middlewares" - "github.com/databricks/cli/experimental/aitools/lib/session" "github.com/databricks/cli/libs/cmdctx" "github.com/databricks/cli/libs/cmdio" "github.com/databricks/cli/libs/log" diff --git a/experimental/aitools/cmd/discover_schema_test.go b/aitools/cmd/discover_schema_test.go similarity index 100% rename from experimental/aitools/cmd/discover_schema_test.go rename to aitools/cmd/discover_schema_test.go diff --git a/experimental/aitools/cmd/flags.go b/aitools/cmd/flags.go similarity index 100% rename from experimental/aitools/cmd/flags.go rename to aitools/cmd/flags.go diff --git a/experimental/aitools/cmd/flags_test.go b/aitools/cmd/flags_test.go similarity index 100% rename from experimental/aitools/cmd/flags_test.go rename to aitools/cmd/flags_test.go diff --git a/experimental/aitools/cmd/get_default_warehouse.go b/aitools/cmd/get_default_warehouse.go similarity index 93% rename from experimental/aitools/cmd/get_default_warehouse.go rename to aitools/cmd/get_default_warehouse.go index 56255864fd..9c853932ee 100644 --- a/experimental/aitools/cmd/get_default_warehouse.go +++ b/aitools/cmd/get_default_warehouse.go @@ -1,9 +1,9 @@ package aitools import ( + "github.com/databricks/cli/aitools/lib/middlewares" + "github.com/databricks/cli/aitools/lib/session" "github.com/databricks/cli/cmd/root" - "github.com/databricks/cli/experimental/aitools/lib/middlewares" - "github.com/databricks/cli/experimental/aitools/lib/session" "github.com/databricks/cli/libs/cmdctx" "github.com/databricks/cli/libs/cmdio" "github.com/databricks/databricks-sdk-go/service/sql" diff --git a/experimental/aitools/cmd/install.go b/aitools/cmd/install.go similarity index 97% rename from experimental/aitools/cmd/install.go rename to aitools/cmd/install.go index b6e87d68b1..3012ef7c9e 100644 --- a/experimental/aitools/cmd/install.go +++ b/aitools/cmd/install.go @@ -6,8 +6,8 @@ import ( "fmt" "strings" - "github.com/databricks/cli/experimental/aitools/lib/agents" - "github.com/databricks/cli/experimental/aitools/lib/installer" + "github.com/databricks/cli/aitools/lib/agents" + "github.com/databricks/cli/aitools/lib/installer" "github.com/databricks/cli/libs/cmdio" "github.com/fatih/color" "github.com/spf13/cobra" diff --git a/experimental/aitools/cmd/install_test.go b/aitools/cmd/install_test.go similarity index 99% rename from experimental/aitools/cmd/install_test.go rename to aitools/cmd/install_test.go index 38639705ea..37e469c816 100644 --- a/experimental/aitools/cmd/install_test.go +++ b/aitools/cmd/install_test.go @@ -7,8 +7,8 @@ import ( "path/filepath" "testing" - "github.com/databricks/cli/experimental/aitools/lib/agents" - "github.com/databricks/cli/experimental/aitools/lib/installer" + "github.com/databricks/cli/aitools/lib/agents" + "github.com/databricks/cli/aitools/lib/installer" "github.com/databricks/cli/libs/cmdio" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/experimental/aitools/cmd/list.go b/aitools/cmd/list.go similarity index 98% rename from experimental/aitools/cmd/list.go rename to aitools/cmd/list.go index 1be1538c9a..f0fe48f07b 100644 --- a/experimental/aitools/cmd/list.go +++ b/aitools/cmd/list.go @@ -8,7 +8,7 @@ import ( "strings" "text/tabwriter" - "github.com/databricks/cli/experimental/aitools/lib/installer" + "github.com/databricks/cli/aitools/lib/installer" "github.com/databricks/cli/libs/cmdio" "github.com/databricks/cli/libs/log" "github.com/spf13/cobra" diff --git a/experimental/aitools/cmd/list_test.go b/aitools/cmd/list_test.go similarity index 100% rename from experimental/aitools/cmd/list_test.go rename to aitools/cmd/list_test.go diff --git a/experimental/aitools/cmd/query.go b/aitools/cmd/query.go similarity index 99% rename from experimental/aitools/cmd/query.go rename to aitools/cmd/query.go index 9200b08fc2..1d219d5717 100644 --- a/experimental/aitools/cmd/query.go +++ b/aitools/cmd/query.go @@ -11,9 +11,9 @@ import ( "syscall" "time" + "github.com/databricks/cli/aitools/lib/middlewares" + "github.com/databricks/cli/aitools/lib/session" "github.com/databricks/cli/cmd/root" - "github.com/databricks/cli/experimental/aitools/lib/middlewares" - "github.com/databricks/cli/experimental/aitools/lib/session" "github.com/databricks/cli/libs/cmdctx" "github.com/databricks/cli/libs/cmdio" "github.com/databricks/cli/libs/env" diff --git a/experimental/aitools/cmd/query_test.go b/aitools/cmd/query_test.go similarity index 100% rename from experimental/aitools/cmd/query_test.go rename to aitools/cmd/query_test.go diff --git a/experimental/aitools/cmd/render.go b/aitools/cmd/render.go similarity index 100% rename from experimental/aitools/cmd/render.go rename to aitools/cmd/render.go diff --git a/experimental/aitools/cmd/render_test.go b/aitools/cmd/render_test.go similarity index 100% rename from experimental/aitools/cmd/render_test.go rename to aitools/cmd/render_test.go diff --git a/experimental/aitools/cmd/scope.go b/aitools/cmd/scope.go similarity index 97% rename from experimental/aitools/cmd/scope.go rename to aitools/cmd/scope.go index 8c6ce0f013..acd012135a 100644 --- a/experimental/aitools/cmd/scope.go +++ b/aitools/cmd/scope.go @@ -8,7 +8,7 @@ import ( "path/filepath" "github.com/charmbracelet/huh" - "github.com/databricks/cli/experimental/aitools/lib/installer" + "github.com/databricks/cli/aitools/lib/installer" "github.com/databricks/cli/libs/cmdio" "github.com/databricks/cli/libs/env" ) @@ -230,10 +230,10 @@ func scopeNotInstalledError(scope, verb, projectDir string, hasGlobal, hasProjec "no project-scoped skills found in the current directory.\n\n"+ "Project-scoped skills are detected based on your working directory.\n"+ "Make sure you are in the project root where you originally ran\n"+ - "'databricks experimental aitools install --project'.\n\n"+ + "'databricks aitools install --project'.\n\n"+ "Expected location: %s/", expectedPath) } else { - msg = "no globally-scoped skills installed. Run 'databricks experimental aitools install --global' to install" + msg = "no globally-scoped skills installed. Run 'databricks aitools install --global' to install" } hint := crossScopeHint(scope, verb, hasGlobal, hasProject) diff --git a/experimental/aitools/cmd/scope_test.go b/aitools/cmd/scope_test.go similarity index 99% rename from experimental/aitools/cmd/scope_test.go rename to aitools/cmd/scope_test.go index ecda25faad..80e5a976a9 100644 --- a/experimental/aitools/cmd/scope_test.go +++ b/aitools/cmd/scope_test.go @@ -7,7 +7,7 @@ import ( "path/filepath" "testing" - "github.com/databricks/cli/experimental/aitools/lib/installer" + "github.com/databricks/cli/aitools/lib/installer" "github.com/databricks/cli/libs/cmdio" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/experimental/aitools/cmd/skills.go b/aitools/cmd/skills.go similarity index 95% rename from experimental/aitools/cmd/skills.go rename to aitools/cmd/skills.go index 9995ff72a0..4f338adc15 100644 --- a/experimental/aitools/cmd/skills.go +++ b/aitools/cmd/skills.go @@ -5,8 +5,8 @@ import ( "errors" "github.com/charmbracelet/huh" - "github.com/databricks/cli/experimental/aitools/lib/agents" - "github.com/databricks/cli/experimental/aitools/lib/installer" + "github.com/databricks/cli/aitools/lib/agents" + "github.com/databricks/cli/aitools/lib/installer" "github.com/spf13/cobra" ) diff --git a/experimental/aitools/cmd/statement.go b/aitools/cmd/statement.go similarity index 100% rename from experimental/aitools/cmd/statement.go rename to aitools/cmd/statement.go diff --git a/experimental/aitools/cmd/statement_cancel.go b/aitools/cmd/statement_cancel.go similarity index 95% rename from experimental/aitools/cmd/statement_cancel.go rename to aitools/cmd/statement_cancel.go index 1774b7abe6..81ee53c271 100644 --- a/experimental/aitools/cmd/statement_cancel.go +++ b/aitools/cmd/statement_cancel.go @@ -18,7 +18,7 @@ func newStatementCancelCmd() *cobra.Command { API returns no body on cancel; this command optimistically reports state=CANCELED on success. Use 'statement status' afterwards to confirm the server-side state if you need certainty.`, - Example: ` databricks experimental aitools tools statement cancel 01ef...`, + Example: ` databricks aitools tools statement cancel 01ef...`, Args: cobra.ExactArgs(1), PreRunE: root.MustWorkspaceClient, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/experimental/aitools/cmd/statement_get.go b/aitools/cmd/statement_get.go similarity index 97% rename from experimental/aitools/cmd/statement_get.go rename to aitools/cmd/statement_get.go index 617b5c274d..9d7c8ef11b 100644 --- a/experimental/aitools/cmd/statement_get.go +++ b/aitools/cmd/statement_get.go @@ -21,7 +21,7 @@ Ctrl+C stops polling but does NOT cancel the server-side statement. Use 'statement cancel ' to terminate explicitly. (This differs from 'tools query', which cancels server-side on Ctrl+C because the user invoked the synchronous path.)`, - Example: ` databricks experimental aitools tools statement get 01ef...`, + Example: ` databricks aitools tools statement get 01ef...`, Args: cobra.ExactArgs(1), PreRunE: root.MustWorkspaceClient, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/experimental/aitools/cmd/statement_status.go b/aitools/cmd/statement_status.go similarity index 94% rename from experimental/aitools/cmd/statement_status.go rename to aitools/cmd/statement_status.go index 9981f49aa6..3e6dd0f860 100644 --- a/experimental/aitools/cmd/statement_status.go +++ b/aitools/cmd/statement_status.go @@ -17,7 +17,7 @@ func newStatementStatusCmd() *cobra.Command { Long: `Single GET against the Statements API. Use this to peek at progress without blocking. For a blocking poll-until-terminal call, use 'statement get'.`, - Example: ` databricks experimental aitools tools statement status 01ef...`, + Example: ` databricks aitools tools statement status 01ef...`, Args: cobra.ExactArgs(1), PreRunE: root.MustWorkspaceClient, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/experimental/aitools/cmd/statement_submit.go b/aitools/cmd/statement_submit.go similarity index 93% rename from experimental/aitools/cmd/statement_submit.go rename to aitools/cmd/statement_submit.go index ac8bf424e5..0cf078222b 100644 --- a/experimental/aitools/cmd/statement_submit.go +++ b/aitools/cmd/statement_submit.go @@ -28,8 +28,8 @@ statement_id immediately, without waiting for results. The statement keeps running server-side. Harvest results with 'statement get ', inspect with 'statement status ', or stop with 'statement cancel '.`, - Example: ` databricks experimental aitools tools statement submit "SELECT pg_sleep(60)" --warehouse - databricks experimental aitools tools statement submit --file query.sql`, + Example: ` databricks aitools tools statement submit "SELECT pg_sleep(60)" --warehouse + databricks aitools tools statement submit --file query.sql`, Args: cobra.MaximumNArgs(1), PreRunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() diff --git a/experimental/aitools/cmd/statement_test.go b/aitools/cmd/statement_test.go similarity index 100% rename from experimental/aitools/cmd/statement_test.go rename to aitools/cmd/statement_test.go diff --git a/experimental/aitools/cmd/tools.go b/aitools/cmd/tools.go similarity index 100% rename from experimental/aitools/cmd/tools.go rename to aitools/cmd/tools.go diff --git a/experimental/aitools/cmd/uninstall.go b/aitools/cmd/uninstall.go similarity index 95% rename from experimental/aitools/cmd/uninstall.go rename to aitools/cmd/uninstall.go index 3eda84cfbc..8ebcecb462 100644 --- a/experimental/aitools/cmd/uninstall.go +++ b/aitools/cmd/uninstall.go @@ -1,7 +1,7 @@ package aitools import ( - "github.com/databricks/cli/experimental/aitools/lib/installer" + "github.com/databricks/cli/aitools/lib/installer" "github.com/spf13/cobra" ) diff --git a/experimental/aitools/cmd/update.go b/aitools/cmd/update.go similarity index 94% rename from experimental/aitools/cmd/update.go rename to aitools/cmd/update.go index c5072d1fb1..32e7ff7745 100644 --- a/experimental/aitools/cmd/update.go +++ b/aitools/cmd/update.go @@ -3,8 +3,8 @@ package aitools import ( "fmt" - "github.com/databricks/cli/experimental/aitools/lib/agents" - "github.com/databricks/cli/experimental/aitools/lib/installer" + "github.com/databricks/cli/aitools/lib/agents" + "github.com/databricks/cli/aitools/lib/installer" "github.com/databricks/cli/libs/cmdio" "github.com/spf13/cobra" ) diff --git a/experimental/aitools/cmd/version.go b/aitools/cmd/version.go similarity index 97% rename from experimental/aitools/cmd/version.go rename to aitools/cmd/version.go index 3df97cbbab..7984682c73 100644 --- a/experimental/aitools/cmd/version.go +++ b/aitools/cmd/version.go @@ -5,7 +5,7 @@ import ( "fmt" "strings" - "github.com/databricks/cli/experimental/aitools/lib/installer" + "github.com/databricks/cli/aitools/lib/installer" "github.com/databricks/cli/libs/cmdio" "github.com/spf13/cobra" ) diff --git a/experimental/aitools/cmd/version_test.go b/aitools/cmd/version_test.go similarity index 97% rename from experimental/aitools/cmd/version_test.go rename to aitools/cmd/version_test.go index d24f7e99f8..e74c411b80 100644 --- a/experimental/aitools/cmd/version_test.go +++ b/aitools/cmd/version_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - "github.com/databricks/cli/experimental/aitools/lib/installer" + "github.com/databricks/cli/aitools/lib/installer" "github.com/databricks/cli/libs/cmdio" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/experimental/aitools/lib/agents/agents.go b/aitools/lib/agents/agents.go similarity index 100% rename from experimental/aitools/lib/agents/agents.go rename to aitools/lib/agents/agents.go diff --git a/experimental/aitools/lib/agents/recommend.go b/aitools/lib/agents/recommend.go similarity index 100% rename from experimental/aitools/lib/agents/recommend.go rename to aitools/lib/agents/recommend.go diff --git a/experimental/aitools/lib/agents/recommend_test.go b/aitools/lib/agents/recommend_test.go similarity index 100% rename from experimental/aitools/lib/agents/recommend_test.go rename to aitools/lib/agents/recommend_test.go diff --git a/experimental/aitools/lib/agents/skills.go b/aitools/lib/agents/skills.go similarity index 100% rename from experimental/aitools/lib/agents/skills.go rename to aitools/lib/agents/skills.go diff --git a/experimental/aitools/lib/agents/skills_test.go b/aitools/lib/agents/skills_test.go similarity index 100% rename from experimental/aitools/lib/agents/skills_test.go rename to aitools/lib/agents/skills_test.go diff --git a/experimental/aitools/lib/installer/SKILLS_VERSION b/aitools/lib/installer/SKILLS_VERSION similarity index 100% rename from experimental/aitools/lib/installer/SKILLS_VERSION rename to aitools/lib/installer/SKILLS_VERSION diff --git a/experimental/aitools/lib/installer/installer.go b/aitools/lib/installer/installer.go similarity index 99% rename from experimental/aitools/lib/installer/installer.go rename to aitools/lib/installer/installer.go index a4ab68e061..5db3b151c7 100644 --- a/experimental/aitools/lib/installer/installer.go +++ b/aitools/lib/installer/installer.go @@ -14,7 +14,7 @@ import ( "strings" "time" - "github.com/databricks/cli/experimental/aitools/lib/agents" + "github.com/databricks/cli/aitools/lib/agents" "github.com/databricks/cli/internal/build" "github.com/databricks/cli/libs/cmdio" "github.com/databricks/cli/libs/env" diff --git a/experimental/aitools/lib/installer/installer_test.go b/aitools/lib/installer/installer_test.go similarity index 99% rename from experimental/aitools/lib/installer/installer_test.go rename to aitools/lib/installer/installer_test.go index b769143906..8bd926637e 100644 --- a/experimental/aitools/lib/installer/installer_test.go +++ b/aitools/lib/installer/installer_test.go @@ -11,7 +11,7 @@ import ( "strings" "testing" - "github.com/databricks/cli/experimental/aitools/lib/agents" + "github.com/databricks/cli/aitools/lib/agents" "github.com/databricks/cli/internal/build" "github.com/databricks/cli/libs/cmdio" "github.com/databricks/cli/libs/log" diff --git a/experimental/aitools/lib/installer/source.go b/aitools/lib/installer/source.go similarity index 100% rename from experimental/aitools/lib/installer/source.go rename to aitools/lib/installer/source.go diff --git a/experimental/aitools/lib/installer/state.go b/aitools/lib/installer/state.go similarity index 100% rename from experimental/aitools/lib/installer/state.go rename to aitools/lib/installer/state.go diff --git a/experimental/aitools/lib/installer/state_test.go b/aitools/lib/installer/state_test.go similarity index 100% rename from experimental/aitools/lib/installer/state_test.go rename to aitools/lib/installer/state_test.go diff --git a/experimental/aitools/lib/installer/uninstall.go b/aitools/lib/installer/uninstall.go similarity index 99% rename from experimental/aitools/lib/installer/uninstall.go rename to aitools/lib/installer/uninstall.go index 9431b9d61c..92c69f7ec9 100644 --- a/experimental/aitools/lib/installer/uninstall.go +++ b/aitools/lib/installer/uninstall.go @@ -9,7 +9,7 @@ import ( "path/filepath" "strings" - "github.com/databricks/cli/experimental/aitools/lib/agents" + "github.com/databricks/cli/aitools/lib/agents" "github.com/databricks/cli/libs/cmdio" "github.com/databricks/cli/libs/log" ) diff --git a/experimental/aitools/lib/installer/uninstall_test.go b/aitools/lib/installer/uninstall_test.go similarity index 99% rename from experimental/aitools/lib/installer/uninstall_test.go rename to aitools/lib/installer/uninstall_test.go index 6c7589f6f2..cf7ada3a9a 100644 --- a/experimental/aitools/lib/installer/uninstall_test.go +++ b/aitools/lib/installer/uninstall_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - "github.com/databricks/cli/experimental/aitools/lib/agents" + "github.com/databricks/cli/aitools/lib/agents" "github.com/databricks/cli/libs/cmdio" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/experimental/aitools/lib/installer/update.go b/aitools/lib/installer/update.go similarity index 99% rename from experimental/aitools/lib/installer/update.go rename to aitools/lib/installer/update.go index 5d81eac0c0..87b62e76ed 100644 --- a/experimental/aitools/lib/installer/update.go +++ b/aitools/lib/installer/update.go @@ -11,7 +11,7 @@ import ( "strings" "time" - "github.com/databricks/cli/experimental/aitools/lib/agents" + "github.com/databricks/cli/aitools/lib/agents" "github.com/databricks/cli/internal/build" "github.com/databricks/cli/libs/cmdio" "github.com/databricks/cli/libs/env" diff --git a/experimental/aitools/lib/installer/update_test.go b/aitools/lib/installer/update_test.go similarity index 99% rename from experimental/aitools/lib/installer/update_test.go rename to aitools/lib/installer/update_test.go index 160cf67c11..4339ddead4 100644 --- a/experimental/aitools/lib/installer/update_test.go +++ b/aitools/lib/installer/update_test.go @@ -8,7 +8,7 @@ import ( "path/filepath" "testing" - "github.com/databricks/cli/experimental/aitools/lib/agents" + "github.com/databricks/cli/aitools/lib/agents" "github.com/databricks/cli/libs/cmdio" "github.com/databricks/cli/libs/log" "github.com/stretchr/testify/assert" diff --git a/experimental/aitools/lib/installer/version.go b/aitools/lib/installer/version.go similarity index 100% rename from experimental/aitools/lib/installer/version.go rename to aitools/lib/installer/version.go diff --git a/experimental/aitools/lib/middlewares/databricks_client.go b/aitools/lib/middlewares/databricks_client.go similarity index 96% rename from experimental/aitools/lib/middlewares/databricks_client.go rename to aitools/lib/middlewares/databricks_client.go index 6abf360e03..738643f9d0 100644 --- a/experimental/aitools/lib/middlewares/databricks_client.go +++ b/aitools/lib/middlewares/databricks_client.go @@ -6,7 +6,7 @@ import ( "fmt" "strings" - "github.com/databricks/cli/experimental/aitools/lib/session" + "github.com/databricks/cli/aitools/lib/session" "github.com/databricks/cli/libs/databrickscfg/profile" "github.com/databricks/databricks-sdk-go" ) diff --git a/experimental/aitools/lib/middlewares/databricks_client_test.go b/aitools/lib/middlewares/databricks_client_test.go similarity index 100% rename from experimental/aitools/lib/middlewares/databricks_client_test.go rename to aitools/lib/middlewares/databricks_client_test.go diff --git a/experimental/aitools/lib/middlewares/warehouse.go b/aitools/lib/middlewares/warehouse.go similarity index 98% rename from experimental/aitools/lib/middlewares/warehouse.go rename to aitools/lib/middlewares/warehouse.go index fc42c2d03c..a77b68e155 100644 --- a/experimental/aitools/lib/middlewares/warehouse.go +++ b/aitools/lib/middlewares/warehouse.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/databricks/cli/experimental/aitools/lib/session" + "github.com/databricks/cli/aitools/lib/session" "github.com/databricks/cli/libs/databrickscfg/cfgpickers" "github.com/databricks/cli/libs/env" "github.com/databricks/databricks-sdk-go" diff --git a/experimental/aitools/lib/session/session.go b/aitools/lib/session/session.go similarity index 100% rename from experimental/aitools/lib/session/session.go rename to aitools/lib/session/session.go diff --git a/experimental/aitools/lib/session/session_test.go b/aitools/lib/session/session_test.go similarity index 100% rename from experimental/aitools/lib/session/session_test.go rename to aitools/lib/session/session_test.go diff --git a/cmd/apps/init.go b/cmd/apps/init.go index 6e6ba2ccee..44d070360e 100644 --- a/cmd/apps/init.go +++ b/cmd/apps/init.go @@ -16,9 +16,9 @@ import ( "text/template" "github.com/charmbracelet/huh" + "github.com/databricks/cli/aitools/lib/agents" + "github.com/databricks/cli/aitools/lib/installer" "github.com/databricks/cli/cmd/root" - "github.com/databricks/cli/experimental/aitools/lib/agents" - "github.com/databricks/cli/experimental/aitools/lib/installer" "github.com/databricks/cli/libs/apps/generator" "github.com/databricks/cli/libs/apps/initializer" "github.com/databricks/cli/libs/apps/manifest" @@ -1135,7 +1135,7 @@ func runCreate(ctx context.Context, opts createOptions) error { // In flags mode, only print a hint — never prompt interactively. if flagsMode { if !agents.HasDatabricksSkillsInstalled(ctx) { - cmdio.LogString(ctx, "Tip: coding agents detected without Databricks skills. Run 'databricks experimental aitools skills install' to install them.") + cmdio.LogString(ctx, "Tip: coding agents detected without Databricks skills. Run 'databricks aitools skills install' to install them.") } } else if err := agents.RecommendSkillsInstall(ctx, installer.InstallAllSkills); err != nil { log.Warnf(ctx, "Skills recommendation failed: %v", err) diff --git a/cmd/cmd.go b/cmd/cmd.go index 54658f6639..10209bd640 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -4,8 +4,8 @@ import ( "context" "strings" + aitoolscmd "github.com/databricks/cli/aitools/cmd" "github.com/databricks/cli/cmd/psql" - aitoolscmd "github.com/databricks/cli/experimental/aitools/cmd" ssh "github.com/databricks/cli/experimental/ssh/cmd" "github.com/databricks/cli/cmd/account" diff --git a/cmd/experimental/experimental.go b/cmd/experimental/experimental.go index 1f8a2cf3e2..9ceccd79ed 100644 --- a/cmd/experimental/experimental.go +++ b/cmd/experimental/experimental.go @@ -3,7 +3,7 @@ package experimental import ( "fmt" - aitoolscmd "github.com/databricks/cli/experimental/aitools/cmd" + aitoolscmd "github.com/databricks/cli/aitools/cmd" "github.com/spf13/cobra" ) diff --git a/tools/testmask/targets.go b/tools/testmask/targets.go index f4566ea7d4..6d88689729 100644 --- a/tools/testmask/targets.go +++ b/tools/testmask/targets.go @@ -27,7 +27,7 @@ var fileTargetMappings = []targetMapping{ }, { prefixes: slices.Concat(commonTriggerPatterns, []string{ - "experimental/aitools/", + "aitools/", }), target: "test-exp-aitools", }, From 1676327ffa1c85b9f9568ef414287dc0ab40cf62 Mon Sep 17 00:00:00 2001 From: James Broadhead Date: Tue, 28 Apr 2026 20:32:52 +0000 Subject: [PATCH 6/8] fix: chain root PersistentPreRunE on aitools alias Defining PersistentPreRunE on the deprecated aitools alias shadowed the root command's hook (cobra's default EnableTraverseRunHooks=false walks up and stops at the first one). Subcommands of 'databricks experimental aitools' lost their cmdio/log/user-agent init and panicked with "no cmdIO found in the context". Chain to the root hook explicitly so the deprecation warning still prints and the rest of CLI initialization runs. Reproducer (before): 'databricks experimental aitools version' panics. After: prints warning, then version output. Co-authored-by: Isaac --- cmd/experimental/experimental.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/cmd/experimental/experimental.go b/cmd/experimental/experimental.go index 9ceccd79ed..2c959a678e 100644 --- a/cmd/experimental/experimental.go +++ b/cmd/experimental/experimental.go @@ -27,11 +27,19 @@ development. They may change or be removed in future versions without notice.`, // `Deprecated` field only fires for the specific command it's set on, so // running 'databricks experimental aitools install' would skip the warning // — use a PersistentPreRunE that runs for every subcommand below the alias. + // + // Cobra walks up the parent chain and runs the FIRST PersistentPreRunE it + // finds, so defining one here would shadow the root's IO/log/user-agent + // initialization (cmd/root/root.go) and panic with "no cmdIO found in the + // context". Chain to the root hook explicitly to preserve setup. aitoolsAlias := aitoolscmd.NewAitoolsCmd() aitoolsAlias.Hidden = true aitoolsAlias.Deprecated = "use 'databricks aitools' instead" - aitoolsAlias.PersistentPreRunE = func(c *cobra.Command, _ []string) error { + aitoolsAlias.PersistentPreRunE = func(c *cobra.Command, args []string) error { fmt.Fprintln(c.ErrOrStderr(), "Warning: 'databricks experimental aitools' is deprecated; use 'databricks aitools' instead.") + if root := c.Root(); root.PersistentPreRunE != nil { + return root.PersistentPreRunE(c, args) + } return nil } cmd.AddCommand(aitoolsAlias) From df1290273e36cddd50254815b68939164beddb23 Mon Sep 17 00:00:00 2001 From: James Broadhead Date: Wed, 29 Apr 2026 15:18:58 +0000 Subject: [PATCH 7/8] Add NEXT_CHANGELOG entry for aitools promotion Co-authored-by: Isaac --- NEXT_CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index 00152d550e..44c82a3fcd 100644 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -4,6 +4,8 @@ ### CLI +* Promote `aitools` from `databricks experimental aitools` to top-level `databricks aitools`. The old `experimental aitools` path remains as a hidden, deprecated alias and prints a deprecation warning. + ### Bundles ### Dependency updates From c1b87a6b103d7a4042d5020c12183953a171d630 Mon Sep 17 00:00:00 2001 From: James Broadhead Date: Wed, 29 Apr 2026 15:40:49 +0000 Subject: [PATCH 8/8] Un-promote aitools tools subtree (keep under experimental) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The skills-management surface (install/update/uninstall/list/version/skills) graduates to top-level `databricks aitools`. The `tools` subtree (query/discover-schema/get-default-warehouse/statement) keeps its "no stability guarantees" disclaimer per `tools.go`, so it stays under `databricks experimental aitools tools` for now. The deprecation warning under `experimental aitools` fires for the skills surface (which has a top-level replacement) but NOT for `tools` subcommands (no top-level alternative exists). Cobra picks the nearest ancestor's PersistentPreRunE, so attaching tools with its own non-warning hook overrides the alias's warning hook for tools-rooted invocations. - aitools/cmd/aitools.go: drop tools wiring; export NewToolsCmd - cmd/experimental/experimental.go: attach tools to alias with non-warning PreRunE that still chains to root - aitools/cmd/{query,discover_schema,get_default_warehouse,statement_*}.go: revert example strings back to `experimental aitools tools …` - aitools/README.md: split into stable (skills) and experimental (tools) sections - NEXT_CHANGELOG.md: clarify which surface graduates Co-authored-by: Isaac --- NEXT_CHANGELOG.md | 2 +- aitools/README.md | 107 ++++++++++++++++----------- aitools/cmd/aitools.go | 16 +++- aitools/cmd/discover_schema.go | 4 +- aitools/cmd/get_default_warehouse.go | 4 +- aitools/cmd/query.go | 14 ++-- aitools/cmd/statement_cancel.go | 2 +- aitools/cmd/statement_get.go | 2 +- aitools/cmd/statement_status.go | 2 +- aitools/cmd/statement_submit.go | 4 +- cmd/experimental/experimental.go | 27 ++++++- 11 files changed, 116 insertions(+), 68 deletions(-) diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index 44c82a3fcd..7d575bb10f 100644 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -4,7 +4,7 @@ ### CLI -* Promote `aitools` from `databricks experimental aitools` to top-level `databricks aitools`. The old `experimental aitools` path remains as a hidden, deprecated alias and prints a deprecation warning. +* Promote the aitools skills-management surface (`install`, `update`, `uninstall`, `list`, `version`, `skills`) from `databricks experimental aitools` to top-level `databricks aitools`. The old `experimental aitools` path remains as a hidden, deprecated alias for these commands and prints a deprecation warning. The `tools` subtree (`query`, `discover-schema`, `get-default-warehouse`, `statement …`) stays under `databricks experimental aitools tools` for now and does not warn. ### Bundles diff --git a/aitools/README.md b/aitools/README.md index 59d2464140..404a44823c 100644 --- a/aitools/README.md +++ b/aitools/README.md @@ -2,52 +2,71 @@ `databricks aitools` exposes commands for coding-agent workflows. -Current commands: +Two surfaces with different stability tiers: + +- **`databricks aitools …`** (top-level) — skills management. Stable. +- **`databricks experimental aitools tools …`** — workspace helpers used by + AI agents. Still experimental; commands and output may change. + +## Skills management (stable) + +Top-level commands for installing and managing Databricks skills in detected +coding agents: -- `databricks aitools skills list` -- `databricks aitools skills install [skill-name]` - `databricks aitools install [skill-name]` -- `databricks aitools tools query` -- `databricks aitools tools discover-schema` -- `databricks aitools tools get-default-warehouse` -- `databricks aitools tools statement submit` -- `databricks aitools tools statement get` -- `databricks aitools tools statement status` -- `databricks aitools tools statement cancel` - -Current behavior: - -- `skills install` installs Databricks skills for detected coding agents. -- `install` is a compatibility alias for `skills install`. -- `tools` exposes a small set of AI-oriented workspace helpers. -- `tools query` accepts a single SQL or multiple SQLs in one invocation. Pass - several positional arguments and/or repeat `--file` to run them in parallel - against the warehouse. Multi-query output is always JSON; control parallelism - with `--concurrency` (default 8). - - ```bash - databricks aitools tools query \ - --warehouse --output json \ - "SELECT count(*) FROM samples.nyctaxi.trips" \ - "SELECT min(tpep_pickup_datetime), max(tpep_pickup_datetime) FROM samples.nyctaxi.trips" \ - "SELECT vendor_id, count(*) FROM samples.nyctaxi.trips GROUP BY 1" - ``` - -- `tools statement` is a low-level lifecycle for asynchronous statements. - `submit` returns a `statement_id` immediately, `get` polls until terminal - and emits rows, `status` peeks without blocking, and `cancel` requests - termination. Ctrl+C on `get` stops polling but does NOT cancel the - server-side statement; use `cancel` for that. - - ```bash - SID=$(databricks aitools tools statement submit \ - --warehouse "SELECT pg_sleep(5)" | jq -r '.statement_id') - databricks aitools tools statement status "$SID" - databricks aitools tools statement get "$SID" - ``` - -Removed behavior: +- `databricks aitools update` +- `databricks aitools uninstall` +- `databricks aitools list` +- `databricks aitools version` + +The hidden `databricks aitools skills {list,install}` subgroup exists as a +backward-compatibility alias for the flat top-level commands. + +## Tools (experimental) + +These commands live under `databricks experimental aitools tools` and are +optimized for AI coding agents like Claude Code and Cursor. Names and output +shapes can change. + +- `databricks experimental aitools tools query` +- `databricks experimental aitools tools discover-schema` +- `databricks experimental aitools tools get-default-warehouse` +- `databricks experimental aitools tools statement submit` +- `databricks experimental aitools tools statement get` +- `databricks experimental aitools tools statement status` +- `databricks experimental aitools tools statement cancel` + +### `tools query` + +Accepts a single SQL or multiple SQLs in one invocation. Pass several +positional arguments and/or repeat `--file` to run them in parallel against the +warehouse. Multi-query output is always JSON; control parallelism with +`--concurrency` (default 8). + +```bash +databricks experimental aitools tools query \ + --warehouse --output json \ + "SELECT count(*) FROM samples.nyctaxi.trips" \ + "SELECT min(tpep_pickup_datetime), max(tpep_pickup_datetime) FROM samples.nyctaxi.trips" \ + "SELECT vendor_id, count(*) FROM samples.nyctaxi.trips GROUP BY 1" +``` + +### `tools statement` + +Low-level lifecycle for asynchronous statements. `submit` returns a +`statement_id` immediately, `get` polls until terminal and emits rows, `status` +peeks without blocking, and `cancel` requests termination. Ctrl+C on `get` +stops polling but does NOT cancel the server-side statement; use `cancel` for +that. + +```bash +SID=$(databricks experimental aitools tools statement submit \ + --warehouse "SELECT pg_sleep(5)" | jq -r '.statement_id') +databricks experimental aitools tools statement status "$SID" +databricks experimental aitools tools statement get "$SID" +``` + +## Removed behavior - there is no MCP server under `aitools` - the old `deploy` and `validate` flows were removed -- command names and behavior in this area may still change diff --git a/aitools/cmd/aitools.go b/aitools/cmd/aitools.go index d110401c00..0d99dcd986 100644 --- a/aitools/cmd/aitools.go +++ b/aitools/cmd/aitools.go @@ -4,6 +4,11 @@ import ( "github.com/spf13/cobra" ) +// NewAitoolsCmd builds the skills-management surface — install, update, +// uninstall, list, version, and the (hidden) skills alias group. The `tools` +// subtree is intentionally not attached here: it remains under +// `databricks experimental aitools tools` until it graduates separately. See +// NewToolsCmd. func NewAitoolsCmd() *cobra.Command { cmd := &cobra.Command{ Use: "aitools", @@ -12,8 +17,7 @@ func NewAitoolsCmd() *cobra.Command { Provides commands to: - Install the AI tools in coding agents (install) -- Manage skills (skills) -- Access tools directly (tools)`, +- Manage skills (skills)`, } cmd.AddCommand(newInstallCmd()) @@ -22,7 +26,13 @@ Provides commands to: cmd.AddCommand(newListCmd()) cmd.AddCommand(newVersionCmd()) cmd.AddCommand(newSkillsCmd()) - cmd.AddCommand(newToolsCmd()) return cmd } + +// NewToolsCmd exposes the experimental tools subtree (query, discover-schema, +// get-default-warehouse, statement) so wrappers can attach it under their own +// parent. Currently only `databricks experimental aitools tools`. +func NewToolsCmd() *cobra.Command { + return newToolsCmd() +} diff --git a/aitools/cmd/discover_schema.go b/aitools/cmd/discover_schema.go index a127b02682..6110505ccc 100644 --- a/aitools/cmd/discover_schema.go +++ b/aitools/cmd/discover_schema.go @@ -114,8 +114,8 @@ many tables you pass in. On Ctrl+C, in-flight statements are cancelled server-side via CancelExecution before the command exits.`, - Example: ` databricks aitools tools discover-schema samples.nyctaxi.trips - databricks aitools tools discover-schema catalog.schema.table1 catalog.schema.table2`, + Example: ` databricks experimental aitools tools discover-schema samples.nyctaxi.trips + databricks experimental aitools tools discover-schema catalog.schema.table1 catalog.schema.table2`, Args: cobra.MinimumNArgs(1), PreRunE: func(cmd *cobra.Command, args []string) error { if concurrency <= 0 { diff --git a/aitools/cmd/get_default_warehouse.go b/aitools/cmd/get_default_warehouse.go index 9c853932ee..e2c0440b87 100644 --- a/aitools/cmd/get_default_warehouse.go +++ b/aitools/cmd/get_default_warehouse.go @@ -26,11 +26,11 @@ The command auto-detects an available warehouse unless DATABRICKS_WAREHOUSE_ID i Returns warehouse ID of the default warehouse. Use --output json to get the full warehouse info including name and state.`, Example: ` # Get warehouse ID in text format (default) - databricks aitools tools get-default-warehouse + databricks experimental aitools tools get-default-warehouse # Output: abc123def456... # Get full warehouse info including name and state in JSON format - databricks aitools tools get-default-warehouse --output json + databricks experimental aitools tools get-default-warehouse --output json # Output: {"id":"abc123def456...","name":"My Warehouse","state":"RUNNING"}`, Args: cobra.NoArgs, PreRunE: root.MustWorkspaceClient, diff --git a/aitools/cmd/query.go b/aitools/cmd/query.go index 1d219d5717..8b9504d4ab 100644 --- a/aitools/cmd/query.go +++ b/aitools/cmd/query.go @@ -102,13 +102,13 @@ or the DATABRICKS_WAREHOUSE_ID environment variable is configured. For a single query, output is JSON in non-interactive contexts. In interactive terminals it renders tables, and large results open an interactive table browser. Use --output csv to export results as CSV.`, - Example: ` databricks aitools tools query "SELECT * FROM samples.nyctaxi.trips LIMIT 5" - databricks aitools tools query --warehouse abc123 "SELECT 1" - databricks aitools tools query --file report.sql - databricks aitools tools query report.sql - databricks aitools tools query --output csv "SELECT * FROM samples.nyctaxi.trips LIMIT 5" - databricks aitools tools query --output json "SELECT 1" "SELECT 2" "SELECT 3" - echo "SELECT 1" | databricks aitools tools query`, + Example: ` databricks experimental aitools tools query "SELECT * FROM samples.nyctaxi.trips LIMIT 5" + databricks experimental aitools tools query --warehouse abc123 "SELECT 1" + databricks experimental aitools tools query --file report.sql + databricks experimental aitools tools query report.sql + databricks experimental aitools tools query --output csv "SELECT * FROM samples.nyctaxi.trips LIMIT 5" + databricks experimental aitools tools query --output json "SELECT 1" "SELECT 2" "SELECT 3" + echo "SELECT 1" | databricks experimental aitools tools query`, Args: cobra.ArbitraryArgs, PreRunE: func(cmd *cobra.Command, args []string) error { if concurrency <= 0 { diff --git a/aitools/cmd/statement_cancel.go b/aitools/cmd/statement_cancel.go index 81ee53c271..1774b7abe6 100644 --- a/aitools/cmd/statement_cancel.go +++ b/aitools/cmd/statement_cancel.go @@ -18,7 +18,7 @@ func newStatementCancelCmd() *cobra.Command { API returns no body on cancel; this command optimistically reports state=CANCELED on success. Use 'statement status' afterwards to confirm the server-side state if you need certainty.`, - Example: ` databricks aitools tools statement cancel 01ef...`, + Example: ` databricks experimental aitools tools statement cancel 01ef...`, Args: cobra.ExactArgs(1), PreRunE: root.MustWorkspaceClient, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/aitools/cmd/statement_get.go b/aitools/cmd/statement_get.go index 9d7c8ef11b..617b5c274d 100644 --- a/aitools/cmd/statement_get.go +++ b/aitools/cmd/statement_get.go @@ -21,7 +21,7 @@ Ctrl+C stops polling but does NOT cancel the server-side statement. Use 'statement cancel ' to terminate explicitly. (This differs from 'tools query', which cancels server-side on Ctrl+C because the user invoked the synchronous path.)`, - Example: ` databricks aitools tools statement get 01ef...`, + Example: ` databricks experimental aitools tools statement get 01ef...`, Args: cobra.ExactArgs(1), PreRunE: root.MustWorkspaceClient, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/aitools/cmd/statement_status.go b/aitools/cmd/statement_status.go index 3e6dd0f860..9981f49aa6 100644 --- a/aitools/cmd/statement_status.go +++ b/aitools/cmd/statement_status.go @@ -17,7 +17,7 @@ func newStatementStatusCmd() *cobra.Command { Long: `Single GET against the Statements API. Use this to peek at progress without blocking. For a blocking poll-until-terminal call, use 'statement get'.`, - Example: ` databricks aitools tools statement status 01ef...`, + Example: ` databricks experimental aitools tools statement status 01ef...`, Args: cobra.ExactArgs(1), PreRunE: root.MustWorkspaceClient, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/aitools/cmd/statement_submit.go b/aitools/cmd/statement_submit.go index 0cf078222b..ac8bf424e5 100644 --- a/aitools/cmd/statement_submit.go +++ b/aitools/cmd/statement_submit.go @@ -28,8 +28,8 @@ statement_id immediately, without waiting for results. The statement keeps running server-side. Harvest results with 'statement get ', inspect with 'statement status ', or stop with 'statement cancel '.`, - Example: ` databricks aitools tools statement submit "SELECT pg_sleep(60)" --warehouse - databricks aitools tools statement submit --file query.sql`, + Example: ` databricks experimental aitools tools statement submit "SELECT pg_sleep(60)" --warehouse + databricks experimental aitools tools statement submit --file query.sql`, Args: cobra.MaximumNArgs(1), PreRunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() diff --git a/cmd/experimental/experimental.go b/cmd/experimental/experimental.go index 2c959a678e..c3b3b3e76e 100644 --- a/cmd/experimental/experimental.go +++ b/cmd/experimental/experimental.go @@ -23,10 +23,15 @@ development. They may change or be removed in future versions without notice.`, } // Keep aitools under experimental as a hidden backward-compatibility alias. - // The primary command is now registered at the top level. Cobra's - // `Deprecated` field only fires for the specific command it's set on, so - // running 'databricks experimental aitools install' would skip the warning - // — use a PersistentPreRunE that runs for every subcommand below the alias. + // The skills-management surface (install/update/uninstall/list/version/skills) + // is now registered at the top level; the deprecation warning steers users + // to it. The `tools` subtree (query/discover-schema/get-default-warehouse/ + // statement) is NOT promoted yet and only lives here, so it must not warn. + // + // Cobra's `Deprecated` field only fires for the specific command it's set + // on, so running 'databricks experimental aitools install' would skip the + // warning — use a PersistentPreRunE that runs for every subcommand below + // the alias. // // Cobra walks up the parent chain and runs the FIRST PersistentPreRunE it // finds, so defining one here would shadow the root's IO/log/user-agent @@ -42,6 +47,20 @@ development. They may change or be removed in future versions without notice.`, } return nil } + + // `tools` is the only home for the experimental tools subtree, so attach + // it here with its own PersistentPreRunE that chains to root WITHOUT + // printing the deprecation warning. Cobra picks the nearest ancestor's + // hook, so this overrides the alias's warning for tools subcommands. + toolsCmd := aitoolscmd.NewToolsCmd() + toolsCmd.PersistentPreRunE = func(c *cobra.Command, args []string) error { + if root := c.Root(); root.PersistentPreRunE != nil { + return root.PersistentPreRunE(c, args) + } + return nil + } + aitoolsAlias.AddCommand(toolsCmd) + cmd.AddCommand(aitoolsAlias) cmd.AddCommand(newWorkspaceOpenCommand())