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
@@ -1531,6 +1531,7 @@
     'HeraldRemarkupFieldValue' => 'applications/herald/value/HeraldRemarkupFieldValue.php',
     'HeraldRemarkupRule' => 'applications/herald/remarkup/HeraldRemarkupRule.php',
     'HeraldRule' => 'applications/herald/storage/HeraldRule.php',
+    'HeraldRuleActionAffectsObjectEdgeType' => 'applications/herald/edge/HeraldRuleActionAffectsObjectEdgeType.php',
     'HeraldRuleAdapter' => 'applications/herald/adapter/HeraldRuleAdapter.php',
     'HeraldRuleAdapterField' => 'applications/herald/field/rule/HeraldRuleAdapterField.php',
     'HeraldRuleController' => 'applications/herald/controller/HeraldRuleController.php',
@@ -1540,7 +1541,9 @@
     'HeraldRuleEditor' => 'applications/herald/editor/HeraldRuleEditor.php',
     'HeraldRuleField' => 'applications/herald/field/rule/HeraldRuleField.php',
     'HeraldRuleFieldGroup' => 'applications/herald/field/rule/HeraldRuleFieldGroup.php',
+    'HeraldRuleIndexEngineExtension' => 'applications/herald/engineextension/HeraldRuleIndexEngineExtension.php',
     'HeraldRuleListController' => 'applications/herald/controller/HeraldRuleListController.php',
+    'HeraldRuleListView' => 'applications/herald/view/HeraldRuleListView.php',
     'HeraldRuleNameTransaction' => 'applications/herald/xaction/HeraldRuleNameTransaction.php',
     'HeraldRulePHIDType' => 'applications/herald/phid/HeraldRulePHIDType.php',
     'HeraldRuleQuery' => 'applications/herald/query/HeraldRuleQuery.php',
@@ -7189,8 +7192,10 @@
       'PhabricatorFlaggableInterface',
       'PhabricatorPolicyInterface',
       'PhabricatorDestructibleInterface',
+      'PhabricatorIndexableInterface',
       'PhabricatorSubscribableInterface',
     ),
+    'HeraldRuleActionAffectsObjectEdgeType' => 'PhabricatorEdgeType',
     'HeraldRuleAdapter' => 'HeraldAdapter',
     'HeraldRuleAdapterField' => 'HeraldRuleField',
     'HeraldRuleController' => 'HeraldController',
@@ -7200,7 +7205,9 @@
     'HeraldRuleEditor' => 'PhabricatorApplicationTransactionEditor',
     'HeraldRuleField' => 'HeraldField',
     'HeraldRuleFieldGroup' => 'HeraldFieldGroup',
+    'HeraldRuleIndexEngineExtension' => 'PhabricatorIndexEngineExtension',
     'HeraldRuleListController' => 'HeraldController',
+    'HeraldRuleListView' => 'AphrontView',
     'HeraldRuleNameTransaction' => 'HeraldRuleTransactionType',
     'HeraldRulePHIDType' => 'PhabricatorPHIDType',
     'HeraldRuleQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
diff --git a/src/applications/harbormaster/controller/HarbormasterPlanViewController.php b/src/applications/harbormaster/controller/HarbormasterPlanViewController.php
--- a/src/applications/harbormaster/controller/HarbormasterPlanViewController.php
+++ b/src/applications/harbormaster/controller/HarbormasterPlanViewController.php
@@ -62,6 +62,7 @@
 
     $builds_view = $this->newBuildsView($plan);
     $options_view = $this->newOptionsView($plan);
+    $rules_view = $this->newRulesView($plan);
 
     $timeline = $this->buildTransactionTimeline(
       $plan,
@@ -76,6 +77,7 @@
           $error,
           $step_list,
           $options_view,
+          $rules_view,
           $builds_view,
           $timeline,
         ));
@@ -486,6 +488,42 @@
       ->appendChild($list);
   }
 
