Skip to content

feat(skills): load Agent Skills from Workspace files, R2, or a manifest - #2771

Merged
mattzcarey merged 9 commits into
mainfrom
feat/skills-workspace-sources
Oct 29, 2026
Merged

mattzcarey merged 9 commits into
mainfrom
feat/skills-workspace-sources

Conversation

@mattzcarey

@mattzcarey mattzcarey commented Oct 29, 2026 •

Copy link
Copy Markdown
Member

Agent Skills in agents/skills are now files. skills.workspace(workspace) reads every /workspace/.agents/skills/<name>/SKILL.md from a Computer Workspace before each turn, skills.r2() reads the same layout from a bucket, and skills.manifest() defines skills in code. The parser follows the Agent Skills spec, and Think and the pi harness share one catalog.

Most of the skills code was left over from Think's first pass and only Think used it:

  • skills were bundled at build time (agents:skills, the Vite plugin, agents/skills/compile) or copied from sources into the Workspace (skillWorkspace), so a skill written in the Workspace was never found
  • the parser accepted any name and dropped invalid skills silently
  • the pi harness had its own copy of the registry, and the two had started to differ
  • Think extensions still had a "skill" context block type from the removed Session load_context model
import { Think, skills } from "@cloudflare/think";

export class MyAgent extends Think<Env> {
  getSkills() {
    return [
      skills.workspace(this.workspace), // /workspace/.agents/skills
      skills.r2(this.env.SKILLS_BUCKET, { prefix: "skills/" })
    ];
  }
}
flowchart LR
  W["workspace()"] --> C["loadSkillCatalog()"]
  R["r2()"] --> C
  M["manifest()"] --> C
  C --> T["createSkillTools() — agents/skills/tools/ai-sdk, used by Think"]
  C --> P["skills() — pi harness"]
Loading
  • parseSkill() checks name (format, length, matches the directory), description, compatibility, metadata and allowed-tools, and keeps unknown frontmatter keys in extraFields. It follows the spec's guide for agents: a skill that breaks a rule still loads, with a warning per broken rule (SkillWarning diagnostic). Skills with no description, an unsafe name or unparseable YAML are skipped and logged. A skill follows the spec when warnings is empty, which is what to check before writing one. Skill tool failures (unknown skill, missing file) are tool errors: the AI SDK tools throw and the pi tools return isError.
  • A SkillSource is list() + readResource(), both returning results. Invalid skills, failing sources and duplicate names become catalog diagnostics. With { previous }, a source that fails to list keeps its last skills, and Think passes its previous catalog each turn.
  • createSkillTools() is exported from agents/skills/tools/ai-sdk, like the other <feature>/tools/ai-sdk exports, so agents/skills itself does not import ai or zod.
  • Think: an overridden getSystemPrompt() now always renders above the context blocks, instead of being dropped once any block (including the skills catalog) exists. The think_skills block is whenChanged: "remind", so a skill changing mid-conversation reaches the model as a reminder and does not rebuild the cached system prompt.
  • Removed: the agents:skills import (it now fails with a migration message), agents/skills/compile, skills-module.d.ts, SkillRegistry, Think's skillWorkspace, and ExtensionSkillBridge. esbuild moved to dev dependencies.
  • skills.fromManifest() is an alias of skills.manifest() and still accepts the old fields (fingerprint, version, resource kind).
  • skills.runner() stays as an experimental fallback for R2 and manifest skills, with a TODO to move to Computer. It no longer compiles TypeScript. Its ctx.workspace access now rejects paths outside /workspace. It lives at agents/skills/runner (Think still exposes skills.runner), so agents/skills no longer pulls in just-bash and codemode: its exports drop from about 310 KiB gzipped to 0.1–33 KiB.
  • Examples: computer-skills (skills as Workspace files, scripts run with exec) and r2-skills replace agent-skills and assistant. Both seed their starter skills on start, with a TODO to use a Computer loader.

Docs: cloudflare/cloudflare-docs#34717.

agents workers, node and harness-pi suites, and Think's workers suite ran. I haven't run the two examples against a live model.

- agents/skills: spec-strict parseSkill, workspace() source, SkillSource
  returning results, loadSkillCatalog + createSkillTools, manifest()
  (fromManifest kept as an alias)
- remove the agents:skills Vite import, agents/skills/compile, and
  skills-module.d.ts; esbuild is now a dev dependency
- Think: drop skillWorkspace and the extension "skill" context type;
  reload the catalog every turn
- pi harness skills() uses the shared catalog
- examples: replace agent-skills and assistant with computer-skills and
  r2-skills
@changeset-bot

changeset-bot Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 9a5096c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
agents Minor
@cloudflare/think Minor
@cloudflare/agent-think Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

agents

npm i https://pkg.pr.new/agents@2771

@cloudflare/ai-chat

npm i https://pkg.pr.new/@cloudflare/ai-chat@2771

@cloudflare/codemode

npm i https://pkg.pr.new/@cloudflare/codemode@2771

hono-agents

npm i https://pkg.pr.new/hono-agents@2771

@cloudflare/shell

npm i https://pkg.pr.new/@cloudflare/shell@2771

@cloudflare/think

npm i https://pkg.pr.new/@cloudflare/think@2771

@cloudflare/voice

npm i https://pkg.pr.new/@cloudflare/voice@2771

@cloudflare/worker-bundler

npm i https://pkg.pr.new/@cloudflare/worker-bundler@2771

commit: 9a5096c

@agent-think

agent-think Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

🟡 agents import sizes: 1 entry point grew

