sf-metadata: Salesforce Metadata Generation and Org Querying Use this skill when the user needs metadata definition or org metadata discovery : custom objects, fields, validation rules, record types, page layouts, permission sets, or schema inspection with CLI. When This Skill Owns the Task Use when the work involves: - object, field, validation rule, record type, layout, profile, or permission-set metadata - , , , and related metadata files - describing schema before coding or Flow work - generating metadata XML from requirements Delegate elsewhere when the user is: - analyzing permission ac…

, api_name.replace('__c', '')):\n self._add_issue(\n 'naming_conventions', 'INFO',\n f'API name should use PascalCase: {api_name}', 2\n )\n\n # Check label is meaningful (not just API name)\n if label and api_name:\n api_clean = api_name.replace('__c', '').replace('_', ' ')\n if label.lower() == api_clean.lower():\n self._add_issue(\n 'naming_conventions', 'INFO',\n 'Label should be user-friendly, not just API name', 1\n )\n\n # Check for abbreviations in labels\n abbreviation_patterns = [\n (r'\\bAcct\\b', 'Account'),\n (r'\\bOpp\\b', 'Opportunity'),\n (r'\\bCont\\b', 'Contact'),\n (r'\\bMgr\\b', 'Manager'),\n (r'\\bNum\\b', 'Number'),\n (r'\\bQty\\b', 'Quantity'),\n ]\n if label:\n for pattern, suggestion in abbreviation_patterns:\n if re.search(pattern, label, re.IGNORECASE):\n self._add_issue(\n 'naming_conventions', 'INFO',\n f'Avoid abbreviations in labels. Consider using \"{suggestion}\"', 1\n )\n break\n\n def _validate_data_integrity(self):\n \"\"\"Validate data integrity settings.\"\"\"\n if self.metadata_type == 'CustomField':\n field_type = self._get_text(self.root, 'type')\n required = self._get_text(self.root, 'required')\n default_value = self._get_text(self.root, 'defaultValue')\n\n # Required fields should have defaults (except lookups)\n if required == 'true' and not default_value:\n if field_type not in ['Lookup', 'MasterDetail']:\n self._add_issue(\n 'data_integrity', 'INFO',\n 'Required fields should consider having a default value', 2\n )\n\n # Number/Currency fields should have precision/scale\n if field_type in ['Number', 'Currency', 'Percent']:\n precision = self._get_text(self.root, 'precision')\n scale = self._get_text(self.root, 'scale')\n if not precision or not scale:\n self._add_issue(\n 'data_integrity', 'WARNING',\n f'{field_type} fields should specify precision and scale', 3\n )\n\n # Lookup/Master-Detail should have relationship name\n if field_type in ['Lookup', 'MasterDetail']:\n rel_name = self._get_text(self.root, 'relationshipName')\n if not rel_name:\n self._add_issue(\n 'data_integrity', 'WARNING',\n 'Relationship fields should have relationshipName', 3\n )\n\n # Check delete constraint for lookups\n if field_type == 'Lookup':\n delete_constraint = self._get_text(self.root, 'deleteConstraint')\n if not delete_constraint:\n self._add_issue(\n 'data_integrity', 'INFO',\n 'Consider setting deleteConstraint for lookup fields', 2\n )\n\n elif self.metadata_type == 'ValidationRule':\n # Check for error message\n error_message = self._get_text(self.root, 'errorMessage')\n if not error_message:\n self._add_issue(\n 'data_integrity', 'WARNING',\n 'Validation rules must have an error message', 5\n )\n elif len(error_message) \u003c 10:\n self._add_issue(\n 'data_integrity', 'INFO',\n 'Error messages should be descriptive', 2\n )\n\n def _validate_security(self):\n \"\"\"Validate security and FLS settings.\"\"\"\n # Check for sensitive field patterns\n api_name = self._get_text(self.root, 'fullName', self.file_name)\n label = self._get_text(self.root, 'label', '')\n description = self._get_text(self.root, 'description', '')\n\n combined_text = f\"{api_name} {label} {description}\".lower()\n\n for pattern in self.SENSITIVE_PATTERNS:\n if re.search(pattern, combined_text, re.IGNORECASE):\n self._add_issue(\n 'security_fls', 'CRITICAL',\n f'Potential sensitive data field detected. Ensure proper FLS and encryption.', 10\n )\n break\n\n # Check sharing model for objects\n if self.metadata_type == 'CustomObject':\n sharing_model = self._get_text(self.root, 'sharingModel')\n if sharing_model == 'ReadWrite':\n self._add_issue(\n 'security_fls', 'INFO',\n 'Public Read/Write sharing model - verify this is intentional', 2\n )\n\n # For Permission Sets/Profiles, check for ModifyAllData or ViewAllData\n if self.metadata_type in ['Profile', 'PermissionSet']:\n user_perms = self.root.findall('.//sf:userPermissions', self.NAMESPACE)\n for perm in user_perms:\n name = self._get_text(perm, 'name')\n enabled = self._get_text(perm, 'enabled')\n if enabled == 'true' and name in ['ModifyAllData', 'ViewAllData']:\n self._add_issue(\n 'security_fls', 'WARNING',\n f'{name} permission enabled - use with caution', 5\n )\n\n def _validate_documentation(self):\n \"\"\"Validate documentation elements.\"\"\"\n description = self._get_text(self.root, 'description')\n help_text = self._get_text(self.root, 'inlineHelpText')\n\n # Check for description\n if self.metadata_type in ['CustomObject', 'CustomField', 'PermissionSet']:\n if not description:\n self._add_issue(\n 'documentation', 'WARNING',\n 'Add a description to explain the purpose', 5\n )\n elif len(description) \u003c 20:\n self._add_issue(\n 'documentation', 'INFO',\n 'Description should be more detailed', 2\n )\n\n # Check for help text on user-facing fields\n if self.metadata_type == 'CustomField':\n field_type = self._get_text(self.root, 'type')\n # User-facing fields should have help text\n if field_type not in ['Formula', 'Summary'] and not help_text:\n self._add_issue(\n 'documentation', 'INFO',\n 'Consider adding help text for user guidance', 2\n )\n\n # Validation rules should have good error messages\n if self.metadata_type == 'ValidationRule':\n error_message = self._get_text(self.root, 'errorMessage')\n if error_message and not any(word in error_message.lower() for word in ['please', 'must', 'should', 'required']):\n self._add_issue(\n 'documentation', 'INFO',\n 'Error messages should be user-friendly and actionable', 2\n )\n\n def _validate_best_practices(self):\n \"\"\"Validate against Salesforce best practices.\"\"\"\n if self.metadata_type == 'Profile':\n self._add_issue(\n 'best_practices', 'INFO',\n 'Consider using Permission Sets instead of Profiles for granular access', 3\n )\n\n if self.metadata_type == 'CustomField':\n field_type = self._get_text(self.root, 'type')\n\n # Check for formula fields with hardcoded IDs\n if field_type == 'Formula':\n formula = self._get_text(self.root, 'formula')\n if formula and re.search(r'[\"\\'][0-9a-zA-Z]{15,18}[\"\\']', formula):\n self._add_issue(\n 'best_practices', 'WARNING',\n 'Avoid hardcoded IDs in formulas - use Custom Settings or Custom Metadata', 5\n )\n\n # Picklist fields should consider Global Value Sets\n if field_type == 'Picklist':\n value_set = self.root.find('.//sf:valueSetDefinition', self.NAMESPACE)\n if value_set is not None:\n values = value_set.findall('.//sf:value', self.NAMESPACE)\n if len(values) > 10:\n self._add_issue(\n 'best_practices', 'INFO',\n 'Consider using a Global Value Set for reusable picklist values', 2\n )\n\n if self.metadata_type == 'ValidationRule':\n # Check for bypass pattern\n formula = self._get_text(self.root, 'errorConditionFormula')\n if formula and '$Permission' not in formula and '$Setup' not in formula:\n self._add_issue(\n 'best_practices', 'INFO',\n 'Consider adding a bypass mechanism for admin/integration users', 3\n )\n\n def _build_results(self) -> Dict:\n \"\"\"Build and return validation results.\"\"\"\n total_score = sum(cat['score'] for cat in self.categories.values())\n max_score = sum(cat['max'] for cat in self.categories.values())\n\n # Calculate rating\n percentage = (total_score / max_score) * 100 if max_score > 0 else 0\n if percentage >= 90:\n rating = '⭐⭐⭐⭐⭐ Excellent'\n elif percentage >= 80:\n rating = '⭐⭐⭐⭐ Very Good'\n elif percentage >= 70:\n rating = '⭐⭐⭐ Good'\n elif percentage >= 60:\n rating = '⭐⭐ Needs Work'\n else:\n rating = '⭐ Critical Issues'\n\n return {\n 'file_path': self.file_path,\n 'metadata_type': self.metadata_type,\n 'overall_score': total_score,\n 'max_score': max_score,\n 'rating': rating,\n 'categories': {\n cat_key: {\n 'name': cat_data['name'],\n 'score': cat_data['score'],\n 'max_score': cat_data['max'],\n 'issues': cat_data['issues']\n }\n for cat_key, cat_data in self.categories.items()\n }\n }\n\n\ndef main():\n \"\"\"CLI entry point with dual-mode input support.\"\"\"\n import json\n\n file_path = None\n\n # Mode 1: Hook mode - read from stdin JSON (PostToolUse hooks)\n if not sys.stdin.isatty():\n try:\n hook_input = json.load(sys.stdin)\n tool_input = hook_input.get(\"tool_input\", {})\n file_path = tool_input.get(\"file_path\", \"\")\n except (json.JSONDecodeError, EOFError):\n pass\n\n # Mode 2: CLI mode - read from command-line argument\n if not file_path and len(sys.argv) >= 2:\n file_path = sys.argv[1]\n\n # Validate we have a file path\n if not file_path:\n print(\"Usage: python validate_metadata.py \u003cmetadata-file.xml>\")\n sys.exit(1)\n\n # Only validate metadata files\n valid_extensions = [\n '.object-meta.xml', '.field-meta.xml', '.permissionset-meta.xml',\n '.profile-meta.xml', '.validationRule-meta.xml', '.recordType-meta.xml',\n '.layout-meta.xml'\n ]\n if not any(file_path.endswith(ext) for ext in valid_extensions):\n sys.exit(0) # Silently skip non-metadata files\n\n validator = MetadataValidator(file_path)\n results = validator.validate()\n\n # Print results\n print(f\"\\n{'=' * 60}\")\n print(f\"🔍 Metadata Validation: {results['metadata_type']}\")\n print(f\"File: {os.path.basename(file_path)}\")\n print(f\"{'=' * 60}\")\n print(f\"\\nScore: {results['overall_score']}/{results['max_score']} {results['rating']}\")\n\n print(\"\\nCategory Breakdown:\")\n for cat_key, cat_data in results['categories'].items():\n score = cat_data['score']\n max_score = cat_data['max_score']\n name = cat_data['name']\n pct = int((score / max_score) * 100) if max_score > 0 else 0\n print(f\" ├─ {name}: {score}/{max_score} ({pct}%)\")\n\n # Print issues\n all_issues = []\n for cat_data in results['categories'].values():\n all_issues.extend(cat_data['issues'])\n\n if all_issues:\n print(\"\\nIssues Found:\")\n for issue in all_issues:\n severity = issue['severity']\n message = issue['message']\n icon = {'CRITICAL': '🔴', 'WARNING': '🟡', 'INFO': '🔵'}.get(severity, '⚪')\n print(f\" {icon} [{severity}] {message}\")\n else:\n print(\"\\n✅ No issues found!\")\n\n print()\n return 0 if results['overall_score'] >= 72 else 1\n\n\nif __name__ == \"__main__\":\n sys.exit(main())\n","content_type":"text/x-python; charset=utf-8","language":"python","size":20169,"content_sha256":"6a19327cf2841afae4da9b50b619d9998bf005673fa792d1366e59e4014a46a3"},{"filename":"README.md","content":"# sf-metadata\n\nSalesforce metadata generation and org-querying skill with 120-point scoring. Build custom objects, fields, permission sets, validation rules, and related metadata with production-focused patterns.\n\n## Features\n\n- **Metadata Generation**: Custom objects, fields, layouts, validation rules, permission sets\n- **Org Querying**: Describe objects and inspect metadata via `sf` CLI\n- **120-Point Scoring**: Validation across structure, naming, security, and best practices\n- **Automatic FLS Follow-Up**: Default to Permission Set generation for new custom objects and fields unless the user opts out\n- **Cross-Skill Orchestration**: Works with sf-flow, sf-data, and sf-deploy\n\n## Installation\n\n```bash\n# Install as part of sf-skills\nnpx skills add Jaganpro/sf-skills\n\n# Or install just this skill\nnpx skills add Jaganpro/sf-skills --skill sf-metadata\n```\n\n## Quick Start\n\n### 1. Invoke the skill\n\n```\nSkill: sf-metadata\nRequest: \"Create a custom object Invoice__c with amount and due date fields\"\n```\n\n### 2. Common tasks\n\n- Generate object and field metadata\n- Query metadata types in a target org\n- Generate or update permission sets for newly added fields\n- Prepare metadata for deployment via sf-deploy\n\n## Documentation\n\n- [SKILL.md](SKILL.md) - Full workflow and orchestration guidance\n- [references/field-and-cli-reference.md](references/field-and-cli-reference.md) - Field types and CLI commands\n- [references/permset-auto-generation.md](references/permset-auto-generation.md) - Automatic permission-set / FLS generation rules\n- [references/best-practices-scoring.md](references/best-practices-scoring.md) - 120-point scoring breakdown\n- [references/orchestration.md](references/orchestration.md) - Cross-skill execution order\n\n## Related Skills\n\n- `sf-flow` - Build automations on top of new metadata\n- `sf-data` - Load test data after deployment\n- `sf-deploy` - Validate and deploy metadata changes\n\n## License\n\nMIT License. See the repository root [LICENSE](../../LICENSE).\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":1995,"content_sha256":"6e2a39f036a015195e7c7ed2634634b5765ef405c8808a6f3a166d40eb30ff0f"},{"filename":"references/best-practices-scoring.md","content":"\u003c!-- Parent: sf-metadata/SKILL.md -->\n\n# Best Practices & Scoring Details (120 Points)\n\n## Category Breakdown\n\n**Structure & Format** (20 points):\n- Valid XML syntax (-10 if invalid)\n- Correct Salesforce namespace: `http://soap.sforce.com/2006/04/metadata` (-5 if missing)\n- API version present and >= 65.0 (-5 if outdated)\n- Correct file path and naming structure (-5 if wrong)\n\n**Naming Conventions** (20 points):\n- Custom objects/fields end with `__c` (-3 each violation)\n- Use PascalCase for API names: `Account_Status__c` not `account_status__c` (-2 each)\n- Meaningful labels (no abbreviations like `Acct`, `Sts`) (-2 each)\n- Relationship names follow pattern: `[ParentObject]_[ChildObjects]` (-3)\n\n**Data Integrity** (20 points):\n- Required fields have sensible defaults or validation (-5)\n- Number fields have appropriate precision/scale (-3)\n- Picklist values properly defined with labels (-3)\n- Relationship delete constraints specified (SetNull, Restrict, Cascade) (-3)\n- Formula field syntax valid (-5)\n- Roll-up summaries reference correct fields (-3)\n\n**Security & FLS** (20 points):\n- Field-Level Security considerations documented (-5 if sensitive field exposed)\n- Sensitive field types flagged (SSN patterns, Credit Card patterns) (-10)\n- Object sharing model appropriate for data sensitivity (-5)\n- Permission Sets preferred over Profile modifications (advisory)\n\n**Documentation** (20 points):\n- Description present and meaningful on objects/fields (-5 if missing)\n- Help text for user-facing fields (-3 each)\n- Clear error messages for validation rules (-3)\n- Inline comments in complex formulas (-3)\n\n**Best Practices** (20 points):\n- Use Permission Sets over Profiles when possible (-3 if Profile-first)\n- Avoid hardcoded Record IDs in formulas (-5 if found)\n- Use Global Value Sets for reusable picklists (advisory)\n- Master-Detail vs Lookup selection appropriate for use case (-3)\n- Record Types have associated Page Layouts (-3)\n\n## Scoring Thresholds\n\n| Rating | Score | Action |\n|--------|-------|--------|\n| Excellent | 108+ | Production-ready |\n| Very Good | 96-107 | Minor improvements |\n| Good | 84-95 | Acceptable, needs work |\n| Below Standard | 72-83 | Address before deploy |\n| Block | \u003c72 | CRITICAL issues |\n\n---\n\n## Field Template Tips\n\n### Number Field: Omit Empty Defaults\n\nDon't include `\u003cdefaultValue>` if it's empty or zero — Salesforce ignores it:\n\n```xml\n\u003c!-- WRONG: Empty default is ignored, adds noise -->\n\u003cCustomField>\n \u003cfullName>Score__c\u003c/fullName>\n \u003ctype>Number\u003c/type>\n \u003cprecision>3\u003c/precision>\n \u003cscale>0\u003c/scale>\n \u003cdefaultValue>\u003c/defaultValue> \u003c!-- Remove this! -->\n\u003c/CustomField>\n\n\u003c!-- CORRECT: Omit defaultValue entirely if not needed -->\n\u003cCustomField>\n \u003cfullName>Score__c\u003c/fullName>\n \u003ctype>Number\u003c/type>\n \u003cprecision>3\u003c/precision>\n \u003cscale>0\u003c/scale>\n\u003c/CustomField>\n\n\u003c!-- CORRECT: Include defaultValue only if you need a specific value -->\n\u003cCustomField>\n \u003cfullName>Priority__c\u003c/fullName>\n \u003ctype>Number\u003c/type>\n \u003cprecision>1\u003c/precision>\n \u003cscale>0\u003c/scale>\n \u003cdefaultValue>3\u003c/defaultValue> \u003c!-- Meaningful default -->\n\u003c/CustomField>\n```\n\n### Standard vs Custom Object Paths\n\n| Object Type | Path Example |\n|-------------|--------------|\n| Standard (Lead) | `objects/Lead/fields/Lead_Score__c.field-meta.xml` |\n| Custom | `objects/MyObject__c/fields/MyField__c.field-meta.xml` |\n\n**Common Mistake**: Using `Lead__c` (with suffix) for standard Lead object.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":3445,"content_sha256":"8c74c34666edb7cc374bb0818b66953ac4e6c45204731b2c9993330420545c9e"},{"filename":"references/custom-object-example.md","content":"\u003c!-- Parent: sf-metadata/SKILL.md -->\n# Custom Object Example: Invoice\n\nThis example demonstrates creating a complete custom object with fields, validation rules, and record types.\n\n## Scenario\n\nCreate an Invoice object for tracking customer invoices with:\n- Auto-numbered invoice number\n- Customer (Account) relationship\n- Line items (child object)\n- Status tracking\n- Validation rules\n\n---\n\n## Step 1: Create Custom Object\n\n**File:** `force-app/main/default/objects/Invoice__c/Invoice__c.object-meta.xml`\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\u003cCustomObject xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003clabel>Invoice\u003c/label>\n \u003cpluralLabel>Invoices\u003c/pluralLabel>\n \u003cdescription>Tracks customer invoices and payment status\u003c/description>\n\n \u003cnameField>\n \u003clabel>Invoice Number\u003c/label>\n \u003ctype>AutoNumber\u003c/type>\n \u003cdisplayFormat>INV-{0000000}\u003c/displayFormat>\n \u003ctrackHistory>false\u003c/trackHistory>\n \u003c/nameField>\n\n \u003cdeploymentStatus>Deployed\u003c/deploymentStatus>\n \u003csharingModel>Private\u003c/sharingModel>\n\n \u003cenableHistory>true\u003c/enableHistory>\n \u003cenableActivities>true\u003c/enableActivities>\n \u003cenableReports>true\u003c/enableReports>\n \u003cenableSearch>true\u003c/enableSearch>\n \u003cenableFeeds>false\u003c/enableFeeds>\n \u003cenableBulkApi>true\u003c/enableBulkApi>\n \u003cenableSharing>true\u003c/enableSharing>\n \u003cenableStreamingApi>true\u003c/enableStreamingApi>\n\n \u003csearchLayouts>\n \u003ccustomTabListAdditionalFields>Name\u003c/customTabListAdditionalFields>\n \u003ccustomTabListAdditionalFields>Account__c\u003c/customTabListAdditionalFields>\n \u003ccustomTabListAdditionalFields>Total_Amount__c\u003c/customTabListAdditionalFields>\n \u003ccustomTabListAdditionalFields>Status__c\u003c/customTabListAdditionalFields>\n \u003clookupDialogsAdditionalFields>Name\u003c/lookupDialogsAdditionalFields>\n \u003clookupDialogsAdditionalFields>Account__c\u003c/lookupDialogsAdditionalFields>\n \u003csearchResultsAdditionalFields>Name\u003c/searchResultsAdditionalFields>\n \u003csearchResultsAdditionalFields>Account__c\u003c/searchResultsAdditionalFields>\n \u003csearchResultsAdditionalFields>Status__c\u003c/searchResultsAdditionalFields>\n \u003c/searchLayouts>\n\n \u003ccompactLayoutAssignment>SYSTEM\u003c/compactLayoutAssignment>\n\u003c/CustomObject>\n```\n\n---\n\n## Step 2: Create Custom Fields\n\n### Account Lookup\n**File:** `force-app/main/default/objects/Invoice__c/fields/Account__c.field-meta.xml`\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Account__c\u003c/fullName>\n \u003clabel>Account\u003c/label>\n \u003ctype>Lookup\u003c/type>\n \u003creferenceTo>Account\u003c/referenceTo>\n \u003crelationshipLabel>Invoices\u003c/relationshipLabel>\n \u003crelationshipName>Invoices\u003c/relationshipName>\n \u003crequired>true\u003c/required>\n \u003cdeleteConstraint>Restrict\u003c/deleteConstraint>\n \u003cdescription>The customer account for this invoice\u003c/description>\n \u003cinlineHelpText>Select the customer account\u003c/inlineHelpText>\n \u003ctrackHistory>true\u003c/trackHistory>\n \u003ctrackTrending>false\u003c/trackTrending>\n\u003c/CustomField>\n```\n\n### Status Picklist\n**File:** `force-app/main/default/objects/Invoice__c/fields/Status__c.field-meta.xml`\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Status__c\u003c/fullName>\n \u003clabel>Status\u003c/label>\n \u003ctype>Picklist\u003c/type>\n \u003crequired>true\u003c/required>\n \u003cdescription>Current status of the invoice\u003c/description>\n \u003cinlineHelpText>Select the invoice status\u003c/inlineHelpText>\n \u003ctrackHistory>true\u003c/trackHistory>\n \u003ctrackTrending>false\u003c/trackTrending>\n \u003cvalueSet>\n \u003crestricted>true\u003c/restricted>\n \u003cvalueSetDefinition>\n \u003csorted>false\u003c/sorted>\n \u003cvalue>\n \u003cfullName>Draft\u003c/fullName>\n \u003cdefault>true\u003c/default>\n \u003clabel>Draft\u003c/label>\n \u003c/value>\n \u003cvalue>\n \u003cfullName>Sent\u003c/fullName>\n \u003cdefault>false\u003c/default>\n \u003clabel>Sent\u003c/label>\n \u003c/value>\n \u003cvalue>\n \u003cfullName>Paid\u003c/fullName>\n \u003cdefault>false\u003c/default>\n \u003clabel>Paid\u003c/label>\n \u003c/value>\n \u003cvalue>\n \u003cfullName>Overdue\u003c/fullName>\n \u003cdefault>false\u003c/default>\n \u003clabel>Overdue\u003c/label>\n \u003c/value>\n \u003cvalue>\n \u003cfullName>Cancelled\u003c/fullName>\n \u003cdefault>false\u003c/default>\n \u003clabel>Cancelled\u003c/label>\n \u003c/value>\n \u003c/valueSetDefinition>\n \u003c/valueSet>\n\u003c/CustomField>\n```\n\n### Invoice Date\n**File:** `force-app/main/default/objects/Invoice__c/fields/Invoice_Date__c.field-meta.xml`\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Invoice_Date__c\u003c/fullName>\n \u003clabel>Invoice Date\u003c/label>\n \u003ctype>Date\u003c/type>\n \u003crequired>true\u003c/required>\n \u003cdefaultValue>TODAY()\u003c/defaultValue>\n \u003cdescription>Date the invoice was issued\u003c/description>\n \u003cinlineHelpText>Date the invoice was created\u003c/inlineHelpText>\n \u003ctrackHistory>true\u003c/trackHistory>\n \u003ctrackTrending>false\u003c/trackTrending>\n\u003c/CustomField>\n```\n\n### Due Date\n**File:** `force-app/main/default/objects/Invoice__c/fields/Due_Date__c.field-meta.xml`\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Due_Date__c\u003c/fullName>\n \u003clabel>Due Date\u003c/label>\n \u003ctype>Date\u003c/type>\n \u003crequired>true\u003c/required>\n \u003cdefaultValue>TODAY() + 30\u003c/defaultValue>\n \u003cdescription>Payment due date\u003c/description>\n \u003cinlineHelpText>Date payment is due (default: 30 days from today)\u003c/inlineHelpText>\n \u003ctrackHistory>true\u003c/trackHistory>\n \u003ctrackTrending>false\u003c/trackTrending>\n\u003c/CustomField>\n```\n\n### Total Amount\n**File:** `force-app/main/default/objects/Invoice__c/fields/Total_Amount__c.field-meta.xml`\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Total_Amount__c\u003c/fullName>\n \u003clabel>Total Amount\u003c/label>\n \u003ctype>Currency\u003c/type>\n \u003cprecision>18\u003c/precision>\n \u003cscale>2\u003c/scale>\n \u003crequired>false\u003c/required>\n \u003cdefaultValue>0\u003c/defaultValue>\n \u003cdescription>Total invoice amount (calculated from line items)\u003c/description>\n \u003cinlineHelpText>Total amount including all line items\u003c/inlineHelpText>\n \u003ctrackHistory>true\u003c/trackHistory>\n \u003ctrackTrending>false\u003c/trackTrending>\n\u003c/CustomField>\n```\n\n### Payment Date\n**File:** `force-app/main/default/objects/Invoice__c/fields/Payment_Date__c.field-meta.xml`\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Payment_Date__c\u003c/fullName>\n \u003clabel>Payment Date\u003c/label>\n \u003ctype>Date\u003c/type>\n \u003crequired>false\u003c/required>\n \u003cdescription>Date payment was received\u003c/description>\n \u003cinlineHelpText>Leave blank until payment is received\u003c/inlineHelpText>\n \u003ctrackHistory>true\u003c/trackHistory>\n \u003ctrackTrending>false\u003c/trackTrending>\n\u003c/CustomField>\n```\n\n### Days Overdue (Formula)\n**File:** `force-app/main/default/objects/Invoice__c/fields/Days_Overdue__c.field-meta.xml`\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Days_Overdue__c\u003c/fullName>\n \u003clabel>Days Overdue\u003c/label>\n \u003ctype>Number\u003c/type>\n \u003cprecision>18\u003c/precision>\n \u003cscale>0\u003c/scale>\n \u003cformula>IF(\n AND(\n ISBLANK(Payment_Date__c),\n Due_Date__c \u003c TODAY(),\n NOT(ISPICKVAL(Status__c, 'Cancelled'))\n ),\n TODAY() - Due_Date__c,\n 0\n)\u003c/formula>\n \u003cformulaTreatBlanksAs>BlankAsZero\u003c/formulaTreatBlanksAs>\n \u003cdescription>Number of days past due date\u003c/description>\n \u003cinlineHelpText>Calculated days overdue (0 if paid or not yet due)\u003c/inlineHelpText>\n \u003ctrackHistory>false\u003c/trackHistory>\n \u003ctrackTrending>false\u003c/trackTrending>\n\u003c/CustomField>\n```\n\n---\n\n## Step 3: Create Validation Rules\n\n### Require Payment Date When Paid\n**File:** `force-app/main/default/objects/Invoice__c/validationRules/Require_Payment_Date_When_Paid.validationRule-meta.xml`\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\u003cValidationRule xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Require_Payment_Date_When_Paid\u003c/fullName>\n \u003cactive>true\u003c/active>\n \u003cdescription>Ensures Payment Date is filled when Status is set to Paid\u003c/description>\n \u003cerrorConditionFormula>AND(\n NOT($Permission.Bypass_Validation__c),\n ISPICKVAL(Status__c, 'Paid'),\n ISBLANK(Payment_Date__c)\n)\u003c/errorConditionFormula>\n \u003cerrorDisplayField>Payment_Date__c\u003c/errorDisplayField>\n \u003cerrorMessage>Payment Date is required when marking an invoice as Paid.\u003c/errorMessage>\n\u003c/ValidationRule>\n```\n\n### Due Date After Invoice Date\n**File:** `force-app/main/default/objects/Invoice__c/validationRules/Due_Date_After_Invoice_Date.validationRule-meta.xml`\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\u003cValidationRule xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Due_Date_After_Invoice_Date\u003c/fullName>\n \u003cactive>true\u003c/active>\n \u003cdescription>Ensures Due Date is on or after Invoice Date\u003c/description>\n \u003cerrorConditionFormula>AND(\n NOT($Permission.Bypass_Validation__c),\n Due_Date__c \u003c Invoice_Date__c\n)\u003c/errorConditionFormula>\n \u003cerrorDisplayField>Due_Date__c\u003c/errorDisplayField>\n \u003cerrorMessage>Due Date must be on or after the Invoice Date.\u003c/errorMessage>\n\u003c/ValidationRule>\n```\n\n---\n\n## Step 4: Create Record Type (Optional)\n\n**File:** `force-app/main/default/objects/Invoice__c/recordTypes/Standard_Invoice.recordType-meta.xml`\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\u003cRecordType xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Standard_Invoice\u003c/fullName>\n \u003cactive>true\u003c/active>\n \u003clabel>Standard Invoice\u003c/label>\n \u003cdescription>Standard invoice for regular billing\u003c/description>\n\u003c/RecordType>\n```\n\n---\n\n## Directory Structure\n\n```\nforce-app/main/default/objects/Invoice__c/\n├── Invoice__c.object-meta.xml\n├── fields/\n│ ├── Account__c.field-meta.xml\n│ ├── Status__c.field-meta.xml\n│ ├── Invoice_Date__c.field-meta.xml\n│ ├── Due_Date__c.field-meta.xml\n│ ├── Total_Amount__c.field-meta.xml\n│ ├── Payment_Date__c.field-meta.xml\n│ └── Days_Overdue__c.field-meta.xml\n├── validationRules/\n│ ├── Require_Payment_Date_When_Paid.validationRule-meta.xml\n│ └── Due_Date_After_Invoice_Date.validationRule-meta.xml\n└── recordTypes/\n └── Standard_Invoice.recordType-meta.xml\n```\n\n---\n\n## Deployment\n\n```bash\n# Validate\nsf project deploy start \\\n --source-dir force-app/main/default/objects/Invoice__c \\\n --target-org myorg \\\n --dry-run\n\n# Deploy\nsf project deploy start \\\n --source-dir force-app/main/default/objects/Invoice__c \\\n --target-org myorg\n```\n\n---\n\n## Next Steps\n\n1. Create Permission Set for Invoice access\n2. Create Page Layout\n3. Create related Line Item object (Master-Detail)\n4. Build Flows for automation\n5. Create Reports and Dashboards\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":11069,"content_sha256":"4468c496130e4185a5df81c69b09855c77a9ecbf8cb45b3e1194c0cb60e23de7"},{"filename":"references/field-and-cli-reference.md","content":"\u003c!-- Parent: sf-metadata/SKILL.md -->\n\n# Field Type Guide, Relationships & CLI Reference\n\n## Field Type Selection Guide\n\n| Type | Salesforce | Notes |\n|------|------------|-------|\n| Text | Text / Text Area (Long/Rich) | ≤255 chars / multi-line / HTML |\n| Numbers | Number / Currency | Decimals or money (org currency) |\n| Boolean | Checkbox | True/False |\n| Choice | Picklist / Multi-Select | Single/multiple predefined options |\n| Date | Date / DateTime | With or without time |\n| Contact | Email / Phone / URL | Validated formats |\n| Relationship | Lookup / Master-Detail | Optional / required parent |\n| Calculated | Formula / Roll-Up | Derived from fields / children |\n\n## Relationship Decision Matrix\n\n| Scenario | Use | Reason |\n|----------|-----|--------|\n| Parent optional | Lookup | Child can exist without parent |\n| Parent required | Master-Detail | Cascade delete, roll-up summaries |\n| Many-to-Many | Junction Object | Two Master-Detail relationships |\n| Self-referential | Hierarchical Lookup | Same object (e.g., Account hierarchy) |\n| Cross-object formula | Master-Detail or Formula | Access parent fields |\n\n## Common Validation Rule Patterns\n\n| Pattern | Formula | Use |\n|---------|---------|-----|\n| Conditional Required | `AND(ISPICKVAL(Status,'Closed'), ISBLANK(Close_Date__c))` | Field required when condition met |\n| Email Regex | `NOT(REGEX(Email__c, \"^[a-zA-Z0-9._-]+@...\"))` | Format validation |\n| Future Date | `Due_Date__c \u003c TODAY()` | Date constraints |\n| Cross-Object | `AND(Account.Type != 'Customer', Amount__c > 100000)` | Related field checks |\n\n---\n\n## sf CLI Quick Reference\n\n### Object & Field Queries\n\n```bash\n# Describe standard or custom object\nsf sobject describe --sobject Account --target-org [alias] --json\n\n# List all custom objects\nsf org list metadata --metadata-type CustomObject --target-org [alias] --json\n\n# List all custom fields on an object\nsf org list metadata --metadata-type CustomField --folder Account --target-org [alias] --json\n```\n\n### Metadata Operations\n\n```bash\n# List all metadata types available\nsf org list metadata-types --target-org [alias] --json\n\n# Retrieve specific metadata\nsf project retrieve start --metadata CustomObject:Account --target-org [alias]\n\n# Generate package.xml from source\nsf project generate manifest --source-dir force-app --name package.xml\n```\n\n### Interactive Generation\n\n```bash\n# Generate custom object interactively\nsf schema generate sobject --label \"My Object\"\n\n# Generate custom field interactively\nsf schema generate field --label \"My Field\" --object Account\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2569,"content_sha256":"f21d48d298431bd10bfffd0855554eb3dff38ba543894df9ddf0d52d47dbb684"},{"filename":"references/field-types-example.md","content":"\u003c!-- Parent: sf-metadata/SKILL.md -->\n# Field Types Example: Complete Reference\n\nThis example demonstrates all common field types with real-world usage.\n\n---\n\n## Text Fields\n\n### Standard Text\n```xml\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Product_SKU__c\u003c/fullName>\n \u003clabel>Product SKU\u003c/label>\n \u003ctype>Text\u003c/type>\n \u003clength>50\u003c/length>\n \u003crequired>true\u003c/required>\n \u003cunique>true\u003c/unique>\n \u003cexternalId>true\u003c/externalId>\n \u003ccaseSensitive>false\u003c/caseSensitive>\n \u003cdescription>Unique product identifier for inventory\u003c/description>\n \u003cinlineHelpText>Enter the unique SKU (e.g., SKU-12345)\u003c/inlineHelpText>\n\u003c/CustomField>\n```\n\n### Long Text Area\n```xml\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Internal_Notes__c\u003c/fullName>\n \u003clabel>Internal Notes\u003c/label>\n \u003ctype>LongTextArea\u003c/type>\n \u003clength>32000\u003c/length>\n \u003cvisibleLines>6\u003c/visibleLines>\n \u003cdescription>Internal team notes (not visible to customers)\u003c/description>\n \u003cinlineHelpText>Add any internal notes or comments\u003c/inlineHelpText>\n\u003c/CustomField>\n```\n\n### Rich Text Area\n```xml\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Product_Description__c\u003c/fullName>\n \u003clabel>Product Description\u003c/label>\n \u003ctype>Html\u003c/type>\n \u003clength>32000\u003c/length>\n \u003cvisibleLines>10\u003c/visibleLines>\n \u003cdescription>Rich text product description for marketing\u003c/description>\n \u003cinlineHelpText>Format description with bold, lists, and images\u003c/inlineHelpText>\n\u003c/CustomField>\n```\n\n---\n\n## Numeric Fields\n\n### Integer (Whole Number)\n```xml\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Quantity__c\u003c/fullName>\n \u003clabel>Quantity\u003c/label>\n \u003ctype>Number\u003c/type>\n \u003cprecision>18\u003c/precision>\n \u003cscale>0\u003c/scale>\n \u003crequired>true\u003c/required>\n \u003cdefaultValue>1\u003c/defaultValue>\n \u003cdescription>Number of units ordered\u003c/description>\n \u003cinlineHelpText>Enter quantity (whole numbers only)\u003c/inlineHelpText>\n\u003c/CustomField>\n```\n\n### Decimal\n```xml\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Weight_Kg__c\u003c/fullName>\n \u003clabel>Weight (kg)\u003c/label>\n \u003ctype>Number\u003c/type>\n \u003cprecision>10\u003c/precision>\n \u003cscale>3\u003c/scale>\n \u003crequired>false\u003c/required>\n \u003cdescription>Product weight in kilograms\u003c/description>\n \u003cinlineHelpText>Enter weight with up to 3 decimal places\u003c/inlineHelpText>\n\u003c/CustomField>\n```\n\n### Currency\n```xml\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Unit_Price__c\u003c/fullName>\n \u003clabel>Unit Price\u003c/label>\n \u003ctype>Currency\u003c/type>\n \u003cprecision>18\u003c/precision>\n \u003cscale>2\u003c/scale>\n \u003crequired>true\u003c/required>\n \u003cdefaultValue>0\u003c/defaultValue>\n \u003cdescription>Price per unit\u003c/description>\n \u003cinlineHelpText>Enter the price per unit\u003c/inlineHelpText>\n\u003c/CustomField>\n```\n\n### Percent\n```xml\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Discount_Percent__c\u003c/fullName>\n \u003clabel>Discount %\u003c/label>\n \u003ctype>Percent\u003c/type>\n \u003cprecision>5\u003c/precision>\n \u003cscale>2\u003c/scale>\n \u003crequired>false\u003c/required>\n \u003cdefaultValue>0\u003c/defaultValue>\n \u003cdescription>Discount percentage applied\u003c/description>\n \u003cinlineHelpText>Enter discount as percentage (e.g., 10 for 10%)\u003c/inlineHelpText>\n\u003c/CustomField>\n```\n\n---\n\n## Date/Time Fields\n\n### Date\n```xml\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Contract_Start_Date__c\u003c/fullName>\n \u003clabel>Contract Start Date\u003c/label>\n \u003ctype>Date\u003c/type>\n \u003crequired>true\u003c/required>\n \u003cdefaultValue>TODAY()\u003c/defaultValue>\n \u003cdescription>Date the contract becomes effective\u003c/description>\n \u003cinlineHelpText>When does this contract take effect?\u003c/inlineHelpText>\n\u003c/CustomField>\n```\n\n### DateTime\n```xml\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Last_Contact_DateTime__c\u003c/fullName>\n \u003clabel>Last Contact Date/Time\u003c/label>\n \u003ctype>DateTime\u003c/type>\n \u003crequired>false\u003c/required>\n \u003cdescription>Last time we contacted this customer\u003c/description>\n \u003cinlineHelpText>Date and time of most recent contact\u003c/inlineHelpText>\n\u003c/CustomField>\n```\n\n---\n\n## Boolean Field\n\n### Checkbox\n```xml\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Is_VIP_Customer__c\u003c/fullName>\n \u003clabel>VIP Customer\u003c/label>\n \u003ctype>Checkbox\u003c/type>\n \u003cdefaultValue>false\u003c/defaultValue>\n \u003cdescription>Indicates if customer has VIP status\u003c/description>\n \u003cinlineHelpText>Check if this is a VIP customer\u003c/inlineHelpText>\n\u003c/CustomField>\n```\n\n---\n\n## Picklist Fields\n\n### Single-Select Picklist\n```xml\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Priority__c\u003c/fullName>\n \u003clabel>Priority\u003c/label>\n \u003ctype>Picklist\u003c/type>\n \u003crequired>true\u003c/required>\n \u003cdescription>Task priority level\u003c/description>\n \u003cinlineHelpText>Select the priority level\u003c/inlineHelpText>\n \u003cvalueSet>\n \u003crestricted>true\u003c/restricted>\n \u003cvalueSetDefinition>\n \u003csorted>false\u003c/sorted>\n \u003cvalue>\n \u003cfullName>Low\u003c/fullName>\n \u003cdefault>false\u003c/default>\n \u003clabel>Low\u003c/label>\n \u003c/value>\n \u003cvalue>\n \u003cfullName>Medium\u003c/fullName>\n \u003cdefault>true\u003c/default>\n \u003clabel>Medium\u003c/label>\n \u003c/value>\n \u003cvalue>\n \u003cfullName>High\u003c/fullName>\n \u003cdefault>false\u003c/default>\n \u003clabel>High\u003c/label>\n \u003c/value>\n \u003cvalue>\n \u003cfullName>Critical\u003c/fullName>\n \u003cdefault>false\u003c/default>\n \u003clabel>Critical\u003c/label>\n \u003c/value>\n \u003c/valueSetDefinition>\n \u003c/valueSet>\n\u003c/CustomField>\n```\n\n### Multi-Select Picklist\n```xml\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Product_Categories__c\u003c/fullName>\n \u003clabel>Product Categories\u003c/label>\n \u003ctype>MultiselectPicklist\u003c/type>\n \u003cvisibleLines>4\u003c/visibleLines>\n \u003crequired>false\u003c/required>\n \u003cdescription>Categories this product belongs to\u003c/description>\n \u003cinlineHelpText>Select all applicable categories\u003c/inlineHelpText>\n \u003cvalueSet>\n \u003crestricted>true\u003c/restricted>\n \u003cvalueSetDefinition>\n \u003csorted>true\u003c/sorted>\n \u003cvalue>\n \u003cfullName>Electronics\u003c/fullName>\n \u003clabel>Electronics\u003c/label>\n \u003c/value>\n \u003cvalue>\n \u003cfullName>Clothing\u003c/fullName>\n \u003clabel>Clothing\u003c/label>\n \u003c/value>\n \u003cvalue>\n \u003cfullName>Home_Garden\u003c/fullName>\n \u003clabel>Home & Garden\u003c/label>\n \u003c/value>\n \u003cvalue>\n \u003cfullName>Sports\u003c/fullName>\n \u003clabel>Sports\u003c/label>\n \u003c/value>\n \u003c/valueSetDefinition>\n \u003c/valueSet>\n\u003c/CustomField>\n```\n\n---\n\n## Relationship Fields\n\n### Lookup\n```xml\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Primary_Contact__c\u003c/fullName>\n \u003clabel>Primary Contact\u003c/label>\n \u003ctype>Lookup\u003c/type>\n \u003creferenceTo>Contact\u003c/referenceTo>\n \u003crelationshipLabel>Primary For\u003c/relationshipLabel>\n \u003crelationshipName>Primary_For\u003c/relationshipName>\n \u003crequired>false\u003c/required>\n \u003cdeleteConstraint>SetNull\u003c/deleteConstraint>\n \u003cdescription>Main contact person for this account\u003c/description>\n \u003cinlineHelpText>Select the primary contact\u003c/inlineHelpText>\n \u003clookupFilter>\n \u003cactive>true\u003c/active>\n \u003cfilterItems>\n \u003cfield>Contact.AccountId\u003c/field>\n \u003coperation>equals\u003c/operation>\n \u003cvalueField>$Source.AccountId\u003c/valueField>\n \u003c/filterItems>\n \u003cisOptional>false\u003c/isOptional>\n \u003c/lookupFilter>\n\u003c/CustomField>\n```\n\n### Master-Detail\n```xml\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Order__c\u003c/fullName>\n \u003clabel>Order\u003c/label>\n \u003ctype>MasterDetail\u003c/type>\n \u003creferenceTo>Order__c\u003c/referenceTo>\n \u003crelationshipLabel>Line Items\u003c/relationshipLabel>\n \u003crelationshipName>Line_Items\u003c/relationshipName>\n \u003crelationshipOrder>0\u003c/relationshipOrder>\n \u003creparentableMasterDetail>false\u003c/reparentableMasterDetail>\n \u003cwriteRequiresMasterRead>false\u003c/writeRequiresMasterRead>\n \u003cdescription>Parent order for this line item\u003c/description>\n \u003cinlineHelpText>The order this line item belongs to\u003c/inlineHelpText>\n\u003c/CustomField>\n```\n\n---\n\n## Special Fields\n\n### Email\n```xml\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Support_Email__c\u003c/fullName>\n \u003clabel>Support Email\u003c/label>\n \u003ctype>Email\u003c/type>\n \u003crequired>false\u003c/required>\n \u003cunique>false\u003c/unique>\n \u003cdescription>Customer support contact email\u003c/description>\n \u003cinlineHelpText>Email address for support inquiries\u003c/inlineHelpText>\n\u003c/CustomField>\n```\n\n### Phone\n```xml\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Mobile_Phone__c\u003c/fullName>\n \u003clabel>Mobile Phone\u003c/label>\n \u003ctype>Phone\u003c/type>\n \u003crequired>false\u003c/required>\n \u003cdescription>Mobile phone number\u003c/description>\n \u003cinlineHelpText>Enter mobile number including country code\u003c/inlineHelpText>\n\u003c/CustomField>\n```\n\n### URL\n```xml\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>LinkedIn_Profile__c\u003c/fullName>\n \u003clabel>LinkedIn Profile\u003c/label>\n \u003ctype>Url\u003c/type>\n \u003crequired>false\u003c/required>\n \u003cdescription>LinkedIn profile URL\u003c/description>\n \u003cinlineHelpText>Enter full LinkedIn URL (https://linkedin.com/in/...)\u003c/inlineHelpText>\n\u003c/CustomField>\n```\n\n---\n\n## Formula Fields\n\n### Text Formula\n```xml\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Full_Address__c\u003c/fullName>\n \u003clabel>Full Address\u003c/label>\n \u003ctype>Text\u003c/type>\n \u003cformula>Street__c & BR() &\nCity__c & \", \" & State__c & \" \" & Postal_Code__c & BR() &\nCountry__c\u003c/formula>\n \u003cdescription>Formatted complete address\u003c/description>\n\u003c/CustomField>\n```\n\n### Number Formula (Calculated)\n```xml\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Line_Total__c\u003c/fullName>\n \u003clabel>Line Total\u003c/label>\n \u003ctype>Currency\u003c/type>\n \u003cprecision>18\u003c/precision>\n \u003cscale>2\u003c/scale>\n \u003cformula>Quantity__c * Unit_Price__c * (1 - BLANKVALUE(Discount_Percent__c, 0) / 100)\u003c/formula>\n \u003cformulaTreatBlanksAs>BlankAsZero\u003c/formulaTreatBlanksAs>\n \u003cdescription>Calculated line item total with discount\u003c/description>\n\u003c/CustomField>\n```\n\n### Checkbox Formula\n```xml\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Is_Overdue__c\u003c/fullName>\n \u003clabel>Is Overdue\u003c/label>\n \u003ctype>Checkbox\u003c/type>\n \u003cformula>AND(\n NOT(ISPICKVAL(Status__c, 'Paid')),\n NOT(ISPICKVAL(Status__c, 'Cancelled')),\n Due_Date__c \u003c TODAY()\n)\u003c/formula>\n \u003cdescription>True if invoice is past due date and not paid\u003c/description>\n\u003c/CustomField>\n```\n\n---\n\n## Roll-Up Summary\n\n```xml\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Total_Line_Items__c\u003c/fullName>\n \u003clabel>Total Line Items\u003c/label>\n \u003ctype>Summary\u003c/type>\n \u003csummarizedField>Order_Line_Item__c.Line_Total__c\u003c/summarizedField>\n \u003csummaryForeignKey>Order_Line_Item__c.Order__c\u003c/summaryForeignKey>\n \u003csummaryOperation>sum\u003c/summaryOperation>\n \u003cdescription>Sum of all line item totals\u003c/description>\n\u003c/CustomField>\n```\n\n### Roll-Up with Filter\n```xml\n\u003cCustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Completed_Tasks_Count__c\u003c/fullName>\n \u003clabel>Completed Tasks\u003c/label>\n \u003ctype>Summary\u003c/type>\n \u003csummaryForeignKey>Project_Task__c.Project__c\u003c/summaryForeignKey>\n \u003csummaryOperation>count\u003c/summaryOperation>\n \u003csummaryFilterItems>\n \u003cfield>Project_Task__c.Status__c\u003c/field>\n \u003coperation>equals\u003c/operation>\n \u003cvalue>Completed\u003c/value>\n \u003c/summaryFilterItems>\n \u003cdescription>Count of completed tasks on this project\u003c/description>\n\u003c/CustomField>\n```\n\n---\n\n## Summary\n\n| Field Type | Use Case | Key Settings |\n|------------|----------|--------------|\n| Text | Short strings | `length` (1-255) |\n| LongTextArea | Multi-line text | `length`, `visibleLines` |\n| Number | Quantities, rates | `precision`, `scale` |\n| Currency | Money | `precision`, `scale` |\n| Date | Calendar dates | - |\n| DateTime | Timestamps | - |\n| Checkbox | True/False | `defaultValue` (required) |\n| Picklist | Single choice | `valueSet` |\n| MultiselectPicklist | Multiple choices | `valueSet`, `visibleLines` |\n| Lookup | Optional relationship | `referenceTo`, `deleteConstraint` |\n| MasterDetail | Required relationship | `referenceTo`, `relationshipOrder` |\n| Formula | Calculated | `formula`, return type |\n| Summary | Aggregation | `summaryOperation`, `summarizedField` |\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":12734,"content_sha256":"07ebd5dc23197055a3c2b7fbac1c5d1ebbc465234cc8389718044516279cfdc4"},{"filename":"references/field-types-guide.md","content":"\u003c!-- Parent: sf-metadata/SKILL.md -->\n# Salesforce Field Types Guide\n\n## Overview\n\nChoosing the right field type is critical for data integrity, user experience, and application performance. This guide helps you select the appropriate field type for your requirements.\n\n---\n\n## Field Type Decision Tree\n\n```\nWhat kind of data?\n├── Text/String\n│ ├── Short (≤255 chars) → Text\n│ ├── Long (>255 chars)\n│ │ ├── Plain text → Long Text Area\n│ │ └── Formatted → Rich Text Area\n│ ├── Predefined values\n│ │ ├── Single select → Picklist\n│ │ └── Multiple select → Multi-Select Picklist\n│ ├── Email format → Email\n│ ├── Phone format → Phone\n│ └── URL format → URL\n├── Numeric\n│ ├── Whole numbers → Number (scale=0)\n│ ├── Decimals → Number (scale>0)\n│ ├── Money → Currency\n│ └── Percentage → Percent\n├── Date/Time\n│ ├── Date only → Date\n│ └── Date + Time → DateTime\n├── True/False → Checkbox\n├── Related Record\n│ ├── Optional parent → Lookup\n│ └── Required parent → Master-Detail\n└── Calculated\n ├── From same record → Formula\n └── From child records → Roll-Up Summary\n```\n\n---\n\n## Text Fields\n\n### Text (Standard)\n**Use When:** Short text values up to 255 characters\n**Max Length:** 255 characters\n**Features:**\n- Can be unique\n- Can be external ID\n- Searchable\n- Can be used in filters\n\n**Examples:** Account codes, serial numbers, short names\n\n```xml\n\u003ctype>Text\u003c/type>\n\u003clength>80\u003c/length>\n```\n\n---\n\n### Long Text Area\n**Use When:** Multi-line text over 255 characters\n**Max Length:** 131,072 characters\n**Limitations:**\n- NOT searchable\n- NOT filterable\n- Cannot be unique\n- Cannot be used in roll-ups\n\n**Examples:** Descriptions, notes, comments\n\n```xml\n\u003ctype>LongTextArea\u003c/type>\n\u003clength>32000\u003c/length>\n\u003cvisibleLines>5\u003c/visibleLines>\n```\n\n---\n\n### Rich Text Area\n**Use When:** Formatted text with HTML\n**Max Length:** 131,072 characters\n**Features:**\n- Bold, italic, underline\n- Lists, links, images\n- Same limitations as Long Text Area\n\n**Examples:** Marketing descriptions, detailed instructions\n\n```xml\n\u003ctype>Html\u003c/type>\n\u003clength>32000\u003c/length>\n\u003cvisibleLines>10\u003c/visibleLines>\n```\n\n---\n\n## Picklist Fields\n\n### Picklist (Single-Select)\n**Use When:** Predefined single choice\n**Max Values:** 1,000 (recommended \u003c 200)\n**Features:**\n- Filterable\n- Reportable\n- Can have default value\n- Restricted option available\n\n**Best Practices:**\n- Use Global Value Sets for reusable values\n- Enable restricted picklist for data quality\n- Consider dependent picklists for hierarchies\n\n```xml\n\u003ctype>Picklist\u003c/type>\n\u003cvalueSet>\n \u003crestricted>true\u003c/restricted>\n \u003cvalueSetDefinition>\n \u003csorted>false\u003c/sorted>\n \u003cvalue>\n \u003cfullName>Option1\u003c/fullName>\n \u003clabel>Option 1\u003c/label>\n \u003cdefault>true\u003c/default>\n \u003c/value>\n \u003c/valueSetDefinition>\n\u003c/valueSet>\n```\n\n---\n\n### Multi-Select Picklist\n**Use When:** Multiple predefined choices\n**Max Values:** 500\n**Limitations:**\n- Cannot be unique\n- Cannot be used in roll-ups\n- Stored as semicolon-separated string\n\n**Formula Access:** Use `INCLUDES()` function\n\n```xml\n\u003ctype>MultiselectPicklist\u003c/type>\n\u003cvisibleLines>4\u003c/visibleLines>\n```\n\n---\n\n## Numeric Fields\n\n### Number\n**Use When:** Numeric values (integers or decimals)\n**Max Precision:** 18 digits total\n**Max Scale:** 17 decimal places\n\n**Configuration:**\n- `precision`: Total digits (1-18)\n- `scale`: Decimal places (0-17)\n\n**Examples:**\n| Use Case | Precision | Scale |\n|----------|-----------|-------|\n| Integer | 18 | 0 |\n| Two decimals | 18 | 2 |\n| Percentage | 5 | 2 |\n\n```xml\n\u003ctype>Number\u003c/type>\n\u003cprecision>18\u003c/precision>\n\u003cscale>2\u003c/scale>\n```\n\n---\n\n### Currency\n**Use When:** Monetary values\n**Features:**\n- Displays with org currency symbol\n- Multi-currency support\n- Respects locale formatting\n\n**Best Practice:** Use precision=18, scale=2 for standard currency\n\n```xml\n\u003ctype>Currency\u003c/type>\n\u003cprecision>18\u003c/precision>\n\u003cscale>2\u003c/scale>\n```\n\n---\n\n### Percent\n**Use When:** Percentage values\n**Storage:** Stored as decimal (50 = 50%)\n**Display:** Shows with % symbol\n\n```xml\n\u003ctype>Percent\u003c/type>\n\u003cprecision>5\u003c/precision>\n\u003cscale>2\u003c/scale>\n```\n\n---\n\n## Date/Time Fields\n\n### Date\n**Use When:** Calendar dates without time\n**Format:** YYYY-MM-DD (internal)\n**Features:**\n- Date picker in UI\n- Timezone neutral\n- Can use TODAY() in formulas\n\n```xml\n\u003ctype>Date\u003c/type>\n```\n\n---\n\n### DateTime\n**Use When:** Timestamps with time component\n**Format:** ISO 8601 with timezone\n**Features:**\n- Date and time picker\n- Timezone aware\n- Can use NOW() in formulas\n\n```xml\n\u003ctype>DateTime\u003c/type>\n```\n\n---\n\n## Boolean Fields\n\n### Checkbox\n**Use When:** True/False values\n**Features:**\n- Always has a value (never null)\n- Default value required\n- Filterable\n\n**Best Practice:** Use clear naming (Is_Active, Has_Permission)\n\n```xml\n\u003ctype>Checkbox\u003c/type>\n\u003cdefaultValue>false\u003c/defaultValue>\n```\n\n---\n\n## Relationship Fields\n\n### Lookup\n**Use When:** Optional relationship to another record\n**Features:**\n- Can be empty (null)\n- No cascade delete (configurable)\n- No roll-up summaries\n- Can be reparented\n\n**Delete Constraints:**\n| Option | Behavior |\n|--------|----------|\n| Clear | Sets to null (default) |\n| SetNull | Sets to null |\n| Restrict | Prevents deletion |\n\n```xml\n\u003ctype>Lookup\u003c/type>\n\u003creferenceTo>Account\u003c/referenceTo>\n\u003crelationshipLabel>Related Records\u003c/relationshipLabel>\n\u003crelationshipName>Related_Records\u003c/relationshipName>\n\u003cdeleteConstraint>SetNull\u003c/deleteConstraint>\n```\n\n---\n\n### Master-Detail\n**Use When:** Required parent relationship\n**Features:**\n- Cannot be empty\n- Cascade delete\n- Supports roll-up summaries\n- Child sharing = parent sharing\n\n**Limitations:**\n- Max 2 per object\n- Cannot convert to Lookup after creation\n- Child object must be empty to create\n\n```xml\n\u003ctype>MasterDetail\u003c/type>\n\u003creferenceTo>Account\u003c/referenceTo>\n\u003crelationshipLabel>Line Items\u003c/relationshipLabel>\n\u003crelationshipName>Line_Items\u003c/relationshipName>\n\u003creparentableMasterDetail>false\u003c/reparentableMasterDetail>\n```\n\n---\n\n## Calculated Fields\n\n### Formula\n**Use When:** Derived value from same record\n**Return Types:** Text, Number, Currency, Percent, Date, DateTime, Checkbox\n**Limits:**\n- 5,000 compiled character limit\n- Can reference up to 10 relationships\n\n**Examples:**\n```\n// Text concatenation\nFirstName & \" \" & LastName\n\n// Conditional\nIF(Amount > 100000, \"Large\", \"Small\")\n\n// Cross-object\nAccount.Industry\n```\n\n```xml\n\u003ctype>Text\u003c/type> \u003c!-- or Number, Currency, etc. -->\n\u003cformula>FirstName__c & \" \" & LastName__c\u003c/formula>\n```\n\n---\n\n### Roll-Up Summary\n**Use When:** Aggregate child records\n**Requires:** Master-Detail relationship\n**Operations:** COUNT, SUM, MIN, MAX\n\n**Limitations:**\n- Only on Master-Detail parent\n- Cannot summarize formula fields\n- Cannot summarize Long Text or Multi-Select\n\n```xml\n\u003ctype>Summary\u003c/type>\n\u003csummaryOperation>sum\u003c/summaryOperation>\n\u003csummarizedField>Line_Item__c.Amount__c\u003c/summarizedField>\n\u003csummaryForeignKey>Line_Item__c.Order__c\u003c/summaryForeignKey>\n```\n\n---\n\n## Special Fields\n\n### Email\n- Max 80 characters\n- Format validation\n- Click-to-email in Lightning\n\n### Phone\n- Max 40 characters\n- Click-to-dial support\n- No format validation\n\n### URL\n- Max 255 characters\n- Clickable link\n- Opens in new tab\n\n### Geolocation\n- Latitude/Longitude\n- Distance formulas\n- Map integration\n\n### Encrypted Text\n- PII protection\n- Mask characters\n- Limited functionality\n\n---\n\n## Field Type Comparison\n\n| Feature | Text | Long Text | Picklist | Number | Lookup | Formula |\n|---------|------|-----------|----------|--------|--------|---------|\n| Searchable | ✅ | ❌ | ✅ | ✅ | ✅ | ✅* |\n| Filterable | ✅ | ❌ | ✅ | ✅ | ✅ | ✅* |\n| Reportable | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |\n| Unique | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ |\n| External ID | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ |\n| Roll-up | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ |\n| Editable | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |\n\n*Formula fields inherit searchability/filterability from return type\n\n---\n\n## Checklist: Choosing a Field Type\n\n1. **Data Nature**\n - [ ] Text, number, date, or boolean?\n - [ ] Predefined values or free-form?\n - [ ] Single value or relationship?\n\n2. **Requirements**\n - [ ] Required or optional?\n - [ ] Unique constraint needed?\n - [ ] External ID for integration?\n\n3. **Usage**\n - [ ] Will it be searched?\n - [ ] Will it be filtered/reported?\n - [ ] Will it be used in formulas?\n - [ ] Will it be used in roll-ups?\n\n4. **Performance**\n - [ ] Expected data volume?\n - [ ] Index needed?\n - [ ] Character limit appropriate?\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":8772,"content_sha256":"5d4b648767aa849c059af2b48318f9d215c0feb80a236470e07648031bd774ce"},{"filename":"references/fls-best-practices.md","content":"\u003c!-- Parent: sf-metadata/SKILL.md -->\n# Field-Level Security (FLS) Best Practices\n\n## Overview\n\nField-Level Security (FLS) controls which users can view and edit specific fields on records. Proper FLS configuration is essential for data security and compliance.\n\n---\n\n## Understanding FLS\n\n### Two Levels of Field Access\n1. **Readable**: User can see the field value\n2. **Editable**: User can modify the field value (implies readable)\n\n### FLS vs Object Permissions\n```\nUser Access = Object Permissions + Field-Level Security + Record Access\n\nObject Permissions: Can user access the object at all?\nFLS: Can user see/edit specific fields?\nRecord Access: Can user access specific records?\n```\n\n### Where FLS is Configured\n- Profiles (base access)\n- Permission Sets (additive access)\n- Permission Set Groups (combined sets)\n\n---\n\n## Best Practices\n\n### 1. Use Permission Sets Over Profiles\n\n**Why:**\n- Profiles are monolithic and hard to maintain\n- Permission Sets are additive and composable\n- Easier to manage feature-based access\n\n**Pattern:**\n```\nProfile: Base access (read-only on most fields)\nPermission Set: Feature-specific edit access\n```\n\n**Example:**\n```xml\n\u003c!-- Permission Set for Invoice Editors -->\n\u003cPermissionSet>\n \u003clabel>Invoice Editor\u003c/label>\n \u003cfieldPermissions>\n \u003ceditable>true\u003c/editable>\n \u003cfield>Invoice__c.Amount__c\u003c/field>\n \u003creadable>true\u003c/readable>\n \u003c/fieldPermissions>\n \u003cfieldPermissions>\n \u003ceditable>true\u003c/editable>\n \u003cfield>Invoice__c.Status__c\u003c/field>\n \u003creadable>true\u003c/readable>\n \u003c/fieldPermissions>\n\u003c/PermissionSet>\n```\n\n---\n\n### 2. Principle of Least Privilege\n\n**Rule:** Grant minimum access needed for the job function\n\n**Steps:**\n1. Start with no access\n2. Add read access where needed\n3. Add edit access only where required\n4. Review periodically\n\n**Anti-Pattern:**\n```xml\n\u003c!-- DON'T: Grant edit on everything -->\n\u003cfieldPermissions>\n \u003ceditable>true\u003c/editable>\n \u003cfield>Account.AnnualRevenue\u003c/field>\n \u003creadable>true\u003c/readable>\n\u003c/fieldPermissions>\n```\n\n**Better:**\n```xml\n\u003c!-- DO: Grant read-only unless edit is required -->\n\u003cfieldPermissions>\n \u003ceditable>false\u003c/editable>\n \u003cfield>Account.AnnualRevenue\u003c/field>\n \u003creadable>true\u003c/readable>\n\u003c/fieldPermissions>\n```\n\n---\n\n### 3. Protect Sensitive Fields\n\n#### Identify Sensitive Fields\n| Category | Examples |\n|----------|----------|\n| PII | SSN, Date of Birth, Driver's License |\n| Financial | Bank Account, Credit Card, Salary |\n| Health | Medical conditions, Insurance |\n| Security | Password, Token, API Key |\n| Business | Trade secrets, Pricing formulas |\n\n#### Protection Strategies\n\n1. **Restrict to Specific Permission Sets**\n```xml\n\u003cPermissionSet>\n \u003clabel>PII_Access\u003c/label>\n \u003cdescription>Access to sensitive PII fields\u003c/description>\n \u003cfieldPermissions>\n \u003ceditable>false\u003c/editable>\n \u003cfield>Contact.SSN__c\u003c/field>\n \u003creadable>true\u003c/readable>\n \u003c/fieldPermissions>\n\u003c/PermissionSet>\n```\n\n2. **Use Shield Platform Encryption**\n- Encrypts data at rest\n- Searchable with deterministic encryption\n- Requires Shield license\n\n3. **Use Classic Encryption (Encrypted Text Field)**\n- Masks display (shows last 4 characters)\n- Limited functionality\n- No additional license needed\n\n---\n\n### 4. FLS in Apex Code\n\n#### Always Check FLS in Apex\n\n**With SOQL:**\n```apex\n// Good: Respects FLS\nList\u003cAccount> accounts = [\n SELECT Name, Industry\n FROM Account\n WITH USER_MODE\n];\n\n// Alternative: Security.stripInaccessible\nList\u003cAccount> accounts = [SELECT Name, Industry, Revenue FROM Account];\nSObjectAccessDecision decision = Security.stripInaccessible(\n AccessType.READABLE,\n accounts\n);\nList\u003cAccount> safeAccounts = decision.getRecords();\n```\n\n**With DML:**\n```apex\n// Good: Respects FLS\nDatabase.insert(accounts, AccessLevel.USER_MODE);\n\n// Alternative: Check before DML\nif (Schema.sObjectType.Account.fields.Industry.isUpdateable()) {\n account.Industry = 'Technology';\n}\n```\n\n---\n\n### 5. Organize Permission Sets by Function\n\n**Pattern:**\n```\n[Object]_[AccessLevel]\n[Feature]_[Role]\n[Integration]_Access\n```\n\n**Example Structure:**\n```\nPermission Sets/\n├── Account_Read_Only.permissionset-meta.xml\n├── Account_Full_Access.permissionset-meta.xml\n├── Invoice_Approver.permissionset-meta.xml\n├── Invoice_Creator.permissionset-meta.xml\n├── ERP_Integration_Access.permissionset-meta.xml\n└── Reports_Power_User.permissionset-meta.xml\n```\n\n---\n\n### 6. Use Permission Set Groups\n\n**Why:**\n- Combine related permission sets\n- Easier role-based assignment\n- Single assignment per user role\n\n**Example:**\n```\nPermission Set Group: Sales_Representative\n├── Account_Full_Access\n├── Contact_Full_Access\n├── Opportunity_Full_Access\n├── Quote_Creator\n└── Reports_Basic\n```\n\n---\n\n### 7. Handle Formula Fields Correctly\n\n**Important:** Formula fields inherit FLS from referenced fields\n\n```\nFormula: Account.Owner.Manager.Name\n\nUser needs READ access to:\n- Account.OwnerId\n- User.ManagerId\n- User.Name (on Manager)\n```\n\n**Best Practice:** Test formulas with different user profiles\n\n---\n\n### 8. Document FLS Decisions\n\n**For each sensitive field, document:**\n- Why it exists\n- Who should have access\n- Which permission sets grant access\n- Review date\n\n**Example:**\n```xml\n\u003cCustomField>\n \u003cfullName>SSN__c\u003c/fullName>\n \u003cdescription>\n Social Security Number - SENSITIVE\n Access: HR_PII_Access permission set only\n Review: Quarterly by Security team\n \u003c/description>\n\u003c/CustomField>\n```\n\n---\n\n## Common Mistakes\n\n### 1. Relying on Page Layout for Security\n```\n❌ \"Users can't see it because it's not on the layout\"\n✅ FLS controls true visibility; layouts are UX only\n```\n\n### 2. Granting Edit Without Business Need\n```\n❌ \"Give them edit just in case they need it\"\n✅ Start read-only, add edit when requested\n```\n\n### 3. Not Checking FLS in Apex\n```\n❌ Assuming controller/trigger runs as system\n✅ Always use WITH USER_MODE or Security.stripInaccessible\n```\n\n### 4. Over-Using System Administrator\n```\n❌ \"Just use System Admin profile\"\n✅ Create specific permission sets for each function\n```\n\n### 5. Not Testing FLS Changes\n```\n❌ Deploy FLS changes without testing\n✅ Test with actual user profiles before deploy\n```\n\n---\n\n## FLS Audit Checklist\n\n### For Each Object\n\n- [ ] All fields reviewed for sensitivity\n- [ ] Sensitive fields have restricted access\n- [ ] Permission Sets exist for each access pattern\n- [ ] No unnecessary edit permissions\n- [ ] Formula fields tested with limited users\n- [ ] Integration users have minimal required access\n\n### For Apex Code\n\n- [ ] All SOQL uses WITH USER_MODE or stripInaccessible\n- [ ] All DML uses USER_MODE or checks isUpdateable()\n- [ ] Tests verify FLS enforcement\n- [ ] No hardcoded field access bypass\n\n### For Deployment\n\n- [ ] FLS changes reviewed by security team\n- [ ] Changes tested with representative users\n- [ ] Rollback plan exists\n- [ ] Documentation updated\n\n---\n\n## Quick Reference\n\n### SOQL FLS Modes\n| Mode | Behavior |\n|------|----------|\n| `WITH USER_MODE` | Enforces FLS and sharing |\n| `WITH SYSTEM_MODE` | Bypasses FLS (use carefully) |\n| Default (no mode) | Depends on context |\n\n### Schema Methods\n| Method | Purpose |\n|--------|---------|\n| `isAccessible()` | Can user read field? |\n| `isUpdateable()` | Can user edit field? |\n| `isCreateable()` | Can user set on create? |\n\n### Security.stripInaccessible\n| AccessType | Strips Fields Not... |\n|------------|----------------------|\n| `READABLE` | Readable by user |\n| `CREATABLE` | Creatable by user |\n| `UPDATABLE` | Updatable by user |\n| `UPSERTABLE` | Creatable or updatable |\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":7672,"content_sha256":"f09c0415f9a2ad532fab1ed594bb44c144f406cc48a893293fd856e813e03cb6"},{"filename":"references/metadata-types-reference.md","content":"\u003c!-- Parent: sf-metadata/SKILL.md -->\n# Salesforce Metadata Types Reference\n\n## Overview\n\nThis guide covers the most common Salesforce metadata types, their file locations, and usage patterns.\n\n---\n\n## Metadata Directory Structure\n\n```\nforce-app/main/default/\n├── objects/\n│ ├── Account/\n│ │ ├── Account.object-meta.xml # Object settings (standard)\n│ │ ├── fields/\n│ │ │ ├── Custom_Field__c.field-meta.xml\n│ │ │ └── ...\n│ │ ├── validationRules/\n│ │ │ └── Rule_Name.validationRule-meta.xml\n│ │ ├── recordTypes/\n│ │ │ └── Record_Type.recordType-meta.xml\n│ │ └── listViews/\n│ │ └── All_Accounts.listView-meta.xml\n│ └── Custom_Object__c/\n│ ├── Custom_Object__c.object-meta.xml # Full object definition\n│ ├── fields/\n│ ├── validationRules/\n│ └── recordTypes/\n├── profiles/\n│ └── Profile_Name.profile-meta.xml\n├── permissionsets/\n│ └── Permission_Set.permissionset-meta.xml\n├── layouts/\n│ └── Object-Layout_Name.layout-meta.xml\n├── classes/\n│ ├── ClassName.cls\n│ └── ClassName.cls-meta.xml\n├── triggers/\n│ ├── TriggerName.trigger\n│ └── TriggerName.trigger-meta.xml\n├── flows/\n│ └── Flow_Name.flow-meta.xml\n├── lwc/\n│ └── componentName/\n│ ├── componentName.html\n│ ├── componentName.js\n│ └── componentName.js-meta.xml\n└── aura/\n └── ComponentName/\n ├── ComponentName.cmp\n └── ComponentName.cmp-meta.xml\n```\n\n---\n\n## Object Metadata\n\n### Custom Object\n**Location:** `objects/[ObjectName__c]/[ObjectName__c].object-meta.xml`\n\n**Contains:**\n- Label and plural label\n- Name field configuration\n- Sharing model\n- Feature toggles (history, activities, reports)\n- Search layouts\n\n```xml\n\u003cCustomObject xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003clabel>Invoice\u003c/label>\n \u003cpluralLabel>Invoices\u003c/pluralLabel>\n \u003cnameField>\n \u003clabel>Invoice Number\u003c/label>\n \u003ctype>AutoNumber\u003c/type>\n \u003cdisplayFormat>INV-{0000}\u003c/displayFormat>\n \u003c/nameField>\n \u003cdeploymentStatus>Deployed\u003c/deploymentStatus>\n \u003csharingModel>Private\u003c/sharingModel>\n\u003c/CustomObject>\n```\n\n### Custom Field\n**Location:** `objects/[ObjectName]/fields/[FieldName__c].field-meta.xml`\n\n**Common Types:**\n| Type | Element |\n|------|---------|\n| Text | `\u003ctype>Text\u003c/type>\u003clength>255\u003c/length>` |\n| Number | `\u003ctype>Number\u003c/type>\u003cprecision>18\u003c/precision>\u003cscale>2\u003c/scale>` |\n| Currency | `\u003ctype>Currency\u003c/type>` |\n| Date | `\u003ctype>Date\u003c/type>` |\n| Checkbox | `\u003ctype>Checkbox\u003c/type>\u003cdefaultValue>false\u003c/defaultValue>` |\n| Picklist | `\u003ctype>Picklist\u003c/type>\u003cvalueSet>...\u003c/valueSet>` |\n| Lookup | `\u003ctype>Lookup\u003c/type>\u003creferenceTo>Account\u003c/referenceTo>` |\n| Master-Detail | `\u003ctype>MasterDetail\u003c/type>` |\n| Formula | `\u003ctype>Text\u003c/type>\u003cformula>...\u003c/formula>` |\n| Roll-Up | `\u003ctype>Summary\u003c/type>` |\n\n---\n\n## Security Metadata\n\n### Profile\n**Location:** `profiles/[ProfileName].profile-meta.xml`\n\n**Contains:**\n- Object permissions\n- Field permissions\n- Tab visibility\n- Record type assignments\n- Layout assignments\n- User permissions\n\n### Permission Set\n**Location:** `permissionsets/[PermissionSetName].permissionset-meta.xml`\n\n**Contains:**\n- Object permissions\n- Field permissions\n- Tab settings\n- Apex class access\n- Visualforce page access\n- Custom permissions\n\n### Permission Set Group\n**Location:** `permissionsetgroups/[GroupName].permissionsetgroup-meta.xml`\n\n```xml\n\u003cPermissionSetGroup xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003clabel>Sales Team\u003c/label>\n \u003cpermissionSets>\n \u003cpermissionSet>Account_Access\u003c/permissionSet>\n \u003cpermissionSet>Opportunity_Access\u003c/permissionSet>\n \u003c/permissionSets>\n\u003c/PermissionSetGroup>\n```\n\n---\n\n## Validation & Business Logic\n\n### Validation Rule\n**Location:** `objects/[ObjectName]/validationRules/[RuleName].validationRule-meta.xml`\n\n```xml\n\u003cValidationRule xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Require_Close_Date\u003c/fullName>\n \u003cactive>true\u003c/active>\n \u003cerrorConditionFormula>\n AND(\n ISPICKVAL(Status__c, 'Closed'),\n ISBLANK(Close_Date__c)\n )\n \u003c/errorConditionFormula>\n \u003cerrorDisplayField>Close_Date__c\u003c/errorDisplayField>\n \u003cerrorMessage>Close Date is required when Status is Closed\u003c/errorMessage>\n\u003c/ValidationRule>\n```\n\n### Record Type\n**Location:** `objects/[ObjectName]/recordTypes/[RecordTypeName].recordType-meta.xml`\n\n```xml\n\u003cRecordType xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>Business_Account\u003c/fullName>\n \u003cactive>true\u003c/active>\n \u003clabel>Business Account\u003c/label>\n \u003cpicklistValues>\n \u003cpicklist>Type\u003c/picklist>\n \u003cvalues>\n \u003cfullName>Customer\u003c/fullName>\n \u003cdefault>true\u003c/default>\n \u003c/values>\n \u003c/picklistValues>\n\u003c/RecordType>\n```\n\n---\n\n## UI Metadata\n\n### Page Layout\n**Location:** `layouts/[ObjectName]-[LayoutName].layout-meta.xml`\n\n**Contains:**\n- Section definitions\n- Field placements\n- Related lists\n- Quick actions\n- Display options\n\n### Lightning Page (FlexiPage)\n**Location:** `flexipages/[PageName].flexipage-meta.xml`\n\n### List View\n**Location:** `objects/[ObjectName]/listViews/[ViewName].listView-meta.xml`\n\n```xml\n\u003cListView xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cfullName>All_Active_Accounts\u003c/fullName>\n \u003ccolumns>NAME\u003c/columns>\n \u003ccolumns>ACCOUNT_TYPE\u003c/columns>\n \u003ccolumns>PHONE1\u003c/columns>\n \u003cfilterScope>Everything\u003c/filterScope>\n \u003cfilters>\n \u003cfield>ACCOUNT.ACTIVE__C\u003c/field>\n \u003coperation>equals\u003c/operation>\n \u003cvalue>1\u003c/value>\n \u003c/filters>\n \u003clabel>All Active Accounts\u003c/label>\n\u003c/ListView>\n```\n\n---\n\n## Automation Metadata\n\n### Flow\n**Location:** `flows/[FlowName].flow-meta.xml`\n\n### Apex Class\n**Location:** `classes/[ClassName].cls` + `classes/[ClassName].cls-meta.xml`\n\n```xml\n\u003c!-- Meta file -->\n\u003cApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003capiVersion>66.0\u003c/apiVersion>\n \u003cstatus>Active\u003c/status>\n\u003c/ApexClass>\n```\n\n### Apex Trigger\n**Location:** `triggers/[TriggerName].trigger` + `triggers/[TriggerName].trigger-meta.xml`\n\n---\n\n## Component Metadata\n\n### Lightning Web Component (LWC)\n**Location:** `lwc/[componentName]/`\n\n```\nlwc/myComponent/\n├── myComponent.html\n├── myComponent.js\n├── myComponent.css (optional)\n└── myComponent.js-meta.xml\n```\n\n### Aura Component\n**Location:** `aura/[ComponentName]/`\n\n```\naura/MyComponent/\n├── MyComponent.cmp\n├── MyComponentController.js\n├── MyComponentHelper.js\n├── MyComponent.css\n└── MyComponent.cmp-meta.xml\n```\n\n---\n\n## Global Value Sets\n\n### Global Value Set\n**Location:** `globalValueSets/[SetName].globalValueSet-meta.xml`\n\n```xml\n\u003cGlobalValueSet xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cmasterLabel>Industry Values\u003c/masterLabel>\n \u003csorted>false\u003c/sorted>\n \u003ccustomValue>\n \u003cfullName>Technology\u003c/fullName>\n \u003cdefault>false\u003c/default>\n \u003clabel>Technology\u003c/label>\n \u003c/customValue>\n \u003ccustomValue>\n \u003cfullName>Finance\u003c/fullName>\n \u003cdefault>false\u003c/default>\n \u003clabel>Finance\u003c/label>\n \u003c/customValue>\n\u003c/GlobalValueSet>\n```\n\n---\n\n## Custom Metadata Types\n\n### Custom Metadata Type Definition\n**Location:** `customMetadata/[TypeName].[RecordName].md-meta.xml`\n\n```xml\n\u003cCustomMetadata xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003clabel>US Config\u003c/label>\n \u003cvalues>\n \u003cfield>Country_Code__c\u003c/field>\n \u003cvalue>US\u003c/value>\n \u003c/values>\n \u003cvalues>\n \u003cfield>Tax_Rate__c\u003c/field>\n \u003cvalue>0.08\u003c/value>\n \u003c/values>\n\u003c/CustomMetadata>\n```\n\n---\n\n## Quick Reference: File Extensions\n\n| Metadata Type | Extension |\n|---------------|-----------|\n| Custom Object | `.object-meta.xml` |\n| Custom Field | `.field-meta.xml` |\n| Profile | `.profile-meta.xml` |\n| Permission Set | `.permissionset-meta.xml` |\n| Validation Rule | `.validationRule-meta.xml` |\n| Record Type | `.recordType-meta.xml` |\n| Page Layout | `.layout-meta.xml` |\n| Flow | `.flow-meta.xml` |\n| Apex Class | `.cls` + `.cls-meta.xml` |\n| Apex Trigger | `.trigger` + `.trigger-meta.xml` |\n| LWC | `.js-meta.xml` |\n| Aura | `.cmp-meta.xml` |\n\n---\n\n## Recent CLI-Supported Metadata Additions\n\nRecent Salesforce CLI / SDR updates added support for several metadata types that were easy to miss in older reference material:\n\n| Current Type | Typical Source Shape | Notes |\n|--------------|----------------------|-------|\n| `CnfgItemSourceDefinition` | `cnfgItemSourceDefinitions/\u003cName>.cnfgItemSourceDefinition-meta.xml` | Replaces older `CnfgMgmtCiSourceDef` naming in source workflows |\n| `ExtlClntAppOauthSecuritySettings` | `extlClntAppOauthSecuritySettings/\u003cName>.ecaOauthSecurity-meta.xml` | Companion metadata for External Client Apps |\n| `UIBundle` | `uiBundles/\u003cName>/...` | Replaces older `WebApplication` naming in source workflows |\n\nWhen working from older examples, prefer the **current** metadata type and suffix names above.\n\n---\n\n## sf CLI Metadata Commands\n\n```bash\n# List metadata types\nsf org list metadata-types --target-org [alias]\n\n# List specific metadata\nsf org list metadata --metadata-type CustomObject --target-org [alias]\n\n# Describe object\nsf sobject describe --sobject Account --target-org [alias]\n\n# Retrieve metadata\nsf project retrieve start --metadata CustomObject:Account\n\n# Deploy metadata\nsf project deploy start --source-dir force-app\n\n# Generate package.xml\nsf project generate manifest --source-dir force-app\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":9715,"content_sha256":"ec482ccea4569ab701808c4c9f87b0221b736e63cef990fa8198d90b79a53289"},{"filename":"references/naming-conventions.md","content":"\u003c!-- Parent: sf-metadata/SKILL.md -->\n# Salesforce Metadata Naming Conventions\n\n## Overview\n\nConsistent naming conventions improve maintainability, discoverability, and team collaboration. Follow these standards for all Salesforce metadata.\n\n---\n\n## Custom Objects\n\n### Format\n```\n[BusinessEntity]__c\n```\n\n### Rules\n- Use PascalCase\n- Singular form (not plural)\n- Max 40 characters (API name)\n- No abbreviations\n- Descriptive and business-meaningful\n\n### Examples\n✅ Good:\n- `Invoice__c`\n- `Product_Catalog__c`\n- `Service_Request__c`\n- `Customer_Feedback__c`\n\n❌ Avoid:\n- `Invoices__c` (plural)\n- `Inv__c` (abbreviated)\n- `SvcReq__c` (abbreviated)\n- `object1__c` (meaningless)\n\n---\n\n## Custom Fields\n\n### Format\n```\n[Descriptive_Name]__c\n```\n\n### Rules\n- Use PascalCase with underscores\n- Indicate purpose, not data type\n- Max 40 characters (API name)\n- Use standard suffixes for relationships\n\n### Standard Suffixes\n| Suffix | Use Case |\n|--------|----------|\n| `_Date` | Date fields (e.g., `Due_Date__c`) |\n| `_Amount` | Currency/Number (e.g., `Total_Amount__c`) |\n| `_Count` | Counts (e.g., `Line_Item_Count__c`) |\n| `_Percent` | Percentages (e.g., `Discount_Percent__c`) |\n| `_Flag` | Boolean indicators (e.g., `Is_Active_Flag__c`) |\n| `_Code` | Codes/identifiers (e.g., `Region_Code__c`) |\n\n### Relationship Fields\n```\n[RelatedObject]__c // Lookup/Master-Detail field\n[RelatedObject]__r // Relationship name (auto-generated)\n```\n\n### Examples\n✅ Good:\n- `Account_Manager__c` (Lookup to User)\n- `Total_Contract_Value__c` (Currency)\n- `Expected_Close_Date__c` (Date)\n- `Is_Primary_Contact__c` (Checkbox)\n\n❌ Avoid:\n- `Amt__c` (abbreviated)\n- `Field1__c` (meaningless)\n- `TCV__c` (acronym without context)\n- `contactLookup__c` (inconsistent casing)\n\n---\n\n## Profiles\n\n### Format\n```\n[Role/Function] [Level]\n```\n\n### Examples\n- `Sales Representative`\n- `Sales Manager`\n- `Marketing User`\n- `System Administrator`\n- `Integration User`\n\n### Notes\n- Standard profiles cannot be renamed\n- Create custom profiles for specific needs\n- Use Permission Sets for granular access\n\n---\n\n## Permission Sets\n\n### Format\n```\n[Feature/Capability]_[AccessLevel]\n```\n\n### Patterns\n| Pattern | Use Case |\n|---------|----------|\n| `[Object]_Full_Access` | Complete CRUD on object |\n| `[Object]_Read_Only` | Read-only access |\n| `[Feature]_Manager` | Feature management |\n| `[Integration]_API` | Integration access |\n\n### Examples\n✅ Good:\n- `Invoice_Full_Access`\n- `Customer_Portal_User`\n- `ERP_Integration_API`\n- `Report_Builder_Access`\n- `Deal_Approval_Manager`\n\n❌ Avoid:\n- `PS1` (meaningless)\n- `John_Smith_Access` (user-specific)\n- `Temp_Access` (ambiguous)\n\n---\n\n## Validation Rules\n\n### Format\n```\n[Object]_[Action]_[Condition]\n```\n\n### Rules\n- Start with object name for organization\n- Use verb describing what it prevents/requires\n- End with condition being validated\n\n### Examples\n✅ Good:\n- `Opportunity_Require_Close_Date_When_Closed`\n- `Account_Prevent_Type_Change_After_Active`\n- `Contact_Require_Email_Or_Phone`\n- `Invoice_Amount_Must_Be_Positive`\n\n❌ Avoid:\n- `VR001` (meaningless)\n- `Check1` (undescriptive)\n- `Validation` (too generic)\n\n---\n\n## Record Types\n\n### Format\n```\n[Category/Type]_[SubCategory]\n```\n\n### Examples\n✅ Good:\n- `Business_Account`\n- `Person_Account`\n- `New_Business_Opportunity`\n- `Renewal_Opportunity`\n- `Support_Case`\n- `Billing_Inquiry`\n\n❌ Avoid:\n- `RT1` (meaningless)\n- `Type1` (undescriptive)\n\n---\n\n## Page Layouts\n\n### Format\n```\n[Object]-[RecordType] Layout\n```\n\n### Examples\n- `Account-Business Account Layout`\n- `Account-Person Account Layout`\n- `Opportunity-New Business Layout`\n- `Case-Support Case Layout`\n\n---\n\n## Quick Reference Table\n\n| Metadata Type | Pattern | Example |\n|---------------|---------|---------|\n| Custom Object | `BusinessEntity__c` | `Invoice__c` |\n| Custom Field | `Descriptive_Name__c` | `Total_Amount__c` |\n| Lookup Field | `RelatedObject__c` | `Primary_Contact__c` |\n| Permission Set | `Feature_AccessLevel` | `Invoice_Manager` |\n| Validation Rule | `Object_Action_Condition` | `Opp_Require_Amount` |\n| Record Type | `Category_SubCategory` | `Business_Account` |\n| Page Layout | `Object-RecordType Layout` | `Account-Business Layout` |\n\n---\n\n## Anti-Patterns to Avoid\n\n### Abbreviations\n| Instead of | Use |\n|------------|-----|\n| `Acct__c` | `Account__c` |\n| `Opp__c` | `Opportunity__c` |\n| `Cont__c` | `Contact__c` |\n| `Amt__c` | `Amount__c` |\n| `Qty__c` | `Quantity__c` |\n\n### Meaningless Names\n| Instead of | Use |\n|------------|-----|\n| `Field1__c` | `Customer_Status__c` |\n| `Custom__c` | `Priority_Level__c` |\n| `Temp__c` | `Processing_Date__c` |\n\n### Inconsistent Casing\n| Instead of | Use |\n|------------|-----|\n| `totalamount__c` | `Total_Amount__c` |\n| `TOTAL_AMOUNT__c` | `Total_Amount__c` |\n| `TotalAmount__c` | `Total_Amount__c` |\n\n---\n\n## Checklist\n\nBefore creating metadata, verify:\n- [ ] Name is PascalCase with underscores\n- [ ] Name describes business purpose\n- [ ] No abbreviations used\n- [ ] Follows standard suffix patterns\n- [ ] Unique within the object/type\n- [ ] Max length constraints met\n- [ ] Consistent with existing patterns\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":5130,"content_sha256":"5ffe4a019aed69f40d9c6cc8f03dfaf58b9b0da562cecf1bd693a5711d44a98b"},{"filename":"references/orchestration.md","content":"\u003c!-- Parent: sf-metadata/SKILL.md -->\n# Multi-Skill Orchestration: sf-metadata Perspective\n\nThis document details how sf-metadata fits into the multi-skill workflow for Salesforce development.\n\n---\n\n## Standard Orchestration Order\n\n```\n┌─────────────────────────────────────────────────────────────────────────────┐\n│ STANDARD MULTI-SKILL ORCHESTRATION ORDER │\n├─────────────────────────────────────────────────────────────────────────────┤\n│ 1. sf-metadata ◀── YOU ARE HERE │\n│ └── Create object/field definitions (LOCAL files) │\n│ │\n│ 2. sf-flow │\n│ └── Create flow definitions (LOCAL files) │\n│ │\n│ 3. sf-deploy │\n│ └── Deploy all metadata (REMOTE) │\n│ │\n│ 4. sf-data │\n│ └── Create test data (REMOTE - objects must exist!) │\n└─────────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## Why sf-metadata Goes First\n\n| Step | Depends On sf-metadata | What Fails Without It |\n|------|------------------------|----------------------|\n| sf-flow | ✅ Must exist | Flow references non-existent field/object |\n| sf-deploy | ✅ Must exist | Nothing to deploy |\n| sf-data | ✅ Must be deployed | `SObject type 'X' not supported` |\n\n**sf-metadata creates the foundation** that all other skills build upon.\n\n---\n\n## Integration + Agentforce Extended Order\n\nWhen building agents with external API integrations:\n\n```\n┌─────────────────────────────────────────────────────────────────────────────┐\n│ INTEGRATION + AGENTFORCE ORCHESTRATION ORDER │\n├─────────────────────────────────────────────────────────────────────────────┤\n│ 1. sf-metadata ◀── YOU ARE HERE │\n│ └── Create object/field definitions │\n│ │\n│ 2. sf-connected-apps │\n│ └── Create OAuth Connected App (if external API needed) │\n│ │\n│ 3. sf-integration │\n│ └── Create Named Credential + External Service │\n│ │\n│ 4. sf-apex │\n│ └── Create @InvocableMethod (if custom logic needed) │\n│ │\n│ 5. sf-flow │\n│ └── Create Flow wrapper (HTTP Callout or Apex wrapper) │\n│ │\n│ 6. sf-deploy │\n│ └── Deploy all metadata │\n│ │\n│ 7. sf-ai-agentforce │\n│ └── Create agent with flow:// target │\n│ │\n│ 8. sf-deploy │\n│ └── Publish agent (sf agent publish authoring-bundle) │\n└─────────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## sf-metadata Responsibilities in Orchestration\n\n### Before sf-flow\n\nsf-metadata must create:\n- Custom Objects (the flow will reference)\n- Custom Fields (used in flow variables, assignments)\n- Picklist Values (used in flow decisions)\n- Record Types (used in flow record creates)\n\n### Before sf-apex\n\nsf-metadata must create:\n- Custom Objects (Apex queries/DML targets)\n- Custom Fields (referenced in SOQL, field sets)\n- Custom Metadata Types (configuration storage)\n\n### Example: Quote Builder Flow\n\n```\nsf-metadata creates:\n├── Quote__c.object-meta.xml\n├── Quote_Line_Item__c.object-meta.xml\n├── Quote__c.Status__c.field-meta.xml (Picklist)\n├── Quote_Line_Item__c.Product__c.field-meta.xml (Lookup)\n└── Quote_Access.permissionset-meta.xml\n\nsf-apex creates:\n└── PricingCalculator.cls (@InvocableMethod)\n\nsf-flow creates:\n└── Quote_Builder_Flow.flow-meta.xml (references above)\n\nsf-deploy:\n└── Deploys all to org\n```\n\n---\n\n## Common Errors from Wrong Order\n\n| Error | Cause | Correct Order |\n|-------|-------|---------------|\n| `Field does not exist: Status__c` | Flow created before field | sf-metadata → sf-flow |\n| `Invalid reference: Quote__c` | Flow created before object | sf-metadata → sf-flow |\n| `SObject type 'Quote__c' not supported` | Data created before deploy | sf-deploy → sf-data |\n| `Cannot find FlowDefinition` | Agent references missing flow | sf-flow → sf-ai-agentforce |\n\n---\n\n## Invocation Pattern\n\nAfter creating metadata with sf-metadata:\n\n```\n# Deploy metadata\nSkill(skill=\"sf-deploy\", args=\"Deploy to [target-org]\")\n\n# Then create test data\nSkill(skill=\"sf-data\", args=\"Create 251 Quote__c records\")\n```\n\n---\n\n## Cross-Skill Integration Table\n\n| From Skill | To sf-metadata | When |\n|------------|----------------|------|\n| sf-apex | → sf-metadata | \"Describe Quote__c\" (discover fields before coding) |\n| sf-flow | → sf-metadata | \"Describe object fields, record types\" (verify structure) |\n| sf-data | → sf-metadata | \"Describe Custom_Object__c fields\" (discover structure) |\n| sf-ai-agentforce | → sf-metadata | \"Create custom object for agent data\" |\n\n---\n\n## Best Practices\n\n1. **Always create Permission Sets** with object/field metadata\n2. **Use sf sobject describe** to verify existing structure before creating\n3. **Check sfdx-project.json** exists before generating metadata\n4. **Use consistent naming** across related objects (Quote__c, Quote_Line_Item__c)\n5. **Document relationships** in object descriptions\n\n---\n\n## Related Documentation\n\n| Topic | Location |\n|-------|----------|\n| Metadata templates | `sf-metadata/assets/` |\n| Field types guide | `sf-metadata/references/field-types-guide.md` |\n| Naming conventions | `sf-metadata/references/naming-conventions.md` |\n| sf-deploy skill | `sf-deploy/SKILL.md` |\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":8129,"content_sha256":"cd9152309bd571f62fe08e7c3af114793c144491f6dac0c9c53bade098c9e97d"},{"filename":"references/permission-set-example.md","content":"\u003c!-- Parent: sf-metadata/SKILL.md -->\n# Permission Set Example: Invoice Manager\n\nThis example demonstrates creating a comprehensive permission set with object permissions, field-level security, and related access.\n\n---\n\n## Scenario\n\nCreate a Permission Set for users who manage invoices:\n- Full CRUD on Invoice object\n- Edit access to specific fields\n- Read access to Account (parent)\n- Tab visibility\n- Custom permission for approvals\n\n---\n\n## Permission Set Definition\n\n**File:** `force-app/main/default/permissionsets/Invoice_Manager.permissionset-meta.xml`\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\u003cPermissionSet xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003c!-- Basic Info -->\n \u003clabel>Invoice Manager\u003c/label>\n \u003cdescription>Full access to manage invoices including creation, editing, and approval. Assign to users responsible for invoice processing.\u003c/description>\n \u003chasActivationRequired>false\u003c/hasActivationRequired>\n\n \u003c!--\n ═══════════════════════════════════════════════════════════════\n OBJECT PERMISSIONS\n ═══════════════════════════════════════════════════════════════\n -->\n\n \u003c!-- Invoice Object: Full CRUD -->\n \u003cobjectPermissions>\n \u003callowCreate>true\u003c/allowCreate>\n \u003callowDelete>true\u003c/allowDelete>\n \u003callowEdit>true\u003c/allowEdit>\n \u003callowRead>true\u003c/allowRead>\n \u003cmodifyAllRecords>false\u003c/modifyAllRecords>\n \u003cobject>Invoice__c\u003c/object>\n \u003cviewAllRecords>false\u003c/viewAllRecords>\n \u003c/objectPermissions>\n\n \u003c!-- Invoice Line Item: Full CRUD (child object) -->\n \u003cobjectPermissions>\n \u003callowCreate>true\u003c/allowCreate>\n \u003callowDelete>true\u003c/allowDelete>\n \u003callowEdit>true\u003c/allowEdit>\n \u003callowRead>true\u003c/allowRead>\n \u003cmodifyAllRecords>false\u003c/modifyAllRecords>\n \u003cobject>Invoice_Line_Item__c\u003c/object>\n \u003cviewAllRecords>false\u003c/viewAllRecords>\n \u003c/objectPermissions>\n\n \u003c!-- Account: Read Only (for invoice lookups) -->\n \u003cobjectPermissions>\n \u003callowCreate>false\u003c/allowCreate>\n \u003callowDelete>false\u003c/allowDelete>\n \u003callowEdit>false\u003c/allowEdit>\n \u003callowRead>true\u003c/allowRead>\n \u003cmodifyAllRecords>false\u003c/modifyAllRecords>\n \u003cobject>Account\u003c/object>\n \u003cviewAllRecords>false\u003c/viewAllRecords>\n \u003c/objectPermissions>\n\n \u003c!--\n ═══════════════════════════════════════════════════════════════\n FIELD PERMISSIONS - Invoice__c\n ═══════════════════════════════════════════════════════════════\n -->\n\n \u003c!-- Account lookup: Read + Edit -->\n \u003cfieldPermissions>\n \u003ceditable>true\u003c/editable>\n \u003cfield>Invoice__c.Account__c\u003c/field>\n \u003creadable>true\u003c/readable>\n \u003c/fieldPermissions>\n\n \u003c!-- Status: Read + Edit -->\n \u003cfieldPermissions>\n \u003ceditable>true\u003c/editable>\n \u003cfield>Invoice__c.Status__c\u003c/field>\n \u003creadable>true\u003c/readable>\n \u003c/fieldPermissions>\n\n \u003c!-- Invoice Date: Read + Edit -->\n \u003cfieldPermissions>\n \u003ceditable>true\u003c/editable>\n \u003cfield>Invoice__c.Invoice_Date__c\u003c/field>\n \u003creadable>true\u003c/readable>\n \u003c/fieldPermissions>\n\n \u003c!-- Due Date: Read + Edit -->\n \u003cfieldPermissions>\n \u003ceditable>true\u003c/editable>\n \u003cfield>Invoice__c.Due_Date__c\u003c/field>\n \u003creadable>true\u003c/readable>\n \u003c/fieldPermissions>\n\n \u003c!-- Total Amount: Read Only (calculated) -->\n \u003cfieldPermissions>\n \u003ceditable>false\u003c/editable>\n \u003cfield>Invoice__c.Total_Amount__c\u003c/field>\n \u003creadable>true\u003c/readable>\n \u003c/fieldPermissions>\n\n \u003c!-- Payment Date: Read + Edit -->\n \u003cfieldPermissions>\n \u003ceditable>true\u003c/editable>\n \u003cfield>Invoice__c.Payment_Date__c\u003c/field>\n \u003creadable>true\u003c/readable>\n \u003c/fieldPermissions>\n\n \u003c!-- Days Overdue: Read Only (formula) -->\n \u003cfieldPermissions>\n \u003ceditable>false\u003c/editable>\n \u003cfield>Invoice__c.Days_Overdue__c\u003c/field>\n \u003creadable>true\u003c/readable>\n \u003c/fieldPermissions>\n\n \u003c!-- Internal Notes: Read + Edit -->\n \u003cfieldPermissions>\n \u003ceditable>true\u003c/editable>\n \u003cfield>Invoice__c.Internal_Notes__c\u003c/field>\n \u003creadable>true\u003c/readable>\n \u003c/fieldPermissions>\n\n \u003c!--\n ═══════════════════════════════════════════════════════════════\n FIELD PERMISSIONS - Invoice_Line_Item__c\n ═══════════════════════════════════════════════════════════════\n -->\n\n \u003cfieldPermissions>\n \u003ceditable>true\u003c/editable>\n \u003cfield>Invoice_Line_Item__c.Product__c\u003c/field>\n \u003creadable>true\u003c/readable>\n \u003c/fieldPermissions>\n\n \u003cfieldPermissions>\n \u003ceditable>true\u003c/editable>\n \u003cfield>Invoice_Line_Item__c.Quantity__c\u003c/field>\n \u003creadable>true\u003c/readable>\n \u003c/fieldPermissions>\n\n \u003cfieldPermissions>\n \u003ceditable>true\u003c/editable>\n \u003cfield>Invoice_Line_Item__c.Unit_Price__c\u003c/field>\n \u003creadable>true\u003c/readable>\n \u003c/fieldPermissions>\n\n \u003cfieldPermissions>\n \u003ceditable>false\u003c/editable>\n \u003cfield>Invoice_Line_Item__c.Line_Total__c\u003c/field>\n \u003creadable>true\u003c/readable>\n \u003c/fieldPermissions>\n\n \u003c!--\n ═══════════════════════════════════════════════════════════════\n TAB SETTINGS\n ═══════════════════════════════════════════════════════════════\n -->\n\n \u003ctabSettings>\n \u003ctab>Invoice__c\u003c/tab>\n \u003cvisibility>Visible\u003c/visibility>\n \u003c/tabSettings>\n\n \u003ctabSettings>\n \u003ctab>Invoice_Line_Item__c\u003c/tab>\n \u003cvisibility>Visible\u003c/visibility>\n \u003c/tabSettings>\n\n \u003c!--\n ═══════════════════════════════════════════════════════════════\n RECORD TYPE ACCESS\n ═══════════════════════════════════════════════════════════════\n -->\n\n \u003crecordTypeVisibilities>\n \u003crecordType>Invoice__c.Standard_Invoice\u003c/recordType>\n \u003cvisible>true\u003c/visible>\n \u003c/recordTypeVisibilities>\n\n \u003crecordTypeVisibilities>\n \u003crecordType>Invoice__c.Credit_Note\u003c/recordType>\n \u003cvisible>true\u003c/visible>\n \u003c/recordTypeVisibilities>\n\n \u003c!--\n ═══════════════════════════════════════════════════════════════\n CUSTOM PERMISSIONS\n ═══════════════════════════════════════════════════════════════\n -->\n\n \u003c!-- Permission to approve invoices over threshold -->\n \u003ccustomPermissions>\n \u003cenabled>true\u003c/enabled>\n \u003cname>Invoice_Approval\u003c/name>\n \u003c/customPermissions>\n\n \u003c!-- Permission to bypass validation rules -->\n \u003ccustomPermissions>\n \u003cenabled>false\u003c/enabled>\n \u003cname>Bypass_Validation\u003c/name>\n \u003c/customPermissions>\n\n \u003c!--\n ═══════════════════════════════════════════════════════════════\n APEX CLASS ACCESS\n ═══════════════════════════════════════════════════════════════\n -->\n\n \u003cclassAccesses>\n \u003capexClass>InvoiceController\u003c/apexClass>\n \u003cenabled>true\u003c/enabled>\n \u003c/classAccesses>\n\n \u003cclassAccesses>\n \u003capexClass>InvoicePDFGenerator\u003c/apexClass>\n \u003cenabled>true\u003c/enabled>\n \u003c/classAccesses>\n\n \u003c!--\n ═══════════════════════════════════════════════════════════════\n PAGE ACCESS (Visualforce/LWC)\n ═══════════════════════════════════════════════════════════════\n -->\n\n \u003cpageAccesses>\n \u003capexPage>InvoicePDF\u003c/apexPage>\n \u003cenabled>true\u003c/enabled>\n \u003c/pageAccesses>\n\n\u003c/PermissionSet>\n```\n\n---\n\n## Related Custom Permission\n\n**File:** `force-app/main/default/customPermissions/Invoice_Approval.customPermission-meta.xml`\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\u003cCustomPermission xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003clabel>Invoice Approval\u003c/label>\n \u003cdescription>Allows user to approve invoices over the standard threshold. Check this permission in Apex using FeatureManagement.checkPermission('Invoice_Approval').\u003c/description>\n \u003cisLicensed>false\u003c/isLicensed>\n\u003c/CustomPermission>\n```\n\n---\n\n## Read-Only Permission Set Variant\n\n**File:** `force-app/main/default/permissionsets/Invoice_Viewer.permissionset-meta.xml`\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\u003cPermissionSet xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003clabel>Invoice Viewer\u003c/label>\n \u003cdescription>Read-only access to invoices. For users who need to view but not modify invoice data.\u003c/description>\n \u003chasActivationRequired>false\u003c/hasActivationRequired>\n\n \u003c!-- Invoice: Read Only -->\n \u003cobjectPermissions>\n \u003callowCreate>false\u003c/allowCreate>\n \u003callowDelete>false\u003c/allowDelete>\n \u003callowEdit>false\u003c/allowEdit>\n \u003callowRead>true\u003c/allowRead>\n \u003cmodifyAllRecords>false\u003c/modifyAllRecords>\n \u003cobject>Invoice__c\u003c/object>\n \u003cviewAllRecords>false\u003c/viewAllRecords>\n \u003c/objectPermissions>\n\n \u003c!-- All fields: Read Only -->\n \u003cfieldPermissions>\n \u003ceditable>false\u003c/editable>\n \u003cfield>Invoice__c.Account__c\u003c/field>\n \u003creadable>true\u003c/readable>\n \u003c/fieldPermissions>\n\n \u003cfieldPermissions>\n \u003ceditable>false\u003c/editable>\n \u003cfield>Invoice__c.Status__c\u003c/field>\n \u003creadable>true\u003c/readable>\n \u003c/fieldPermissions>\n\n \u003cfieldPermissions>\n \u003ceditable>false\u003c/editable>\n \u003cfield>Invoice__c.Total_Amount__c\u003c/field>\n \u003creadable>true\u003c/readable>\n \u003c/fieldPermissions>\n\n \u003c!-- Tab: Visible -->\n \u003ctabSettings>\n \u003ctab>Invoice__c\u003c/tab>\n \u003cvisibility>Visible\u003c/visibility>\n \u003c/tabSettings>\n\u003c/PermissionSet>\n```\n\n---\n\n## Permission Set Group\n\n**File:** `force-app/main/default/permissionsetgroups/Finance_Team.permissionsetgroup-meta.xml`\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\u003cPermissionSetGroup xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003clabel>Finance Team\u003c/label>\n \u003cdescription>Combined permissions for Finance team members including invoice management and reporting.\u003c/description>\n \u003cpermissionSets>\n \u003cpermissionSet>Invoice_Manager\u003c/permissionSet>\n \u003cpermissionSet>Report_Builder\u003c/permissionSet>\n \u003cpermissionSet>Dashboard_Viewer\u003c/permissionSet>\n \u003c/permissionSets>\n \u003cstatus>Enabled\u003c/status>\n\u003c/PermissionSetGroup>\n```\n\n---\n\n## Using Custom Permission in Apex\n\n```apex\npublic class InvoiceService {\n\n public static void approveInvoice(Invoice__c invoice) {\n // Check custom permission\n if (invoice.Total_Amount__c > 10000 &&\n !FeatureManagement.checkPermission('Invoice_Approval')) {\n throw new InsufficientPermissionException(\n 'You do not have permission to approve invoices over $10,000'\n );\n }\n\n invoice.Status__c = 'Approved';\n update invoice;\n }\n\n public class InsufficientPermissionException extends Exception {}\n}\n```\n\n---\n\n## Directory Structure\n\n```\nforce-app/main/default/\n├── permissionsets/\n│ ├── Invoice_Manager.permissionset-meta.xml\n│ └── Invoice_Viewer.permissionset-meta.xml\n├── permissionsetgroups/\n│ └── Finance_Team.permissionsetgroup-meta.xml\n└── customPermissions/\n └── Invoice_Approval.customPermission-meta.xml\n```\n\n---\n\n## Deployment\n\n```bash\n# Deploy permission set\nsf project deploy start \\\n --source-dir force-app/main/default/permissionsets/Invoice_Manager.permissionset-meta.xml \\\n --target-org myorg\n\n# Deploy all security metadata\nsf project deploy start \\\n --source-dir force-app/main/default/permissionsets \\\n --source-dir force-app/main/default/permissionsetgroups \\\n --source-dir force-app/main/default/customPermissions \\\n --target-org myorg\n```\n\n---\n\n## Assignment\n\n```bash\n# Assign permission set to user\nsf org assign permset --name Invoice_Manager --target-org myorg --on-behalf-of [email protected]\n\n# Assign permission set group\nsf org assign permset --name Finance_Team --target-org myorg --on-behalf-of [email protected]\n```\n\n> Tip: when `sf org assign permset --json` fails, inspect the full JSON payload. Current CLI versions include richer multi-error details for permission-set assignment failures.\n\n---\n\n## Best Practices Summary\n\n1. **Name by function**: `Invoice_Manager`, not `Finance_PS_1`\n2. **Document purpose**: Clear description for each permission set\n3. **Least privilege**: Only grant what's needed\n4. **Group related sets**: Use Permission Set Groups for roles\n5. **Use Custom Permissions**: For feature flags in Apex\n6. **Separate read/write**: Create viewer variants for read-only users\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":14151,"content_sha256":"3bf63aed1cc8f4caff462320c8377195ef2528340aa869ef660acef890107267"},{"filename":"references/permset-auto-generation.md","content":"\u003c!-- Parent: sf-metadata/SKILL.md -->\n\n# Permission Set Auto-Generation\n\nWhen creating custom objects or fields, default to generating or updating a Permission Set unless the user explicitly opts out.\n\n## Core rule\n\n**Object CRUD does not make custom fields visible.**\nNew metadata work should normally include both:\n- `\u003cobjectPermissions>` for the object\n- `\u003cfieldPermissions>` for eligible custom fields\n\n## Default workflow\n\n1. **Collect field information** from the metadata being created or changed\n2. **Build or update a Permission Set by default** for the affected object\n3. **Include eligible custom fields** with the correct read/edit behavior\n4. **Exclude only fields that Salesforce treats as system-managed or always-available in Permission Set metadata**\n5. **Write the Permission Set** to `force-app/main/default/permissionsets/[ObjectName]_Access.permissionset-meta.xml`\n6. **Tell the user what was included and excluded**\n\n## Eligible field guidance\n\n| Field type / category | Include in Permission Set? | Guidance |\n|---|---|---|\n| Optional custom fields | YES | `readable=true`, `editable=true` |\n| Formula fields | YES | `readable=true`, `editable=false` |\n| Roll-up summary fields | YES | `readable=true`, `editable=false` |\n| Universally required custom fields | Usually NO | Salesforce commonly treats these as always-available / excluded in modern metadata retrievals |\n| Master-Detail relationship fields | Usually NO | Commonly treated as parent-controlled / excluded in Permission Set metadata |\n| Name / system-managed fields | NO | Do not generate explicit field permissions |\n\n## Generated output expectations\n\nA generated Permission Set should:\n- include object permissions for the target object\n- include field permissions for eligible custom fields\n- use read-only field permissions for calculated fields\n- clearly document any excluded fields and why they were skipped\n\n## Example generated Permission Set\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\u003cPermissionSet xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n \u003cdescription>Auto-generated: Grants access to Customer_Feedback__c and eligible custom fields\u003c/description>\n \u003chasActivationRequired>false\u003c/hasActivationRequired>\n \u003clabel>Customer Feedback Access\u003c/label>\n\n \u003cobjectPermissions>\n \u003callowCreate>true\u003c/allowCreate>\n \u003callowDelete>true\u003c/allowDelete>\n \u003callowEdit>true\u003c/allowEdit>\n \u003callowRead>true\u003c/allowRead>\n \u003cmodifyAllRecords>false\u003c/modifyAllRecords>\n \u003cobject>Customer_Feedback__c\u003c/object>\n \u003cviewAllRecords>true\u003c/viewAllRecords>\n \u003c/objectPermissions>\n\n \u003cfieldPermissions>\n \u003ceditable>true\u003c/editable>\n \u003cfield>Customer_Feedback__c.Optional_Field__c\u003c/field>\n \u003creadable>true\u003c/readable>\n \u003c/fieldPermissions>\n\n \u003cfieldPermissions>\n \u003ceditable>false\u003c/editable>\n \u003cfield>Customer_Feedback__c.Score_Band__c\u003c/field>\n \u003creadable>true\u003c/readable>\n \u003c/fieldPermissions>\n\u003c/PermissionSet>\n```\n\n## Opt-out guidance\n\nIf the user explicitly says they do **not** want a Permission Set generated, still call out the exact FLS follow-up they must handle manually.\n\n## Implementation note\n\nThe generator script under `hooks/scripts/generate_permission_set.py` should be treated as the default automation path for this workflow.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":3310,"content_sha256":"b8c1ac3f57b097d322f15362e079e85f669b7f805f5d4430ae980dce661d089b"},{"filename":"references/profile-permission-guide.md","content":"\u003c!-- Parent: sf-metadata/SKILL.md -->\n# Profiles vs Permission Sets Guide\n\n## Overview\n\nSalesforce provides two primary mechanisms for controlling user access: Profiles and Permission Sets. Understanding when to use each is critical for maintainable security architecture.\n\n---\n\n## Quick Comparison\n\n| Aspect | Profile | Permission Set |\n|--------|---------|----------------|\n| Assignment | One per user (required) | Multiple per user |\n| Access model | Defines base access | Adds to profile |\n| Modification | All-or-nothing | Granular additions |\n| Standard items | Yes (System Admin, etc.) | No standard sets |\n| Best for | Base access, login settings | Feature-based access |\n\n---\n\n## When to Use Profiles\n\n### Use Profiles For:\n\n1. **Login Settings**\n - Login hours\n - Login IP ranges\n - Password policies\n\n2. **Default Settings**\n - Default record types\n - Default page layouts\n - Default applications\n\n3. **Base Object Access**\n - Minimum required object permissions\n - Tab visibility defaults\n\n4. **License-Based Access**\n - Different profiles for different licenses\n - Platform vs Full Salesforce users\n\n### Profile Best Practices\n\n```\n✅ Create minimal profiles (least privilege)\n✅ Use descriptive names (Sales_User, Service_User)\n✅ Document what each profile provides\n✅ Review profiles quarterly\n\n❌ Don't create user-specific profiles\n❌ Don't manage feature access in profiles\n❌ Don't clone System Administrator\n```\n\n---\n\n## When to Use Permission Sets\n\n### Use Permission Sets For:\n\n1. **Feature Access**\n - Invoice approval\n - Report building\n - API access\n\n2. **Object/Field Access**\n - Read access to sensitive objects\n - Edit access to specific fields\n\n3. **Temporary Access**\n - Project-based access\n - Training access\n\n4. **Integration Users**\n - API permissions\n - System access\n\n### Permission Set Best Practices\n\n```\n✅ Create feature-focused sets\n✅ Use consistent naming conventions\n✅ Combine into Permission Set Groups\n✅ Document purpose and audience\n\n❌ Don't duplicate profile permissions\n❌ Don't create user-specific sets\n❌ Don't include login settings\n```\n\n---\n\n## Architecture Patterns\n\n### Pattern 1: Minimal Profile + Permission Sets (Recommended)\n\n```\nProfile: Base_User\n├── Read access to common objects\n├── Default applications\n└── Login settings\n\nPermission Sets (assigned as needed):\n├── Invoice_Creator\n├── Invoice_Approver\n├── Report_Builder\n├── API_Access\n└── Admin_Tools\n```\n\n**Benefits:**\n- Flexible\n- Easy to audit\n- Scalable\n\n---\n\n### Pattern 2: Role-Based Permission Set Groups\n\n```\nPermission Set Groups:\n├── Sales_Representative\n│ ├── Account_Full_Access\n│ ├── Contact_Full_Access\n│ ├── Opportunity_Full_Access\n│ └── Reports_Basic\n│\n├── Sales_Manager\n│ ├── Sales_Representative (inherit)\n│ ├── Team_Reports\n│ └── Approval_Authority\n│\n└── Sales_Operations\n ├── Sales_Representative (inherit)\n ├── Data_Import\n └── Admin_Reports\n```\n\n**Benefits:**\n- Role-aligned\n- Inheritance via groups\n- Single assignment point\n\n---\n\n### Pattern 3: Functional Decomposition\n\n```\nBase Layer (Profile):\n└── Standard_User_Profile\n\nFeature Layer (Permission Sets):\n├── CRM_Features\n├── Marketing_Features\n├── Service_Features\n└── Commerce_Features\n\nObject Layer (Permission Sets):\n├── Custom_Invoice_Access\n├── Custom_Product_Access\n└── Integration_Object_Access\n\nAdmin Layer (Permission Sets):\n├── User_Management\n├── Data_Management\n└── System_Configuration\n```\n\n---\n\n## Permission Set Groups\n\n### What Are They?\nPermission Set Groups bundle multiple Permission Sets into a single assignable unit.\n\n### Structure\n```xml\n\u003cPermissionSetGroup>\n \u003clabel>Sales Team Access\u003c/label>\n \u003cpermissionSets>\n \u003cpermissionSet>Account_Full_Access\u003c/permissionSet>\n \u003cpermissionSet>Contact_Full_Access\u003c/permissionSet>\n \u003cpermissionSet>Opportunity_Full_Access\u003c/permissionSet>\n \u003c/permissionSets>\n\u003c/PermissionSetGroup>\n```\n\n### Benefits\n- Single assignment = multiple permissions\n- Easier onboarding\n- Consistent access across role\n- Simpler audit trail\n\n### Muting Permission Sets\nTemporarily remove specific permissions from a group:\n```xml\n\u003cMutingPermissionSet>\n \u003clabel>Remove_Delete_Access\u003c/label>\n \u003cobjectPermissions>\n \u003callowDelete>false\u003c/allowDelete>\n \u003cobject>Account\u003c/object>\n \u003c/objectPermissions>\n\u003c/MutingPermissionSet>\n```\n\n---\n\n## Migration Strategy\n\n### Moving from Profiles to Permission Sets\n\n1. **Audit Current State**\n ```\n - List all profiles and their permissions\n - Identify unique permission combinations\n - Map profiles to user roles\n ```\n\n2. **Design Permission Sets**\n ```\n - Group permissions by feature/function\n - Create atomic permission sets\n - Plan permission set groups\n ```\n\n3. **Create Minimal Profiles**\n ```\n - Clone existing profiles\n - Remove feature-specific permissions\n - Keep only base access + settings\n ```\n\n4. **Create Permission Sets**\n ```\n - Build feature-based sets\n - Test with pilot users\n - Document each set's purpose\n ```\n\n5. **Migrate Users**\n ```\n - Assign new minimal profile\n - Assign relevant permission sets\n - Verify access is equivalent\n ```\n\n6. **Deprecate Old Profiles**\n ```\n - Remove users from old profiles\n - Archive (don't delete) old profiles\n - Monitor for issues\n ```\n\n---\n\n## Common Scenarios\n\n### Scenario 1: New Feature Rollout\n\n**Situation:** Rolling out new invoice approval feature\n\n**Solution:**\n```\nCreate: Invoice_Approval_Permission_Set\n├── Object: Invoice__c (Read, Edit)\n├── Field: Approval_Status__c (Edit)\n├── Field: Approver_Comments__c (Edit)\n└── Apex: Invoice_Approval_Controller (Execute)\n\nAssign to: Users who approve invoices\n```\n\n---\n\n### Scenario 2: Temporary Contractor Access\n\n**Situation:** Contractors need limited access for 3 months\n\n**Solution:**\n```\nProfile: Contractor_Base (minimal)\nPermission Set: Project_XYZ_Access (time-limited)\n\nProcess:\n1. Assign Contractor_Base profile\n2. Assign Project_XYZ_Access permission set\n3. Set calendar reminder for removal\n4. Remove permission set at project end\n```\n\n---\n\n### Scenario 3: Integration User\n\n**Situation:** External system needs API access\n\n**Solution:**\n```\nProfile: Integration_User (minimal, API-only)\nPermission Sets:\n├── API_Enabled (system permission)\n├── ERP_Objects_Access (specific objects)\n└── ERP_Fields_Access (specific fields)\n\nNo: UI access, reports, dashboards\nYes: API, specific objects/fields only\n```\n\n---\n\n## Anti-Patterns to Avoid\n\n### 1. Profile Proliferation\n```\n❌ John_Smith_Profile\n❌ Marketing_Temp_Profile\n❌ Sales_With_Reports_Profile\n\n✅ Standard profiles + targeted permission sets\n```\n\n### 2. Cloning System Administrator\n```\n❌ Clone System Admin for power users\n❌ Modify cloned admin for \"limited admin\"\n\n✅ Build from minimal profile + specific sets\n```\n\n### 3. Permission Set Sprawl\n```\n❌ One permission set per user request\n❌ Overlapping permission sets\n❌ Undocumented permission sets\n\n✅ Feature-aligned, documented sets\n✅ Regular audit and consolidation\n```\n\n### 4. Mixing Concerns\n```\n❌ Profile with feature permissions\n❌ Permission set with login settings\n\n✅ Profiles: settings + base access\n✅ Permission sets: feature access only\n```\n\n---\n\n## Audit Checklist\n\n### Profiles\n- [ ] Each profile has clear purpose\n- [ ] No user-specific profiles\n- [ ] Minimal permissions (least privilege)\n- [ ] Login settings appropriate\n- [ ] Documented and reviewed\n\n### Permission Sets\n- [ ] Named by feature/function\n- [ ] No overlapping permissions\n- [ ] Documented purpose\n- [ ] Grouped logically\n- [ ] Assignment tracked\n\n### Permission Set Groups\n- [ ] Role-aligned groupings\n- [ ] No redundant inclusions\n- [ ] Muting sets used appropriately\n- [ ] Easy to understand structure\n\n---\n\n## Quick Reference\n\n### Profile Contains\n- User license\n- Login hours/IP ranges\n- Password policies\n- Default record types\n- Default page layouts\n- Default applications\n- Base object permissions\n- Tab visibility\n\n### Permission Set Contains\n- Object permissions (additive)\n- Field permissions (additive)\n- Apex class access\n- Visualforce page access\n- Custom permissions\n- Connected app access\n- External data source access\n\n### Permission Set Group Contains\n- Multiple permission sets\n- Muting permission sets (optional)\n- Calculated permissions (union)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":8598,"content_sha256":"51dd8f40336ed29100364ad8d0c1f0daeb8b7dc80c68f2ad862ffc7593366950"},{"filename":"references/sf-cli-commands.md","content":"\u003c!-- Parent: sf-metadata/SKILL.md -->\n# Salesforce CLI Commands Reference\n\n## Overview\n\nThis guide covers sf CLI v2 commands for metadata operations, org queries, and deployment tasks.\n\n---\n\n## Authentication\n\n### Authorize an Org\n```bash\n# Web login (interactive)\nsf org login web --alias myorg\n\n# JWT flow (CI/CD)\nsf org login jwt \\\n --client-id \u003cclient_id> \\\n --jwt-key-file server.key \\\n --username [email protected] \\\n --alias myorg\n\n# SFDX Auth URL (from file)\nsf org login sfdx-url --sfdx-url-file authFile.txt --alias myorg\n```\n\n### List Connected Orgs\n```bash\nsf org list\n\n# With details\nsf org list --verbose\n```\n\n### Display Org Info\n```bash\nsf org display --target-org myorg\n\n# JSON output\nsf org display --target-org myorg --json\n```\n\n---\n\n## Object & Field Queries\n\n### Describe an Object\n```bash\n# Standard or custom object\nsf sobject describe --sobject Account --target-org myorg\n\n# JSON output (for parsing)\nsf sobject describe --sobject Account --target-org myorg --json\n\n# Tooling API object\nsf sobject describe --sobject ApexClass --target-org myorg --use-tooling-api\n```\n\n### List Objects\n```bash\n# All objects\nsf sobject list --target-org myorg --sobject all\n\n# Custom objects only\nsf sobject list --target-org myorg --sobject custom\n\n# Standard objects only\nsf sobject list --target-org myorg --sobject standard\n```\n\n### Parse Object Fields (with jq)\n```bash\n# List all field names\nsf sobject describe --sobject Account --target-org myorg --json | \\\n jq -r '.result.fields[].name'\n\n# List custom fields only\nsf sobject describe --sobject Account --target-org myorg --json | \\\n jq -r '.result.fields[] | select(.custom == true) | .name'\n\n# Get field details\nsf sobject describe --sobject Account --target-org myorg --json | \\\n jq '.result.fields[] | {name, type, length, label}'\n```\n\n---\n\n## Metadata Operations\n\n### List Metadata Types\n```bash\n# All available metadata types\nsf org list metadata-types --target-org myorg\n\n# JSON output\nsf org list metadata-types --target-org myorg --json\n```\n\n### List Metadata of a Type\n```bash\n# Custom Objects\nsf org list metadata --metadata-type CustomObject --target-org myorg\n\n# Custom Fields (specify folder/object)\nsf org list metadata --metadata-type CustomField --folder Account --target-org myorg\n\n# Profiles\nsf org list metadata --metadata-type Profile --target-org myorg\n\n# Permission Sets\nsf org list metadata --metadata-type PermissionSet --target-org myorg\n\n# Flows\nsf org list metadata --metadata-type Flow --target-org myorg\n\n# Apex Classes\nsf org list metadata --metadata-type ApexClass --target-org myorg\n```\n\n---\n\n## Retrieve Metadata\n\n### Retrieve by Metadata Type\n```bash\n# Single type\nsf project retrieve start --metadata CustomObject:Account --target-org myorg\n\n# Multiple items\nsf project retrieve start \\\n --metadata CustomObject:Account \\\n --metadata CustomObject:Contact \\\n --target-org myorg\n\n# Wildcard (all of type)\nsf project retrieve start --metadata \"CustomObject:*\" --target-org myorg\n```\n\n### Retrieve from Manifest (package.xml)\n```bash\nsf project retrieve start --manifest manifest/package.xml --target-org myorg\n```\n\n### Retrieve to Specific Directory\n```bash\nsf project retrieve start \\\n --metadata CustomObject:Account \\\n --target-org myorg \\\n --output-dir ./retrieved\n```\n\n---\n\n## Deploy Metadata\n\n### Deploy Source Directory\n```bash\n# Deploy all source\nsf project deploy start --source-dir force-app --target-org myorg\n\n# Dry run (validation only)\nsf project deploy start --source-dir force-app --target-org myorg --dry-run\n\n# With specific test level\nsf project deploy start \\\n --source-dir force-app \\\n --target-org myorg \\\n --test-level RunLocalTests\n```\n\n### Deploy Specific Metadata\n```bash\nsf project deploy start \\\n --metadata CustomObject:Invoice__c \\\n --target-org myorg\n```\n\n### Deploy from Manifest\n```bash\nsf project deploy start --manifest manifest/package.xml --target-org myorg\n```\n\n### Check Deploy Status\n```bash\n# Poll for status\nsf project deploy report --job-id \u003cjobId>\n\n# Resume watching\nsf project deploy resume --job-id \u003cjobId>\n```\n\n### Test Levels\n| Level | Description |\n|-------|-------------|\n| `NoTestRun` | No tests (sandbox only) |\n| `RunSpecifiedTests` | Run specific tests |\n| `RunLocalTests` | Run org tests (non-managed) |\n| `RunAllTestsInOrg` | Run all tests |\n\n---\n\n## Generate Metadata\n\n### Generate Custom Object\n```bash\nsf schema generate sobject --label \"My Object\"\n```\n\n### Generate Custom Field\n```bash\nsf schema generate field --label \"My Field\" --object Account\n```\n\n### Generate Package.xml\n```bash\n# From source directory\nsf project generate manifest --source-dir force-app --name package.xml\n\n# From org metadata\nsf project generate manifest \\\n --from-org myorg \\\n --metadata-type CustomObject \\\n --name package.xml\n```\n\n---\n\n## Data Operations\n\n### Query Records (SOQL)\n```bash\n# Simple query\nsf data query --query \"SELECT Id, Name FROM Account LIMIT 10\" --target-org myorg\n\n# Export to CSV\nsf data query \\\n --query \"SELECT Id, Name FROM Account\" \\\n --target-org myorg \\\n --result-format csv > accounts.csv\n\n# Bulk export (large data, > 2,000 records)\nsf data export bulk \\\n --query \"SELECT Id, Name FROM Account\" \\\n --target-org myorg \\\n --output-file accounts.csv\n```\n\n### Import/Export Records\n```bash\n# Export to JSON\nsf data export tree \\\n --query \"SELECT Id, Name, Industry FROM Account WHERE Industry != null\" \\\n --target-org myorg \\\n --output-dir ./data\n\n# Import from JSON\nsf data import tree --files data/Account.json --target-org myorg\n```\n\n---\n\n## Apex Operations\n\n### Execute Anonymous Apex\n```bash\n# From command line\nsf apex run --target-org myorg --file scripts/anonymous.apex\n\n# Interactive\nsf apex run --target-org myorg\n```\n\n### Run Tests\n```bash\n# All local tests\nsf apex run test --target-org myorg --test-level RunLocalTests\n\n# Specific test class\nsf apex run test --target-org myorg --tests MyTestClass\n\n# Specific test method\nsf apex run test --target-org myorg --tests MyTestClass.testMethod\n\n# With code coverage\nsf apex run test --target-org myorg --code-coverage --test-level RunLocalTests\n```\n\n---\n\n## Useful Patterns\n\n### Check Object Exists\n```bash\nsf sobject describe --sobject MyObject__c --target-org myorg --json | \\\n jq -r '.status'\n# Returns 0 if exists, 1 if not\n```\n\n### Get Field API Names\n```bash\nsf sobject describe --sobject Account --target-org myorg --json | \\\n jq -r '.result.fields[].name' | sort\n```\n\n### Get Custom Field Count\n```bash\nsf sobject describe --sobject Account --target-org myorg --json | \\\n jq '[.result.fields[] | select(.custom == true)] | length'\n```\n\n### List All Custom Objects\n```bash\nsf org list metadata --metadata-type CustomObject --target-org myorg --json | \\\n jq -r '.result[].fullName' | grep '__c

