Ledger Gateway Override
This skill overrides all inline HubSpot write instructions in slash commands. Load this BEFORE executing any HubSpot writes. Governance overrides command text.
Rule
Every HubSpot write — Listing creation, object updates, association creation, engagement creation, custom event fire, property creation — MUST be routed through Ledger.
Slash commands contain inline mcp__hubspot__hubspot-batch-create-objects, hubspot-batch-update-objects, hubspot-create-engagement, and hubspot-batch-create-associations instructions. These predate Ledger and describe WHAT to write, not HOW to execute. Treat them as write specifications, not executable instructions.
Custom events (Sentinel Phase A) are first-class HubSpot write operations subject to the same validation: event-name whitelist, primary-object type matching, property schema compliance, owner attribution, and idempotency. Ledger validates all 5 constraints before fire.
Routing Pattern
When a slash command specifies a HubSpot write, spawn Ledger:
Agent(subagent_type: "ledger", prompt: "
Write request from {command name}:
- Operation: {create | update | associate | engagement | custom-event}
- Object type: {listings | appointments | contacts | notes | interest | deliverable | etc.}
- Properties: {copy the properties block from the command}
- Associations: {copy the association block from the command}
- Event name (if custom-event): {event name from custom-events.json}
- Event properties (if custom-event): {copy properties block}
Validate against property-index and custom-events.json before writing. Return created/updated IDs.
")
What Ledger Does
- Loads
agents/hubspot-write-gateway/AGENT.mdfor full context - Runs
ToolSearchto load HubSpot MCP write tool schemas - Validates properties against
skills/hubspot/property-index/files - Validates association types against
skills/hubspot/property-index/associations.json - Executes the write via local MCP (
mcp__hubspot__hubspot-*) - Returns confirmed IDs to the calling command
Fallback
If Ledger agent spawn fails (tool unavailable, MCP down), use the HubSpot CLI as a validated fallback:
node scripts/hubspot/api.js create {object} --props '{...}'
node scripts/hubspot/api.js associate {from_type} {from_id} {to_type} {to_id} --type {typeId}
Even in fallback, validate properties against property-index before writing.
Custom Event Validation Contract
Custom events (Sentinel Phase A) validate against a 5-point contract:
| # | Constraint | Validation | Source of Truth |
|---|---|---|---|
| 1 | Event-name whitelist | Event name must exist in registry | skills/hubspot/property-index/custom-events.json (12 registered templates) |
| 2 | Primary-object type | Primary object type (COMPANY or CONTACT) must match template definition | Template's primaryObject field |
| 3 | Property schema | Property names must exist in template's propertyDefinitions; types must match (string/number/datetime) |
Template's propertyDefinitions array |
| 4 | Owner attribution | practitioner_owner_id must be numeric string (Sentinel Phase A requirement) |
Matches regex ^\d+$ |
| 5 | Idempotency | Prevent duplicate fires within 60-second window using event name + primary_object_id + occurredAt | Ledger local cache (CLI) or broker KV cache |
Special case: signal_severity — HubSpot API defines as type: "string" (no enum support at definition time). Ledger enforces enum: low | medium | high | critical. CLI blocks invalid value; broker soft-checks; HubSpot rejects.
Failure codes:
custom_event_unknown_template— Event name not in registrycustom_event_primary_object_missing— Primary object missing or type mismatchcustom_event_property_not_in_schema— Property not in template definitioncustom_event_property_type_mismatch— Property value doesn't match declared typecustom_event_owner_id_invalid— practitioner_owner_id invalid formatcustom_event_signal_severity_invalid— signal_severity not one of low|medium|high|critical
Detection Triggers
If you catch yourself doing any of these, STOP and route through Ledger:
- Calling
ToolSearchto loadhubspot-batch-create-objectsorhubspot-batch-update-objects - Calling
ToolSearchto loadhubspot-create-engagement - Calling
ToolSearchto loadhubspot-batch-create-associations - Calling
ToolSearchto loadhubspot-custom-eventsor similar event-fire tool - Writing HubSpot CLI create/update/associate/custom-event commands directly
These are signs of Ledger bypass. The only agent that should load HubSpot write tool schemas is Ledger itself.