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
@@ -2664,6 +2664,7 @@
     'PhabricatorUserPreferences' => 'applications/settings/storage/PhabricatorUserPreferences.php',
     'PhabricatorUserProfile' => 'applications/people/storage/PhabricatorUserProfile.php',
     'PhabricatorUserProfileEditor' => 'applications/people/editor/PhabricatorUserProfileEditor.php',
+    'PhabricatorUserProjectsDatasource' => 'applications/people/typeahead/PhabricatorUserProjectsDatasource.php',
     'PhabricatorUserRealNameField' => 'applications/people/customfield/PhabricatorUserRealNameField.php',
     'PhabricatorUserRolesField' => 'applications/people/customfield/PhabricatorUserRolesField.php',
     'PhabricatorUserSchemaSpec' => 'applications/people/storage/PhabricatorUserSchemaSpec.php',
@@ -6080,6 +6081,7 @@
     'PhabricatorUserPreferences' => 'PhabricatorUserDAO',
     'PhabricatorUserProfile' => 'PhabricatorUserDAO',
     'PhabricatorUserProfileEditor' => 'PhabricatorApplicationTransactionEditor',
+    'PhabricatorUserProjectsDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
     'PhabricatorUserRealNameField' => 'PhabricatorUserCustomField',
     'PhabricatorUserRolesField' => 'PhabricatorUserCustomField',
     'PhabricatorUserSchemaSpec' => 'PhabricatorConfigSchemaSpec',
diff --git a/src/applications/people/typeahead/PhabricatorUserProjectsDatasource.php b/src/applications/people/typeahead/PhabricatorUserProjectsDatasource.php
new file mode 100644
--- /dev/null
+++ b/src/applications/people/typeahead/PhabricatorUserProjectsDatasource.php
@@ -0,0 +1,85 @@
+<?php
+
+final class PhabricatorUserProjectsDatasource
+  extends PhabricatorTypeaheadCompositeDatasource {
+
+  public function getPlaceholderText() {
+    return pht('Type projects(<user>)...');
+  }
+
+  public function getDatasourceApplicationClass() {
+    return 'PhabricatorProjectApplication';
+  }
+
+  public function getComponentDatasources() {
+    return array(
+      new PhabricatorPeopleDatasource(),
+    );
+  }
+
+  public function getDatasourceFunctions() {
+    return array(
+      'projects' => array(
+        'name' => pht("Find results in any of a user's projects."),
+      ),
+    );
+  }
+
+  protected function didLoadResults(array $results) {
+    foreach ($results as $result) {
+      $result
+        ->setTokenType(PhabricatorTypeaheadTokenView::TYPE_FUNCTION)
+        ->setIcon('fa-briefcase')
+        ->setPHID('projects('.$result->getPHID().')')
+        ->setDisplayName(pht('Projects: %s', $result->getDisplayName()))
+        ->setName($result->getName().' projects');
+    }
+
+    return $results;
+  }
+
+  protected function evaluateFunction($function, array $argv_list) {
+    $phids = array();
+    foreach ($argv_list as $argv) {
+      $phids[] = head($argv);
+    }
+
+    $projects = id(new PhabricatorPeopleQuery())
+      ->setViewer($this->getViewer())
+      ->needMembers(true)
+      ->withPHIDs($phids)
+      ->execute();
+
+    $results = array();
+    foreach ($projects as $project) {
+      foreach ($project->getMemberPHIDs() as $phid) {
+        $results[$phid] = $phid;
+      }
+    }
+
+    return array_values($results);
+  }
+
+  public function renderFunctionTokens($function, array $argv_list) {
+    $phids = array();
+    foreach ($argv_list as $argv) {
+      $phids[] = head($argv);
+    }
+
+    $tokens = $this->renderTokens($phids);
+    foreach ($tokens as $token) {
+      if ($token->isInvalid()) {
+        $token
+          ->setValue(pht('Projects: Invalid User'));
+      } else {
+        $token
+          ->setTokenType(PhabricatorTypeaheadTokenView::TYPE_FUNCTION)
+          ->setKey('projects('.$token->getKey().')')
+          ->setValue(pht('Projects: %s', $token->getValue()));
+      }
+    }
+
+    return $tokens;
+  }
+
+}
diff --git a/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php b/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php
--- a/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php
+++ b/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php
@@ -25,10 +25,22 @@
     $offset = $this->getOffset();
     $limit = $this->getLimit();
 
+    // If the input query is a function like `members(platy`, and we can
+    // parse the function, we strip the function off and hand the stripped
+    // query to child sources. This makes it easier to implement function
+    // sources in terms of real object sources.
+    $raw_query = $this->getRawQuery();
+    if (self::isFunctionToken($raw_query)) {
+      $function = $this->parseFunction($raw_query, $allow_partial = true);
+      if ($function) {
+        $raw_query = head($function['argv']);
+      }
+    }
+
     $results = array();
     foreach ($this->getUsableDatasources() as $source) {
       $source
-        ->setRawQuery($this->getRawQuery())
+        ->setRawQuery($raw_query)
         ->setQuery($this->getQuery())
         ->setViewer($this->getViewer());
 
@@ -36,7 +48,9 @@
         $source->setLimit($offset + $limit);
       }
 
-      $results[] = $source->loadResults();
+      $source_results = $source->loadResults();
+      $source_results = $source->didLoadResults($source_results);
+      $results[] = $source_results;
     }
 
     $results = array_mergev($results);
diff --git a/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php b/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php
--- a/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php
+++ b/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php
@@ -90,6 +90,10 @@
   abstract public function getDatasourceApplicationClass();
   abstract public function loadResults();
 
+  protected function didLoadResults(array $results) {
+    return $results;
+  }
+
   public static function tokenizeString($string) {
     $string = phutil_utf8_strtolower($string);
     $string = trim($string);
@@ -261,8 +265,17 @@
   /**
    * @task functions
    */
+  public function getDatasourceFunctions() {
+    return array();
+  }
+
+
+  /**
+   * @task functions
+   */
   protected function canEvaluateFunction($function) {
-    return false;
+    $functions = $this->getDatasourceFunctions();
+    return isset($functions[$function]);
   }
 
 
diff --git a/src/applications/typeahead/view/PhabricatorTypeaheadTokenView.php b/src/applications/typeahead/view/PhabricatorTypeaheadTokenView.php
--- a/src/applications/typeahead/view/PhabricatorTypeaheadTokenView.php
+++ b/src/applications/typeahead/view/PhabricatorTypeaheadTokenView.php
@@ -40,6 +40,10 @@
     return $token;
   }
 
+  public function isInvalid() {
+    return ($this->getTokenType() == self::TYPE_INVALID);
+  }
+
   public function setKey($key) {
     $this->key = $key;
     return $this;