Skip to content

Commit d7d005f

Browse files
committed
feat: move cli-compat manifest to CLI repo with 3-tier fallback
Move cli-compat.json from the AppKit repo to internal/build/ in the CLI repo. This simplifies the architecture: - Embed the full manifest via go:embed (no build-time resolution tool) - Drop the pindepversions build hook and dep_versions.json - Replace the cache library with simple file-based local caching The manifest is now resolved with a 3-tier fallback: 1. Fresh local cache (< 1h old) 2. Remote fetch from GitHub (with retry) 3. Stale local cache (if remote fails) 4. Embedded manifest (compiled into binary) Also: - Add OWNERS entries for cli-compat.json and libs/depversions/ - Add internal/build/README.md documenting the manifest - Add bump-cli-compat Claude Code skill for updating versions - Add comprehensive tests for the fallback chain and manifest validation Signed-off-by: Pawel Kosiec <pawel.kosiec@databricks.com>
1 parent 62b8645 commit d7d005f

11 files changed

Lines changed: 489 additions & 126 deletions

File tree

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
---
2+
name: bump-cli-compat
3+
description: "Bump cli-compat.json with new AppKit and Agent Skills versions, then create a PR. Use when the user says 'bump cli-compat', 'update cli-compat', 'bump compatibility manifest', 'new appkit release cli-compat', or wants to update the CLI compatibility manifest after an AppKit or Agent Skills release."
4+
user-invocable: true
5+
allowed-tools: Read, Edit, Write, Bash, Glob, Grep, AskUserQuestion
6+
---
7+
8+
# Bump CLI Compatibility Manifest
9+
10+
Updates `internal/build/cli-compat.json` with new AppKit and Agent Skills versions, validates the result, and creates a PR.
11+
12+
## Arguments
13+
14+
Parse the user's input for optional version arguments:
15+
16+
- `--appkit <version>` or first positional arg → AppKit version (e.g. `0.28.0`)
17+
- `--skills <version>` or second positional arg → Agent Skills version (e.g. `0.1.6`)
18+
- No args → auto-detect latest versions from GitHub tags
19+
20+
Versions should be provided **without** the `v` prefix (e.g. `0.28.0`, not `v0.28.0`). If provided with the prefix, strip it.
21+
22+
## Workflow
23+
24+
### Step 1: Resolve versions
25+
26+
If both `appkit` and `skills` versions were provided as arguments, skip to Step 2.
27+
28+
Otherwise, fetch the latest tags from GitHub:
29+
30+
```bash
31+
# Latest appkit version (strip leading 'v')
32+
gh api repos/databricks/appkit/tags --jq '.[0].name' | sed 's/^v//'
33+
34+
# Latest skills version (strip leading 'v')
35+
gh api repos/databricks/databricks-agent-skills/tags --jq '.[0].name' | sed 's/^v//'
36+
```
37+
38+
Show the resolved versions to the user and ask:
39+
40+
> The latest versions are:
41+
> - AppKit: `{appkit_version}`
42+
> - Agent Skills: `{skills_version}`
43+
>
44+
> Have these versions been evaluated (evals passed with no regressions)?
45+
46+
**Do NOT proceed until the user confirms.** If the user says no or wants different versions, ask them to provide the correct versions.
47+
48+
### Step 2: Validate tags exist
49+
50+
Verify that the corresponding Git tags exist on GitHub:
51+
52+
```bash
53+
gh api repos/databricks/appkit/git/ref/tags/v{appkit_version} --jq '.ref' 2>&1
54+
gh api repos/databricks/databricks-agent-skills/git/ref/tags/v{skills_version} --jq '.ref' 2>&1
55+
```
56+
57+
If either tag doesn't exist, report the error and stop.
58+
59+
### Step 3: Read current manifest
60+
61+
Read `internal/build/cli-compat.json`. Note the current versions and the list of versioned entries.
62+
63+
### Step 4: Update the manifest
64+
65+
Update **all entries** (both `next` and all versioned CLI entries) to the new appkit and skills versions. This is the "no template changes" scenario — a simple search & replace.
66+
67+
Write the updated `internal/build/cli-compat.json`.
68+
69+
### Step 5: Validate
70+
71+
Run the Go tests to ensure the manifest is well-formed:
72+
73+
```bash
74+
go test ./libs/depversions/... -run TestEmbeddedManifest -v
75+
```
76+
77+
If validation fails, show the errors and fix them before proceeding.
78+
79+
### Step 6: Create branch, commit, and PR
80+
81+
```bash
82+
# Create a new branch from the current branch (or main)
83+
git checkout -b bump-cli-compat-appkit-{appkit_version}-skills-{skills_version}
84+
85+
# Stage and commit
86+
git add internal/build/cli-compat.json
87+
git commit -s -m "chore: bump cli-compat to appkit {appkit_version}, skills {skills_version}"
88+
89+
# Push and create PR
90+
git push -u origin HEAD
91+
gh pr create \
92+
--title "chore: bump cli-compat to appkit {appkit_version}, skills {skills_version}" \
93+
--body "$(cat <<'EOF'
94+
## Summary
95+
Bump `cli-compat.json` to use:
96+
- AppKit `{appkit_version}`
97+
- Agent Skills `{skills_version}`
98+
99+
## Checklist
100+
- [ ] Evals passed with no regressions
101+
- [ ] `go test ./libs/depversions/... -run TestEmbeddedManifest` passes
102+
EOF
103+
)"
104+
```
105+
106+
Show the PR URL to the user when done.
107+
108+
## Examples
109+
110+
### Example: With explicit versions
111+
```
112+
/bump-cli-compat 0.28.0 0.1.6
113+
```
114+
Validates tags exist, updates manifest, creates PR.
115+
116+
### Example: Auto-detect latest
117+
```
118+
/bump-cli-compat
119+
```
120+
Fetches latest tags, asks for eval confirmation, then updates and creates PR.
121+
122+
### Example: With flags
123+
```
124+
/bump-cli-compat --appkit 0.28.0 --skills 0.1.6
125+
```
126+
Same as positional args.

