diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1620,16 +1620,23 @@
     'NuanceItemActionController' => 'applications/nuance/controller/NuanceItemActionController.php',
     'NuanceItemCommand' => 'applications/nuance/storage/NuanceItemCommand.php',
     'NuanceItemCommandQuery' => 'applications/nuance/query/NuanceItemCommandQuery.php',
+    'NuanceItemCommandTransaction' => 'applications/nuance/xaction/NuanceItemCommandTransaction.php',
     'NuanceItemController' => 'applications/nuance/controller/NuanceItemController.php',
     'NuanceItemEditor' => 'applications/nuance/editor/NuanceItemEditor.php',
     'NuanceItemListController' => 'applications/nuance/controller/NuanceItemListController.php',
     'NuanceItemManageController' => 'applications/nuance/controller/NuanceItemManageController.php',
+    'NuanceItemOwnerTransaction' => 'applications/nuance/xaction/NuanceItemOwnerTransaction.php',
     'NuanceItemPHIDType' => 'applications/nuance/phid/NuanceItemPHIDType.php',
+    'NuanceItemPropertyTransaction' => 'applications/nuance/xaction/NuanceItemPropertyTransaction.php',
     'NuanceItemQuery' => 'applications/nuance/query/NuanceItemQuery.php',
+    'NuanceItemQueueTransaction' => 'applications/nuance/xaction/NuanceItemQueueTransaction.php',
+    'NuanceItemRequestorTransaction' => 'applications/nuance/xaction/NuanceItemRequestorTransaction.php',
     'NuanceItemSearchEngine' => 'applications/nuance/query/NuanceItemSearchEngine.php',
+    'NuanceItemSourceTransaction' => 'applications/nuance/xaction/NuanceItemSourceTransaction.php',
     'NuanceItemTransaction' => 'applications/nuance/storage/NuanceItemTransaction.php',
     'NuanceItemTransactionComment' => 'applications/nuance/storage/NuanceItemTransactionComment.php',
     'NuanceItemTransactionQuery' => 'applications/nuance/query/NuanceItemTransactionQuery.php',
+    'NuanceItemTransactionType' => 'applications/nuance/xaction/NuanceItemTransactionType.php',
     'NuanceItemType' => 'applications/nuance/item/NuanceItemType.php',
     'NuanceItemUpdateWorker' => 'applications/nuance/worker/NuanceItemUpdateWorker.php',
     'NuanceItemViewController' => 'applications/nuance/controller/NuanceItemViewController.php',
@@ -1651,6 +1658,7 @@
     'NuanceQueueTransaction' => 'applications/nuance/storage/NuanceQueueTransaction.php',
     'NuanceQueueTransactionComment' => 'applications/nuance/storage/NuanceQueueTransactionComment.php',
     'NuanceQueueTransactionQuery' => 'applications/nuance/query/NuanceQueueTransactionQuery.php',
+    'NuanceQueueTransactionType' => 'applications/nuance/xaction/NuanceQueueTransactionType.php',
     'NuanceQueueViewController' => 'applications/nuance/controller/NuanceQueueViewController.php',
     'NuanceSchemaSpec' => 'applications/nuance/storage/NuanceSchemaSpec.php',
     'NuanceSource' => 'applications/nuance/storage/NuanceSource.php',
@@ -1672,6 +1680,7 @@
     'NuanceSourceTransaction' => 'applications/nuance/storage/NuanceSourceTransaction.php',
     'NuanceSourceTransactionComment' => 'applications/nuance/storage/NuanceSourceTransactionComment.php',
     'NuanceSourceTransactionQuery' => 'applications/nuance/query/NuanceSourceTransactionQuery.php',
+    'NuanceSourceTransactionType' => 'applications/nuance/xaction/NuanceSourceTransactionType.php',
     'NuanceSourceViewController' => 'applications/nuance/controller/NuanceSourceViewController.php',
     'NuanceTransaction' => 'applications/nuance/storage/NuanceTransaction.php',
     'NuanceWorker' => 'applications/nuance/worker/NuanceWorker.php',
