DEV Community

lujianfu2008
lujianfu2008

Posted on

Teaching Your AI Assistant New Skills at Runtime — Without Rewriting It

Last post I showed the architecture of my local AI assistant, Xiaoqingting (Little Dragonfly). This one is about the part users actually notice: how the assistant gains new abilities without me shipping a new version.

Say "review this PR properly" or "write me a weekly report" — those are not generic chat behaviors, they're procedures. Procedures belong in prompts, and prompts belong in files. Here's the system we ended up with.

The Core Idea: A Skill Is a Folder

A skill is nothing more than a directory with a manifest and instructions:

skills/
└── pr-review/
    ├── SKILL.md          # name, description, trigger hints, the procedure
    └── checklist.md      # optional reference material
Enter fullscreen mode Exit fullscreen mode

SKILL.md is markdown with a tiny front-matter:

---
name: pr-review
description: "Structured code review following our team checklist"
triggers: [review, code review, CR]
---

You are performing a code review. Steps:
1. Read the diff and summarize what changed in one sentence.
2. Check correctness first, then edge cases, then style — in that order.
3. Cite file:line for every finding. No vague advice.
...
Enter fullscreen mode Exit fullscreen mode

At session start, the server scans the skills directory, reads every manifest, and injects a table of contents into the system prompt — name, one-line description, when to use it. Not the full text. When the user's request matches a skill, the assistant reads the full SKILL.md on demand.

Why On-Demand Loading Beats Dumping Everything

My first version injected all skill bodies into the system prompt at once. Three skills in, this was fine. Ten skills in, two problems showed up:

  1. Prompt bloat — every turn paid the token cost of ten procedures, most of them irrelevant
  2. Attention dilution — the model started blending procedures, applying the deploy checklist during a casual chat

The fix — load manifests always, load bodies on demand — cut the system prompt by ~70% and made skill-following more accurate, because each procedure arrives fresh, right when it's relevant, with nothing else competing for attention.

This mirrors how the big agent platforms converged on the same design (progressive disclosure of instructions), which was reassuring to discover after the fact.

The Marketplace: A Registry URL, Not an App Store

Users shouldn't have to hand-copy folders. So the assistant supports a skills registry — you point it at a URL serving a JSON manifest:

{
  "skills": [
    { "id": "pr-review", "version": "1.2.0",
      "url": "https://cdn.example.com/skills/pr-review-1.2.0.zip",
      "sha256": "b41d8c..." },
    ...
  ]
}
Enter fullscreen mode Exit fullscreen mode

The client shows the list, you tick what you want, it downloads and verifies each pack before mounting. Sets SKILLS_REGISTRY_URL, get a marketplace.

Deliberate scope cut: our registry only distributes pure-markdown skills. No scripts, no executables in skill packs, version one. Every "skills marketplace" that allowed arbitrary code turned into a supply-chain nightmare waiting for a Tuesday. Markdown instructions can still be abused (more below), but they can't rm -rf anything by themselves.

The Security Part You Should Not Skip

Skills are prompts, and prompts are instructions the model will follow. That makes the skills folder an injection surface, and we treat it like one:

  1. Curated registries only. The registry URL is configured by the user, not discovered at runtime. The assistant cannot install skills on its own — installs always require explicit user confirmation
  2. Checksums enforced. Registry entries carry a sha256; a mismatch aborts the mount, no exceptions
  3. Permissions stay with tools, not skills. A skill can ask the model to run commands, but whether commands actually run is decided by the server's tool allowlist. A malicious skill file can at worst produce confident nonsense — it cannot escalate its own privileges
  4. Size and count caps. A skill manifest is capped; so is the total. The failure mode of "unlimited skills" is a system prompt the size of a novel

Rule 3 is the one that matters. Skills change what the model says; the tool allowlist changes what it can do. Never let a downloaded file touch the second layer.

What It Looks Like in Practice

I added a "release-notes" skill as a test: given a version range, read the commits, group them by user-facing impact, write notes in a fixed format. It took one markdown file, four minutes, zero code — and the next morning the assistant produced better release notes than the template I'd been copy-pasting for two years.

That's the whole pitch: the assistant's capability list should be data, not code. Ship the engine once; let the skills folder grow forever.

The implementation lives in github.com/lujianfu2008/xiaoqingting — @blm/server has the loader and registry client, and a couple of example skills are in skills/.

Next post, probably the last architecture one: the LLM gateway — multi-provider routing, per-user quotas, and why "model not found" was secretly a protocol bug. Follow me if you're enjoying the series.

Top comments (0)