Skip to content

feat(appkit): Agent Skills (v1) — SKILL.md progressive disclosure for agents - #532

Draft
MarioCadenas wants to merge 8 commits into
agents-discovery-dxfrom
feat/agent-skills
Draft

feat(appkit): Agent Skills (v1) — SKILL.md progressive disclosure for agents#532
MarioCadenas wants to merge 8 commits into
agents-discovery-dxfrom
feat/agent-skills

Conversation

@MarioCadenas

Copy link
Copy Markdown
Collaborator

Agent Skills (v1)

Runtime Agent Skills for the agents plugin — the SKILL.md format Claude Code / Cursor use, brought to AppKit agents. Only each skill's name + description sit in the system prompt (always-on, cheap); the full body loads on demand. Works on any Databricks-served model — AppKit implements the progressive disclosure itself, so it doesn't depend on a provider-native skills feature. Fills the seam the loader already reserved (RESERVED_DIRS = new Set(["skills"])).

Not to be confused with the dev-time "Databricks Agent Skills" product (Claude Code skills for building apps) — this is a runtime capability of deployed agents.

What a skill is

A directory with a SKILL.md (frontmatter name + description, Markdown body) plus optional bundled reference files. Frontmatter is an Anthropic-format superset (also tolerates license, allowed-tools, metadata); unknown keys warn, not error — so skills authored elsewhere drop in.