@@ -6720,16 +6729,23 @@
       'PhabricatorPolicyInterface',
     ),
     'NuanceItemCommandQuery' => 'NuanceQuery',
+    'NuanceItemCommandTransaction' => 'NuanceItemTransactionType',
     'NuanceItemController' => 'NuanceController',
     'NuanceItemEditor' => 'PhabricatorApplicationTransactionEditor',
     'NuanceItemListController' => 'NuanceItemController',
     'NuanceItemManageController' => 'NuanceController',
+    'NuanceItemOwnerTransaction' => 'NuanceItemTransactionType',
     'NuanceItemPHIDType' => 'PhabricatorPHIDType',
+    'NuanceItemPropertyTransaction' => 'NuanceItemTransactionType',
     'NuanceItemQuery' => 'NuanceQuery',
+    'NuanceItemQueueTransaction' => 'NuanceItemTransactionType',
+    'NuanceItemRequestorTransaction' => 'NuanceItemTransactionType',
     'NuanceItemSearchEngine' => 'PhabricatorApplicationSearchEngine',
+    'NuanceItemSourceTransaction' => 'NuanceItemTransactionType',
     'NuanceItemTransaction' => 'NuanceTransaction',
     'NuanceItemTransactionComment' => 'PhabricatorApplicationTransactionComment',
     'NuanceItemTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
+    'NuanceItemTransactionType' => 'PhabricatorModularTransactionType',
     'NuanceItemType' => 'Phobject',
     'NuanceItemUpdateWorker' => 'NuanceWorker',
     'NuanceItemViewController' => 'NuanceController',
@@ -6755,6 +6771,7 @@
     'NuanceQueueTransaction' => 'NuanceTransaction',
     'NuanceQueueTransactionComment' => 'PhabricatorApplicationTransactionComment',
     'NuanceQueueTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