Entry point Exports Largest gzip change Size now
🟡 agents/harness/pi 1 resized +957 B (+4.43%) 22 KiB
🆕 agents/skills 2 resized, 16 new, 4 removed up to -307.5 KiB (-99.22%) 2.4 KiB
🆕 agents/skills/runner 1 new — 375.9 KiB
🆕 agents/skills/tools/ai-sdk 1 new — 91.5 KiB
🟢 agents/vite 1 resized -46.9 KiB (-15.76%) 250.7 KiB
➖ agents/skills/compile 2 removed — —
Changed exports (28)
Import Gzip change Size now
🟡 agents/harness/pi#skills +957 B (+4.43%) 22 KiB
🆕 agents/skills/runner#runner — 375.9 KiB
🆕 agents/skills/tools/ai-sdk#createSkillTools — 91.5 KiB
🆕 agents/skills#workspace — 33.2 KiB
🆕 agents/skills#parseSkill — 31.5 KiB
🆕 agents/skills#formatSkill — 16.7 KiB
🆕 agents/skills#manifest — 2.4 KiB
🆕 agents/skills#loadSkillCatalog — 1.7 KiB
🆕 agents/skills#parseSkillName — 464 B
🆕 agents/skills#parseSkillResourcePath — 315 B
🆕 agents/skills#formatSkillDiagnostic — 298 B
🆕 agents/skills#renderSkillResource — 254 B
🆕 agents/skills#SkillSourceError — 219 B
🆕 agents/skills#InvalidSkillResourcePathError — 183 B
🆕 agents/skills#SkillResourceNotFoundError — 163 B
🆕 agents/skills#UnknownSkillError — 146 B
🆕 agents/skills#SkillParseError — 133 B
🆕 agents/skills#isModelInvocable — 124 B
🆕 agents/skills#DEFAULT_WORKSPACE_SKILLS_ROOT — 77 B
🟢 agents/skills#fromManifest -307.5 KiB (-99.22%) 2.4 KiB
🟢 agents/skills#r2 -297.1 KiB (-89.98%) 33.1 KiB
🟢 agents/vite#default -46.9 KiB (-15.76%) 250.7 KiB
➖ agents/skills#parseSkillFrontmatter — —
➖ agents/skills#parseSkillMarkdown — —
➖ agents/skills#runner — —
➖ agents/skills#SkillRegistry — —
➖ agents/skills/compile#compileSkillScript — —
➖ agents/skills/compile#isCompilableSkillScript — —
How this works

Each runtime export is bundled on its own, minified, and gzipped. Changes smaller than 100 B, or smaller than 1% and 1 KiB, are ignored. Growth over 10% or 5 KiB is marked 🔴. This report is informational and does not fail CI. The workflow artifact contains every measurement.

Compared 08747d9a → 9a5096c8 · workflow run · reported by agent-think[bot]

Keeps ai and zod out of the agents/skills entry, matching the other
<feature>/tools/ai-sdk exports.
@mattzcarey
mattzcarey marked this pull request as ready for review October 29, 2026 13:51
devin-ai-integration[bot]

This comment was marked as resolved.

…ew fixes

- skills.runner: ctx.workspace (JS, Python, Bash) resolves . and .. and
  rejects paths outside /workspace
- loadSkillCatalog({ previous }): a failing source keeps its last skills;
  Think passes its previous catalog
- read resources from the source object that listed the skill, so sources
  sharing an id do not misroute
- r2 readResource reads the object directly instead of relisting
- move SKILL.md text parsing to markdown.ts so the pi skills extension
  does not load yaml
- single-line changesets
…alog as a reminder block

- an overridden getSystemPrompt() is always the top of the system prompt,
  above configureContext() blocks and the skills catalog, instead of being
  dropped once any block exists; Think's default stays a fallback
- the think_skills block is whenChanged: "remind", so skill changes
  mid-conversation do not rebuild the frozen prompt and break the
  provider's prefix cache
- vite: importing agents:skills fails with a migration message
- manifest()/fromManifest() accept the old fields (fingerprint, version,
  rawContent, resource kind/size/precompiled); kind is honored
…e runner to agents/skills/runner

- parseSkill({ mode }): strict by default; sources parse leniently, loading
  skills with spec-format or directory-mismatch names, long descriptions,
  and invalid optional fields, and reporting each as a SkillWarning
  diagnostic. Missing descriptions, unsafe names, and non-YAML frontmatter
  are still rejected; unquoted ': ' values are repaired. Workspace and R2
  read resources from the directory a lenient name came from.
- runner() moves to agents/skills/runner so agents/skills no longer loads
  just-bash and codemode (~310 KiB gzipped -> 0.1-33 KiB per export).
  Think's skills namespace still includes runner; a type test guards the
  re-export list.
devin-ai-integration[bot]

This comment was marked as resolved.

…th their validation error

- remove parse modes, lenient warnings, YAML repair, and the name fallback
- SkillParseError.issues lists every broken rule
- sources list a skill that fails validation as invalid under its
  directory; the catalog keeps it (prompt section, tool enum) and
  activate_skill / read_skill_resource fail with InvalidSkillError
- AI SDK skill tools throw (tool error); pi tools return isError
…a rule with warnings

One parser, no modes. parseSkill() returns warnings for broken spec rules
and fails only for skills that cannot be used (no description, unsafe
name, unparseable YAML), which are skipped and logged as the guide
recommends. A skill follows the spec when warnings is empty; the examples
reject it on write otherwise. Skill tool failures stay tool errors.
@mattzcarey
mattzcarey merged commit 54ae3e8 into main Oct 29, 2026
26 checks passed
@mattzcarey
mattzcarey deleted the feat/skills-workspace-sources branch October 29, 2026 17:09
@github-actions github-actions Bot mentioned this pull request Oct 29, 2026
Sign up for free to 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