How it works

  • Every visible skill's name + description is injected into the agent's system prompt.
  • Two read-only built-in tools are added to any agent with a catalog: load_skill(skill) returns the body + a manifest of bundled files; read_skill_file(skill, path) reads one of those files (through a directory-containment guard).
  • The model auto-loads a skill when a task matches; a user can force one for a turn with /skill-name in chat (or useAgentChat's send(msg, { skill })).

Sources & visibility

  • Global bundleconfig/agents/skills/, per-agentconfig/agents/<id>/skills/, and a catalog UC Volume (skillsVolume / DATABRICKS_VOLUME_AGENT_SKILLS), read as the service principal.
  • Per-agent skills are always visible; global skills are opt-in via skills: [...] frontmatter (or autoInheritSkills).
  • Name collisions resolve to qualified <scope>:name; the bare name errors as ambiguous.

Commits (phased, independently reviewable)

  1. feat(appkit): load and resolve agent skills from bundle sources — model, parser, loader, per-agent catalog resolution
  2. feat(appkit): expose skills to agents via prompt catalog and load_skill — disclosure + built-in tools (bundle e2e)
  3. feat(appkit): source agent skills from a Unity Catalog volume — catalog source, SP-read
  4. feat(appkit): let users load skills from chat (/skill-name + picker) — client UX + forced load
  5. feat(appkit): document agent skills, wire sub-agents, ship example skill
  • plus a plugin-catalog sync and two dev-playground commits (a haiku demo skill + a /-triggered skill menu) for hands-on testing.

Try it in dev-playground

pnpm --filter=dev-playground dev, open /agent (Helper agent):

  • Type / → a menu of the agent's skills (/haiku); ↑/↓ + Enter/Tab to insert.
  • /haiku what's the weather in Paris? forces the skill; "give me a haiku about NYC taxi trips" triggers auto-load (watch the load_skill tool call).

Tests & verification

New coverage across skills.test.ts, dispatch-tool-call, skill-volume, skill-client, and the use-agent-chat hook. Full appkit (3075) and appkit-ui (366) suites pass; all packages typecheck; docs build succeeds.

Deferred to v2 (non-goals here)

Script/code execution from skills; allowed-tools enforcement (advisory only in v1); per-user (OBO) skill volumes; TTL refresh of volume listings; marketplace / end-user-uploaded skills; standalone runAgent skill parity.

@github-actions

github-actionsBot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

📦 Bundle size report

Compared against bundle-size-baseline.json (main).

@databricks/appkit

npm tarball (packed): 877 KB (+37 KB) — gzipped download (dist + bin; excludes release-only docs/NOTICE).

distrawgzip
JS (runtime)906 KB (+37 KB)317 KB (+14 KB)
Type declarations326 KB (+12 KB)114 KB (+4.6 KB)
Source maps1.8 MB (+70 KB)591 KB (+25 KB)
Other11 KB3.7 KB
Total3.0 MB (+118 KB)1.0 MB (+44 KB)
Per-entry composition (own code — deps external (as shipped))
EntryInitial (gz)Lazy (gz)Total (gz)node_modules (min)Own code (min)
.88 KB2.5 KB91 KBexternal288 KB
./beta56 KB (+7.2 KB)457 B56 KB (+7.2 KB)external164 KB (+21 KB)
./type-generator21 KB0 B21 KBexternal61 KB

Chunks:

EntryChunkLoadSize (gz)
.index.jsinitial84 KB
.utils.jsinitial4.0 KB
.remote-tunnel-manager.jslazy2.5 KB
./betabeta.jsinitial40 KB
./betastream-manager.jsinitial5.8 KB
./betawide-event-emitter.jsinitial3.2 KB
./betadatabricks.jsinitial3.0 KB
./betaconfiguration.jsinitial2.1 KB
./betaservice-context.jsinitial1.3 KB
./betaclient.jsinitial434 B
./betaclient-options.jsinitial220 B
./betasupervisor-api.jslazy192 B
./betadatabricks.jslazy142 B
./betaindex.jslazy123 B
./type-generatorindex.jsinitial21 KB

@databricks/appkit-ui

npm tarball (packed): 343 KB (+466 B) — gzipped download (dist + bin; excludes release-only docs/NOTICE).

distrawgzip
JS (runtime)390 KB (+316 B)131 KB (+159 B)
Type declarations228 KB (+300 B)83 KB (+130 B)
Source maps754 KB (+906 B)248 KB (+295 B)
CSS16 KB (-462 B)3.2 KB (-90 B)
Total1.4 MB (+1.0 KB)465 KB (+494 B)
Per-entry composition (consumer bundle — deps bundled, peerDeps external)
EntryInitial (gz)Lazy (gz)Total (gz)node_modules (min)Own code (min)
./js5.3 KB49 KB55 KB208 KB14 KB
./js/beta20 B0 B20 B0 B0 B
./react432 KB (+248 B)49 KB481 KB (+248 B)1.3 MB175 KB (+168 B)
./react/beta1.0 KB0 B1.0 KB0 B1.9 KB

Chunks:

EntryChunkLoadSize (gz)
./jsindex.jsinitial5.2 KB
./jschunkinitial120 B
./jsapache-arrowlazy49 KB
./js/betabeta.jsinitial20 B
./reactindex.jsinitial430 KB
./reacttslibinitial2.1 KB
./reactapache-arrowlazy49 KB
./react/betabeta.jsinitial1.0 KB

@github-actions

github-actionsBot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

🤖 AppKit PR bot

🔬 Run evals

Start an eval for this PR from the evals-monitor app: Go to Evals Monitor →

📦 Try this PR's app template

Scaffolds a new app from this PR's SDK build. Run it in any folder (requires the GitHub CLI — gh auth login — and the Databricks CLI):

gh run download 32261036570 -R databricks/appkit -n appkit-template-0.61.1-pr.fa9865d-feat-agent-skills-532 -D appkit-pr-532 \
&& unzip -o "appkit-pr-532/appkit-template-0.61.1-pr.fa9865d-feat-agent-skills-532.zip" -d "appkit-pr-532" \
&& databricks apps init --template "appkit-pr-532"

The template pins @databricks/appkit and @databricks/appkit-ui to tarballs built from this branch, so the scaffolded app runs against this PR's code.

…er/agents
Every agent is a folder under server/agents/<id>/ holding agent.md (markdown)
or agent.ts (code); the folder name is the id.
- Code loader scans <id>/agent.{ts,tsx,js,mjs}, built-first: a relative dir
resolves dist/<name>|build/<name> before source, an absolute dir is verbatim,
so a bundled server never imports .ts under plain Node.
- Markdown loader skips folders without agent.md so code + asset dirs coexist;
drop the RESERVED_DIRS list.
- One `dir` knob (default server/agents) feeds both loaders; codeAgentsDir
retired. config/agents is read as a deprecated fallback (per-agent merge, new
location wins, one-time warning); cross-location sub-agent refs resolve.
- Cross-kind sub-agent references resolve by folder id.
- Migrate template, dev-playground, docs, and tests to the folder layout; add
fallback / built-first / cross-dir test coverage.
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
Follow-up to the review + inconsistency fan-out:
- findEntryFile now rethrows non-ENOENT/ENOTDIR errors (an unreadable agent
folder no longer silently vanishes in prod).
- Clearer discovered-vs-markdown collision message (covers the cross-root
config/agents fallback case, not just one folder).
- Template tsdown: scope clean:true to the agents case so a non-agents
scaffold's build config is unchanged.
- Docs: fix DATABRICKS_SERVING_ENDPOINT_NAME, the auto-inherit default
(off for both), cycle-rejection scope, /api/agents/approve path,
defaultAgent precedence, dir:false wording, stale-dist note, and add
the agents/generationParams frontmatter keys + toolCallTimeoutMs limit.
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
Ships the server build wiring from the package so a scaffolded app's
tsdown.server.config.ts is a one-liner instead of hand-maintained config:
import { appkitServerConfig } from '@databricks/appkit/tsdown';
export default appkitServerConfig();
- appkitServerConfig(overrides?, opts?) auto-detects server/agents/<id>/agent.ts
and adds the entry glob + clean only when code agents exist.
- Object overrides merge with intent (entry unioned so the agent glob can't be
clobbered, external composed, other keys win); a function override receives
the computed base for full control.
- Dependency-free (node: builtins only) so it stays lean at build time.
- New ./tsdown export subpath (attw + publint clean); template drops its
{{if .plugins.agents}} conditional.
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
Markdown agents need no build change; code agents require the server build
to emit them (dev via tsx hides this — only a bundled build breaks). Points
at the appkitServerConfig() preset as the one-line fix, notes the manual
entry-glob alternative, and the startup warning that catches a forgotten
build change.
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
…ion .ts-only
From the /simplify pass:
- Extract agentDirNames() so both loaders share one folder-selection policy
(dir + symlink) instead of duplicating the subtle filter + comment.
- Code-agent source detection is .ts-only (resolveCodeAgentsDir source exts +
hasCodeAgentSources), matching the build entry glob — an agent.tsx would
otherwise load in dev but never be emitted for a prod bundle.
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
…ents)
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
@MarioCadenas
MarioCadenas changed the base branch from main to agents-discovery-dxAugust 19, 2026 13:57
…xtures
Exercise the previously-untested skill sources/paths in the reference app:
- global `bullet-brief` skill; helper opts into it (multi-entry menu on a code agent)
- per-agent `query/skills/routing-brief` (bundle-agent source + bundled reference.md)
- per-agent `query/skills/haiku` collides with global `haiku` (query opts in),
forcing qualified agent:haiku / bundle:haiku addressing
- add `query` to the /agent page picker so its skills surface in the input
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@MarioCadenas