Glossary
Who this is for: anyone who meets a repo-specific term in these docs (mechanism 1, gloss, roster, coverage gate, envelope) and wants it pinned down.
This repository's own vocabulary. These terms are assumed everywhere and defined nowhere else. Salesforce platform terms are not covered here — the skills themselves define those.
Counts and sizes below were measured on this checkout on 2026-08-15, and the command that produced each moving number is named next to it. They move; python3 scripts/check_doc_counts.py is the authority on the corpus-scale ones.
The routing tier
This section covers the path that ships. It is the vocabulary architecture.md uses most.
mechanism 1 / mechanism 2 / mechanism 3 — Shorthand for the three ways a question reaches a skill package, used throughout the docs because they have completely different properties and get conflated otherwise.
- Mechanism 1 — the model-driven roster scan. No index, no build step, no API
key. The only one that works on a fresh clone or a plugin install, and therefore the one nearly every real session uses.
- Mechanism 2 — the MCP
search_skilltool. The server is real and ships assource, but it is not auto-wired:
.claude-plugin/plugin.jsonhas nomcpServerskey, so installing the plugin does not connect it. It also needs a built index. - Mechanism 3 —
scripts/search_knowledge.py. Needs a localpython3 scripts/build_index.py(orscripts/bootstrap.py) first.
git ls-files vector_index returns three files — manifest.json, query-fixtures.json, query-variants.json — and none of them is the index or the embeddings. That single command is why the ordering above is not a matter of taste. Any accuracy or speed figure in these docs names which mechanism it measures.
router skill — One of the 12 generated SKILL.md files under .claude/skills/: a top-level salesforce entry router plus 11 domain routers (salesforce-apex, salesforce-admin, and so on, one per domain). A router contains no Salesforce guidance. It is a map. Each of the 11 domain routers names its scope, points at its roster, lists all three mechanisms, and carries exactly 8 featured entry points, the decision trees and templates relevant to that domain, its scoped run-time agents, and exactly 4 standing rules. The top-level salesforce entry router instead carries the domain table, the cross-domain entry points and its own 4 rules, and hands off. All 12 say the same thing in their own words — "Do not answer from this router: it is a map, not the territory." Generated by scripts/build_plugin.py from registry/skills.json; never hand-edited.
The router's description: frontmatter does more work than its body, because the description is what the host loads at session start while the body is not. Each one carries three things: the domain's scope, trigger vocabulary in the phrasings users actually type, and explicit negative routing — "Owns calling an external API FROM Salesforce; salesforce-integration owns inbound … NOT for SOSL — use salesforce-data." The disclaimers matter more than the keyword list, because domains overlap and surface vocabulary alone routes wrong.
roster (or skill-index) — references/skill-index.md inside a domain router: a complete list of that domain's packages, one line each. There are 11 rosters, one per domain, and their gloss lines sum to exactly 1,027 — admin 253, apex 158, architect 104, data 101, lwc 82, devops 70, flow 63, integration 61, agentforce 53, security 48, omnistudio 34 (registry/skills.json, domain_counts). The top-level salesforce router has no roster because it only hands off to domain routers.
The word that matters here is one. Claude reads a single roster, not eleven; an Apex question costs 158 glosses rather than 1,027. Generated by scripts/build_plugin.py.
gloss — The one-line description of a package on a roster line, produced by build_gloss() (scripts/build_plugin.py:979). This is where routing precision is won or lost, so its composition is fixed and every part is budgeted:
| Constant | Value | Line | Bounds |
|---|---|---|---|
MAX_GLOSS_CHARS | 220 | scripts/build_plugin.py:281 | the whole gloss |
GLOSS_TRIGGER_CAP | 150 | :287 | the trigger list |
GLOSS_NOTFOR_CAP | 140 | :288 | the NOT for … clauses |
GLOSS_LEAD_CAP | 150 | :289 | the lead phrase |
GLOSS_LEAD_MIN | 40 | :292 | below this the lead is dropped, not shipped as a stub |
Three things about it are routinely got wrong:
- Its input is the
descriptionstring, not thetriggers:YAML block.build_glossis called asbuild_gloss(skill.get("description", ""))(scripts/build_plugin.py:1349), andsplit_description()(:860) cuts that one string on a literalTriggers:/Trigger keywords:/Trigger phrases:marker and on a sentence-initialNOT for. The frontmattertriggers:list is a different list, consumed by chunk indexing (pipelines/sync_engine.py:104) and duplicate detection (pipelines/similarity.py); it does not appear inregistry/skills.jsonat all. Adding a phrase there changes search, not routing. - Budget priority and print order are different orders. Priority — who gets
paid first — is triggers →
NOT for …redirect → lead, with the lead paid out of whatever is left (:989-1008). Print order on the line is lead →Triggers: …→NOT for …(:1010-1017). The roster header states the priority order, so reading it as the printed order will surprise you. - **Truncation drops whole units, so the order you write triggers in decides
which survive.**
_clip_keywords()(:891) keeps whole comma-separated keywords until the budget runs out and then appends, …; it never cuts mid-phrase, because a half phrase is unmatchable._clip_clauses()(:933) does the same forNOT for …clauses and re-attaches theuse <target>tail when the first clause alone overflows, so a redirect never names a destination the reader cannot resolve.
Because the lead is paid last, a long trigger list can push it off the line entirely. apex/recursive-trigger-prevention is a shipped example: its gloss is 201 of 220 characters and contains no lead at all.
check_gloss_coverage — scripts/check_gloss_coverage.py, which answers "did the vocabulary we just wrote reach the surface that actually routes?" It buckets every package into routed (the term is in the gloss), clipped (declared in the description's Triggers: clause but lost to the 220-char cap), lead prose only, and body only. Only clipped is a defect, and it is the only bucket that makes the script exit 1, so it can gate a content wave. A term appearing merely in a body is normal — promoting those has already cost this repo 5pp of retrieval accuracy once.
python3 scripts/check_gloss_coverage.py subagent --domain agentforce
tier — The word is used for two different things in this repository, and mixing them up is a real source of confusion.
The read path has four tiers, which is the numbering architecture.md uses. Tier 0 is what the host loads at session start: the description: frontmatter of the 12 routers, 67 commands and 48 agent loaders, no bodies. Tier 1 is a router body, loaded when the model picks a domain. Tier 2 is that domain's roster. Tier 3 is the skill package itself.
The token budget uses tier1_tokens for the whole of what the read path calls Tier 0. installing-the-plugin.md follows the budget's numbering rather than the read path's, so "Tier 1" there means the always-on descriptions, "Tier 2" the skill packages and rosters, and "Tier 3" the agent playbooks — one lower than the read-path numbering at every level. tier1_tokens is the key python3 scripts/build_plugin.py --measure emits, and the number the 6,000-token budget is checked against. Measured 2026-08-15: routers 1,921 + commands 1,412 + agents 2,157.2 = 5,490 tokens, against a flat export of all 1,027 skill descriptions at 138,694 — a ratio of 3.96%. That ratio is the architectural justification for the routing tier existing at all. The token model is an estimate calibrated against a real Claude Code install, not a meter reading; say estimated, calibrated.
coverage gate — see Retrieval. Worth knowing here for the asymmetry: mechanisms 2 and 3 have one, and mechanism 1 does not. A model scanning a roster always finds a plausible line, so the shipped path cannot fail by returning nothing — it fails by opening the wrong package. The architecture compensates with instructions rather than arithmetic: the NOT for X — use Y redirects, the negative routing in every router description, and the standing rule forbidding an "uncovered" claim without pasted lookup output.
Corpus and authoring
skill package — One directory under skills/<domain>/<slug>/ holding everything about one topic: a SKILL.md, a references/ folder with exactly four files (examples.md, gotchas.md, well-architected.md, llm-anti-patterns.md), and optionally templates/ and scripts/. The unit of authorship, review and retrieval. Machine-generated metadata never lives inside a package. All 1,027 packages carry all five required files, re-verified 2026-08-15.
SKILL.md — The canonical file of a skill package. YAML frontmatter on top, Markdown body below. The body must contain a ## Recommended Workflow section of three to seven numbered steps. Everything a machine knows about a skill is derived from this file.
frontmatter — The YAML block delimited by --- at the top of a SKILL.md or AGENT.md. It is the single canonical metadata source: name, description, category, tags, triggers, inputs, outputs, dependencies, version, updated. Nothing may duplicate it in a separate metadata file. The description: field is load-bearing three times over: it becomes the package's gloss on a roster (mechanism 1), it feeds the name/description bonus in keyword ranking (mechanisms 2 and 3), and its embedded Triggers: clause is the only trigger vocabulary routing ever sees.
trigger keywords (or triggers) — Ambiguous in this repo, and the ambiguity matters:
- The
triggers:frontmatter list is indexed alongside the skill body(
pipelines/sync_engine.py:104) and weighted in duplicate detection. It affects mechanisms 2 and 3. It is not inregistry/skills.jsonand does not reach a roster. - The
Triggers:clause inside thedescriptionstring is whatbuild_glossreads. It is the only trigger vocabulary that affects mechanism 1.
Neither is an Apex trigger. Retrieval performs noticeably better on phrasings close to a curated trigger than on free-form symptom descriptions, and the gap is the single biggest caveat on any retrieval number in these docs. Measured 2026-08-15 on mechanism 3, the 1,356 curated fixtures score 98.4% Hit@1 while the 154 hand-written held-out queries score 40.3% — about 58 points apart:
python3 evals/measurement/run_heldout.py \
--queries vector_index/query-fixtures.json --use-domain --json # 98.4%
python3 evals/measurement/run_heldout.py --json # 40.3%
domain — The top-level bucket a skill lives in, and the first path segment of its id: admin, apex, lwc, flow, omnistudio, agentforce, security, integration, data, devops, architect. Eleven of them. A skill id is always <domain>/<slug>. Each domain has exactly one router and one roster, and --domain filters retrieval to one bucket.
template — A canonical, cross-skill building block under templates/ — the one TriggerHandler, ApplicationLogger, SecurityUtils, TestDataFactory, LWC skeleton, Flow fault path, Agentforce action shell. 73 tracked files (git ls-files templates | wc -l). Skills link to these rather than inlining their own variants. A skill-local file under skills/.../templates/ is a placeholder or worksheet; when a second skill starts referencing it, it gets promoted to templates/.
decision tree — A routing document under standards/decision-trees/ consulted before a technology is chosen, so that "Flow or Apex" is answered once and cited, rather than re-argued inside every skill. Seven exist: automation-selection, flow-pattern-selector, agentforce-capability-selector, async-selection, integration-pattern-selection, sharing-selection and performance-tuning. standards/decision-trees/README.md is the authoritative table. Agents cite the specific branch that resolved their choice.
probe — A read-only diagnostic query bundled with an agent, defining what to ask a Salesforce org before making a recommendation. Probes are verified by executing their SOQL against a real org, so a probe that references a field that does not exist fails a harness rather than silently misleading an agent.
envelope — The structured JSON wrapper a runtime agent returns around its output: the findings, the confidence score, the ambiguities, and the citations of every skill, template and decision-tree branch consulted. Its schema is validated by the MCP server, and consuming tools are required to preserve it rather than flatten it into prose. See consumer-responsibilities.md.
Agents
run-time agent — An agent that does real Salesforce work in your codebase or org: refactor this Apex, design this permission model, audit this LWC. Frontmatter class: runtime, status: stable. These are what a consumer of the library invokes. 48 are active.
build-time agent — An agent that maintains the library itself: skill builders, the validator, the content researcher. Frontmatter class: build. A consumer never runs these. 14 exist. The split is documented in ../agents/_shared/RUNTIME_VS_BUILD.md.
deprecated alias — A retired agent left in place as a stub with status: deprecated and a deprecated_in_favor_of pointer, plus a slash-command alias that redirects to the replacement. Stubs live for two minor versions. They keep class: runtime, so class alone does not tell you whether an agent is active — both the MCP health tool and scripts/check_doc_counts.py read status as well and agree on the split (48 runtime, 14 build, 14 deprecated, 76 total, re-verified 2026-08-15). All 14 current stubs redirect to audit-router. If two agent counts disagree, one of them is stale. See MIGRATION.md.
agent loader — The flat generated file that makes an AGENT.md playbook invocable as a subagent. There are two byte-identical copies of each: 48 under .claude/agents/ (plugin-scoped) and 48 as agents/<id>.md (project-scoped). Both are produced by scripts/build_plugin.py and must never be hand-edited; the playbook itself is agents/<id>/AGENT.md and is hand-authored.
runtime orphan — A skill package no agent cites. The validator emits a WARN, not an error (scripts/validate_repo.py:475, inside _check_orphan_skills at :425), and a package can silence the advisory by recording runtime_orphan: true plus a runtime_orphan_reason in its frontmatter. On this checkout 509 packages are cited by at least one agent's dependencies.skills: block, 518 are not, and 54 carry the explicit opt-out. The severity is deliberate: this check used to be an ERROR whose message handed the reader a paste-ready command, which made mass citation the cheapest route to a green build and produced 555 machine-generated citations whose description was just the slug title-cased. What carries ERROR severity now is citation quality, on the reasoning that a citation an agent will not read is worse than no citation at all.
Retrieval
Everything in this section describes mechanisms 2 and 3, which do not exist until you build an index.
chunk — A retrieval-sized slice of a document, typically a section under one heading. Skill files, knowledge imports and templates are all chunked. The index in this checkout holds 135,409 chunks across 1,027 skills (vector_index/manifest.json, key chunk_count). Search operates on chunks; results are then rolled up to skills.
lexical index — The SQLite FTS5 full-text table at vector_index/lexical.sqlite, built by pipelines/lexical_index.py. It indexes each chunk's title, tags and text; everything else is stored unindexed. Queries are lowercased, split, and joined as prefix terms with OR. This layer is mandatory for mechanisms 2 and 3 and needs no API key. 169 MB in this checkout, and gitignored.
skills-only window — A second lexical query issued with skills_only=True whenever the first 30-chunk window contains any chunk with no skill_id (scripts/search_knowledge.py:337-343, mcp/sfskills-mcp/src/sfskills_mcp/skills.py:233-243). Knowledge imports and official-source chunks can never aggregate into a skill, so without this they spend window slots without being able to answer — measured at 20 of 30 slots on "set up single sign on" and 24 of 30 on "share data between two lightning web components", both of which returned no coverage while the owning skill sat in the index. Skipped entirely when the first window is already all-skill.
embeddings — 384-dimension vectors produced by the fastembed backend, used to rerank lexical hits by semantic similarity at a weight of 0.2, hard-coded in pipelines/ranking.py:128. Their status is narrower than either phrasing this repo has used: embeddings.enabled: true is set in config/retrieval-config.yaml, but fastembed is commented out of requirements.txt (line 12), so they are configured on and inert until you install fastembed yourself — neither opt-in behind a flag nor on by default. With no backend present the system logs a warning and falls back to lexical-only, and both surfaces skip embedding the query entirely when no vector file loaded, so the flag cannot cost an install that has nothing to compare against.
Two files are defined. vector_index/skill_embeddings.jsonl holds one vector per skill — 1,027 lines, 5.0 MB — and it is what both search surfaces actually load. vector_index/embeddings.jsonl holds one vector per chunk; the current pipeline does not build it, it is absent from this checkout (manifest.json records "embedding_count": 0), and the ~535 MB cost quoted in older docs describes that file. Measured benefit of installing fastembed, over 154 held-out queries on 2026-08-15: +1.3pp Hit@1 (39.0% → 40.3%) and +5.2pp Hit@3 (48.7% → 53.9%).
vector_index — The directory holding all retrieval artifacts: the chunk text (127 MB), the lexical index (169 MB), the skill embeddings (5.0 MB), a manifest recording counts and content hashes, and the query fixtures. 301 MB on this checkout (du -sh vector_index/). Everything in it is generated, and only three files are tracked in git — manifest.json, query-fixtures.json and query-variants.json (git ls-files vector_index). The large files are rebuilt with python3 scripts/bootstrap.py. Note that the committed manifest.json describes artifacts a fresh clone does not have; it is an integrity baseline, not a statement about your working tree.
registry/skills.json — The whole corpus as one normalised JSON document: every skill's id, name, category, description, tags, file location, official sources and lifecycle status, plus domain_counts and skill_count. Generated from the SKILL.md frontmatter. It is what the MCP server enriches search hits from, what scripts/build_plugin.py generates the rosters from, and what the count lint treats as the authority on corpus size.
coverage gate — The decision about whether retrieval is confident enough to answer at all, as opposed to which skill wins. A skill is kept if max_score >= min_skill_max_score (1.0) or score >= min_skill_score (1.5), both thresholds from config/retrieval-config.yaml. Note the two numbers are different units: the score of the single best chunk, and a cumulative sum across every chunk the skill matched. When nothing clears the gate the CLI prints Coverage: NONE, telling the consumer to fall back to official Salesforce sources; the MCP server returns has_coverage: false with an empty skills list. Both surfaces apply the same predicate (scripts/search_knowledge.py:364, mcp/sfskills-mcp/src/sfskills_mcp/skills.py:265-266) — they have not always, and evals/measurement/check_cli_mcp_parity.py now gates that in CI. rank_score is deliberately excluded: the name/description bonus decides which skill answers, not whether to answer, and folding it in would let a title coincidence manufacture coverage the corpus does not have. See architecture.md.
Read Coverage: NONE as "this index has nothing above threshold", never as "the library has nothing". On a clone with no index it means only that no index was built, and the routers instruct the model to fall back to mechanism 1 rather than report a gap.
harness — A re-runnable verification script that checks behaviour rather than structure. Three exist against a live org, one per job in .github/workflows/org-validation.yml: probe SOQL execution, agent structural and dependency checks, and skill factuality sampling. Reports land under docs/validation/. Contrast with the structural validators, which only check shape.
golden eval — An output-quality test case for a flagship skill, under evals/golden/, carrying assertions, a rubric and a reference answer. Markdown-based, linted by python3 evals/scripts/run_evals.py --structure. The structure lint does run in CI on every pull request (.github/workflows/validate.yml, job evals); what nothing in CI does is score an answer against its rubric. Coverage is 10 of 1,027 packages (1.0%) across 4 of 11 domains — apex 4, integration 3, lwc 2, flow 1 — with three P0 cases each.
query fixture — A curated query paired with the skill it must return, 1,356 of them in vector_index/query-fixtures.json. Enforced inside the sharded validate_repo.py run in CI, which asserts the expected skill appears in the top top_k (default 3), and separately errors if any skill has no fixture at all (scripts/validate_repo.py:355-387). Distinguish these from the held-out queries in evals/measurement/heldout-queries.json: 154 hand-written realistic phrasings, scored by evals/measurement/run_heldout.py, whose thresholds are not gated in CI. Fixtures paraphrase indexed triggers: text and therefore measure the easy case; the held-out set is the honest one, and the two land about 58 points apart.
Tooling
bootstrap — scripts/bootstrap.py, the one command that turns a fresh clone into a working search install: it builds vector_index/chunks.jsonl and vector_index/lexical.sqlite and installs the 67 slash commands into .claude/commands/. It writes nothing tracked, so git status is clean when it finishes. Prefer it over scripts/build_index.py, which reaches the same retrieval outcome through pipelines.sync_engine.write_state and dirties about 1,029 tracked files on a fresh clone (it nulls vector_embedding across the registry records whenever the embedding backend is unavailable).
skill_sync — scripts/skill_sync.py, the one command that regenerates everything derived from the skill packages: the registry, the chunk file, the lexical index, the embeddings and docs/SKILLS.md. --all for the whole repository, --skill for one package, --skip-embeddings for the fast path the pre-commit hook uses. Run it after any skill change. Contributors run this; consumers run bootstrap.py.
build_plugin — scripts/build_plugin.py, which regenerates the routing tier from registry/skills.json: 121 artifacts in total — 23 files under .claude/skills/ (1 entry router + 11 domain routers + 11 rosters), 48 loaders under .claude/agents/, their 48 byte-identical agents/<id>.md twins, and .claude-plugin/plugin.json + .claude-plugin/marketplace.json. --check is the drift gate and fails on any mismatch against a fresh build. --measure prints the token budget. Both are read-only.
validate_repo — scripts/validate_repo.py, the gate that must exit 0 before a change ships. It checks frontmatter, required package files, AGENT.md structure, that every citation resolves to a real file, citation quality, query fixtures, and that no generated artifact has drifted from what the current sources would produce. The full gate list with file and line citations is generated into ../standards/validation-gates.md.
check_doc_counts — scripts/check_doc_counts.py, a narrower lint that derives every corpus-scale number from registry/skills.json and the agent frontmatter, then asserts the docs quoting those numbers still agree. A clean run prints one line beginning Doc counts consistent:.
check_gloss_coverage — see the routing tier. Answers whether a term reaches the shipped roster, which no other gate checks.
MCP server — mcp/sfskills-mcp, a Model Context Protocol server exposing 50 tools (python3 scripts/check_doc_counts.py prints the live count): skill, agent, template and decision-tree retrieval, plus live Salesforce org metadata and read-only SOQL. Published to PyPI as sfskills-mcp: 0.5.0 in-tree, 0.4.10 the newest PyPI release (checked 2026-10-03). It runs over stdio and resolves its data root from SFSKILLS_REPO_ROOT. It is the fastest way to query the library and the only way to ask questions about your actual org — but it is not wired up by installing the plugin, so a user has to connect it themselves.
export target — A tool-native rendering of the corpus produced by scripts/export_skills.py. Eight exist (PLATFORMS in that file): Claude skills, Cursor rules, an MCP-servable bundle, Windsurf, Aider conventions, Augment, Codex CLI prompts, and the cross-tool .agents convention. Targets are not equal in fidelity — only claude, cursor and mcp are first-class (FIRST_CLASS_TARGETS); the parity contract is multi-ai-parity.md.