+    'NuanceQueueTransactionType' => 'PhabricatorModularTransactionType',
     'NuanceQueueViewController' => 'NuanceQueueController',
     'NuanceSchemaSpec' => 'PhabricatorConfigSchemaSpec',
     'NuanceSource' => array(
@@ -6781,8 +6798,9 @@
     'NuanceSourceTransaction' => 'NuanceTransaction',
     'NuanceSourceTransactionComment' => 'PhabricatorApplicationTransactionComment',
     'NuanceSourceTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
+    'NuanceSourceTransactionType' => 'PhabricatorModularTransactionType',
     'NuanceSourceViewController' => 'NuanceSourceController',
-    'NuanceTransaction' => 'PhabricatorApplicationTransaction',
+    'NuanceTransaction' => 'PhabricatorModularTransaction',
     'NuanceWorker' => 'PhabricatorWorker',
     'OwnersConduitAPIMethod' => 'ConduitAPIMethod',
     'OwnersEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod',
diff --git a/src/applications/nuance/editor/NuanceItemEditor.php b/src/applications/nuance/editor/NuanceItemEditor.php
--- a/src/applications/nuance/editor/NuanceItemEditor.php
+++ b/src/applications/nuance/editor/NuanceItemEditor.php
@@ -14,104 +14,10 @@
   public function getTransactionTypes() {
     $types = parent::getTransactionTypes();
 
-    $types[] = NuanceItemTransaction::TYPE_OWNER;
-    $types[] = NuanceItemTransaction::TYPE_SOURCE;
-    $types[] = NuanceItemTransaction::TYPE_REQUESTOR;
-    $types[] = NuanceItemTransaction::TYPE_PROPERTY;
-    $types[] = NuanceItemTransaction::TYPE_QUEUE;
-    $types[] = NuanceItemTransaction::TYPE_COMMAND;
-
-    $types[] = PhabricatorTransactions::TYPE_EDGE;
-    $types[] = PhabricatorTransactions::TYPE_COMMENT;
     $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
     $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
 
     return $types;
   }
 
-  protected function getCustomTransactionOldValue(
-    PhabricatorLiskDAO $object,
-    PhabricatorApplicationTransaction $xaction) {
-
-    switch ($xaction->getTransactionType()) {
-      case NuanceItemTransaction::TYPE_REQUESTOR:
-        return $object->getRequestorPHID();
-      case NuanceItemTransaction::TYPE_SOURCE:
-        return $object->getSourcePHID();
-      case NuanceItemTransaction::TYPE_OWNER:
-        return $object->getOwnerPHID();
-      case NuanceItemTransaction::TYPE_QUEUE:
-        return $object->getQueuePHID();
-      case NuanceItemTransaction::TYPE_PROPERTY:
-        $key = $xaction->getMetadataValue(
-          NuanceItemTransaction::PROPERTY_KEY);
-        return $object->getNuanceProperty($key);
-      case NuanceItemTransaction::TYPE_COMMAND:
-        return null;
-    }
-
-    return parent::getCustomTransactionOldValue($object, $xaction);
-  }
-
-  protected function getCustomTransactionNewValue(
-    PhabricatorLiskDAO $object,
-    PhabricatorApplicationTransaction $xaction) {
-
-    switch ($xaction->getTransactionType()) {
-      case NuanceItemTransaction::TYPE_REQUESTOR:
-      case NuanceItemTransaction::TYPE_SOURCE:
-      case NuanceItemTransaction::TYPE_OWNER:
-      case NuanceItemTransaction::TYPE_PROPERTY:
-      case NuanceItemTransaction::TYPE_QUEUE:
-      case NuanceItemTransaction::TYPE_COMMAND:
-        return $xaction->getNewValue();
-    }
-
-    return parent::getCustomTransactionNewValue($object, $xaction);
-  }
-
-  protected function applyCustomInternalTransaction(
-    PhabricatorLiskDAO $object,
-    PhabricatorApplicationTransaction $xaction) {
-
-    switch ($xaction->getTransactionType()) {
-      case NuanceItemTransaction::TYPE_REQUESTOR:
-        $object->setRequestorPHID($xaction->getNewValue());
-        break;
-      case NuanceItemTransaction::TYPE_SOURCE:
-        $object->setSourcePHID($xaction->getNewValue());
-        break;
-      case NuanceItemTransaction::TYPE_OWNER:
-        $object->setOwnerPHID($xaction->getNewValue());
-        break;
-      case NuanceItemTransaction::TYPE_QUEUE:
-        $object->setQueuePHID($xaction->getNewValue());
-        break;
-      case NuanceItemTransaction::TYPE_PROPERTY:
-        $key = $xaction->getMetadataValue(
-          NuanceItemTransaction::PROPERTY_KEY);
-        $object->setNuanceProperty($key, $xaction->getNewValue());
-        break;
-      case NuanceItemTransaction::TYPE_COMMAND:
-        break;
-    }
-  }
-
-  protected function applyCustomExternalTransaction(
-    PhabricatorLiskDAO $object,
-    PhabricatorApplicationTransaction $xaction) {
-
-    switch ($xaction->getTransactionType()) {
-      case NuanceItemTransaction::TYPE_REQUESTOR:
-      case NuanceItemTransaction::TYPE_SOURCE:
-      case NuanceItemTransaction::TYPE_OWNER:
-      case NuanceItemTransaction::TYPE_PROPERTY:
-      case NuanceItemTransaction::TYPE_QUEUE:
-      case NuanceItemTransaction::TYPE_COMMAND:
-        return;
-    }
-
-    return parent::applyCustomExternalTransaction($object, $xaction);
-  }
-
 }
diff --git a/src/applications/nuance/item/NuanceItemType.php b/src/applications/nuance/item/NuanceItemType.php
--- a/src/applications/nuance/item/NuanceItemType.php
+++ b/src/applications/nuance/item/NuanceItemType.php
@@ -115,7 +115,7 @@
     }
 
     $xaction = id(new NuanceItemTransaction())
