[1/5] Aitools: state tracking, manifest source, directory rename#4810
[1/5] Aitools: state tracking, manifest source, directory rename#4810simonfaltum merged 7 commits intomainfrom
Conversation
…tory Add state types (InstallState) with atomic load/save persistence, path resolution (GlobalSkillsDir, ProjectSkillsDir stub), ManifestSource interface with GitHub implementation, latest release discovery (FetchLatestRelease), and Clock abstraction. Extend SkillMeta with v2 fields (Experimental, Description, MinCLIVer). Refactor FetchManifest to delegate to GitHubManifestSource. Rename canonical skills directory from .databricks/agent-skills to .databricks/aitools/skills with backward-compat check for the old path. Co-authored-by: Isaac
- Rename SkillsRef->Release, LastChecked->LastUpdated (time.Time), simplify Skills to map[string]string, add IncludeExperimental and Scope fields. - Remove unused Clock/RealClock from source.go. - Add trailing newline to SaveState JSON output. - Improve FetchLatestRelease doc comment on error/fallback contract. - Document intentional DATABRICKS_SKILLS_REF duplication. Co-authored-by: Isaac
Suggested reviewersBased on git history of the changed files, these people are best suited to review:
Confidence: high Eligible reviewersBased on CODEOWNERS, these people or teams could also review: @databricks/eng-apps-devex, @lennartkats-db Suggestions based on git history of 6 changed files (3 scored). See CODEOWNERS for path-specific ownership rules. |
arsenyinfo
left a comment
There was a problem hiding this comment.
From my understanding, after these changes we're always pulling latest skills rather than pinned version - is it intentional?
Other than that, given the new canonical path, I'd advocate for migration mechanism when installer is triggered
|
re Migration: I don't think we should be adding migration for the directory rename. This is an experimental feature with a small number of users who opted in. HasDatabricksSkillsInstalled() already detects both old and new paths, so we can surface a "please reinstall" message when we detect the old path. I don't think we really need a migration at this stage |
Skills version is pinned at CLI build time via defaultSkillsRepoRef. No need to call the GitHub releases API for version discovery. Co-authored-by: Isaac
|
Commit: ead07cf |
…mpotent install (#4811) ## PR Stack 1. [1/5] State + release discovery + directory rename (#4810) 2. **[2/5] Install writes state + interactive agent selection** (this PR) 3. [3/5] Update + uninstall + version commands (#4812) 4. [4/5] List improvements + command restructuring + flags (#4813) 5. [5/5] Project scope (--project/--global) (pending) **Base**: `simonfaltum/aitools-pr1-state` (PR 1) ## Why Install currently has no state tracking, no filtering, and outputs every file download to the console. Users can't tell what version they have, and there's no way to install for specific agents. ## Changes Before: `skills install` downloads everything, prints every file, has no state, no filtering, no agent selection. Now: - `InstallSkillsForAgents(ctx, src, agents, opts)` as the core install function. `InstallAllSkills` becomes a thin wrapper (signature preserved for `cmd/apps/init.go` compat). - State written to `.state.json` after successful install. Merges with existing state (doesn't overwrite). - Idempotent: second install skips already-present skills with matching versions. - Experimental filtering: skip `experimental: true` skills by default. - `min_cli_version` enforcement: skip incompatible skills with warning (hard error for single-skill install). - Interactive agent selection via `charmbracelet/huh` multi-select. Skip prompt for 1 agent, all detected for non-interactive. - Legacy install detection: prints "reinstall" message when old install found without state. - Concise default output (2 lines). Per-file detail only at debug level. ## Test plan - [x] State created after install-all and install-single - [x] Experimental filtering (skip by default, include with flag) - [x] min_cli_version: warning for all, hard error for single - [x] Idempotent: skip same version, update changed - [x] Legacy detection with helpful message - [x] Interactive prompt for 2+ agents, skip for 1 - [x] Non-interactive: all detected, no prompt - [x] `InstallAllSkills` signature preserved - [x] Concise output, per-file at debug level
## PR Stack 1. [1/5] State + release discovery + directory rename (#4810) 2. [2/5] Install writes state + interactive agent selection (#4811) 3. **[3/5] Update + uninstall + version commands** (this PR) 4. [4/5] List improvements + command restructuring + flags (#4813) 5. [5/5] Project scope (--project/--global) (pending) **Base**: `simonfaltum/aitools-pr2-install` (PR 2) ## Why Users can install skills but can't update, uninstall, or check what version they have. These are core lifecycle gaps. ## Changes Three new commands, each small but grouped because they share patterns. **`aitools update`**: Compares installed release against latest. Downloads changed skills. Flags: `--check` (dry run), `--force` (re-download), `--no-new` (don't auto-add new manifest skills). Authoritative release detection (distinguishes real API response from fallback). Applies experimental and min_cli_version filtering. Warns on skills removed from manifest. **`aitools uninstall`**: Removes skill directories from canonical location. Removes symlinks from ALL agent directories (full registry scan, not just detected). Cleans orphaned symlinks. Only removes symlinks pointing to canonical dir (safe for third-party skills). Deletes `.state.json` on success. **`aitools version`**: Shows installed version, skill count, last updated date. Best-effort staleness check against latest release. Graceful offline degradation. Suppresses staleness check when `DATABRICKS_SKILLS_REF` is set. ## Test plan - [x] Update: no state -> error, already up to date, version diff, check dry run, force, no-new, new skill auto-installed, removed skill warning - [x] Uninstall: removes dirs + symlinks, orphan cleanup, state deletion, no state -> error, missing dirs handled - [x] Version: installed/up-to-date, update available, not installed, offline graceful - [x] All lint checks pass
…ude-experimental flags (#4813) ## PR Stack 1. [1/5] State + release discovery + directory rename (#4810) 2. [2/5] Install writes state + interactive agent selection (#4811) 3. [3/5] Update + uninstall + version commands (#4812) 4. **[4/5] List improvements + command restructuring + flags** (this PR) 5. [5/5] Project scope (--project/--global) (#4814) Manifest v2 PR: databricks/databricks-agent-skills#35 **Base**: `simonfaltum/aitools-pr3-lifecycle` (PR 3) ## Why Commands are nested under `skills` which burns namespace for future component types (hooks, etc.). There's no way to install specific skills, target specific agents from the CLI, or see installed status in the list output. ## Changes **New `list` command**: Table output with skill names, versions, installed status, `[experimental]` tags. Sorted alphabetically. Uses `tabwriter` for alignment. **Flat command structure**: `aitools install/update/uninstall/list/version` at the top level. Hidden `skills install` and `skills list` aliases for backward compat. **Flags**: - `--skills` (string, comma-separated) on install, update, uninstall: operate on specific skills - `--skills` (bool) on list, version: show detailed skills view - `--agents` (string, comma-separated) on install: target specific agents, validates against registry, skips interactive prompt - `--include-experimental` on install: include experimental skills **Selective uninstall**: `--skills` on uninstall removes only named skills, preserves state file with remaining. ## Test plan - [x] `install --skills`, `--agents`, `--include-experimental` flags work - [x] `--agents` validates against registry, errors on unknown - [x] `uninstall --skills` selective removal, state preserved - [x] `update --skills` selective update - [x] `list` shows detailed table - [x] `skills install` and `skills list` hidden aliases work (Execute path tested) - [x] `cmd/apps/init.go` integration preserved - [x] All lint checks pass
## PR Stack 1. [1/5] State + release discovery + directory rename (#4810) 2. [2/5] Install writes state + interactive agent selection (#4811) 3. [3/5] Update + uninstall + version commands (#4812) 4. [4/5] List improvements + command restructuring + flags (#4813) 5. **[5/5] Project scope (--project/--global)** (this PR) Manifest v2 PR: databricks/databricks-agent-skills#35 **Base**: `simonfaltum/aitools-pr4-restructure` (PR 4) ## Why Skills are currently global-only. Teams working on the same project can't share a curated set of skills via their repo. Project-scoped installation puts skills alongside the code, so they can be committed to git and shared. ## Changes Before: All skills install to `~/.databricks/aitools/skills/` (global only). Now: - `--project` flag on install, update, uninstall: operates on `<cwd>/.databricks/aitools/skills/` - `--global` flag: explicit global scope (default behavior) - `--global` + `--project` -> error - Interactive scope prompt on install (default: global). Uses `huh.NewSelect` in cmd layer. - Non-interactive defaults to global. - `SupportsProjectScope` field on `Agent` struct. Only Claude Code and Cursor support project scope. - Incompatible agents get a warning, not an error: "Skipped <agent>: does not support project-scoped skills." - Version shows both scopes when both exist. - State includes `scope: "project"` field for project installs. ## Test plan - [x] `--project` installs to cwd-relative directory - [x] `--global` + `--project` -> error - [x] No flag, interactive -> scope prompt shown, default is global - [x] No flag, non-interactive -> global (no prompt) - [x] Incompatible agents warned, not errored - [x] Symlinks only created for capable agents in project scope - [x] Version shows both scopes when both exist - [x] `SupportsProjectScope` set correctly for all 6 agents - [x] All lint checks pass
PR Stack
This is part of the aitools feature-complete initiative. PRs should be reviewed and merged in order.
Manifest v2 PR: (pending in databricks-agent-skills)
Why
The aitools skills installer has no state tracking. There's no record of what was installed, at what version, or when. This blocks every lifecycle command (update, uninstall, version). The manifest fetching logic is also hardcoded with no abstraction for testing.
Changes
Before: Skills install to
~/.databricks/agent-skills/with no state file.FetchManifestis inlined ininstaller.gowith a hardcoded ref and no way to mock it in tests.Now:
InstallStatetype withLoadState/SaveState(atomic write via temp+rename) for tracking installed skills, release ref, and timestampsManifestSourceinterface withGitHubManifestSource, separating manifest fetching from install logic. Enables test mocking.FetchLatestReleaseto discover newest release from GitHub API. Falls back to pinned ref on network failure.SkillMeta(Experimental,Description,MinCLIVer) with omitempty for backward compat with v1 manifests.databricks/agent-skillsto.databricks/aitools/skillsHasDatabricksSkillsInstalledfor the old pathNo behavior changes to existing commands except the directory path.
Test plan
LoadStatereturns nil, nil for nonexistent fileSaveState+LoadStateroundtrip preserves all fields including optional onesSaveStatecreates nested directories, writes trailing newlineLoadStatereturns error for corrupt JSONGlobalSkillsDirresolves correctlyProjectSkillsDirreturns ErrNotImplementedHasDatabricksSkillsInstalleddetects legacy path