Trigger Consolidator

Consolidates Apex triggers for a specified sObject into a single handler class.

Trigger Consolidator Agent

What This Agent Does

Finds every Apex trigger on a given sObject across the user's force-app tree, checks the target org (if connected) for additional triggers, and produces a consolidation plan that lifts them all into a single <Object>TriggerHandler extends TriggerHandler class using the canonical framework from templates/apex/TriggerHandler.cls + templates/apex/TriggerControl.cls. The output is a migration patch plus a deactivation order so nothing is live-broken mid-migration.

Scope: One sObject per invocation. Returns a plan + patch set; never deploys.


Invocation

  • Direct read — "Follow agents/trigger-consolidator/AGENT.md for the Account object"
  • Slash command/consolidate-triggers
  • MCPget_agent("trigger-consolidator")

Mandatory Reads Before Starting

  1. agents/_shared/AGENT_CONTRACT.md
  2. skills/apex/trigger-framework/SKILL.md — via get_skill
  3. templates/apex/TriggerHandler.cls + templates/apex/TriggerControl.cls
  4. templates/apex/cmdt/Trigger_Setting__mdt.object-meta.xml — the metadata record schema the framework uses
  5. skills/apex/recursive-trigger-prevention/SKILL.md — recursion-prevention patterns baked into the framework
  6. agents/_shared/DELIVERABLE_CONTRACT.md — Wave 10 output contract (persistence + scope guardrails)

Inputs

InputRequiredExample
object_api_nameyesAccount, Opportunity, Custom_Object__c
force_app_rootyesforce-app/main/default
target_org_aliasnoif set, the agent also queries the org for additional triggers

Plan

Step 1 — Discover triggers

Grep <force_app_root>/triggers/ for files matching trigger\s+\w+\s+on\s+<object_api_name>. Record:

  • Trigger file path
  • Events handled (before insert, after update, etc.)
  • Whether logic is inline or delegated to a handler class

If target_org_alias is set, call validate_against_org(skill_id="apex/trigger-framework", target_org=..., object_name=<object_api_name>) and merge its findings with the local scan.

Step 2 — Classify

Group the triggers into three buckets:

BucketWhat it means
Already on the frameworkTrigger body is a one-liner that news-up a TriggerHandler subclass
Has a handler but ad-hocDelegates to a class but that class doesn't extend TriggerHandler
Inline logicReal Apex inside the trigger file

Step 3 — Draft the consolidation

Produce:

  1. A single new handler class<Object>TriggerHandler extends TriggerHandler, with one virtual method override per event the user's current triggers handle.
  2. A single replacement trigger filetrigger <Object>Trigger on <Object> (before insert, after insert, ...) { new <Object>TriggerHandler().run(); }.
  3. Deprecation instructions — which old trigger files to delete (or leave disabled via TriggerControl) and in what order.

Preserve the original logic line-for-line inside the new handler's event methods. Do NOT refactor the business logic — that's the apex-refactorer agent's job.

Step 4 — Metadata scaffolding

Produce a Custom Metadata Type record the user must deploy so TriggerControl knows the handler is active:

<records>
  <fullName>{{object_api_name}}</fullName>
  <values><field>Object_API_Name__c</field><value xsi:type="xsd:string">{{object_api_name}}</value></values>
  <values><field>Handler_Class__c</field><value xsi:type="xsd:string">{{object_api_name}}TriggerHandler</value></values>
  <values><field>Is_Active__c</field><value xsi:type="xsd:boolean">true</value></values>
</records>

Step 5 — Deactivation plan

Order matters — give the user an explicit sequence:

  1. Deploy the new <Object>TriggerHandler class (inactive via Trigger_Setting__mdt.Is_Active__c = false).
  2. Deploy the consolidated trigger + delete the old triggers in the same deployment.
  3. Deploy the CMDT record flipping Is_Active__c = true.
  4. Monitor Application_Log__c for 24 hours.

Emphasize: the CMDT switch must come LAST so the rollback is "flip Is_Active__c to false".


Output Contract

One markdown document:

  1. Discovery — every trigger found (local + org), with event matrix.
  2. Proposed consolidation — the new handler class + new trigger file, fenced by target path.
  3. Migration steps — numbered deployment sequence.
  4. Risk notes — triggers that touch the same event in conflicting ways, order-of-execution concerns, any handler that uses Trigger.isExecuting gymnastics the framework handles differently.
  5. Citations — skill ids + template paths.

Persistence (Wave 10 contract)

Conforms to agents/_shared/DELIVERABLE_CONTRACT.md.

  • Markdown report: docs/reports/trigger-consolidator/<run_id>.md
  • JSON envelope: docs/reports/trigger-consolidator/<run_id>.json
  • Atomic write: both files succeed or neither is left on disk.
  • Run ID: ISO-8601 UTC compact timestamp (colons → dashes) OR UUID; ≥ 8 chars.
  • Interactive opt-out: --no-persist flag renders the full report inline and emits the envelope as a fenced JSON block in chat instead of writing files.

Scope Guardrails (Wave 10 contract)

Per agents/_shared/DELIVERABLE_CONTRACT.md:

  • Canonical data surface: this agent's declared probes + the MCP tool set. No ad-hoc code generation to substitute for probes — if the probe's SOQL doesn't cover a need, extend the probe in a PR.
  • No new project dependencies: if a consumer asks for a format beyond markdown or json, refer them to skills/admin/agent-output-formats for conversion paths. Do NOT run npm install / pip install in the consumer's project.
  • No silent dimension drops: dimensions touched but not fully compared are recorded in the envelope's dimensions_skipped[] with state: count-only | partial | not-run — never omitted, never prose-only.

Escalation / Refusal Rules

  • Zero triggers found → STOP with note "no consolidation needed".
  • One trigger found AND it already extends the framework → STOP with confidence: HIGH, no change required.
  • Triggers use Process Builder or Record-Triggered Flow that fires on the same events → flag as confidence: MEDIUM and recommend running flow-analyzer before consolidating.
  • Managed-package triggers exist on the same object → DO NOT touch them. Flag and exclude.

What This Agent Does NOT Do

  • Does not refactor business logic inside the triggers — preserves it verbatim.
  • Does not run the security-scanner or soql-optimizer — recommends them.
  • Does not deploy anything.
  • Does not modify managed-package triggers.