sf-metadata: Salesforce Metadata Generation and Org Querying Use this skill when the user needs metadata definition or org metadata discovery : custom objects, fields, validation rules, record types, page layouts, permission sets, or schema inspection with CLI. When This Skill Owns the Task Use when the work involves: - object, field, validation rule, record type, layout, profile, or permission-set metadata - , , , and related metadata files - describing schema before coding or Flow work - generating metadata XML from requirements Delegate elsewhere when the user is: - analyzing permission ac…

\n```\n\n### Validate Deployment\n```bash\nsf project deploy start \\\n --source-dir force-app \\\n --target-org myorg \\\n --dry-run \\\n --test-level RunLocalTests \\\n --json | jq '.result.status'\n```\n\n---\n\n## Environment Variables\n\n| Variable | Purpose |\n|----------|---------|\n| `SF_TARGET_ORG` | Default target org |\n| `SF_ACCESS_TOKEN` | Auth token |\n| `SF_INSTANCE_URL` | Instance URL |\n| `SF_API_VERSION` | API version |\n\n---\n\n## Common Flags\n\n| Flag | Short | Description |\n|------|-------|-------------|\n| `--target-org` | `-o` | Target org alias |\n| `--json` | | JSON output |\n| `--wait` | `-w` | Wait time (minutes) |\n| `--verbose` | | Verbose output |\n| `--help` | `-h` | Show help |\n\n---\n\n## Quick Reference\n\n### Daily Operations\n```bash\n# Check org\nsf org display -o myorg\n\n# Deploy changes\nsf project deploy start -d force-app -o myorg\n\n# Run tests\nsf apex run test -o myorg -l RunLocalTests -c\n\n# Query data\nsf data query -q \"SELECT Id FROM Account LIMIT 1\" -o myorg\n```\n\n### Metadata Discovery\n```bash\n# What's in the org?\nsf org list metadata-types -o myorg\n\n# What objects exist?\nsf sobject list -o myorg --sobject all\n\n# Describe an object\nsf sobject describe -s Account -o myorg\n```\n\n### CI/CD Pipeline\n```bash\n# Authenticate\nsf org login jwt ...\n\n# Validate\nsf project deploy start -d force-app -o myorg --dry-run -l RunLocalTests\n\n# Deploy\nsf project deploy start -d force-app -o myorg -l RunLocalTests\n\n# Run additional tests\nsf apex run test -o myorg -l RunLocalTests -c -r human\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":8257,"content_sha256":"4ce14bbf783a3e593e60db37e411484b5c6c0562b9f3f539fcc8dd56e8f3975e"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"sf-metadata: Salesforce Metadata Generation and Org Querying","type":"text"}]},{"type":"paragraph","content":[{"text":"Use this skill when the user needs ","type":"text"},{"text":"metadata definition or org metadata discovery","type":"text","marks":[{"type":"strong"}]},{"text":": custom objects, fields, validation rules, record types, page layouts, permission sets, or schema inspection with ","type":"text"},{"text":"sf","type":"text","marks":[{"type":"code_inline"}]},{"text":" CLI.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"When This Skill Owns the Task","type":"text"}]},{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"sf-metadata","type":"text","marks":[{"type":"code_inline"}]},{"text":" when the work involves:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"object, field, validation rule, record type, layout, profile, or permission-set metadata","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":".object-meta.xml","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":".field-meta.xml","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":".profile-meta.xml","type":"text","marks":[{"type":"code_inline"}]},{"text":", and related metadata files","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"describing schema before coding or Flow work","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"generating metadata XML from requirements","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Delegate elsewhere when the user is:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"analyzing permission access rather than defining metadata → ","type":"text"},{"text":"sf-permissions","type":"text","marks":[{"type":"link","attrs":{"href":"../sf-permissions/SKILL.md","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"deploying metadata → ","type":"text"},{"text":"sf-deploy","type":"text","marks":[{"type":"link","attrs":{"href":"../sf-deploy/SKILL.md","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"editing Flow XML → ","type":"text"},{"text":"sf-flow","type":"text","marks":[{"type":"link","attrs":{"href":"../sf-flow/SKILL.md","title":null}}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Required Context to Gather First","type":"text"}]},{"type":"paragraph","content":[{"text":"Ask for or infer:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"whether the user wants ","type":"text"},{"text":"generation","type":"text","marks":[{"type":"strong"}]},{"text":" or ","type":"text"},{"text":"querying","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"metadata type(s) involved","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"target object / field / package directory","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"target org alias if querying is required","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"whether new custom objects or fields should also include ","type":"text"},{"text":"permission-set / FLS generation","type":"text","marks":[{"type":"strong"}]}]}]}]},{"type":"paragraph","content":[{"text":"Unless the user explicitly opts out, assume new custom objects or fields need permission-set follow-up.","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Recommended Workflow","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"1. Choose the mode","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Mode","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Use when","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"generation","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"the user wants new or updated metadata XML","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"querying","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"the user needs object / field / metadata discovery","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"2. Start from templates or CLI describe data","type":"text"}]},{"type":"paragraph","content":[{"text":"For generation, use the assets under:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"assets/objects/","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"assets/fields/","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"assets/permission-sets/","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"assets/profiles/","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"assets/record-types/","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"assets/validation-rules/","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"assets/layouts/","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"paragraph","content":[{"text":"For querying, prefer ","type":"text"},{"text":"sf","type":"text","marks":[{"type":"code_inline"}]},{"text":" metadata and ","type":"text"},{"text":"sobject describe","type":"text","marks":[{"type":"code_inline"}]},{"text":" commands.","type":"text"}]},{"type":"paragraph","content":[{"text":"Recent SDR/CLI support worth knowing when reading older examples: ","type":"text"},{"text":"CnfgItemSourceDefinition","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"ExtlClntAppOauthSecuritySettings","type":"text","marks":[{"type":"code_inline"}]},{"text":", and ","type":"text"},{"text":"UIBundle","type":"text","marks":[{"type":"code_inline"}]},{"text":" are now source-supported under their current names. See ","type":"text"},{"text":"references/metadata-types-reference.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/metadata-types-reference.md","title":null}}]},{"text":".","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"3. Validate metadata quality","type":"text"}]},{"type":"paragraph","content":[{"text":"Check:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"naming conventions","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"structural correctness","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"field-type fit","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"security / FLS implications","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"downstream deployment dependencies","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"4. Plan permission impact by default","type":"text"}]},{"type":"paragraph","content":[{"text":"When new custom fields or objects are created:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"default to generating or updating a Permission Set unless the user opts out","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"include ","type":"text"},{"text":"fieldPermissions","type":"text","marks":[{"type":"code_inline"}]},{"text":" for ","type":"text"},{"text":"eligible custom fields","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"note any metadata categories that are excluded because Salesforce treats them as system-managed or always-available","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"remember that object CRUD alone does ","type":"text"},{"text":"not","type":"text","marks":[{"type":"strong"}]},{"text":" make custom fields visible","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"5. Hand off deployment","type":"text"}]},{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"sf-deploy","type":"text","marks":[{"type":"link","attrs":{"href":"../sf-deploy/SKILL.md","title":null}}]},{"text":" when the user needs the metadata rolled out.","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"High-Signal Rules","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"field-level security is often the hidden blocker after deployment","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"object permissions ≠ field permissions","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"prefer permission sets over profile-centric access patterns","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"generate Permission Set follow-up by default for new custom objects and fields","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"include ","type":"text"},{"text":"fieldPermissions","type":"text","marks":[{"type":"code_inline"}]},{"text":" for eligible custom fields instead of leaving FLS as a manual afterthought","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"avoid hardcoded IDs in formulas or metadata logic","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"validation rules should have intentional bypass strategy when operationally necessary","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"create metadata before attempting Flow or data tasks that depend on it","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Output Format","type":"text"}]},{"type":"paragraph","content":[{"text":"When finishing, report in this order:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Metadata created or queried","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Files created or updated","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Key schema/security decisions","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Permission / layout follow-ups","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Deploy next step","type":"text","marks":[{"type":"strong"}]}]}]}]},{"type":"paragraph","content":[{"text":"Suggested shape:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"text"},"content":[{"text":"Metadata task: \u003cgenerate / query>\nItems: \u003cobjects, fields, rules, layouts, permsets>\nFiles: \u003cpaths>\nNotes: \u003cnaming, field types, security, dependencies>\nNext step: \u003cdeploy, assign permset, or verify in Setup>","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Cross-Skill Integration","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Need","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Delegate to","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Reason","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"deploy metadata","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"sf-deploy","type":"text","marks":[{"type":"link","attrs":{"href":"../sf-deploy/SKILL.md","title":null}}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"rollout and validation","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"build Flows on new schema","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"sf-flow","type":"text","marks":[{"type":"link","attrs":{"href":"../sf-flow/SKILL.md","title":null}}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"declarative automation","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"build Apex on new schema","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"sf-apex","type":"text","marks":[{"type":"link","attrs":{"href":"../sf-apex/SKILL.md","title":null}}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"code against metadata","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"analyze permission access after creation","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"sf-permissions","type":"text","marks":[{"type":"link","attrs":{"href":"../sf-permissions/SKILL.md","title":null}}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"access auditing","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"seed data after deploy","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"sf-data","type":"text","marks":[{"type":"link","attrs":{"href":"../sf-data/SKILL.md","title":null}}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"test data creation","type":"text"}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Reference Map","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Start here","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/field-and-cli-reference.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/field-and-cli-reference.md","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/metadata-types-reference.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/metadata-types-reference.md","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/naming-conventions.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/naming-conventions.md","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/orchestration.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/orchestration.md","title":null}}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Security / scoring / examples","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/fls-best-practices.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/fls-best-practices.md","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/permset-auto-generation.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/permset-auto-generation.md","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/best-practices-scoring.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/best-practices-scoring.md","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/field-types-guide.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/field-types-guide.md","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/field-types-example.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/field-types-example.md","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/custom-object-example.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/custom-object-example.md","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/permission-set-example.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/permission-set-example.md","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/profile-permission-guide.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/profile-permission-guide.md","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/sf-cli-commands.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/sf-cli-commands.md","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"assets/","type":"text","marks":[{"type":"link","attrs":{"href":"assets/","title":null}}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Score Guide","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Score","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Meaning","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"108+","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"strong production-ready metadata","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"96–107","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"good metadata with minor review items","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"84–95","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"acceptable but validate carefully","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\u003c 84","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"block deployment until corrected","type":"text"}]}]}]}]}]},"metadata":{"date":"2026-11-02","name":"sf-metadata","author":"@skillopedia","source":{"stars":423,"repo_name":"sf-skills","origin_url":"https://github.com/Jaganpro/sf-skills/blob/HEAD/skills/sf-metadata/SKILL.md","repo_owner":"Jaganpro","body_sha256":"c7b6b6ad829e57e51f49b31f925ab66e79a7043df8f1a9381f3f7b82f140081f","cluster_key":"47a0629872a31505c6e233b98410e149afe4941b8ddb46a7de32fd618b970fb6","clean_bundle":{"format":"clean-skill-bundle-v1","source":"Jaganpro/sf-skills/skills/sf-metadata/SKILL.md","text_bytes":193910,"source_commit":"53c9956c4279f8e9abda51164a3e9444811f0e8e","skills_sh_rank":10230,"attachment_count":39,"text_attachments":39,"attachment_storage":"skill_attachments","binary_attachments":0},"cluster_size":1,"skill_md_path":"skills/sf-metadata/SKILL.md","import_metadata":{"date":"2026-11-02","author":"@skillopedia","version":"v1","category":"integrations-apis","category_label":"Integrations"},"exact_dupes_collapsed_into_this":0},"license":"MIT","version":"v1","category":"integrations-apis","metadata":{"author":"Jag Valaiyapathy","scoring":"120 points across 6 categories","version":"1.2.0"},"import_tag":"skills-sh-top20k-2026-11","description":"Salesforce metadata generation and querying with 120-point scoring. TRIGGER when: user creates custom objects, fields, validation rules, or touches .object-meta.xml, .field-meta.xml, .profile-meta.xml files. DO NOT TRIGGER when: permission set analysis (use sf-permissions), deploying metadata (use sf-deploy), or Flow XML (use sf-flow).\n"}},"renderedAt":1793661547852}

sf-metadata: Salesforce Metadata Generation and Org Querying Use this skill when the user needs metadata definition or org metadata discovery : custom objects, fields, validation rules, record types, page layouts, permission sets, or schema inspection with CLI. When This Skill Owns the Task Use when the work involves: - object, field, validation rule, record type, layout, profile, or permission-set metadata - , , , and related metadata files - describing schema before coding or Flow work - generating metadata XML from requirements Delegate elsewhere when the user is: - analyzing permission ac…