Appearance
Authoring a Skill for BoB
How to take a skill from idea to provisioned-into-a-project inside BoB. This guide is the BoB-integration layer on top of the skill-creator skill: skill-creator owns the build mechanics (scope → plan → scaffold → edit → package → iterate); this guide owns the BoB-specific wrapper around it — which surface to choose, where a finished skill lives, how it gets provisioned and promoted, and what to check before it lands.
Don't duplicate
skill-creator. When you reach the "write the SKILL.md" step, invoke/skill-creator(or read its SKILL.md) and follow it. This guide deliberately says nothing about anatomy, progressive disclosure, or degrees of freedom — those areskill-creator's job.
1. First decide: skill, command, or agent?
BoB extends Claude Code through three surfaces. Picking the wrong one is the most common authoring mistake, so resolve this before you build anything.
| Surface | What it is | Reach for it when… | Lives in |
|---|---|---|---|
| Skill | Auto-loaded procedural knowledge — a workflow, convention, or domain expertise Claude pulls in on its own when the description matches. | The capability is knowledge or a repeatable workflow that should activate implicitly whenever the task matches, with no explicit user invocation. | skills/ (universal) or registry/skills/ (provisioned) |
| Command | A user-invoked /slash entry point — an explicit, named action. | The user should deliberately trigger a discrete operation by name (and it's fine — or better — that nothing happens unless they ask). | commands/ (universal) or registry/commands/ (provisioned) |
| Agent | A specialized Task subagent with its own context, model, and tools. | The work needs isolated context or a distinct role/model — fan-out, an adversarial reviewer, a long search that shouldn't pollute the main thread. | agents/ (universal) or registry/agents/ (provisioned) |
One concrete example of each:
- Skill —
timelord: whenever a doc references "today" or a relative date, Claude should automatically verify the real date. No one types/timelord; it activates on description match. → a skill. - Command —
/start-work: the user explicitly decides "begin a new branch for this issue now." It's a deliberate, named action with side effects. → a command. - Agent —
code-reviewer: a review should run in its own context with a critical role and its own model budget, returning only its verdict to the main loop. → an agent (authored via theagent-builderskill, the agent analogue ofskill-creator).
Rule of thumb: implicit knowledge → skill, explicit action → command, isolated role → agent. When a feature wants both an implicit workflow and a /slash entry point, that's two artifacts (a skill plus a thin command that invokes it), not one overloaded skill.
2. Build it
Author the skill with skill-creator — that is the entire build step, and this guide does not repeat it:
Slash command only — runs inside a Claude Code session (skill-creator is a skill with no terminal entrypoint):
/skill-creatorBuild it in the registry (registry/skills/<name>/) unless it is genuinely universal (needed by every project — like timelord or commit), in which case it goes in skills/. When in doubt, author it in registry/ — promoting registry → universal later is cheaper than discovering a "universal" skill only one project actually uses.
3. Register it into BoB
A finished skill directory is just files until BoB knows about it. Registration is two moves, depending on where it lives:
Universal skill (skills/)
Universal skills auto-load globally — no manifest, no symlink. They reach the runtime (BOB_HOME, ~/.claude/) when you deploy:
Terminal only — deploy.sh is a shell script with no slash equivalent:
bash
scripts/deploy.sh --dry-run # preview the sync
scripts/deploy.sh # sync BOB_SOURCE → BOB_HOMERegistry skill (registry/skills/)
Registry skills are not auto-loaded — they are provisioned per project. Two steps:
- Sync the source into the runtime so the registry copy exists in
BOB_HOME(Terminal only —deploy.shis the shell sync mechanism, no slash equivalent):bashscripts/deploy.sh - Add orchestrator metadata to the skill's frontmatter so the recommendation engine (
scripts/orchestrator/recommend.js) can suggest it to the right projects:yamlA skill for a specific product or vendor (Eloqua, OpenReplay, a particular SaaS) must setapplies_to: stacks: [cloudflare-workers, d1] # stacks this skill is for project_types: [api, backend] recommended_for: [development, ops] category: backend-runtime required_with: [skills/api-designing] # optional co-requisites opt_in: true # only for product/vendor integrations — see belowopt_in: true(#1980): the stack cannot tell whether a project uses that product, so the engine never auto-recommends it and it is provisioned only by an explicitbob provision add(a declared entry is kept, never a would-remove). Leave the flag off for skills the stack genuinely implies (cloudflare-devfor a Workers project). This is what lets/provisionand the orchestrator answer "is this skill applicable to this project?" — see the Orchestrator Guide.
4. Provision it into a project
Registry skills only become active in a project that declares them. Both paths manage the same manifest — pick whichever you're in.
Slash command:
/provision add skill <name>Terminal: from the target project,
bash
bob provision add skills/<name> # add to provisions/<project>.json + symlink it in
bob provision status # confirm it's linked (and not duplicating a global item)
bob provision refresh # reconcile all symlinks to match the manifestThe manifest at provisions/<project>.json is the single source of truth for which registry items a project loads; bob provision only ever reconciles symlinks to match it (declarative, idempotent — re-run freely).
Global-aware (#412): if the skill is already global for this machine,
bob provisionde-dupes it rather than double-provisioning; if a registry skill's name collides with a global one but diverges,bob provision statusreports it as a conflict with a resolution hint.
5. Promote a project-local skill upward
If you authored a skill inside one project and want it available to BoB globally, promote it into the source of truth rather than copying files by hand:
Terminal only — bob promote is a shell alias for promotion; there is no slash equivalent:
bash
bob promote # promote a local item to the global source (BOB_SOURCE)After bob promote lands the skill in BOB_SOURCE (in skills/ or registry/skills/), run scripts/deploy.sh to sync it to the runtime, then bob provision in any project that should load it. (bob link does the inverse — link an existing global item into a project without promoting.)
The full path, end to end:
author (registry/skills/) → deploy.sh → cdprov add (in project)
project-local skill → cdp (promote) → deploy.sh → cdprov add6. Pre-add validation checklist
Run this checklist before a skill is promoted into BoB (bob promote) or added to a manifest (bob provision add). It is the gate the promotion flow references — a skill that fails any line is not ready to land.
- [ ] Frontmatter complete —
nameand adescriptionthat states what the skill does and when to use it (the description is the only thing Claude sees when deciding to auto-load — vague descriptions never fire). - [ ] Triggers are concrete — the description names the situations/phrases that should activate the skill, not just its topic. "Use when X, Y, or Z" beats "knowledge about X."
- [ ] Kebab-case naming — directory and
nameare lowercase kebab-case and match each other (skill-authoring, notSkillAuthoringorskill_authoring). - [ ] Idempotent — any bundled
scripts/are safe to re-run; the skill describes a repeatable workflow with no destructive side effects on a second invocation (the Prime Directive — seeskill-creator's IaC principle). - [ ] No overlap — it doesn't duplicate an existing skill. Check
skills/andregistry/skills/first; if an existing skill is close, extend it instead of forking. - [ ] Orchestrator metadata (registry skills only) —
applies_to/recommended_for/categoryset, so the recommendation engine can place it;opt_in: trueif it is a product/vendor integration the stack alone cannot justify (#1980). - [ ] Right surface — re-confirm §1: this is genuinely implicit knowledge, not a disguised command or agent.
Security gate
Every item that enters the registry is scanned by NVIDIA SkillSpector (#1328), static-only (--no-llm): deterministic, no API key, and no item content leaves the machine. The gate augments human review at promotion — it never replaces it. A clean scan does not mean the checklist above is done, and a reviewer still reads the item.
An item enters the registry one of two ways, and each is scanned:
bob promoterunsskillspector scan <item> --no-llmbefore it copies anything. A risk score over SkillSpector's threshold refuses the promotion and leaves the local file in place;CAUTIONwarns and promotes; a machine without SkillSpector says so and promotes, with the CI gate as the backstop.- A PR runs the
skillspectorjob in CI on every changed item underskills/,commands/,agents/orregistry/. It fails only on a new finding: anything already reviewed is listed in the committed.skillspector-baseline.yaml. Until that file is committed, the job only reports.bob provision addlinks items that are already in the registry, so the CI gate covers it.
The engine is scripts/security/skillspector-gate.sh (check, items, scan, baseline, bootstrap); it pins SkillSpector to one commit and uv to one checksummed release. To scan an item yourself:
bash
scripts/security/skillspector-gate.sh bootstrap ~/.cache/skillspector # prints the bin dir
skillspector scan registry/skills/<name> --no-llmA new finding in your PR: fix the item, or — if the finding is a false positive or an accepted risk — add an entry to .skillspector-baseline.yaml with a reason that says why, in the same PR. BoB's autonomous-loop skills legitimately trip the "excessive agency" rules, which is what the baseline is for. Never add a broad glob rules: entry to quiet a finding: a rule survives future edits and can hide new malicious content.
Regenerating the baseline: run the SkillSpector baseline sweep workflow (gh workflow run skillspector-baseline.yml), download its skillspector-baseline artifact, review every entry, and commit it. Do this whenever SKILLSPECTOR_REF is bumped: exact fingerprints bind the scanner version and stop matching after a bump.
7. Retire, demote or promote an item
Every project that linked an item keeps a symlink to it. Moving or deleting the item in BOB_SOURCE therefore needs one more step, or the next bob ready in every consuming project finds a dangling link it cannot explain (#2314):
- Move or delete the item —
registry/<type>/↔<type>/for a demotion or promotion; delete (and tag, per the archive procedure) for a retirement. - Record it in
scripts/lib/retired-items.json— one entry withtype,name,from(where it used to live),disposition(removed·superseded-by+replacement·moved-to-registry·moved-to-universal) andretired_by(the issue). This is required:make check-retired-itemsfails on any item path git history has seen that is absent without a record, and names the exact entry to add. make check— the gate is part of it.- Deploy. Consuming projects converge on their next
bob readyorbob provision refresh: a link to a promoted item is retargeted, one to a demoted item is retargeted when the project declares it and otherwise pruned with abob provision add <type> <name>hint, one to a retired item is pruned naming the disposition — each action named, nothing unknown deleted. The fleet snapshot'sbroken_linksper project confirms it per machine.
A promotion is the mirror of §5 and takes the same record (moved-to-universal). The reference for the file, its gate and what derives from it is Retired Items.
A promotion is a move, never a copy (#2735). Leaving the old file behind creates a name that exists on both sides — and the two sides resolve differently per project:
bob initlinks the universal copy,bob provisionlinks the registry one, and the registry link shadows the universal one where a manifest declares it./requirementsat like that for most of this repo's life: the two files drifted into different commands, 15 projects ran one and 5 ran the other, and because_bob-home.farm-worker.jsonprovisions its commands, unattended farm runs and attended laptop sessions executed different instructions under the same name.make check-item-collisionsnow refuses the shape — delete the old file in the same commit as the move.
See also
skill-creator— the build mechanics this guide wraps.agent-builder— the agent analogue, when §1 points you to an agent.- Orchestrator Guide — how
applies_tometadata drives provisioning recommendations. - Project Setup Guide —
bob init/bob provisionwiring for a project.