-      ->setTransactionType(NuanceItemTransaction::TYPE_COMMAND)
+      ->setTransactionType(NuanceItemCommandTransaction::TRANSACTIONTYPE)
       ->setNewValue(
         array(
           'command' => $command->getCommand(),
diff --git a/src/applications/nuance/source/NuanceSourceDefinition.php b/src/applications/nuance/source/NuanceSourceDefinition.php
--- a/src/applications/nuance/source/NuanceSourceDefinition.php
+++ b/src/applications/nuance/source/NuanceSourceDefinition.php
@@ -162,18 +162,19 @@
     $xactions = array();
 
     $xactions[] = id(new NuanceItemTransaction())
-      ->setTransactionType(NuanceItemTransaction::TYPE_SOURCE)
+      ->setTransactionType(NuanceItemSourceTransaction::TRANSACTIONTYPE)
       ->setNewValue($source->getPHID());
 
     // TODO: Eventually, apply real routing rules. For now, just put everything
     // in the default queue for the source.
     $xactions[] = id(new NuanceItemTransaction())
-      ->setTransactionType(NuanceItemTransaction::TYPE_QUEUE)
+      ->setTransactionType(NuanceItemQueueTransaction::TRANSACTIONTYPE)
       ->setNewValue($source->getDefaultQueuePHID());
 
+    // TODO: Maybe this should all be modular transactions now?
     foreach ($properties as $key => $property) {
       $xactions[] = id(new NuanceItemTransaction())
-        ->setTransactionType(NuanceItemTransaction::TYPE_PROPERTY)
+        ->setTransactionType(NuanceItemPropertyTransaction::TRANSACTIONTYPE)
         ->setMetadataValue(NuanceItemTransaction::PROPERTY_KEY, $key)
         ->setNewValue($property);
     }
diff --git a/src/applications/nuance/storage/NuanceItemTransaction.php b/src/applications/nuance/storage/NuanceItemTransaction.php
--- a/src/applications/nuance/storage/NuanceItemTransaction.php
+++ b/src/applications/nuance/storage/NuanceItemTransaction.php
@@ -5,13 +5,6 @@
 
   const PROPERTY_KEY = 'property.key';
 
-  const TYPE_OWNER = 'nuance.item.owner';
-  const TYPE_REQUESTOR = 'nuance.item.requestor';
-  const TYPE_SOURCE = 'nuance.item.source';
-  const TYPE_PROPERTY = 'nuance.item.property';
-  const TYPE_QUEUE = 'nuance.item.queue';
-  const TYPE_COMMAND = 'nuance.item.command';
-
   public function getApplicationTransactionType() {
     return NuanceItemPHIDType::TYPECONST;
   }
@@ -20,61 +13,8 @@
     return new NuanceItemTransactionComment();
   }
 
-  public function shouldHide() {
-    $old = $this->getOldValue();
-    $type = $this->getTransactionType();
-
-    switch ($type) {
-      case self::TYPE_REQUESTOR:
-      case self::TYPE_SOURCE:
-        return ($old === null);
-    }
-
-    return parent::shouldHide();
-  }
-
-  public function getRequiredHandlePHIDs() {
-    $old = $this->getOldValue();
-    $new = $this->getNewValue();
-    $type = $this->getTransactionType();
-
-    $phids = parent::getRequiredHandlePHIDs();
-    switch ($type) {
-      case self::TYPE_QUEUE:
-        if ($old) {
-          $phids[] = $old;
-        }
-        if ($new) {
-          $phids[] = $new;
-        }
-        break;
-    }
-
-    return $phids;
-  }
-
-  public function getTitle() {
-    $old = $this->getOldValue();
-    $new = $this->getNewValue();
-    $type = $this->getTransactionType();
-
-    $author_phid = $this->getAuthorPHID();
-
-    switch ($type) {
-      case self::TYPE_QUEUE:
-        return pht(
-          '%s routed this item to the %s queue.',
-          $this->renderHandleLink($author_phid),
-          $this->renderHandleLink($new));
-      case self::TYPE_COMMAND:
-        // TODO: Give item types a chance to render this properly.
-        return pht(
-          '%s applied command "%s" to this item.',
-          $this->renderHandleLink($author_phid),
-          idx($new, 'command'));
-    }
-
-    return parent::getTitle();
+  public function getBaseTransactionClass() {
+    return 'NuanceItemTransactionType';
   }
 
 }
diff --git a/src/applications/nuance/storage/NuanceQueueTransaction.php b/src/applications/nuance/storage/NuanceQueueTransaction.php
--- a/src/applications/nuance/storage/NuanceQueueTransaction.php
+++ b/src/applications/nuance/storage/NuanceQueueTransaction.php
@@ -12,6 +12,10 @@
     return new NuanceQueueTransactionComment();
   }
 