+  private function newRulesView(HarbormasterBuildPlan $plan) {
+    $viewer = $this->getViewer();
+
+    $rules = id(new HeraldRuleQuery())
+      ->setViewer($viewer)
+      ->withDisabled(false)
+      ->withAffectedObjectPHIDs(array($plan->getPHID()))
+      ->needValidateAuthors(true)
+      ->execute();
+
+    $list = id(new HeraldRuleListView())
+      ->setViewer($viewer)
+      ->setRules($rules)
+      ->newObjectList();
+
+    $list->setNoDataString(pht('No active Herald rules trigger this build.'));
+
+    $more_href = new PhutilURI(
+      '/herald/',
+      array('affectedPHID' => $plan->getPHID()));
+
+    $more_link = id(new PHUIButtonView())
+      ->setTag('a')
+      ->setIcon('fa-list-ul')
+      ->setText(pht('View All Rules'))
+      ->setHref($more_href);
+
+    $header = id(new PHUIHeaderView())
+      ->setHeader(pht('Run By Herald Rules'))
+      ->addActionLink($more_link);
+
+    return id(new PHUIObjectBoxView())
+      ->setHeader($header)
+      ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
+      ->appendChild($list);
+  }
 
   private function newOptionsView(HarbormasterBuildPlan $plan) {
     $viewer = $this->getViewer();
diff --git a/src/applications/harbormaster/herald/HarbormasterRunBuildPlansHeraldAction.php b/src/applications/harbormaster/herald/HarbormasterRunBuildPlansHeraldAction.php
--- a/src/applications/harbormaster/herald/HarbormasterRunBuildPlansHeraldAction.php
+++ b/src/applications/harbormaster/herald/HarbormasterRunBuildPlansHeraldAction.php
@@ -91,4 +91,9 @@
       'Run build plans: %s.',
       $this->renderHandleList($value));
   }
+
+  public function getPHIDsAffectedByAction(HeraldActionRecord $record) {
+    return $record->getTarget();
+  }
+
 }
diff --git a/src/applications/herald/action/HeraldAction.php b/src/applications/herald/action/HeraldAction.php
--- a/src/applications/herald/action/HeraldAction.php
+++ b/src/applications/herald/action/HeraldAction.php
@@ -401,4 +401,8 @@
     return null;
   }
 
+  public function getPHIDsAffectedByAction(HeraldActionRecord $record) {
+    return array();
+  }
+
 }
diff --git a/src/applications/herald/edge/HeraldRuleActionAffectsObjectEdgeType.php b/src/applications/herald/edge/HeraldRuleActionAffectsObjectEdgeType.php
new file mode 100644
--- /dev/null
+++ b/src/applications/herald/edge/HeraldRuleActionAffectsObjectEdgeType.php
@@ -0,0 +1,8 @@
+<?php
+
+final class HeraldRuleActionAffectsObjectEdgeType
+  extends PhabricatorEdgeType {
+
+  const EDGECONST = 69;
+
+}
diff --git a/src/applications/herald/editor/HeraldRuleEditor.php b/src/applications/herald/editor/HeraldRuleEditor.php
--- a/src/applications/herald/editor/HeraldRuleEditor.php
+++ b/src/applications/herald/editor/HeraldRuleEditor.php
@@ -74,4 +74,8 @@
     return $body;
   }
 
+  protected function supportsSearch() {
+    return true;
+  }
+
 }
diff --git a/src/applications/herald/engineextension/HeraldRuleIndexEngineExtension.php b/src/applications/herald/engineextension/HeraldRuleIndexEngineExtension.php
new file mode 100644
--- /dev/null
+++ b/src/applications/herald/engineextension/HeraldRuleIndexEngineExtension.php
@@ -0,0 +1,92 @@
+<?php
+
+final class HeraldRuleIndexEngineExtension
+  extends PhabricatorIndexEngineExtension {
+
+  const EXTENSIONKEY = 'herald.actions';
+
+  public function getExtensionName() {
+    return pht('Herald Actions');
+  }
+
+  public function shouldIndexObject($object) {
+    if (!($object instanceof HeraldRule)) {
+      return false;
+    }
+
+    return true;
+  }
+
+  public function indexObject(
+    PhabricatorIndexEngine $engine,
+    $object) {
+
+    $edge_type = HeraldRuleActionAffectsObjectEdgeType::EDGECONST;
+
+    $old_edges = PhabricatorEdgeQuery::loadDestinationPHIDs(
+      $object->getPHID(),
+      $edge_type);
+    $old_edges = array_fuse($old_edges);
+
+    $new_edges = $this->getPHIDsAffectedByActions($object);
+    $new_edges = array_fuse($new_edges);
+
+    $add_edges = array_diff_key($new_edges, $old_edges);
+    $rem_edges = array_diff_key($old_edges, $new_edges);
+
+    if (!$add_edges && !$rem_edges) {
+      return;
+    }
+
+    $editor = new PhabricatorEdgeEditor();
+
+    foreach ($add_edges as $phid) {
+      $editor->addEdge($object->getPHID(), $edge_type, $phid);
+    }
+
+    foreach ($rem_edges as $phid) {
+      $editor->removeEdge($object->getPHID(), $edge_type, $phid);
+    }
+
+    $editor->save();
+  }
+
+  public function getIndexVersion($object) {
+    $phids = $this->getPHIDsAffectedByActions($object);
+    sort($phids);
+    $phids = implode(':', $phids);
+    return PhabricatorHash::digestForIndex($phids);
+  }
+
+  private function getPHIDsAffectedByActions(HeraldRule $rule) {
+    $viewer = $this->getViewer();
+
+    $rule = id(new HeraldRuleQuery())
+      ->setViewer($viewer)
+      ->withIDs(array($rule->getID()))
+      ->needConditionsAndActions(true)
+      ->executeOne();
+    if (!$rule) {
+      return array();
+    }
+
+    $phids = array();
+
+    $actions = HeraldAction::getAllActions();
+    foreach ($rule->getActions() as $action_record) {
+      $action = idx($actions, $action_record->getAction());
+
+      if (!$action) {
+        continue;
+      }
+
+      foreach ($action->getPHIDsAffectedByAction($action_record) as $phid) {
+        $phids[] = $phid;
+      }
+    }
+
+    $phids = array_fuse($phids);
+    return array_keys($phids);
+  }
+
+}
diff --git a/src/applications/herald/query/HeraldRuleQuery.php b/src/applications/herald/query/HeraldRuleQuery.php
--- a/src/applications/herald/query/HeraldRuleQuery.php
+++ b/src/applications/herald/query/HeraldRuleQuery.php
@@ -11,6 +11,7 @@
   private $active;
   private $datasourceQuery;
   private $triggerObjectPHIDs;
