From f5e63fd06a873346d2eb5b8c64bd68317fa07caa Mon Sep 17 00:00:00 2001 From: Ayush Gupta Date: Mon, 4 May 2026 11:34:12 +0530 Subject: [PATCH] @W-22252932 [Meta Skill] Skill Creator (#232) * @W-22252932 [Meta Skill] Skill Creator * @W-22252932 [Meta Skill] Skill Creator * @W-22252932 [Meta Skill] Skill Creator * @W-22252932 [Meta Skill] Skill Creator * @W-22252932 [Meta Skill] Skill Creator * @W-22252932 [Meta Skill] Skill Creator * @W-22252932 [Meta Skill] Skill Creator * @W-22252932 [Meta Skill] Skill Creator --- skills/creating-sf-skill/SKILL.md | 367 ++++++++++++++++++ .../examples/simple-metadata-skill/SKILL.md | 87 +++++ .../assets/validation_rule_template.xml | 9 + .../examples/require_email_on_contact.xml | 9 + .../references/formula_patterns.md | 85 ++++ .../references/best_practices.md | 149 +++++++ .../references/progressive_disclosure.md | 85 ++++ .../references/validation_rules.md | 129 ++++++ .../templates/frontmatter_reference.yaml | 92 +++++ .../templates/skill_template.md | 109 ++++++ .../templates/tests_structure.md | 98 +++++ 11 files changed, 1219 insertions(+) create mode 100644 skills/creating-sf-skill/SKILL.md create mode 100644 skills/creating-sf-skill/examples/simple-metadata-skill/SKILL.md create mode 100644 skills/creating-sf-skill/examples/simple-metadata-skill/assets/validation_rule_template.xml create mode 100644 skills/creating-sf-skill/examples/simple-metadata-skill/examples/require_email_on_contact.xml create mode 100644 skills/creating-sf-skill/examples/simple-metadata-skill/references/formula_patterns.md create mode 100644 skills/creating-sf-skill/references/best_practices.md create mode 100644 skills/creating-sf-skill/references/progressive_disclosure.md create mode 100644 skills/creating-sf-skill/references/validation_rules.md create mode 100644 skills/creating-sf-skill/templates/frontmatter_reference.yaml create mode 100644 skills/creating-sf-skill/templates/skill_template.md create mode 100644 skills/creating-sf-skill/templates/tests_structure.md diff --git a/skills/creating-sf-skill/SKILL.md b/skills/creating-sf-skill/SKILL.md new file mode 100644 index 0000000..a0d89d0 --- /dev/null +++ b/skills/creating-sf-skill/SKILL.md @@ -0,0 +1,367 @@ +--- +name: creating-sf-skill +description: "AI-assisted skill authoring pipeline for the afv-library. Use when the user wants to create a new skill, update an existing skill, generate a skill spec, scaffold skill files, or add a new capability to the skill catalog. TRIGGER when: user says create skill, new skill, skill creator, author skill, scaffold skill, generate skill, update skill, add a skill, skill pipeline. DO NOT TRIGGER when: user is directly editing an existing SKILL.md without asking for guided authoring.Invoke this skill whenever someone needs to add a new capability to the afv-library skill catalog, or wants to update/improve an existing skill. This includes creating skills for Apex, metadata, LWC, Flow, Agentforce, or any Salesforce domain." +license: LICENSE.txt has complete terms +metadata: + version: "1.0" + stage: Pilot +--- + +# Instructions + +You are a contributor onboarding tool for the [afv-library](https://github.com/forcedotcom/afv-library). +Your job is to take minimal input and generate a complete, validated skill as fast as possible. +Ask **one thing at a time**. Generate first, refine after. Do not explain the pipeline. + +The full contribution lifecycle has 5 phases: + +| Phase | What | Status | +|-------|------|--------| +| 1 | Gather authoritative input | **This skill handles** | +| 2 | Generate v1 Draft | **This skill handles** | +| 3 | Generate test stubs | **This skill handles** | +| 4 | Run eval, move to Under Review | Next step for contributor | +| 5 | Push PR to afv-library, CI publishes | Final step for contributor | + +--- + +## On Start + +If the user passed `$ARGUMENTS` (a skill name), check if `skills/$0/SKILL.md` already exists. +If yes, use `AskUserQuestion`: options `Update existing skill` | `Create new skill with different name`. + +Otherwise proceed to Step 1. + +--- + +## Step 1 — Infer or confirm skill type + +**Try to infer the skill type from the user's message before asking.** + +| If the user mentions… | Infer type | +|----------------------|------------| +| metadata, object, field, validation rule, permission set, flow, layout, component, prompt template | Metadata generation | +| Apex class, trigger, batch, LWC, JavaScript, test class | Code generation | +| deploy, debug, setup, migrate, process, pipeline | Workflow / process | + +- If confident: state the inferred type inline. Suggest 2-3 gerund skill names, **pick one as your recommendation, and briefly explain why** (e.g. most specific, matches naming convention, clearest intent). Move to Step 2. +- If genuinely uncertain: use `AskUserQuestion`: + +``` +question: "What kind of skill do you want to create?" +header: "Skill type" +options: + - label: "Metadata generation" + description: "Creates Salesforce metadata — custom objects, fields, validation rules, etc." + - label: "Code generation" + description: "Generates Apex classes, triggers, LWC components, or other code artifacts." + - label: "Workflow / process" + description: "Guides the user through a multi-step process — deployments, debugging, org setup, etc." + - label: "Other" + description: "Something else — I'll describe it." +``` + +After confirming type, **suggest 2-3 skill names inline** using the gerund naming convention +(e.g., `generating-validation-rule`, `building-data-cloud-connector`). Present as text, not a question. + +--- + +## Step 2 — Describe the skill + gather reference material + +**Do not expose step numbers to the user.** Never say "Step 2" or label sections in user-facing messages. + +Use `AskUserQuestion` to understand the use case: + +``` +header: "Use case" +question: "What's the use case for this skill? Tell me what problem it solves, who would use it, and what it should produce. + +If you have any examples, schemas, or docs handy, feel free to share them too — a file path, URL, or paste works." +options: + - label: "I'll describe it here" + description: "Type your use case and I'll generate from that." + - label: "I have reference material" + description: "I'll share a schema, example file, or doc." +``` + +Read every resource the user provides. Then summarize what you extracted — keep it tight, 2-3 bullets max: + +> **Extracted context:** +> • … +> • … + +**Now generate the description** using both the user's description and the extracted context. +Expand it to include trigger phrases, `TRIGGER when` / `DO NOT TRIGGER when` clauses, and the word "use". + +**Print the description as plain text in your response message first**, then call `AskUserQuestion`. The user cannot see the description inside the tool's question or option fields — it must appear in the message body before the tool call. + +Example message format: +``` +Here's the skill description I've drafted: + +> **Skill name:** `generating-` +> +> **Description:** + +Does this capture it? +``` + +Then use `AskUserQuestion`: + +``` +question: "Does this description capture what you want the skill to do?" +header: "Description" +options: + - label: "Looks good (Recommended)" + description: "Use this and proceed to generation." + - label: "I want to edit it" + description: "Tell me what to change." +``` + +If they edit, incorporate and re-confirm. + +**Silent background work before generating:** +- Scan `skills/` for existing skills with overlapping scope (duplicate check). +- Identify dependency candidates from existing skill names. +- Infer gotchas from domain knowledge and the provided reference material. + +--- + +## Step 3 — Generate + +Tell the user: **"Generating Skill..."** + +Then do the work. Do not ask any more questions. + +1. Read `./references/progressive_disclosure.md` — use it to decide what + goes in SKILL.md vs `assets/` vs `references/` vs `examples/`. +2. Read `./templates/skill_template.md`. +3. Read `./templates/frontmatter_reference.yaml`. +4. Read `./references/best_practices.md`. +5. Generate all files following the rules below. + +### What goes WHERE — hard rules + +SKILL.md is **only** for the workflow, rules, and gotchas. Everything else goes into subdirectories. + +| Content type | Where it goes | +|-------------|---------------| +| Code templates (`.cls`, `.xml`, `.js`, `.html`) | `assets/` | +| Code examples / sample output | `examples/` | +| API specs, schemas, XML definitions | `references/` or `assets/` | +| Detailed reference tables (> 20 rows) | `references/` | +| Step-by-step guides for sub-procedures | `references/` | +| Input/output example pairs | `examples/` | +| Configuration files, manifests | `assets/` | + +**What stays in SKILL.md**: frontmatter, overview (1-3 sentences), scope, required inputs, +workflow steps, constraint table, gotchas table (short), output expectations (file list only), +cross-skill integration table, and Reference File Index. + +### How to reference files from SKILL.md + +Every file in `assets/`, `references/`, or `examples/` **must** have a specific load instruction +in SKILL.md. Use this pattern: + +```markdown +1. **Read the service template** — load `assets/service.cls` before generating. +2. **For REST endpoints**, read `references/rest_api_patterns.md` for status codes. +3. **See example output** in `examples/basic_service.cls` for the expected structure. +``` + +Never write "see references/ for details." Always name the specific file and scenario. + +### Directory structure to create + +``` +skills// +├── SKILL.md # Workflow + rules + gotchas ONLY (target < 300 lines) +├── assets/ # Code templates, XML schemas, config files +├── references/ # Prose docs, detailed tables, sub-guides +├── examples/ # Input/output pairs, sample generated files +└── tests/ + └── evals/ + ├── -/ + │ ├── prompt.md # Exact trigger prompt (no heading — just the prompt text) + │ └── gold/ # Expected output artifact + ├── -/ + │ ├── prompt.md + │ └── gold/ + └── -/ + ├── prompt.md + └── gold/ +``` + +Read `./templates/tests_structure.md` before scaffolding `tests/`. + +Create `assets/`, `references/`, and `examples/` only if there is content to put in them. +Do NOT create `tests/unit/` — only create `tests/evals/` with 2-3 datasets. + +### Generating SKILL.md content + +**Frontmatter — always set `stage: Draft`:** + +```yaml +--- +name: +description: "" +license: LICENSE.txt has complete terms +metadata: + version: "1.0" + stage: Draft +--- +``` + +**Body rules:** +- Add what the agent lacks, omit what it knows. +- Task-oriented: every section = an instruction, not a description. +- Target < 300 lines for SKILL.md body. + +**Required sections:** + +| Section | What to write | +|---------|---------------| +| Title + overview | 1-3 sentences — what and why | +| Scope | In-scope / out-of-scope boundary | +| Required Inputs | What context to gather before acting | +| Workflow | Numbered steps with `read` instructions | +| Rules | Hard constraints table | +| Gotchas | Short table of pitfalls — max 10 rows | +| Output Expectations | List of files produced (not their content) | +| Cross-Skill Integration | When to delegate (if applicable) | +| Reference File Index | Maps every subdirectory file to when it's read | + +### Write all files + +1. Write `skills//SKILL.md`. +2. Write each `assets/` file — code templates, schemas. +3. Write each `references/` file — detailed guides, tables. +4. Write each `examples/` file — sample inputs/outputs. +5. Write `tests/evals/` datasets — see Step 4 below for eval content rules. + +### Validate + +Run the validator: + +```bash +npx tsx scripts/validate-skills.ts 2>&1 +``` + +For the full list of rules, see `./references/validation_rules.md`. + +**If validation fails**: fix the issues and re-run. Only surface to the user if you cannot +resolve an issue yourself. + +--- + +## Step 4 — Review + +Tell the user: + +> **"Your skill is generated and in draft state — please review and let me know if you'd like any changes."** + +Then print the file tree and key decisions: + +``` +skills// +├── SKILL.md +├── assets/ +├── references/ +├── examples/ +└── tests/ + └── evals//, /, / + +Key decisions: +• +• +• +``` + +Use `AskUserQuestion`: + +``` +question: "Would you like to make any changes?" +header: "Review" +options: + - label: "Looks good" + description: "Proceed to generating eval datasets." + - label: "I want changes" + description: "Tell me what to modify and I'll update the skill." +``` + +If changes requested: collect feedback, edit files, re-validate, re-print, return here. + +--- + +## Step 5 — Generate eval datasets + +Read `./templates/tests_structure.md` before writing eval files. + +For each of 2-3 positive trigger scenarios (derived from the skill description): + +**`tests/evals/-/prompt.md`** — write the exact prompt a user would type. +No heading, no title, no markdown framing — just the raw prompt text: + +``` + +``` + +**`tests/evals/-/gold/`** — expected output file with the +correct extension for the artifact type (e.g. `ContactEmail.validationRule-meta.xml`, `AccountService.cls`). +Infer extension from skill type. Mark with a stub comment at the top: + +``` +# STUB — review and update expected output before running eval +``` + +Do **not** create `seed-data/` folders — those are filled in by the contributor during eval. + +Use `AskUserQuestion`: + +``` +question: "Eval stubs generated. How do they look?" +header: "Evals" +options: + - label: "Looks good" + description: "Proceed to next steps." + - label: "Add or change some" + description: "Tell me what to adjust." +``` + +--- + +## Step 6 — Done + +Print the final summary: + +``` +Skill: +Location: skills// +Stage: Draft + +What this skill does: +• <1-line summary of primary capability> +• +• + +Next steps: +1. Run the eval prompts in tests/evals/ and review the outputs against gold/. + When the outputs look right, update the frontmatter: stage: Under Review +2. Once you're happy with the skill, open a PR to forcedotcom/afv-library. + CI will validate the skill and publish it to the catalog. +``` + +--- + +## Gotchas (for you, the agent) + +| Issue | What to do | +|-------|------------| +| Description missing "use" | Validator requires it. Always include "Use when..." in generated descriptions. | +| YAML parse error | Descriptions contain `: ` — always wrap in double quotes. | +| Gerund naming | First word must end in `-ing`. Suggest names that follow this. | +| Body over 500 lines | Split into `references/`. See `./references/progressive_disclosure.md`. | +| User gives vague input | Don't ask repeatedly — make your best guess, generate, and confirm. | +| Validation fails | Fix it yourself. Only ask the user if you genuinely can't resolve it. | +| No reference material provided | Generate representative stubs; mark everything `# STUB`. | +| Skill type is clear from user message | Do not ask — infer it, state it, move on. | diff --git a/skills/creating-sf-skill/examples/simple-metadata-skill/SKILL.md b/skills/creating-sf-skill/examples/simple-metadata-skill/SKILL.md new file mode 100644 index 0000000..50d8560 --- /dev/null +++ b/skills/creating-sf-skill/examples/simple-metadata-skill/SKILL.md @@ -0,0 +1,87 @@ +--- +name: generating-validation-rule +description: "Create and update Salesforce validation rules for any standard or custom object. Use when the user asks to add a validation rule, enforce field requirements, prevent invalid data entry, or implement record-level business logic constraints. TRIGGER when: user says validation rule, field validation, required field check, data constraint, record validation, prevent invalid data. DO NOT TRIGGER when: user asks about Flow validation or Apex validation logic — delegate to generating-flow or generating-apex." +metadata: + version: "1.0" + stage: Draft + license: LICENSE.txt has complete terms +--- + +# Generating Validation Rules + +Create validation rules that enforce business logic at the record level. + +## Scope + +- **In scope**: Creating new validation rules, updating existing rules, formula syntax, + error message placement, activation/deactivation. +- **Out of scope**: Flow-based validation (use `generating-flow`), Apex triggers for + complex validation (use `generating-apex`). + +## Required Inputs + +- Target object (standard or custom) +- Business rule to enforce (in plain language) +- Error message text +- Error location (top of page or specific field) + +Defaults: +- Active: true +- Description: auto-generated from the business rule + +## Workflow + +1. **Identify the object** — confirm the API name of the target object. +2. **Understand the rule** — translate the business requirement into a boolean formula. +3. **Check existing rules** — look for overlapping validation rules on the same object. +4. **Read the metadata template** — load `./assets/validation_rule_template.xml` before generating. +5. **Write the formula** — the formula must evaluate to `TRUE` when the data is **invalid**. + For common formula patterns, read `./references/formula_patterns.md`. +6. **Set error message** — clear, user-friendly message explaining what's wrong and how to fix it. +7. **Create metadata file** — generate the `.validationRule-meta.xml` using the template structure. + Compare against `./examples/require_email_on_contact.xml` for expected output format. +8. **Syntax check** — verify the formula compiles (field API names, function syntax). +9. **Edge case review** — test with null values, blank strings, boundary conditions. + +## Rules + +| Constraint | Rationale | +|-----------|-----------| +| Formula evaluates to TRUE on invalid data | Salesforce convention — TRUE = error | +| Use API names, not labels | Labels change; API names are stable | +| Handle null fields with `ISBLANK()` | Prevent null pointer errors | +| Use `PRIORVALUE()` only in update context | Not available on insert | + +## Gotchas + +| Issue | Resolution | +|-------|------------| +| Rule fires on record types it shouldn't | Add `RecordType.DeveloperName` check to formula | +| Rule blocks data migration/bulk loads | Add bypass via Custom Permission or Custom Metadata | +| `ISCHANGED()` always false on insert | Guard with `NOT(ISNEW())` before using `ISCHANGED()` | +| Formula too long (> 5000 chars) | Split into multiple rules or use a helper formula field | +| Error on wrong field | Verify field API name in `errorConditionFormula` attribute | + +## Output Expectations + +Deliverables per validation rule: +- `.validationRule-meta.xml` + +File structure follows the template in `./assets/validation_rule_template.xml`. + +## Cross-Skill Integration + +| Need | Delegate to | +|------|-------------| +| Complex multi-object validation | `generating-apex` (trigger-based) | +| Flow-based validation with user prompts | `generating-flow` | +| Custom object creation | `generating-custom-object` | +| Field creation for formula references | `generating-custom-field` | + +## Reference File Index + +| File | When to read | +|------|-------------| +| `./assets/validation_rule_template.xml` | Before generating any validation rule metadata file | +| `./references/formula_patterns.md` | When writing the formula — common patterns and functions | +| `./examples/require_email_on_contact.xml` | To verify generated output matches expected format | diff --git a/skills/creating-sf-skill/examples/simple-metadata-skill/assets/validation_rule_template.xml b/skills/creating-sf-skill/examples/simple-metadata-skill/assets/validation_rule_template.xml new file mode 100644 index 0000000..99dadd5 --- /dev/null +++ b/skills/creating-sf-skill/examples/simple-metadata-skill/assets/validation_rule_template.xml @@ -0,0 +1,9 @@ + + + {ObjectApiName}.{RuleDeveloperName} + true + {Plain language description of what this rule enforces} + {Formula that evaluates TRUE when data is INVALID} + {FieldApiName — omit for page-level errors} + {User-friendly message: what's wrong and how to fix it} + diff --git a/skills/creating-sf-skill/examples/simple-metadata-skill/examples/require_email_on_contact.xml b/skills/creating-sf-skill/examples/simple-metadata-skill/examples/require_email_on_contact.xml new file mode 100644 index 0000000..b2dbc17 --- /dev/null +++ b/skills/creating-sf-skill/examples/simple-metadata-skill/examples/require_email_on_contact.xml @@ -0,0 +1,9 @@ + + + Contact.Require_Email + true + Requires an email address on all Contact records + ISBLANK(Email) + Email + Email is required on Contact records. Please provide a valid email address. + diff --git a/skills/creating-sf-skill/examples/simple-metadata-skill/references/formula_patterns.md b/skills/creating-sf-skill/examples/simple-metadata-skill/references/formula_patterns.md new file mode 100644 index 0000000..b7ec3c9 --- /dev/null +++ b/skills/creating-sf-skill/examples/simple-metadata-skill/references/formula_patterns.md @@ -0,0 +1,85 @@ +# Common Validation Rule Formula Patterns + +## Required field (non-blank) + +``` +ISBLANK(Field__c) +``` + +Error: "Field is required." + +## Required field only on specific record type + +``` +AND( + RecordType.DeveloperName = "Enterprise", + ISBLANK(Field__c) +) +``` + +## Numeric range check + +``` +OR( + Amount__c <= 0, + Amount__c > 1000000 +) +``` + +Error: "Amount must be between 1 and 1,000,000." + +## Date must be in the future + +``` +Close_Date__c <= TODAY() +``` + +Error: "Close date must be after today." + +## Date comparison (end after start) + +``` +End_Date__c <= Start_Date__c +``` + +Error: "End date must be after start date." + +## Field changed validation (update only) + +``` +AND( + NOT(ISNEW()), + ISCHANGED(Stage__c), + ISPICKVAL(PRIORVALUE(Stage__c), "Closed Won") +) +``` + +Error: "Cannot change stage after Closed Won." + +## Bypass with Custom Permission + +Wrap any formula to allow admin bypass: + +``` +AND( + NOT($Permission.Bypass_Validation_Rules), + {your formula here} +) +``` + +## Regex pattern match (email format) + +``` +NOT(REGEX(Email__c, "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$")) +``` + +## Cross-field dependency + +``` +AND( + ISPICKVAL(Type__c, "Partner"), + ISBLANK(Partner_Account__c) +) +``` + +Error: "Partner Account is required when Type is Partner." diff --git a/skills/creating-sf-skill/references/best_practices.md b/skills/creating-sf-skill/references/best_practices.md new file mode 100644 index 0000000..7faad58 --- /dev/null +++ b/skills/creating-sf-skill/references/best_practices.md @@ -0,0 +1,149 @@ +# Skill Authoring Best Practices + +Principles for writing high-quality skills. Based on patterns observed across the +afv-library and the Agent Skills best practices guide. + +## Core Principles + +### 1. Add What the Agent Lacks, Omit What It Knows + +The most common mistake is including general knowledge the LLM already has. +Focus exclusively on: + +- **Project-specific conventions** — naming patterns, directory structure, coding standards + unique to this project. +- **Domain-specific procedures** — workflows, API quirks, deployment steps that are + not publicly documented or are team-specific. +- **Gotchas** — failure modes, edge cases, known bugs that the agent would not anticipate. + +**Omit**: general programming concepts, language syntax, well-known design patterns. + +### 2. Extract from a Hands-On Task + +The best skills are written after doing the task manually: + +1. Perform the task yourself (or watch someone do it). +2. Note every decision point, tool invocation, and gotcha encountered. +3. Write the skill as the instructions you wish you had before starting. +4. Feed real execution traces back into the skill. + +### 3. Refine with Real Execution + +> "The first draft of a skill usually needs refinement. Run the skill against real +> tasks, then feed the results — all of them, not just failures — back into the +> creation process." + +After generating a skill: +- Run it against 3-5 real prompts. +- Read the full execution trace, not just the final output. +- Identify: false positives, false negatives, wasted tokens, vague instructions. + +### 4. Task-Oriented, Not Concept-Oriented + +Structure skills around what the agent should **do**, not what **exists**. + +**Bad**: "Apex supports various class types including Service, Selector, Domain..." + +**Good**: "1. Identify the class type needed. 2. Read the matching template from assets/. +3. Generate the class following the template pattern." + +### 5. Concise Over Comprehensive + +Every token in a SKILL.md costs compute and risks confusing the agent with +irrelevant instructions. Cut ruthlessly: + +- Remove sections the agent never follows. +- Remove examples that duplicate other examples. +- Remove caveats about edge cases that never happen. + +## Description Writing + +The description is the most important field — it determines when the skill triggers. + +### Do + +- Front-load the primary use case. +- Include specific keywords users say: "Apex", ".cls", "trigger", "batch job". +- Add `TRIGGER when:` and `DO NOT TRIGGER when:` clauses. +- **Be pushy**: list implicit triggers where the user may not use the domain term directly. +- Keep it factual and specific. + +### Don't + +- Use vague language: "helps with Salesforce development". +- Include implementation details: "uses the AccountService pattern". +- Make it too narrow: only one exact phrase triggers it. +- Make it too broad: triggers on everything. + +### Be Pushy About Triggers + +Err on the side of listing more implicit triggers, not fewer. A skill that never fires is useless; +a skill that fires on a near-miss is recoverable. Explicitly call out contexts where the skill +applies **even if the user doesn't name the domain directly**: + +> "TRIGGER when: user asks to add a rule, restrict a field, or enforce a policy — even if they +> don't explicitly say 'validation rule' or 'Apex'." + +This is especially important for domain keywords the user may not know (e.g., they say "make this +field required" not "add a required validation rule"). + +### Template + +``` +. ALWAYS ACTIVATE when . +Use this skill for . TRIGGER when: . +DO NOT TRIGGER when: . +``` + +## Workflow Structure + +### Phase-Based + +For multi-step skills, use numbered phases: + +```markdown +### Phase 1 — Discover +1. **Read project conventions** — check for existing patterns. +2. **Identify inputs** — what context is needed. + +### Phase 2 — Generate +3. **Read template** — load the matching template. +4. **Author code** — generate following the template. + +### Phase 3 — Validate +5. **Run checks** — execute validation tools. +6. **Report** — present results. +``` + +### Decision Matrices + +For complex decisions, use tables instead of nested conditionals: + +```markdown +| Scenario | Pattern | Template | +|----------|---------|----------| +| Standard async work | Queueable | assets/queueable.cls | +| Large datasets | Batch Apex | assets/batch.cls | +| Recurring schedule | Schedulable | assets/schedulable.cls | +``` + +## Anti-Patterns + +| Anti-Pattern | Why It's Bad | Fix | +|-------------|-------------|-----| +| Wall of text with no structure | Agent can't find relevant instructions | Use headers, tables, numbered steps | +| Generic advice | Wastes tokens on things the agent knows | Add only project-specific knowledge | +| Deeply nested conditionals | Agent loses track of which branch it's in | Flatten into decision tables | +| Too many optional steps | Agent follows all of them, wasting time | Make steps required or remove them | +| Missing gotchas section | Agent hits known pitfalls | Add gotchas from real execution failures | +| Referencing files that don't exist | Agent hallucinates content | Verify all referenced paths exist | +| Duplicating content from other skills | Wastes tokens and risks staleness | Reference the other skill instead | + +## Cross-Skill Integration Patterns + +When your skill needs another skill's capability: + +1. **Delegate explicitly**: "For Apex tests, delegate to `generating-apex-test` skill." +2. **Define boundaries clearly**: "This skill handles X. For Y, use Z skill." +3. **Don't duplicate**: If another skill covers a topic, reference it, don't copy. diff --git a/skills/creating-sf-skill/references/progressive_disclosure.md b/skills/creating-sf-skill/references/progressive_disclosure.md new file mode 100644 index 0000000..23043b1 --- /dev/null +++ b/skills/creating-sf-skill/references/progressive_disclosure.md @@ -0,0 +1,85 @@ +# Progressive Disclosure — What Goes Where + +SKILL.md is the workflow controller. It tells the agent what to do and when to read other files. +It does **not** contain the detailed content itself. + +## Hard Rules + +These are not guidelines. Always follow them. + +| Content type | Goes in | Example filename | +|-------------|---------|-----------------| +| Code templates | `assets/` | `service.cls`, `batch.cls`, `rest_resource.cls` | +| XML schemas / metadata templates | `assets/` | `meta_template.xml`, `object_schema.xml` | +| Config samples, manifests | `assets/` | `sfdx-project.json`, `package.xml` | +| API reference docs | `references/` | `api_patterns.md`, `rest_endpoints.md` | +| Detailed decision tables (> 20 rows) | `references/` | `error_codes.md`, `field_mappings.md` | +| Step-by-step sub-procedures | `references/` | `deployment_steps.md`, `migration_guide.md` | +| Edge case handling guides | `references/` | `edge_cases.md`, `null_handling.md` | +| Full input/output examples | `examples/` | `basic_usage.md`, `AccountService.cls` | +| Sample generated files | `examples/` | `example_output.xml`, `sample_trigger.trigger` | + +## What Stays in SKILL.md + +Only these belong in the main file: + +- **Frontmatter** (name, description, metadata) +- **Overview** (1-3 sentences) +- **Scope** (in/out boundary) +- **Required Inputs** (bullet list of what to gather) +- **Workflow** (numbered steps with read instructions to subdirectory files) +- **Rules/Constraints** (short table — max 15 rows) +- **Gotchas** (short table — max 10 rows) +- **Output Expectations** (file list only, not content) +- **Cross-Skill Integration** (delegation table) +- **Reference File Index** (maps every subdirectory file to its trigger) + +Target: **< 300 lines** for SKILL.md body. + +## How to Reference from SKILL.md + +Every file in a subdirectory needs a specific load instruction in the workflow section. + +**Good — embedded in a workflow step:** + +```markdown +1. **Read the service template** — load `assets/service.cls` before generating. +2. **Check error handling patterns** — if the class needs custom exceptions, read `references/error_handling.md`. +3. **Compare against example** — verify output matches `examples/AccountService.cls`. +``` + +**Good — in the Reference File Index:** + +```markdown +| File | When to read | +|------|-------------| +| `assets/service.cls` | Before generating any service class | +| `references/error_handling.md` | When implementing custom exception handling | +| `examples/AccountService.cls` | To verify generated output matches expected format | +``` + +**Bad — vague references the agent will ignore:** + +```markdown +See the `references/` directory for more details. +Check `assets/` for templates. +``` + +## Common Mistakes + +| Mistake | Why it's wrong | Fix | +|---------|---------------|-----| +| Inlining a 50-line code template in SKILL.md | Bloats the file, wastes tokens on every invocation | Put in `assets/`, add a read instruction | +| Pasting an API spec into the workflow | Spec content is static reference, not workflow | Put in `references/`, read only when needed | +| Adding example output inline | Examples are for validation, not every-run context | Put in `examples/`, reference from output section | +| Creating subdirectory but not referencing it | Agent never reads unreferenced files | Add entry to Reference File Index | +| Using "see references/" without naming a file | Agent doesn't know which file to read | Always name the specific file | + +## Token Budget + +| Component | Target | Maximum | +|-----------|--------|---------| +| SKILL.md body | < 300 lines | 500 lines | +| Single reference file | < 200 lines | 300 lines | +| Single asset file | No line limit | Keep focused on one template | +| Single example file | < 100 lines | 200 lines | diff --git a/skills/creating-sf-skill/references/validation_rules.md b/skills/creating-sf-skill/references/validation_rules.md new file mode 100644 index 0000000..a002961 --- /dev/null +++ b/skills/creating-sf-skill/references/validation_rules.md @@ -0,0 +1,129 @@ +# Validation Rules Reference + +Complete reference for all validation checks enforced by `scripts/validate-skills.ts`. +The validator runs structure checks first (before reading SKILL.md), then content checks. + +## Structure Checks + +These run on every entry in `skills/` before SKILL.md is read. +A fatal error aborts all content checks for that entry. + +### 1. Entry Must Be a Directory + +- **Severity**: Error (fatal) +- **Rule**: No loose files in `skills/` — only directories. +- **Fix**: Move the file into a skill directory or remove it. + +### 2. Must Contain SKILL.md + +- **Severity**: Error (fatal) +- **Rule**: Every skill directory must have a `SKILL.md` file. +- **Fix**: Create `SKILL.md` with proper frontmatter and body. + +### 3. Name Must Be Kebab-Case + +- **Severity**: Error +- **Pattern**: `^[a-z0-9]+(-[a-z0-9]+)*$` +- **Allowed**: lowercase letters, digits, hyphens +- **Not allowed**: uppercase, underscores, dots, spaces +- **Examples**: + - `generating-apex` (valid) + - `Generating-Apex` (invalid — uppercase) + - `generating_apex` (invalid — underscore) + +### 4. Name <= 64 Characters + +- **Severity**: Error +- **Rule**: Directory name must not exceed 64 characters. + +### 5. Gerund First Word + +- **Severity**: Warning (not blocking) +- **Rule**: First word of the skill name should end in `-ing`. +- **Rationale**: Convention for consistency (e.g., `generating-`, `building-`, `deploying-`). +- **Examples**: + - `generating-apex` (pass) + - `agentforce-development` (warning — "agentforce" doesn't end in -ing) + +### 6. No Nested Skills + +- **Severity**: Error +- **Rule**: No subdirectory of a skill may contain its own `SKILL.md`. +- **Fix**: Flatten nested skills to be siblings under `skills/`. + +## Content Checks + +These run after SKILL.md is read successfully. + +### 7. Valid YAML Frontmatter Block + +- **Severity**: Error (fatal) +- **Rule**: SKILL.md must start with `---\n...\n---` YAML frontmatter. +- **Fix**: Add frontmatter between `---` delimiters at the top of the file. + +### 8. JSON-Compatible YAML + +- **Severity**: Error +- **Rule**: Frontmatter must parse with `js-yaml` JSON_SCHEMA. +- **Common cause**: Unquoted values containing `: ` (colon + space). +- **Fix**: Wrap values in single or double quotes. + ```yaml + # BAD + description: Primary skill: generates Apex classes + + # GOOD + description: "Primary skill: generates Apex classes" + ``` + +### 9. `name` Matches Directory + +- **Severity**: Error +- **Rule**: The `name` field in frontmatter must exactly match the directory name. +- **Fix**: Ensure `name: generating-apex` if the directory is `skills/generating-apex/`. + +### 10. `description` Present and Non-Empty + +- **Severity**: Error +- **Rule**: Frontmatter must include a `description` field with content. + +### 11. Body Non-Empty + +- **Severity**: Error +- **Rule**: There must be content after the frontmatter block. + +### 12. Description >= 20 Words + +- **Severity**: Error +- **Rule**: Description must contain at least 20 words. +- **Rationale**: Short descriptions don't provide enough trigger context. + +### 13. Description <= 1024 Characters + +- **Severity**: Error +- **Rule**: Description must not exceed 1024 characters. + +### 14. Description Contains "use" + +- **Severity**: Error +- **Rule**: Description must include the word "use" (case-insensitive). +- **Rationale**: Enforces trigger/activation language. +- **Fix**: Include phrases like "Use when...", "Use this skill for...", "Used to...". + +### 15. Body <= 500 Lines + +- **Severity**: Warning (not blocking) +- **Rule**: Skill body should be under 500 lines for context efficiency. +- **Fix**: Extract detailed content into `references/` with conditional load instructions. + +## Running Validation + +```bash +# Validate all skills +npm run validate:skills + +# Validate only changed skills (CI mode) +npm run validate:skills -- --changed --base=origin/main + +# Validate a specific skill (filter output) +npx tsx scripts/validate-skills.ts 2>&1 | grep -A5 "" +``` diff --git a/skills/creating-sf-skill/templates/frontmatter_reference.yaml b/skills/creating-sf-skill/templates/frontmatter_reference.yaml new file mode 100644 index 0000000..41cdc39 --- /dev/null +++ b/skills/creating-sf-skill/templates/frontmatter_reference.yaml @@ -0,0 +1,92 @@ +# AFV-Library Skill Frontmatter — Complete Field Reference +# +# All skills in skills//SKILL.md must include YAML frontmatter +# between --- delimiters. This file documents every supported field. +# +# Validation: scripts/validate-skills.ts + +# ============================================================ +# REQUIRED FIELDS +# ============================================================ + +name: + type: string + required: true + description: "Unique skill identifier. Must match the directory name exactly." + validation: + pattern: "^[a-z0-9]+(-[a-z0-9]+)*$" + max_length: 64 + example: "generating-apex" + +description: + type: string + required: true + description: > + What the skill does and when it should activate. This is the primary + signal used for skill routing — it must be rich and specific. + validation: + min_words: 20 + max_chars: 1024 + must_contain: "use" + tips: + - "Include TRIGGER when and DO NOT TRIGGER when clauses" + - "Front-load the most important use case" + - "Include specific keywords users would say" + - "Must be wrapped in double quotes if it contains ': '" + example: > + "Primary Apex authoring skill for class generation, refactoring, and review. + ALWAYS ACTIVATE when the user mentions Apex, .cls, triggers, or asks to + create/refactor a class. Use this skill for requests involving SObject CRUD, + mapping collections, or code review of existing Apex." + +# ============================================================ +# OPTIONAL FIELDS +# ============================================================ + +license: + type: string + required: false + description: "License for the skill. Top-level frontmatter field — NOT nested under metadata." + default: "LICENSE.txt has complete terms" + example: "LICENSE.txt" + +metadata: + type: object + required: false + fields: + version: + type: string + description: "Version. New skills use \"1.0\"." + example: "1.0" + stage: + type: enum + values: ["Draft", "Under Review", "Published"] + description: "Current lifecycle stage." + argument-hint: + type: string + description: "CLI usage hint shown in autocomplete." + example: " [--type service|selector|batch]" + +# ============================================================ +# COMMON MISTAKES +# ============================================================ +# +# 1. Unquoted description with ": " — causes YAML parse error +# BAD: description: Primary skill: generates Apex +# GOOD: description: "Primary skill: generates Apex" +# +# 2. Name doesn't match directory +# Directory: skills/generating-apex/ +# Frontmatter name must be: generating-apex +# +# 3. Description too short +# Must be at least 20 words. Include trigger context. +# +# 4. Missing "use" in description +# Validator checks for the word "use" (case-insensitive) +# Include: "Use when...", "Use this skill for...", etc. +# +# 5. license nested under metadata +# BAD: metadata: +# license: ... +# GOOD: license: Apache-2.0 # top-level field diff --git a/skills/creating-sf-skill/templates/skill_template.md b/skills/creating-sf-skill/templates/skill_template.md new file mode 100644 index 0000000..aabc7aa --- /dev/null +++ b/skills/creating-sf-skill/templates/skill_template.md @@ -0,0 +1,109 @@ +--- +name: +description: "" +license: LICENSE.txt has complete terms +metadata: + version: "1.0" + stage: Draft +--- + +# + +<1-3 sentence overview: what this skill does and why it exists.> + +## Scope + +- **In scope**: +- **Out of scope**: + +--- + +## Required Inputs + +Gather or infer before proceeding: + +- : +- : +- : + +Defaults unless specified: +- +- + +If the user provides a clear, complete request, generate immediately without unnecessary back-and-forth. + +--- + +## Workflow + +All steps are sequential. Do not skip or reorder. If blocked, stop and ask for missing context. + +1. **** + - + - + +2. **Read the template** — load `assets/` before generating. + +3. **** + - + - For , read `references/.md`. + +4. **** + - + - Compare output against `examples/`. + +--- + +## Rules / Constraints + + + +| Constraint | Rationale | +|-----------|-----------| +| | | +| | | + +--- + +## Gotchas + + + +| Issue | Resolution | +|-------|------------| +| | | +| | | + +--- + +## Output Expectations + +Deliverables: +- : `` +- : `` + +File structure follows the template in `assets/`. + +--- + +## Cross-Skill Integration + + + +| Need | Delegate to | +|------|-------------| +| | `` skill | +| | `` skill | + +--- + +## Reference File Index + + + + +| File | When to read | +|------|-------------| +| `assets/` | Before generating — use as the starting structure | +| `references/.md` | When handling | +| `examples/` | To verify generated output matches expected format | diff --git a/skills/creating-sf-skill/templates/tests_structure.md b/skills/creating-sf-skill/templates/tests_structure.md new file mode 100644 index 0000000..07e65de --- /dev/null +++ b/skills/creating-sf-skill/templates/tests_structure.md @@ -0,0 +1,98 @@ +# Tests Directory Structure + +Every skill in afv-library must include a `tests/` directory. This is the canonical layout. + +## Full Structure + +``` +skills// +└── tests/ + └── evals/ + ├── -/ + │ ├── prompt.md # Exact trigger prompt for this scenario + │ ├── gold/ # Expected output artifact(s) + │ └── seed-data/ # Input dependencies + ├── -/ + │ ├── prompt.md + │ ├── gold/ + │ └── seed-data/ + └── -/ + ├── prompt.md + ├── gold/ + └── seed-data/ +``` + +--- + +## evals/ + +### Dataset naming + +`-` — kebab-case, descriptive, specific to the test case. + +Examples: +- `generating-validation-rule-required-field` +- `generating-apex-service-class` +- `deploying-permission-set-with-field-access` + +Generate **2-3 datasets** covering the main positive trigger scenarios. Scenarios should be +distinct — different objects, different rule types, or different complexity levels. + +### prompt.md + +The exact prompt a user would type to trigger the skill for this scenario. No heading, no title, +no markdown framing — just the raw prompt text. + +**Format:** +``` + +``` + +**Example:** +``` +Create a validation rule that requires the Email field on the Contact object. +``` + +### gold/ + +Expected output artifact(s) the skill should produce. Use the correct file extension for the +artifact type — do not use `expected.md`. + +| Skill type | Extension examples | +|------------|-------------------| +| Validation rule | `ContactEmailRequired.validationRule-meta.xml` | +| Apex class | `AccountService.cls` | +| LWC component | `myComponent.html`, `myComponent.js` | +| Custom object | `My_Object__c.object-meta.xml` | +| Permission set | `My_Permission_Set.permissionset-meta.xml` | + +Mark the top of every gold file as a stub: +``` + +``` +or for non-XML: +``` +# STUB — review and update expected output before running eval +``` + +### seed-data/ + +Input dependencies the eval needs to run. This is the context the skill would normally gather +from the org or the user: +- Object field lists (JSON) +- Existing metadata samples (XML) +- Schema fragments +- Any other input fixture + +Derive from reference material provided during authoring. If none was provided, generate +representative seed data and mark it as a stub. + +--- + +## Lifecycle + +| Stage | Who | Action | +|-------|-----|--------| +| Draft | Agent (this skill) | Scaffold all stubs, mark everything `# STUB` | +| Under Review | Contributor | Fill in gold files, validate fixtures, run evals manually | +| Published | CI | Evals run automatically on PRs |