+  public function getBaseTransactionClass() {
+    return 'NuanceSourceTransactionType';
+  }
+
   public function getTitle() {
     $old = $this->getOldValue();
     $new = $this->getNewValue();
diff --git a/src/applications/nuance/storage/NuanceSourceTransaction.php b/src/applications/nuance/storage/NuanceSourceTransaction.php
--- a/src/applications/nuance/storage/NuanceSourceTransaction.php
+++ b/src/applications/nuance/storage/NuanceSourceTransaction.php
@@ -14,6 +14,10 @@
     return new NuanceSourceTransactionComment();
   }
 
+  public function getBaseTransactionClass() {
+    return 'NuanceSourceTransactionType';
+  }
+
   public function shouldHide() {
     $old = $this->getOldValue();
     $new = $this->getNewValue();
diff --git a/src/applications/nuance/storage/NuanceTransaction.php b/src/applications/nuance/storage/NuanceTransaction.php
--- a/src/applications/nuance/storage/NuanceTransaction.php
+++ b/src/applications/nuance/storage/NuanceTransaction.php
@@ -1,7 +1,7 @@
 <?php
 
 abstract class NuanceTransaction
-  extends PhabricatorApplicationTransaction {
+  extends PhabricatorModularTransaction {
 
   public function getApplicationName() {
     return 'nuance';
diff --git a/src/applications/nuance/xaction/NuanceItemCommandTransaction.php b/src/applications/nuance/xaction/NuanceItemCommandTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/nuance/xaction/NuanceItemCommandTransaction.php
@@ -0,0 +1,22 @@
+<?php
+
+final class NuanceItemCommandTransaction
+  extends NuanceItemTransactionType {
+
+  const TRANSACTIONTYPE = 'nuance.item.command';
+
+  public function generateOldValue($object) {
+    return null;
+  }
+
+  public function applyInternalEffects($object, $value) {
+    // TODO: Probably implement this.
+  }
+
+  public function getTitle() {
+    return pht(
+      '%s applied a command to this item.',
+      $this->renderAuthor());
+  }
+
+}
diff --git a/src/applications/nuance/xaction/NuanceItemOwnerTransaction.php b/src/applications/nuance/xaction/NuanceItemOwnerTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/nuance/xaction/NuanceItemOwnerTransaction.php
@@ -0,0 +1,27 @@
+<?php
+
+final class NuanceItemOwnerTransaction
+  extends NuanceItemTransactionType {
+
+  const TRANSACTIONTYPE = 'nuance.item.owner';
+
+  public function generateOldValue($object) {
+    return $object->getOwnerPHID();
+  }
+
+  public function applyInternalEffects($object, $value) {
+    $object->setOwnerPHID($value);
+  }
+
+  public function getTitle() {
+
+    // TODO: Assign, unassign strings probably need variants.
+
+    return pht(
+      '%s reassigned this item from %s to %s.',
+      $this->renderAuthor(),
+      $this->renderHandle($this->getOldValue()),
+      $this->renderHandle($this->getNewValue()));
+  }
+
+}
diff --git a/src/applications/nuance/xaction/NuanceItemPropertyTransaction.php b/src/applications/nuance/xaction/NuanceItemPropertyTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/nuance/xaction/NuanceItemPropertyTransaction.php
@@ -0,0 +1,27 @@
+<?php
+
+final class NuanceItemPropertyTransaction
+  extends NuanceItemTransactionType {
+
+  const TRANSACTIONTYPE = 'nuance.item.property';
+
+  public function generateOldValue($object) {
+    $property_key = NuanceItemTransaction::PROPERTY_KEY;
+    $key = $this->getMetadataValue($property_key);
+    return $object->getNuanceProperty($key);
+  }
+
+  public function applyInternalEffects($object, $value) {
+    $property_key = NuanceItemTransaction::PROPERTY_KEY;
+    $key = $this->getMetadataValue($property_key);
+
+    $object->setNuanceProperty($key, $value);
+  }
+
+  public function getTitle() {
+    return pht(
+      '%s set a property on this item.',
+      $this->renderAuthor());
+  }
+
+}
diff --git a/src/applications/nuance/xaction/NuanceItemQueueTransaction.php b/src/applications/nuance/xaction/NuanceItemQueueTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/nuance/xaction/NuanceItemQueueTransaction.php
@@ -0,0 +1,25 @@
+<?php
+
+final class NuanceItemQueueTransaction
+  extends NuanceItemTransactionType {
+
+  const TRANSACTIONTYPE = 'nuance.item.queue';
+
+  public function generateOldValue($object) {
+    return $object->getQueuePHID();
+  }
+
+  public function applyInternalEffects($object, $value) {
+    $object->setQueuePHID($value);
+  }
+
+  public function getTitle() {
+    return pht(
+      '%s rerouted this item from %s to %s.',
+      $this->renderAuthor(),
+      $this->renderHandle($this->getOldValue()),
+      $this->renderHandle($this->getNewValue()));
+  }
+
+
+}
diff --git a/src/applications/nuance/xaction/NuanceItemRequestorTransaction.php b/src/applications/nuance/xaction/NuanceItemRequestorTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/nuance/xaction/NuanceItemRequestorTransaction.php
@@ -0,0 +1,16 @@
+<?php
+
+final class NuanceItemRequestorTransaction
+  extends NuanceItemTransactionType {
+
+  const TRANSACTIONTYPE = 'nuance.item.requestor';
+
+  public function generateOldValue($object) {
+    return $object->getRequestorPHID();
+  }
+
+  public function applyInternalEffects($object, $value) {
+    $object->setRequestorPHID($value);
+  }
+
+}
diff --git a/src/applications/nuance/xaction/NuanceItemSourceTransaction.php b/src/applications/nuance/xaction/NuanceItemSourceTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/nuance/xaction/NuanceItemSourceTransaction.php
@@ -0,0 +1,16 @@
+<?php
+
+final class NuanceItemSourceTransaction
+  extends NuanceItemTransactionType {
+
+  const TRANSACTIONTYPE = 'nuance.item.source';
+
+  public function generateOldValue($object) {
+    return $object->getSourcePHID();
+  }
+
+  public function applyInternalEffects($object, $value) {
+    $object->setSourcePHID($value);
+  }
+
+}
diff --git a/src/applications/nuance/xaction/NuanceItemTransactionType.php b/src/applications/nuance/xaction/NuanceItemTransactionType.php
new file mode 100644
--- /dev/null
+++ b/src/applications/nuance/xaction/NuanceItemTransactionType.php
@@ -0,0 +1,4 @@
+<?php
+
+abstract class NuanceItemTransactionType
+  extends PhabricatorModularTransactionType {}
diff --git a/src/applications/nuance/xaction/NuanceQueueTransactionType.php b/src/applications/nuance/xaction/NuanceQueueTransactionType.php
new file mode 100644
--- /dev/null
+++ b/src/applications/nuance/xaction/NuanceQueueTransactionType.php
@@ -0,0 +1,4 @@
+<?php
+
+abstract class NuanceQueueTransactionType
+  extends PhabricatorModularTransactionType {}
diff --git a/src/applications/nuance/xaction/NuanceSourceTransactionType.php b/src/applications/nuance/xaction/NuanceSourceTransactionType.php
new file mode 100644
--- /dev/null
+++ b/src/applications/nuance/xaction/NuanceSourceTransactionType.php
@@ -0,0 +1,4 @@
+<?php
+
+abstract class NuanceSourceTransactionType
+  extends PhabricatorModularTransactionType {}