Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .agent/skills/pr-checklist/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ Before submitting a PR, run these commands to match what CI checks. CI uses the
# 5. If you changed files in python/:
./task pydabs-codegen pydabs-test pydabs-lint pydabs-docs

# 6. If you changed experimental/aitools or experimental/ssh:
./task test-exp-aitools # only if aitools code changed
# 6. If you changed aitools/, experimental/aitools/, or experimental/ssh/:
./task test-exp-aitools # only if aitools code changed (top-level or experimental)
./task test-exp-ssh # only if ssh code changed
```

Expand Down
3 changes: 2 additions & 1 deletion .github/OWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,6 @@
# Internal
/internal/ team:platform

# Experimental
# AI tools
/aitools/ team:eng-apps-devex @lennartkats-db
/experimental/aitools/ team:eng-apps-devex @lennartkats-db
2 changes: 2 additions & 0 deletions NEXT_CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

### CLI

* Promote the aitools skills-management surface (`install`, `update`, `uninstall`, `list`, `version`) from `databricks experimental aitools` to top-level `databricks aitools`. The old paths under `databricks experimental aitools` continue to work as silent backward-compat aliases. The `tools` subtree (`query`, `discover-schema`, `get-default-warehouse`, `statement …`) and the `skills` alias group remain under `databricks experimental aitools`.

### Bundles

### Dependency updates
5 changes: 3 additions & 2 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -606,8 +606,9 @@ tasks:
# generic `test` target (the catch-all) instead.

test-exp-aitools:
desc: Run experimental aitools unit and acceptance tests
desc: Run aitools (top-level + experimental) unit and acceptance tests
sources:
- aitools/**
- experimental/aitools/**
- acceptance/apps/**
- "{{.EMBED_SOURCES}}"
Expand All @@ -616,7 +617,7 @@ tasks:
{{.GO_TOOL}} gotestsum \
--format ${GOTESTSUM_FORMAT:-pkgname-and-test-fails} \
--no-summary=skipped \
--packages ./experimental/aitools/... \
--packages "./aitools/... ./experimental/aitools/..." \
-- -timeout=${LOCAL_TIMEOUT:-30m}
- |
{{.GO_TOOL}} gotestsum \
Expand Down
1 change: 1 addition & 0 deletions acceptance/help/output.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
15 changes: 15 additions & 0 deletions aitools/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Databricks AI Tools

`databricks aitools` installs and manages Databricks skills for detected coding agents.

## Commands

- `databricks aitools install [skill-name]` (or `--skills <name>[,<name>...]` for multiple)
- `databricks aitools update`
- `databricks aitools uninstall`
- `databricks aitools list`
- `databricks aitools version`

Supported agents: Claude Code, Cursor, Codex CLI, OpenCode, GitHub Copilot, Antigravity.

The `tools` subtree (`query`, `discover-schema`, `get-default-warehouse`, `statement …`) and the `skills` alias group remain under `databricks experimental aitools` while their stability story is still in flux.
25 changes: 25 additions & 0 deletions aitools/cmd/aitools.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package aitools

import (
"github.com/spf13/cobra"
)

func NewAitoolsCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "aitools",
Short: "Databricks AI Tools for coding agents",
Long: `Manage Databricks AI Tools.

Provides commands to install, update, and manage Databricks skills for
detected coding agents (Claude Code, Cursor, Codex CLI, OpenCode, GitHub
Copilot, Antigravity).`,
}

cmd.AddCommand(NewInstallCmd())
cmd.AddCommand(NewUpdateCmd())
cmd.AddCommand(NewUninstallCmd())
cmd.AddCommand(NewListCmd())
cmd.AddCommand(NewVersionCmd())

return cmd
}
File renamed without changes.
File renamed without changes.
63 changes: 56 additions & 7 deletions experimental/aitools/cmd/install.go → aitools/cmd/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,59 @@ import (
"fmt"
"strings"

"github.com/databricks/cli/experimental/aitools/lib/agents"
"github.com/databricks/cli/experimental/aitools/lib/installer"
"github.com/charmbracelet/huh"
"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"
)

func newInstallCmd() *cobra.Command {
// PromptAgentSelection and InstallSkillsForAgentsFn are package-level for
// testability. They are exported so wrappers in other packages
// (experimental/aitools/cmd/skills.go) can override them in tests.
var (
PromptAgentSelection = defaultPromptAgentSelection
InstallSkillsForAgentsFn = installer.InstallSkillsForAgents
)

func defaultPromptAgentSelection(ctx context.Context, detected []*agents.Agent) ([]*agents.Agent, error) {
options := make([]huh.Option[string], 0, len(detected))
agentsByName := make(map[string]*agents.Agent, len(detected))
for _, a := range detected {
options = append(options, huh.NewOption(a.DisplayName, a.Name).Selected(true))
agentsByName[a.Name] = a
}

var selected []string
err := huh.NewMultiSelect[string]().
Title("Select coding agents to install skills for").
Description("space to toggle, enter to confirm").
Options(options...).
Value(&selected).
Run()
if err != nil {
return nil, err
}

if len(selected) == 0 {
return nil, errors.New("at least one agent must be selected")
}

result := make([]*agents.Agent, 0, len(selected))
for _, name := range selected {
result = append(result, agentsByName[name])
}
return result, nil
}

func NewInstallCmd() *cobra.Command {
var skillsFlag, agentsFlag string
var includeExperimental bool
var projectFlag, globalFlag bool

cmd := &cobra.Command{
Use: "install",
Use: "install [skill-name]",
Short: "Install AI skills for coding agents",
Long: `Install Databricks AI skills for detected coding agents.

Expand All @@ -28,11 +67,21 @@ Use --project to install to the current project directory instead.
When multiple agents are detected, skills are stored in a canonical location
and symlinked to each agent to avoid duplication.

Pass a single skill name as a positional argument to install just that skill,
or use --skills name1,name2 for multiple. The two forms are mutually exclusive.

Supported agents: Claude Code, Cursor, Codex CLI, OpenCode, GitHub Copilot, Antigravity`,
Args: cobra.NoArgs,
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()

if len(args) == 1 {
if skillsFlag != "" {
return errors.New("cannot use positional [skill-name] together with --skills; pick one")
}
skillsFlag = args[0]
}

// Resolve scope.
scope, err := resolveScopeWithPrompt(ctx, projectFlag, globalFlag)
if err != nil {
Expand Down Expand Up @@ -65,7 +114,7 @@ Supported agents: Claude Code, Cursor, Codex CLI, OpenCode, GitHub Copilot, Anti
case len(detected) == 1:
targetAgents = detected
case cmdio.IsPromptSupported(ctx):
targetAgents, err = promptAgentSelection(ctx, detected)
targetAgents, err = PromptAgentSelection(ctx, detected)
if err != nil {
return err
}
Expand All @@ -84,7 +133,7 @@ Supported agents: Claude Code, Cursor, Codex CLI, OpenCode, GitHub Copilot, Anti
installer.PrintInstallingFor(ctx, targetAgents)

src := &installer.GitHubManifestSource{}
return installSkillsForAgentsFn(ctx, src, targetAgents, opts)
return InstallSkillsForAgentsFn(ctx, src, targetAgents, opts)
},
}

Expand Down
Loading
Loading