.github/OWNERS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,9 @@
5959
# Internal
6060
/internal/ team:platform
6161

62+
# CLI compatibility manifest
63+
/internal/build/cli-compat.json team:eng-apps-devex team:platform
64+
/libs/depversions/ team:eng-apps-devex team:platform
65+
6266
# Experimental
6367
/experimental/aitools/ team:eng-apps-devex @lennartkats-db

.goreleaser.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ version: 2
33
before:
44
hooks:
55
- go mod download
6-
- go run ./internal/pindepversions --version {{ .Version }}
76

87
builds:
98
- env:

cmd/apps/init.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import (
1919
"github.com/databricks/cli/cmd/root"
2020
"github.com/databricks/cli/experimental/aitools/lib/agents"
2121
"github.com/databricks/cli/experimental/aitools/lib/installer"
22-
"github.com/databricks/cli/internal/build"
2322
"github.com/databricks/cli/libs/apps/generator"
2423
"github.com/databricks/cli/libs/apps/initializer"
2524
"github.com/databricks/cli/libs/apps/manifest"
@@ -171,7 +170,7 @@ Environment variables:
171170
cmd.Flags().StringVar(&templatePath, "template", "", "Template path (local directory or GitHub URL)")
172171
cmd.Flags().StringVar(&branch, "branch", "", "Git branch or tag (for GitHub templates, mutually exclusive with --version)")
173172
versionDesc := "AppKit version to use (use 'latest' for main branch)"
174-
if v := build.GetDepVersions().AppKit; v != "" {
173+
if v := depversions.EmbeddedDefaultAppKitVersion(); v != "" {
175174
versionDesc = fmt.Sprintf("AppKit version to use (default: %s, use 'latest' for main branch)", v)
176175
}
177176
cmd.Flags().StringVar(&version, "version", "", versionDesc)

internal/build/README.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# CLI Compatibility Manifest
2+
3+
`cli-compat.json` maps Databricks CLI versions to compatible AppKit and Agent Skills versions. The CLI uses this manifest to determine which template version to use for `apps init` and which skills version to use for `aitools install`.
4+
5+
## Manifest format
6+
7+
```json
8+
{
9+
"next": { "appkit": "0.24.0", "skills": "0.1.4" },
10+
"0.299.0": { "appkit": "0.24.0", "skills": "0.1.4" }
11+
}
12+
```
13+
14+
- Each key is a CLI version (`X.Y.Z`) or `"next"`.
15+
- Each value specifies the compatible `appkit` and `skills` versions.
16+
- `"next"` is used for CLI versions newer than any listed entry and for dev builds.
17+
18+
## How the CLI resolves versions
19+
20+
1. **Exact match** on CLI version → use that entry.
21+
2. **No exact match**, between two entries → use the nearest lower version's entry.
22+
3. **Newer than all entries** → use the highest versioned entry.
23+
4. **Older than all entries** → use the lowest (oldest) entry.
24+
5. **Dev builds** (`0.0.0-dev*`) → use `"next"`.
25+
26+
## Manifest sources (fallback chain)
27+
28+
At runtime, the CLI resolves the manifest from three sources:
29+
30+
1. **Local cache** (`~/.cache/databricks/compat-manifest.json`) — used if fresh (< 1 hour old).
31+
2. **Remote fetch** from GitHub — used when cache is stale or missing. On success, the local cache is updated.
32+
3. **Stale local cache** — if remote fetch fails but a previously cached file exists (even if expired), it is used as-is.
33+
4. **Embedded manifest** — compiled into the binary via `go:embed`. Used as last resort when both remote and local cache fail.
34+
35+
## When to update
36+
37+
After each AppKit release:
38+
39+
1. **Run evals** on the new AppKit version. If there is no regression, proceed.
40+
2. **Open a PR** to update `cli-compat.json`. The change depends on the type of release:
41+
- **No template changes** (just an AppKit/skills version bump): search & replace all version occurrences in the manifest and update `next`.
42+
- **Template changes that don't require new CLI features**: test the last 3 CLI versions with the new template and update matching entries.
43+
- **Template changes that require new CLI features**: add a new entry for the minimum CLI version that supports them; older entries keep pointing to the previous template version.
44+
45+
This process is manual for now but can be automated as part of the release workflow in the future. Use the `/bump-cli-compat` Claude Code skill to automate the update and PR creation.
46+
47+
## Validation
48+
49+
The manifest is validated by Go tests in `libs/depversions/`:
50+
51+
```bash
52+
go test ./libs/depversions/... -run TestEmbeddedManifest -v
53+
```
54+
55+
This checks: valid JSON, `"next"` key present, at least one versioned entry, valid semver keys, `next` versions >= all entries, and ascending key order.

internal/build/cli-compat.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"next": { "appkit": "0.24.0", "skills": "0.1.4" },
3+
"0.299.0": { "appkit": "0.24.0", "skills": "0.1.4" }
4+
}

internal/build/dep_versions.go

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,9 @@
11
package build
22

3-
import (
4-
_ "embed"
5-
"encoding/json"
6-
"sync"
7-
)
3+
import _ "embed"
84

9-
//go:embed dep_versions.json
10-
var depVersionsJSON []byte
11-
12-
// DepVersions holds build-time resolved dependency versions.
13-
type DepVersions struct {
14-
AppKit string `json:"appkit"`
15-
AgentSkills string `json:"skills"`
16-
}
17-
18-
var depVersions = sync.OnceValue(func() DepVersions {
19-
var dv DepVersions
20-
_ = json.Unmarshal(depVersionsJSON, &dv)
21-
return dv
22-
})
23-
24-
// GetDepVersions returns the build-time resolved dependency versions.
25-
// Returns zero-value DepVersions if not set (dev builds).
26-
func GetDepVersions() DepVersions {
27-
return depVersions()
28-
}
5+
// EmbeddedManifestJSON is the cli-compat.json manifest embedded at compile time.
6+
// Used as the last-resort fallback when both remote fetch and local cache fail.
7+
//
8+
//go:embed cli-compat.json
9+
var EmbeddedManifestJSON []byte

internal/build/dep_versions.json

Lines changed: 0 additions & 1 deletion
This file was deleted.

internal/pindepversions/main.go

Lines changed: 0 additions & 46 deletions
This file was deleted.

0 commit comments

Comments
 (0)