Skip to content

Commit efb069b

Browse files
authored
docs: wire AppKit plugin CLI into create/audit/review Claude commands (#369)
1 parent 4ee02ce commit efb069b

8 files changed

Lines changed: 205 additions & 11 deletions

File tree

.claude/commands/audit-core-plugin.md

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ If **neither** path exists, stop and output:
2828
> - `packages/appkit/src/plugins/{PLUGIN_NAME}/`
2929
> - `packages/appkit/src/connectors/{PLUGIN_NAME}/`
3030
>
31-
> Available plugins can be listed with: `ls packages/appkit/src/plugins/`
31+
> Available plugins can be listed with: `npx @databricks/appkit plugin list --dir packages/appkit/src/plugins --json`
32+
> (Falls back to `ls packages/appkit/src/plugins/` if the CLI is unavailable.)
3233
3334
If at least one path exists, proceed.
3435

@@ -51,6 +52,37 @@ Read **all** files under:
5152

5253
Collect the full contents of every file. You need the complete source to evaluate all 9 categories.
5354

55+
## Step 3.5: CLI Cross-Checks
56+
57+
Before evaluating files by hand, run the AppKit CLI checks below and capture their output. Each result feeds into a specific category in Step 5; treat any non-zero exit as a finding under that category.
58+
59+
```bash
60+
# Schema-validates manifest.json against the plugin-manifest schema.
61+
# Failures → Category 1 (Manifest Design), severity MUST.
62+
npx @databricks/appkit plugin validate packages/appkit/src/plugins/{PLUGIN_NAME}
63+
64+
# Confirms the plugin is discoverable from the synced manifest with the expected
65+
# displayName, package, stability, and resource counts. Mismatches → Category 1
66+
# (Manifest Design) or Category 0 (Structural Completeness).
67+
npx @databricks/appkit plugin list --dir packages/appkit/src/plugins --json \
68+
| jq '.[] | select(.name == "{PLUGIN_NAME}")'
69+
70+
# Previews the template manifest the loader would emit (no --write).
71+
# Use the output to verify the plugin appears, that resources match manifest.json,
72+
# and that no warnings about orphaned resources / removed plugins are printed.
73+
# Sync-time warnings → Category 1 (Manifest Design), severity SHOULD unless the
74+
# plugin is missing entirely (then MUST).
75+
#
76+
# In the monorepo, --plugins-dir points sync at the source manifests (matching
77+
# the sync:template script). Without it, sync scans node_modules/@databricks/
78+
# appkit/dist/plugins/, which may be missing or stale.
79+
npx @databricks/appkit plugin sync --plugins-dir packages/appkit/src/plugins --json
80+
```
81+
82+
If `plugin validate` exits non-zero, record a MUST finding under Category 1 with the validator's error output as the description, and continue to Step 4 — the rest of the audit still applies.
83+
84+
If `packages/appkit/src/plugins/{PLUGIN_NAME}/` does not exist (connector-only package), skip the three CLI checks and proceed.
85+
5486
## Step 4: Structural Completeness Check
5587

5688
If `packages/appkit/src/plugins/{PLUGIN_NAME}/` does not exist (connector-only package), mark Structural Completeness as **N/A** in the scorecard and proceed to Step 5.
@@ -76,6 +108,12 @@ Treat each missing `MUST` file as a **MUST**-severity finding under the "Structu
76108

77109
Before evaluating, read the shared review rules in `.claude/references/plugin-review-guidance.md` and apply them throughout this step (deduplication, cache-key tracing).
78110

111+
Fold the Step 3.5 CLI results into the matching categories:
112+
- `plugin validate` failures → Category 1 (Manifest Design), MUST.
113+
- `plugin list --json` mismatches between manifest fields and synced output → Category 1 (Manifest Design), SHOULD unless the plugin is absent (MUST).
114+
- `plugin sync --json` warnings about orphaned resources / removed plugins → Category 0 (Structural Completeness) or Category 1, severity per the warning text.
115+
- If the manifest declares `"stability": "beta"`, also run `npx @databricks/appkit plugin promote {PLUGIN_NAME} --to ga --dry-run`. Any rewrites it would perform that conflict with the current `/beta` re-export wiring → Category 0 (Structural Completeness), SHOULD.
116+
79117
Evaluate the plugin code against **all 9 categories** from the Category Index in `plugin-review-guidance.md`. Check each category's NEVER/MUST/SHOULD rules from the best-practices reference.
80118

81119
For each guideline in each category, determine whether the plugin **passes**, **violates**, or is **not applicable** (e.g., SSE rules for a non-streaming plugin). Record findings with:

.claude/commands/create-core-plugin.md

Lines changed: 98 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,47 @@ Use the answers to determine:
3838

3939
## 2. Scaffold with the CLI
4040

41-
Run the scaffolding command to generate boilerplate. Pipe answers non-interactively if possible, or run it interactively:
41+
Run the scaffolding command to generate boilerplate. **Always prefer the non-interactive form** — the agent already gathered every required answer in Step 1, and the interactive prompts will hang in headless sessions.
42+
43+
### 2a. Non-interactive (default)
44+
45+
Required flags: `--placement`, `--path`, `--name`, `--description`. Optional but recommended: `--display-name`, plus one of `--resources` (CSV of types) or `--resources-json` (full specs).
46+
47+
Simple case (just resource types, defaults filled in):
48+
49+
```bash
50+
npx @databricks/appkit plugin create \
51+
--placement in-repo \
52+
--path packages/appkit/src/plugins/{name} \
53+
--name {name} \
54+
--display-name "{Display Name}" \
55+
--description "{description}" \
56+
--resources sql_warehouse,volume
57+
```
58+
59+
Full-spec case (custom `resourceKey`, `permission`, `fields.env`):
60+
61+
```bash
62+
npx @databricks/appkit plugin create \
63+
--placement in-repo \
64+
--path packages/appkit/src/plugins/{name} \
65+
--name {name} \
66+
--display-name "{Display Name}" \
67+
--description "{description}" \
68+
--resources-json '[{"type":"sql_warehouse","resourceKey":"sql-warehouse","permission":"CAN_USE","fields":{"id":{"env":"DATABRICKS_WAREHOUSE_ID","description":"SQL Warehouse ID"}}}]'
69+
```
70+
71+
Add `--force` only when intentionally regenerating into a non-empty directory.
72+
73+
### 2b. Interactive fallback
74+
75+
Use this **only** when the user explicitly asks for non-GA stability — `--placement`/`--path`/`--name`/`--description` work non-interactively, but the `stability` prompt (`ga` vs `beta`) is interactive-only. Run:
4276

4377
```bash
4478
npx @databricks/appkit plugin create
4579
```
4680

47-
Select **In-repo** placement and target path `packages/appkit/src/plugins/{name}`. Fill in the name, display name, description, and resources based on the gathered requirements.
81+
Pick **In-repo** placement and target path `packages/appkit/src/plugins/{name}`. If you need `beta` and cannot run interactively, scaffold with the non-interactive command above (which defaults to `ga`), then hand-edit `manifest.json` to add `"stability": "beta"` — promotion to GA later goes through `appkit plugin promote` (see section 8).
4882

4983
This generates `manifest.json`, the plugin class file, and `index.ts`. Then enhance the generated files following the patterns below.
5084

@@ -274,6 +308,19 @@ Example resource entry:
274308
}
275309
```
276310

311+
> **Tip:** When the resource was already known at scaffold time, prefer wiring it through `--resources-json` in Step 2a instead of hand-editing `manifest.json`. When a resource is discovered *after* scaffolding, use `appkit plugin add-resource` instead of editing the JSON by hand:
312+
>
313+
> ```bash
314+
> npx @databricks/appkit plugin add-resource \
315+
> --path packages/appkit/src/plugins/{name} \
316+
> --type sql_warehouse \
317+
> --resource-key sql-warehouse \
318+
> --permission CAN_USE \
319+
> --fields-json '{"id":{"env":"DATABRICKS_WAREHOUSE_ID","description":"SQL Warehouse ID"}}'
320+
> ```
321+
>
322+
> Use `--no-required` for optional resources, `--dry-run` to preview the updated manifest without writing.
323+
277324
### 4f. User API Scopes (OBO)
278325
279326
If the plugin performs operations on behalf of the logged-in user via `this.asUser(req)`, it requires one or more `user_api_scopes` in the Databricks Apps bundle config (`databricks.yml`). Without the correct scopes, OBO calls will fail at runtime.
@@ -348,11 +395,58 @@ Any plugin using `this.asUser(req)` must declare `user_api_scopes` in the bundle
348395
349396
## 7. After Scaffolding
350397
351-
Run these to verify:
398+
Run these to verify, in order:
352399
353400
```bash
401+
# 1. Schema-check the generated/edited manifest before anything else.
402+
npx @databricks/appkit plugin validate packages/appkit/src/plugins/{name}
403+
404+
# 2. Type/build/test the plugin.
354405
pnpm build
355406
pnpm typecheck
356407
pnpm test
357-
npx @databricks/appkit plugin sync --write
408+
409+
# 3. Re-sync the template manifest so the new plugin is picked up.
410+
# In the AppKit monorepo prefer the workspace script — it wraps the CLI with
411+
# `--plugins-dir packages/appkit/src/plugins` (so sync reads source manifests
412+
# rather than `node_modules/@databricks/appkit/dist/plugins/`, which may be
413+
# missing or stale) and `--output template/appkit.plugins.json` (the file
414+
# that ships to consumers, instead of the project-root default that a bare
415+
# `appkit plugin sync` writes).
416+
pnpm run sync:template
417+
418+
# Equivalent direct invocation — works both inside and outside the monorepo
419+
# (use it when you want to bypass the wrapper or pass extra flags):
420+
# npx @databricks/appkit plugin sync --write \
421+
# --plugins-dir packages/appkit/src/plugins \
422+
# --output template/appkit.plugins.json
423+
```
424+
425+
If the plugin must always ship with the template (i.e. be marked mandatory) even when not auto-detected via the server file's `plugins: [...]` array, pass it explicitly:
426+
427+
```bash
428+
pnpm run sync:template -- --require-plugins server,{name}
429+
# or, equivalently, directly via the CLI:
430+
# npx @databricks/appkit plugin sync --write \
431+
# --plugins-dir packages/appkit/src/plugins \
432+
# --output template/appkit.plugins.json \
433+
# --require-plugins server,{name}
434+
```
435+
436+
> **Note:** `--require-plugins` is **non-additive** — Commander treats it as a single string and the last value wins. The `sync:template` script already passes `--require-plugins server`, so when you override it from the CLI you **must repeat `server`** in the comma-separated list (e.g. `server,{name}`) or the `server` plugin will silently lose its `requiredByTemplate` flag. If you invoke the CLI directly via `npx` instead of going through `sync:template`, also pass `--plugins-dir packages/appkit/src/plugins` (so sync reads the source manifests rather than `node_modules/@databricks/appkit/dist/plugins/`, which may be missing or stale) and `--output template/appkit.plugins.json` (so the synced file lands where consumers expect it).
437+
438+
Use `npx @databricks/appkit plugin list --json` to confirm the plugin shows up in the synced manifest with the expected `displayName`, `package`, `stability`, and resource counts.
439+
440+
## 8. Stability and Promotion (only if the plugin is non-GA)
441+
442+
If the plugin was scaffolded as `beta` (see Section 2b), it must be re-exported from the `/beta` import path, not the GA root. When ready to graduate, **do not edit `manifest.json` and import barrels by hand** — use `promote`, which updates the manifest, rewrites `@databricks/appkit``@databricks/appkit/beta` (and `appkit-ui/js` / `appkit-ui/react`) imports across the repo, and re-runs `sync:template`:
443+
444+
```bash
445+
# Preview every change first.
446+
npx @databricks/appkit plugin promote {name} --to ga --dry-run
447+
448+
# Apply (will run the generators + sync:template automatically).
449+
npx @databricks/appkit plugin promote {name} --to ga
358450
```
451+
452+
Promotion is one-way (`beta → ga` only). Use `--skip-imports` or `--skip-sync` only if you intend to run those steps separately.

.claude/commands/review-core-plugin.md

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,55 @@ Read the file `.claude/references/plugin-best-practices.md`.
7474

7575
For each **relevant** category identified in Step 4, extract all NEVER, MUST, and SHOULD guidelines from that category section.
7676

77+
## Step 5.5: CLI Cross-Checks (per touched plugin)
78+
79+
For **each** plugin detected in Step 3, run the AppKit CLI checks below before doing the textual review. Treat each non-zero exit or warning as a finding under the indicated category in Step 6.
80+
81+
```bash
82+
# Schema-validate the touched manifest. Failures → Category 1 (Manifest Design), MUST.
83+
npx @databricks/appkit plugin validate packages/appkit/src/plugins/{plugin-name}
84+
85+
# Preview the synced template manifest. Watch for:
86+
# - The plugin missing from the output when the diff was supposed to add it
87+
# → Category 0 / Category 1, MUST.
88+
# - "Plugin '...' was removed. The following resource env vars may be orphaned: ..."
89+
# when the diff deletes a plugin → flag as a release-note / migration concern.
90+
# - displayName / package / resource counts that differ from manifest.json
91+
# → Category 1, SHOULD.
92+
#
93+
# In the monorepo, --plugins-dir points sync at the source manifests (matching
94+
# the sync:template script). Without it, sync scans node_modules/@databricks/
95+
# appkit/dist/plugins/, which may be missing or stale.
96+
npx @databricks/appkit plugin sync --plugins-dir packages/appkit/src/plugins --json
97+
```
98+
99+
Conditional checks (only when the diff matches):
100+
101+
```bash
102+
# Diff changes manifest.json's "stability" field, OR adds/removes the /beta
103+
# import path for this plugin. The dry-run shows exactly which manifest fields
104+
# and which import sites promote would touch — the diff should match. Any
105+
# divergence → Category 0 (Structural Completeness), MUST.
106+
npx @databricks/appkit plugin promote {plugin-name} --to ga --dry-run
107+
108+
# Diff adds entries to manifest.json's resources.required / resources.optional
109+
# arrays. Re-run the canonical scaffolder against an unmodified copy and compare
110+
# — the diff should match what add-resource would have produced (alias,
111+
# resourceKey, permission, fields.env defaults). Hand-rolled entries that drift
112+
# from the defaults → Category 1, SHOULD.
113+
npx @databricks/appkit plugin add-resource \
114+
--path packages/appkit/src/plugins/{plugin-name} \
115+
--type {resource-type} \
116+
--dry-run
117+
```
118+
119+
Capture the relevant output and reference it from the corresponding findings in Step 6.
120+
77121
## Step 6: Best-Practices Review
78122

79123
Before evaluating, read the shared review rules in `.claude/references/plugin-review-guidance.md` and apply them throughout this step (deduplication, cache-key tracing).
80124

81-
For each plugin detected in Step 3, review the changed code against the scoped guidelines from Step 5.
125+
For each plugin detected in Step 3, review the changed code against the scoped guidelines from Step 5, and **fold in the CLI results from Step 5.5** under the categories noted there.
82126

83127
For each finding:
84128
- Identify the **severity** (NEVER, MUST, or SHOULD)

.github/workflows/ci.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,10 @@ jobs:
7777
exit 1
7878
fi
7979
- name: Build shared package dist (for sync:template CLI)
80-
# `pnpm run sync:template` runs through `packages/shared/bin/appkit.js`
81-
# which imports the built `packages/shared/dist/cli/index.js`. The
82-
# lint job doesn't otherwise build, so build just shared's dist
80+
# `pnpm run sync:template` invokes the `appkit` bin (from
81+
# `packages/appkit/bin/appkit.js`), which delegates to
82+
# `packages/shared/bin/appkit.js` → `packages/shared/dist/cli/index.js`.
83+
# The lint job doesn't otherwise build, so build just shared's dist
8384
# before invoking sync. We invoke tsdown directly rather than
8485
# `pnpm --filter shared build:package` because the latter also
8586
# re-runs `generate-schema-types.ts`, which writes the raw (unformatted)

knip.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,5 @@
3030
".github/scripts/**"
3131
],
3232
"ignoreDependencies": ["json-schema-to-typescript"],
33-
"ignoreBinaries": ["tarball"]
33+
"ignoreBinaries": ["tarball", "appkit"]
3434
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"packageManager": "pnpm@10.21.0",
77
"scripts": {
88
"build": "pnpm -r --filter=!docs build:package && pnpm sync:template && pnpm exec tsx tools/generate-plugin-doc-banners.ts",
9-
"sync:template": "node packages/shared/bin/appkit.js plugin sync --write --silent --plugins-dir packages/appkit/src/plugins --output template/appkit.plugins.json --require-plugins server",
9+
"sync:template": "appkit plugin sync --write --silent --plugins-dir packages/appkit/src/plugins --output template/appkit.plugins.json --require-plugins server",
1010
"build:watch": "pnpm -r --filter=!dev-playground --filter=!docs build:watch",
1111
"check:fix": "biome check --write .",
1212
"check": "biome check .",

packages/appkit/bin/appkit.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/usr/bin/env node
2+
3+
// In-source shim so `npx @databricks/appkit …` resolves to the real CLI when
4+
// consuming this package from the monorepo (node_modules/@databricks/appkit is
5+
// a pnpm workspace symlink to packages/appkit, so no published tarball ever
6+
// runs). The npm spec requires `bin` paths to live inside the package, so we
7+
// can't point `bin` directly at packages/shared/bin/appkit.js — this file
8+
// exists solely to delegate.
9+
//
10+
// The published npm package is unaffected: tools/dist-appkit.ts overwrites
11+
// this file with packages/shared/bin/appkit.js and copies the bundled CLI
12+
// into ./dist/cli/, so end consumers run the same code from a self-contained
13+
// tarball.
14+
import "../../shared/bin/appkit.js";

packages/appkit/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
"version": "0.35.2",
55
"main": "./dist/index.js",
66
"types": "./dist/index.d.ts",
7+
"bin": {
8+
"appkit": "./bin/appkit.js"
9+
},
710
"packageManager": "pnpm@10.21.0",
811
"license": "Apache-2.0",
912
"repository": {

0 commit comments

Comments
 (0)