+  private $affectedObjectPHIDs;
 
   private $needConditionsAndActions;
   private $needAppliedToPHIDs;
@@ -61,6 +62,11 @@
     return $this;
   }
 
+  public function withAffectedObjectPHIDs(array $phids) {
+    $this->affectedObjectPHIDs = $phids;
+    return $this;
+  }
+
   public function needConditionsAndActions($need) {
     $this->needConditionsAndActions = $need;
     return $this;
@@ -261,9 +267,31 @@
         $this->triggerObjectPHIDs);
     }
 
+    if ($this->affectedObjectPHIDs) {
+      $where[] = qsprintf(
+        $conn,
+        'edge_affects.dst IN (%Ls)',
+        $this->affectedObjectPHIDs);
+    }
+
     return $where;
   }
 
+  protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) {
+    $joins = parent::buildJoinClauseParts($conn);
+
+    if ($this->affectedObjectPHIDs !== null) {
+      $joins[] = qsprintf(
+        $conn,
+        'JOIN %T edge_affects ON rule.phid = edge_affects.src
+          AND edge_affects.type = %d',
+        PhabricatorEdgeConfig::TABLE_NAME_EDGE,
+        HeraldRuleActionAffectsObjectEdgeType::EDGECONST);
+    }
+
+    return $joins;
+  }
+
   private function validateRuleAuthors(array $rules) {
     // "Global" and "Object" rules always have valid authors.
     foreach ($rules as $key => $rule) {
diff --git a/src/applications/herald/query/HeraldRuleSearchEngine.php b/src/applications/herald/query/HeraldRuleSearchEngine.php
--- a/src/applications/herald/query/HeraldRuleSearchEngine.php
+++ b/src/applications/herald/query/HeraldRuleSearchEngine.php
@@ -55,6 +55,10 @@
           pht('(Show All)'),
           pht('Show Only Disabled Rules'),
           pht('Show Only Enabled Rules')),
+      id(new PhabricatorPHIDsSearchField())
+        ->setLabel(pht('Affected Objects'))
+        ->setKey('affectedPHIDs')
+        ->setAliases(array('affectedPHID')),
     );
   }
 
@@ -81,6 +85,10 @@
       $query->withActive($map['active']);
     }
 
+    if ($map['affectedPHIDs'] !== null) {
+      $query->withAffectedObjectPHIDs($map['affectedPHIDs']);
+    }
+
     return $query;
   }
 
