sf-compact
Convert Salesforce metadata XML to AI-friendly compact formats. Semantically lossless roundtrip.
Salesforce metadata XML is extremely verbose — profiles, permission sets, flows, and objects can be 20,000–50,000+ lines of XML with 70–85% structural overhead. This burns tokens and money when AI tools (Claude Code, Codex, Cursor, etc.) read or edit your metadata.
sf-compact converts it to compact YAML or JSON, saving 42–54% of tokens depending on format.
Output Formats
| Format | Preserves order | Human-readable | Token savings |
|---|---|---|---|
yaml |
No | Yes | ~49% |
yaml-ordered |
Yes | Yes | ~42% |
json |
Yes | Less | ~54% |
- yaml — groups repeated elements into arrays. Most compact YAML, but sibling order may change. Best for order-insensitive types (Profile, PermissionSet).
- yaml-ordered — uses
_childrensequences to preserve exact element order. Best for order-sensitive types (Flow, FlexiPage, Layout). - json — compact single-line JSON with arrays. Preserves order, fewest tokens, less human-readable.
Before / After
XML (848 tokens):
false
Salesforce
true
Account.AnnualRevenue
true
false
Account.BillingCity
true
...
YAML (432 tokens — 49% reduction):
_tag: Profile
_ns: http://soap.sforce.com/2006/04/metadata
custom: false
userLicense: Salesforce
fieldPermissions:
- editable: true
field: Account.AnnualRevenue
readable: true
- editable: false
field: Account.BillingCity
readable: true
...
JSON (389 tokens — 54% reduction):
Install
npm (recommended — no build required)
Homebrew (macOS / Linux)
From crates.io (Rust required)
From source
Usage
Pack (XML → compact format)
# Pack entire project (default: YAML format)
# Pack as JSON for maximum token savings
# Pack specific directories
# Pack only profiles
Unpack (compact format → XML)
Auto-detects format by file extension (.yaml or .json).
Stats (preview savings)
Analyze metadata and preview token/byte savings without writing files.
)
) )
Use --files for per-file breakdown, --include to filter by glob pattern.
Configuration
sf-compact uses a .sfcompact.yaml config file for per-type format control.
# Create config with smart defaults (yaml-ordered for order-sensitive types)
# Set format for specific types (batch — multiple types in one call)
# Change default format for all types
# Skip a metadata type from conversion
# View current configuration
Default config after config init:
default_format: yaml
formats:
Flow: yaml-ordered
FlexiPage: yaml-ordered
Layout: yaml-ordered
skip:
When pack runs, it reads .sfcompact.yaml and applies the format per metadata type. The --format CLI flag overrides the config for a single run.
Watch (auto-pack on changes)
Watches source directories for XML changes and automatically repacks. Runs an initial pack, then monitors for file changes.
# Watch default force-app directory
# Watch with JSON format
Diff (detect unpacked changes)
Compare current XML metadata against the last packed output. Shows new, modified, and deleted files.
)
)
MCP Server
sf-compact includes a built-in MCP server for direct AI tool integration.
# Add to your project's .mcp.json
# Or start manually
This exposes sf_compact_pack, sf_compact_unpack, and sf_compact_stats as MCP tools that Claude Code, Cursor, and other MCP-compatible tools can discover and use automatically.
AI Instructions
Generate a provider-agnostic markdown file with usage instructions for any AI tool:
Manifest
Output supported metadata types in JSON (includes format support and order-sensitivity flags):
Supported Metadata Types
75 file extensions mapping to Salesforce metadata types across 9 categories:
| Category | Types |
|---|---|
| Security | Profile, PermissionSet, PermissionSetGroup, RemoteSiteSetting, CspTrustedSite, ConnectedApp, SharingRules, CustomPermission, Role, Group, AuthProvider, SamlSsoConfig, Certificate |
| Schema | CustomObject, CustomField, ValidationRule, CustomMetadata, GlobalValueSet, StandardValueSet, RecordType, MatchingRule, DuplicateRule, CustomIndex, TopicsForObjects, CustomObjectTranslation, CustomFieldTranslation, FieldSet |
| Code | ApexClass, ApexTrigger, ApexComponent, ApexPage, LightningComponentBundle (js/css/html/xml), AuraDefinitionBundle (cmp/evt), StaticResource |
| Automation | Flow*, Workflow, WorkflowRule, AssignmentRules, AutoResponseRules, EscalationRules |
| UI | Layout*, CustomLabels, CustomApplication, CustomTab, FlexiPage*, CustomSite, QuickAction, PathAssistant, ListView, CompactLayout, WebLink, HomePageLayout, AppMenu, Community, Letterhead |
| Analytics | ReportType, Report, Dashboard |
| Integration | ExternalServiceRegistration, NamedCredential, ExternalCredential, InstalledPackage |
| Notifications | CustomNotificationType, NotificationTypeConfig, LightningMessageChannel, PlatformEventChannelMember |
| Content | EmailTemplate, ManagedContentType, CleanDataService, IframeWhiteListUrlSettings, Settings |
* Order-sensitive types — config init defaults these to yaml-ordered to preserve element order.
Workflow
- Configure (once):
sf-compact config init— creates.sfcompact.yamlwith smart defaults - Pull metadata from Salesforce (
sf project retrieve) - Pack:
sf-compact pack— creates.sf-compact/with compact files - Work with compact files — let AI tools read/edit the YAML/JSON format
- Unpack:
sf-compact unpack— restores XML for deployment - Deploy to Salesforce (
sf project deploy)
Use
sf-compact watchduring development to auto-pack on changes, andsf-compact diffto check if a repack is needed.
Tip: Add
.sf-compact/to.gitignoreif you treat it as a build artifact, or commit it for AI-friendly diffs.
How it works
- Parses Salesforce metadata XML into a tree structure
- Groups repeated elements (e.g.,
<fieldPermissions>) into arrays (YAML) or_childrensequences (yaml-ordered, JSON) - Coerces booleans:
"true"→true,"false"→false. All other values (including numeric strings like"59.0","0012") are preserved as-is - Flattens simple key-value containers into inline mappings
- Preserves namespaces, attributes, and all structural information for semantically lossless roundtrip
- Order-sensitive types (Flow, FlexiPage, Layout) default to
yaml-orderedformat, which preserves exact element order via_childrensequences
Token counting uses the cl100k_base tokenizer (same family used by GPT-4 and Claude).
License
MIT