@@ -127,54 +135,18 @@
     PhabricatorSavedQuery $query,
     array $handles) {
     assert_instances_of($rules, 'HeraldRule');
-
     $viewer = $this->requireViewer();
-    $handles = $viewer->loadHandles(mpull($rules, 'getAuthorPHID'));
-
-    $content_type_map = HeraldAdapter::getEnabledAdapterMap($viewer);
-
-    $list = id(new PHUIObjectItemListView())
-      ->setUser($viewer);
-    foreach ($rules as $rule) {
-      $monogram = $rule->getMonogram();
-
-      $item = id(new PHUIObjectItemView())
-        ->setObjectName($monogram)
-        ->setHeader($rule->getName())
-        ->setHref("/{$monogram}");
-
-      if ($rule->isPersonalRule()) {
-        $item->addIcon('fa-user', pht('Personal Rule'));
-        $item->addByline(
-          pht(
-            'Authored by %s',
-            $handles[$rule->getAuthorPHID()]->renderLink()));
-      } else if ($rule->isObjectRule()) {
-        $item->addIcon('fa-briefcase', pht('Object Rule'));
-      } else {
-        $item->addIcon('fa-globe', pht('Global Rule'));
-      }
-
-      if ($rule->getIsDisabled()) {
-        $item->setDisabled(true);
-        $item->addIcon('fa-lock grey', pht('Disabled'));
-      } else if (!$rule->hasValidAuthor()) {
-        $item->setDisabled(true);
-        $item->addIcon('fa-user grey', pht('Author Not Active'));
-      }
-
-      $content_type_name = idx($content_type_map, $rule->getContentType());
-      $item->addAttribute(pht('Affects: %s', $content_type_name));
-
-      $list->addItem($item);
-    }
+
+    $list = id(new HeraldRuleListView())
+      ->setViewer($viewer)
+      ->setRules($rules)
+      ->newObjectList();
 
     $result = new PhabricatorApplicationSearchResultView();
     $result->setObjectList($list);
     $result->setNoDataString(pht('No rules found.'));
 
     return $result;
-
   }
 
   protected function getNewUserBody() {
diff --git a/src/applications/herald/storage/HeraldRule.php b/src/applications/herald/storage/HeraldRule.php
--- a/src/applications/herald/storage/HeraldRule.php
+++ b/src/applications/herald/storage/HeraldRule.php
@@ -6,6 +6,7 @@
     PhabricatorFlaggableInterface,
     PhabricatorPolicyInterface,
     PhabricatorDestructibleInterface,
+    PhabricatorIndexableInterface,
     PhabricatorSubscribableInterface {
 
   const TABLE_RULE_APPLIED = 'herald_ruleapplied';
diff --git a/src/applications/herald/view/HeraldRuleListView.php b/src/applications/herald/view/HeraldRuleListView.php
new file mode 100644
--- /dev/null
+++ b/src/applications/herald/view/HeraldRuleListView.php
@@ -0,0 +1,65 @@
+<?php
+
+final class HeraldRuleListView
+  extends AphrontView {
+
+  private $rules;
+
+  public function setRules(array $rules) {
+    assert_instances_of($rules, 'HeraldRule');
+    $this->rules = $rules;
+    return $this;
+  }
+
+  public function render() {
+    return $this->newObjectList();
+  }
+
+  public function newObjectList() {
+    $viewer = $this->getViewer();
+    $rules = $this->rules;
+
+    $handles = $viewer->loadHandles(mpull($rules, 'getAuthorPHID'));
+
+    $content_type_map = HeraldAdapter::getEnabledAdapterMap($viewer);
+
+    $list = id(new PHUIObjectItemListView())
+      ->setViewer($viewer);
+    foreach ($rules as $rule) {
+      $monogram = $rule->getMonogram();
+
+      $item = id(new PHUIObjectItemView())
+        ->setObjectName($monogram)
+        ->setHeader($rule->getName())
+        ->setHref($rule->getURI());
+
+      if ($rule->isPersonalRule()) {
+        $item->addIcon('fa-user', pht('Personal Rule'));
+        $item->addByline(
+          pht(
+            'Authored by %s',
+            $handles[$rule->getAuthorPHID()]->renderLink()));
+      } else if ($rule->isObjectRule()) {
+        $item->addIcon('fa-briefcase', pht('Object Rule'));
+      } else {
+        $item->addIcon('fa-globe', pht('Global Rule'));
+      }
+
+      if ($rule->getIsDisabled()) {
+        $item->setDisabled(true);
+        $item->addIcon('fa-lock grey', pht('Disabled'));
+      } else if (!$rule->hasValidAuthor()) {
+        $item->setDisabled(true);
+        $item->addIcon('fa-user grey', pht('Author Not Active'));
+      }
+
+      $content_type_name = idx($content_type_map, $rule->getContentType());
+      $item->addAttribute(pht('Affects: %s', $content_type_name));
+
+      $list->addItem($item);
+    }
+
+    return $list;
+  }
+
+}