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
@@ -2381,6 +2381,7 @@
     'PhabricatorIRCProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorIRCProtocolAdapter.php',
     'PhabricatorIconRemarkupRule' => 'applications/macro/markup/PhabricatorIconRemarkupRule.php',
     'PhabricatorIconSet' => 'applications/files/iconset/PhabricatorIconSet.php',
+    'PhabricatorIconSetEditField' => 'applications/transactions/editfield/PhabricatorIconSetEditField.php',
     'PhabricatorIconSetIcon' => 'applications/files/iconset/PhabricatorIconSetIcon.php',
     'PhabricatorImageMacroRemarkupRule' => 'applications/macro/markup/PhabricatorImageMacroRemarkupRule.php',
     'PhabricatorImageTransformer' => 'applications/files/PhabricatorImageTransformer.php',
@@ -2845,7 +2846,8 @@
     'PhabricatorProjectDAO' => 'applications/project/storage/PhabricatorProjectDAO.php',
     'PhabricatorProjectDatasource' => 'applications/project/typeahead/PhabricatorProjectDatasource.php',
     'PhabricatorProjectDescriptionField' => 'applications/project/customfield/PhabricatorProjectDescriptionField.php',
-    'PhabricatorProjectEditDetailsController' => 'applications/project/controller/PhabricatorProjectEditDetailsController.php',
+    'PhabricatorProjectEditController' => 'applications/project/controller/PhabricatorProjectEditController.php',
+    'PhabricatorProjectEditEngine' => 'applications/project/engine/PhabricatorProjectEditEngine.php',
     'PhabricatorProjectEditPictureController' => 'applications/project/controller/PhabricatorProjectEditPictureController.php',
     'PhabricatorProjectFeedController' => 'applications/project/controller/PhabricatorProjectFeedController.php',
     'PhabricatorProjectFulltextEngine' => 'applications/project/search/PhabricatorProjectFulltextEngine.php',
@@ -3187,6 +3189,7 @@
     'PhabricatorStorageSchemaSpec' => 'infrastructure/storage/schema/PhabricatorStorageSchemaSpec.php',
     'PhabricatorStorageSetupCheck' => 'applications/config/check/PhabricatorStorageSetupCheck.php',
     'PhabricatorStreamingProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorStreamingProtocolAdapter.php',
+    'PhabricatorStringListEditField' => 'applications/transactions/editfield/PhabricatorStringListEditField.php',
     'PhabricatorSubscribableInterface' => 'applications/subscriptions/interface/PhabricatorSubscribableInterface.php',
     'PhabricatorSubscribedToObjectEdgeType' => 'applications/transactions/edges/PhabricatorSubscribedToObjectEdgeType.php',
     'PhabricatorSubscribersEditField' => 'applications/transactions/editfield/PhabricatorSubscribersEditField.php',
@@ -3746,6 +3749,7 @@
     'ProjectDefaultEditCapability' => 'applications/project/capability/ProjectDefaultEditCapability.php',
     'ProjectDefaultJoinCapability' => 'applications/project/capability/ProjectDefaultJoinCapability.php',
     'ProjectDefaultViewCapability' => 'applications/project/capability/ProjectDefaultViewCapability.php',
+    'ProjectEditConduitAPIMethod' => 'applications/project/conduit/ProjectEditConduitAPIMethod.php',
     'ProjectQueryConduitAPIMethod' => 'applications/project/conduit/ProjectQueryConduitAPIMethod.php',
     'ProjectRemarkupRule' => 'applications/project/remarkup/ProjectRemarkupRule.php',
     'ProjectRemarkupRuleTestCase' => 'applications/project/remarkup/__tests__/ProjectRemarkupRuleTestCase.php',
@@ -6642,6 +6646,7 @@
     'PhabricatorIRCProtocolAdapter' => 'PhabricatorProtocolAdapter',
     'PhabricatorIconRemarkupRule' => 'PhutilRemarkupRule',
     'PhabricatorIconSet' => 'Phobject',
+    'PhabricatorIconSetEditField' => 'PhabricatorEditField',
     'PhabricatorIconSetIcon' => 'Phobject',
     'PhabricatorImageMacroRemarkupRule' => 'PhutilRemarkupRule',
     'PhabricatorImageTransformer' => 'Phobject',
@@ -7192,7 +7197,8 @@
     'PhabricatorProjectDAO' => 'PhabricatorLiskDAO',
     'PhabricatorProjectDatasource' => 'PhabricatorTypeaheadDatasource',
     'PhabricatorProjectDescriptionField' => 'PhabricatorProjectStandardCustomField',
-    'PhabricatorProjectEditDetailsController' => 'PhabricatorProjectController',
+    'PhabricatorProjectEditController' => 'PhabricatorProjectController',
+    'PhabricatorProjectEditEngine' => 'PhabricatorEditEngine',
     'PhabricatorProjectEditPictureController' => 'PhabricatorProjectController',
     'PhabricatorProjectFeedController' => 'PhabricatorProjectController',
     'PhabricatorProjectFulltextEngine' => 'PhabricatorFulltextEngine',
@@ -7594,6 +7600,7 @@
     'PhabricatorStorageSchemaSpec' => 'PhabricatorConfigSchemaSpec',
     'PhabricatorStorageSetupCheck' => 'PhabricatorSetupCheck',
     'PhabricatorStreamingProtocolAdapter' => 'PhabricatorProtocolAdapter',
+    'PhabricatorStringListEditField' => 'PhabricatorEditField',
     'PhabricatorSubscribedToObjectEdgeType' => 'PhabricatorEdgeType',
     'PhabricatorSubscribersEditField' => 'PhabricatorTokenizerEditField',
     'PhabricatorSubscribersQuery' => 'PhabricatorQuery',
@@ -8300,6 +8307,7 @@
     'ProjectDefaultEditCapability' => 'PhabricatorPolicyCapability',
     'ProjectDefaultJoinCapability' => 'PhabricatorPolicyCapability',
     'ProjectDefaultViewCapability' => 'PhabricatorPolicyCapability',
+    'ProjectEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod',
     'ProjectQueryConduitAPIMethod' => 'ProjectConduitAPIMethod',
     'ProjectRemarkupRule' => 'PhabricatorObjectRemarkupRule',
     'ProjectRemarkupRuleTestCase' => 'PhabricatorTestCase',
diff --git a/src/applications/project/application/PhabricatorProjectApplication.php b/src/applications/project/application/PhabricatorProjectApplication.php
--- a/src/applications/project/application/PhabricatorProjectApplication.php
+++ b/src/applications/project/application/PhabricatorProjectApplication.php
@@ -43,8 +43,6 @@
       '/project/' => array(
         '(?:query/(?P<queryKey>[^/]+)/)?' => 'PhabricatorProjectListController',
         'filter/(?P<filter>[^/]+)/' => 'PhabricatorProjectListController',
-        'details/(?P<id>[1-9]\d*)/'
-          => 'PhabricatorProjectEditDetailsController',
         'archive/(?P<id>[1-9]\d*)/'
           => 'PhabricatorProjectArchiveController',
         'lock/(?P<id>[1-9]\d*)/'
@@ -61,7 +59,8 @@
           => 'PhabricatorProjectViewController',
         'picture/(?P<id>[1-9]\d*)/'
           => 'PhabricatorProjectEditPictureController',
-        'create/' => 'PhabricatorProjectEditDetailsController',
+        $this->getEditRoutePattern('edit/')
+          => 'PhabricatorProjectEditController',
         'subprojects/(?P<id>[1-9]\d*)/'
           => 'PhabricatorProjectSubprojectsController',
         'milestones/(?P<id>[1-9]\d*)/'
@@ -97,21 +96,9 @@
   }
 
   public function getQuickCreateItems(PhabricatorUser $viewer) {
-    $can_create = PhabricatorPolicyFilter::hasCapability(
-      $viewer,
-      $this,
-      ProjectCreateProjectsCapability::CAPABILITY);
-
-    $items = array();
-    if ($can_create) {
-      $item = id(new PHUIListItemView())
-        ->setName(pht('Project'))
-        ->setIcon('fa-briefcase')
-        ->setHref($this->getBaseURI().'create/');
-      $items[] = $item;
-    }
-
-    return $items;
+    return id(new PhabricatorProjectEditEngine())
+      ->setViewer($viewer)
+      ->loadQuickCreateItems();
   }
 
   protected function getCustomCapabilities() {
diff --git a/src/applications/project/conduit/ProjectEditConduitAPIMethod.php b/src/applications/project/conduit/ProjectEditConduitAPIMethod.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/conduit/ProjectEditConduitAPIMethod.php
@@ -0,0 +1,19 @@
+<?php
+
+final class ProjectEditConduitAPIMethod
+  extends PhabricatorEditEngineAPIMethod {
+
+  public function getAPIMethodName() {
+    return 'project.edit';
+  }
+
+  public function newEditEngine() {
+    return new PhabricatorProjectEditEngine();
+  }
+
+  public function getMethodSummary() {
+    return pht(
+      'Apply transactions to create a new project or edit an existing one.');
+  }
+
+}
diff --git a/src/applications/project/controller/PhabricatorProjectEditController.php b/src/applications/project/controller/PhabricatorProjectEditController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/controller/PhabricatorProjectEditController.php
@@ -0,0 +1,12 @@
+<?php
+
+final class PhabricatorProjectEditController
+  extends PhabricatorProjectController {
+
+  public function handleRequest(AphrontRequest $request) {
+    return id(new PhabricatorProjectEditEngine())
+      ->setController($this)
+      ->buildResponse();
+  }
+
+}
diff --git a/src/applications/project/controller/PhabricatorProjectEditDetailsController.php b/src/applications/project/controller/PhabricatorProjectEditDetailsController.php
deleted file mode 100644
--- a/src/applications/project/controller/PhabricatorProjectEditDetailsController.php
+++ /dev/null
@@ -1,282 +0,0 @@
-<?php
-
-final class PhabricatorProjectEditDetailsController
-  extends PhabricatorProjectController {
-
-  public function handleRequest(AphrontRequest $request) {
-    $viewer = $request->getViewer();
-    $id = $request->getURIData('id');
-
-    if ($id) {
-     $id = $request->getURIData('id');
-     $is_new = false;
-
-      $project = id(new PhabricatorProjectQuery())
-        ->setViewer($viewer)
-        ->withIDs(array($id))
-        ->needSlugs(true)
-        ->needImages(true)
-        ->requireCapabilities(
-          array(
-            PhabricatorPolicyCapability::CAN_VIEW,
-            PhabricatorPolicyCapability::CAN_EDIT,
-          ))
-          ->executeOne();
-      if (!$project) {
-        return new Aphront404Response();
-      }
-
-    } else {
-      $is_new = true;
-
-      $this->requireApplicationCapability(
-        ProjectCreateProjectsCapability::CAPABILITY);
-
-      $project = PhabricatorProject::initializeNewProject($viewer);
-    }
-
-    $field_list = PhabricatorCustomField::getObjectFields(
-      $project,
-      PhabricatorCustomField::ROLE_EDIT);
-    $field_list
-      ->setViewer($viewer)
-      ->readFieldsFromStorage($project);
-
-    $e_name = true;
-    $e_slugs = false;
-    $e_edit = null;
-
-    $v_name = $project->getName();
-    $project_slugs = $project->getSlugs();
-    $project_slugs = mpull($project_slugs, 'getSlug', 'getSlug');
-    $v_primary_slug = $project->getPrimarySlug();
-    unset($project_slugs[$v_primary_slug]);
-    $v_slugs = $project_slugs;
-    $v_color = $project->getColor();
-    $v_icon = $project->getIcon();
-
-    $validation_exception = null;
-
-    if ($request->isFormPost()) {
-      $e_name = null;
-      $e_slugs = null;
-
-      $v_name = $request->getStr('name');
-      $v_slugs = $request->getStrList('slugs');
-      $v_view = $request->getStr('can_view');
-      $v_edit = $request->getStr('can_edit');
-      $v_join = $request->getStr('can_join');
-      $v_color = $request->getStr('color');
-      $v_icon = $request->getStr('icon');
-
-      $type_name = PhabricatorProjectTransaction::TYPE_NAME;
-      $type_slugs = PhabricatorProjectTransaction::TYPE_SLUGS;
-      $type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY;
-      $type_icon = PhabricatorProjectTransaction::TYPE_ICON;
-      $type_color = PhabricatorProjectTransaction::TYPE_COLOR;
-
-      $xactions = array();
-
-      $xactions[] = id(new PhabricatorProjectTransaction())
-        ->setTransactionType($type_name)
-        ->setNewValue($v_name);
-
-      $xactions[] = id(new PhabricatorProjectTransaction())
-        ->setTransactionType($type_slugs)
-        ->setNewValue($v_slugs);
-
-      $xactions[] = id(new PhabricatorProjectTransaction())
-        ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)
-        ->setNewValue($v_view);
-
-      $xactions[] = id(new PhabricatorProjectTransaction())
-        ->setTransactionType($type_edit)
-        ->setNewValue($v_edit);
-
-      $xactions[] = id(new PhabricatorProjectTransaction())
-        ->setTransactionType(PhabricatorTransactions::TYPE_JOIN_POLICY)
-        ->setNewValue($v_join);
-
-      $xactions[] = id(new PhabricatorProjectTransaction())
-        ->setTransactionType($type_icon)
-        ->setNewValue($v_icon);
-
-      $xactions[] = id(new PhabricatorProjectTransaction())
-        ->setTransactionType($type_color)
-        ->setNewValue($v_color);
-
-      $xactions = array_merge(
-        $xactions,
-        $field_list->buildFieldTransactionsFromRequest(
-          new PhabricatorProjectTransaction(),
-          $request));
-
-      $editor = id(new PhabricatorProjectTransactionEditor())
-        ->setActor($viewer)
-        ->setContentSourceFromRequest($request)
-        ->setContinueOnNoEffect(true);
-
-      if ($is_new) {
-        $xactions[] = id(new PhabricatorProjectTransaction())
-          ->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
-          ->setMetadataValue(
-            'edge:type',
-            PhabricatorProjectProjectHasMemberEdgeType::EDGECONST)
-          ->setNewValue(
-            array(
-              '+' => array($viewer->getPHID() => $viewer->getPHID()),
-            ));
-      }
-
-      try {
-
-        $editor->applyTransactions($project, $xactions);
-
-        if ($request->isAjax()) {
-          return id(new AphrontAjaxResponse())
-            ->setContent(array(
-              'phid' => $project->getPHID(),
-              'name' => $project->getName(),
-            ));
-        }
-
-        $redirect_uri =
-          $this->getApplicationURI('profile/'.$project->getID().'/');
-
-        return id(new AphrontRedirectResponse())->setURI($redirect_uri);
-      } catch (PhabricatorApplicationTransactionValidationException $ex) {
-        $validation_exception = $ex;
-
-        $e_name = $ex->getShortMessage($type_name);
-        $e_slugs = $ex->getShortMessage($type_slugs);
-        $e_edit = $ex->getShortMessage($type_edit);
-
-        $project->setViewPolicy($v_view);
-        $project->setEditPolicy($v_edit);
-        $project->setJoinPolicy($v_join);
-      }
-    }
-
-    if ($is_new) {
-      $header_name = pht('Create a New Project');
-      $title = pht('Create Project');
-    } else {
-      $header_name = pht('Edit Project');
-      $title = pht('Edit Project');
-    }
-
-    $policies = id(new PhabricatorPolicyQuery())
-      ->setViewer($viewer)
-      ->setObject($project)
-      ->execute();
-    $v_slugs = implode(', ', $v_slugs);
-
-    $form = id(new AphrontFormView())
-      ->setUser($viewer)
-      ->appendChild(
-        id(new AphrontFormTextControl())
-          ->setLabel(pht('Name'))
-          ->setName('name')
-          ->setValue($v_name)
-          ->setError($e_name));
-    $field_list->appendFieldsToForm($form);
-
-    $shades = PhabricatorProjectIconSet::getColorMap();
-
-    $form
-      ->appendChild(
-        id(new PHUIFormIconSetControl())
-          ->setLabel(pht('Icon'))
-          ->setName('icon')
-          ->setIconSet(new PhabricatorProjectIconSet())
-          ->setValue($v_icon))
-      ->appendChild(
-        id(new AphrontFormSelectControl())
-          ->setLabel(pht('Color'))
-          ->setName('color')
-          ->setValue($v_color)
-          ->setOptions($shades));
-
-    if (!$is_new) {
-      $form->appendChild(
-        id(new AphrontFormStaticControl())
-        ->setLabel(pht('Primary Hashtag'))
-        ->setCaption(pht('The primary hashtag is derived from the name.'))
-        ->setValue($v_primary_slug));
-    }
-
-    $form
-      ->appendChild(
-        id(new AphrontFormTextControl())
-          ->setLabel(pht('Additional Hashtags'))
-          ->setCaption(pht(
-            'Specify a comma-separated list of additional hashtags.'))
-          ->setName('slugs')
-          ->setValue($v_slugs)
-          ->setError($e_slugs))
-      ->appendChild(
-        id(new AphrontFormPolicyControl())
-          ->setUser($viewer)
-          ->setName('can_view')
-          ->setPolicyObject($project)
-          ->setPolicies($policies)
-          ->setCapability(PhabricatorPolicyCapability::CAN_VIEW))
-      ->appendChild(
-        id(new AphrontFormPolicyControl())
-          ->setUser($viewer)
-          ->setName('can_edit')
-          ->setPolicyObject($project)
-          ->setPolicies($policies)
-          ->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
-          ->setError($e_edit))
-      ->appendChild(
-        id(new AphrontFormPolicyControl())
-          ->setUser($viewer)
-          ->setName('can_join')
-          ->setCaption(
-            pht('Users who can edit a project can always join a project.'))
-          ->setPolicyObject($project)
-          ->setPolicies($policies)
-          ->setCapability(PhabricatorPolicyCapability::CAN_JOIN));
-
-    if ($request->isAjax()) {
-      $errors = array();
-      if ($validation_exception) {
-        $errors = mpull($ex->getErrors(), 'getMessage');
-      }
-      $dialog = id(new AphrontDialogView())
-        ->setUser($viewer)
-        ->setWidth(AphrontDialogView::WIDTH_FULL)
-        ->setTitle($header_name)
-        ->setErrors($errors)
-        ->appendForm($form)
-        ->addSubmitButton($title)
-        ->addCancelButton('/project/');
-      return id(new AphrontDialogResponse())->setDialog($dialog);
-    }
-
-    $form->appendChild(
-      id(new AphrontFormSubmitControl())
-      ->addCancelButton($this->getApplicationURI())
-      ->setValue(pht('Save')));
-
-    $form_box = id(new PHUIObjectBoxView())
-      ->setHeaderText($title)
-      ->setValidationException($validation_exception)
-      ->setForm($form);
-
-    if (!$is_new) {
-      $nav = $this->buildIconNavView($project);
-      $nav->selectFilter("details/{$id}/");
-      $nav->appendChild($form_box);
-    } else {
-      $nav = array($form_box);
-    }
-
-    return $this->buildApplicationPage(
-      $nav,
-      array(
-        'title' => $title,
-      ));
-  }
-}
diff --git a/src/applications/project/controller/PhabricatorProjectListController.php b/src/applications/project/controller/PhabricatorProjectListController.php
--- a/src/applications/project/controller/PhabricatorProjectListController.php
+++ b/src/applications/project/controller/PhabricatorProjectListController.php
@@ -26,16 +26,9 @@
   protected function buildApplicationCrumbs() {
     $crumbs = parent::buildApplicationCrumbs();
 
-    $can_create = $this->hasApplicationCapability(
-      ProjectCreateProjectsCapability::CAPABILITY);
-
-    $crumbs->addAction(
-      id(new PHUIListItemView())
-        ->setName(pht('Create Project'))
-        ->setHref($this->getApplicationURI('create/'))
-        ->setIcon('fa-plus-square')
-        ->setWorkflow(!$can_create)
-        ->setDisabled(!$can_create));
+    id(new PhabricatorProjectEditEngine())
+      ->setViewer($this->getViewer())
+      ->addActionToCrumbs($crumbs);
 
     return $crumbs;
   }
diff --git a/src/applications/project/controller/PhabricatorProjectProfileController.php b/src/applications/project/controller/PhabricatorProjectProfileController.php
--- a/src/applications/project/controller/PhabricatorProjectProfileController.php
+++ b/src/applications/project/controller/PhabricatorProjectProfileController.php
@@ -76,7 +76,7 @@
       id(new PhabricatorActionView())
         ->setName(pht('Edit Details'))
         ->setIcon('fa-pencil')
-        ->setHref($this->getApplicationURI("details/{$id}/"))
+        ->setHref($this->getApplicationURI("edit/{$id}/"))
         ->setDisabled(!$can_edit)
         ->setWorkflow(!$can_edit));
 
diff --git a/src/applications/project/customfield/PhabricatorProjectDescriptionField.php b/src/applications/project/customfield/PhabricatorProjectDescriptionField.php
--- a/src/applications/project/customfield/PhabricatorProjectDescriptionField.php
+++ b/src/applications/project/customfield/PhabricatorProjectDescriptionField.php
@@ -13,7 +13,8 @@
           'description' => pht('Short project description.'),
           'fulltext'    => PhabricatorSearchDocumentFieldType::FIELD_BODY,
         ),
-      ));
+      ),
+      $internal = true);
   }
 
 }
diff --git a/src/applications/project/editor/PhabricatorProjectTransactionEditor.php b/src/applications/project/editor/PhabricatorProjectTransactionEditor.php
--- a/src/applications/project/editor/PhabricatorProjectTransactionEditor.php
+++ b/src/applications/project/editor/PhabricatorProjectTransactionEditor.php
@@ -745,4 +745,38 @@
     return $copy;
   }
 
+  protected function expandTransactions(
+    PhabricatorLiskDAO $object,
+    array $xactions) {
+
+    $actor = $this->getActor();
+    $actor_phid = $actor->getPHID();
+
+    $results = parent::expandTransactions($object, $xactions);
+
+    // Automatically add the author as a member when they create a project
+    // if they're using the web interface.
+
+    $content_source = $this->getContentSource();
+    $source_web = PhabricatorContentSource::SOURCE_WEB;
+    $is_web = ($content_source->getSource() === $source_web);
+
+    if ($this->getIsNewObject() && $is_web) {
+      if ($actor_phid) {
+        $type_member = PhabricatorProjectProjectHasMemberEdgeType::EDGECONST;
+
+        $results[] = id(new PhabricatorProjectTransaction())
+          ->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
+          ->setMetadataValue('edge:type', $type_member)
+          ->setNewValue(
+            array(
+              '+' => array($actor_phid => $actor_phid),
+            ));
+      }
+    }
+
+    return $results;
+  }
+
+
 }
diff --git a/src/applications/project/engine/PhabricatorProjectEditEngine.php b/src/applications/project/engine/PhabricatorProjectEditEngine.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/engine/PhabricatorProjectEditEngine.php
@@ -0,0 +1,126 @@
+<?php
+
+final class PhabricatorProjectEditEngine
+  extends PhabricatorEditEngine {
+
+  const ENGINECONST = 'projects.project';
+
+  public function getEngineName() {
+    return pht('Projects');
+  }
+
+  public function getSummaryHeader() {
+    return pht('Configure Project Forms');
+  }
+
+  public function getSummaryText() {
+    return pht('Configure forms for creating projects.');
+  }
+
+  public function getEngineApplicationClass() {
+    return 'PhabricatorProjectApplication';
+  }
+
+  protected function newEditableObject() {
+    return PhabricatorProject::initializeNewProject($this->getViewer());
+  }
+
+  protected function newObjectQuery() {
+    return id(new PhabricatorProjectQuery())
+      ->needSlugs(true);
+  }
+
+  protected function getObjectCreateTitleText($object) {
+    return pht('Create New Project');
+  }
+
+  protected function getObjectEditTitleText($object) {
+    return pht('Edit %s', $object->getName());
+  }
+
+  protected function getObjectEditShortText($object) {
+    return $object->getName();
+  }
+
+  protected function getObjectCreateShortText() {
+    return pht('Create Project');
+  }
+
+  protected function getObjectViewURI($object) {
+    return $object->getURI();
+  }
+
+  protected function getCreateNewObjectPolicy() {
+    return $this->getApplication()->getPolicy(
+      ProjectCreateProjectsCapability::CAPABILITY);
+  }
+
+  protected function newBuiltinEngineConfigurations() {
+    $configuration = head(parent::newBuiltinEngineConfigurations());
+
+    // TODO: This whole method is clumsy, and the ordering for the custom
+    // field is especially clumsy. Maybe try to make this more natural to
+    // express.
+
+    $configuration
+      ->setFieldOrder(
+        array(
+          'name',
+          'std:project:internal:description',
+          'icon',
+          'color',
+          'slugs',
+          'subscriberPHIDs',
+        ));
+
+    return array(
+      $configuration,
+    );
+  }
+
+  protected function buildCustomEditFields($object) {
+    $slugs = mpull($object->getSlugs(), 'getSlug');
+    $slugs = array_fuse($slugs);
+    unset($slugs[$object->getPrimarySlug()]);
+    $slugs = array_values($slugs);
+
+    return array(
+      id(new PhabricatorTextEditField())
+        ->setKey('name')
+        ->setLabel(pht('Name'))
+        ->setTransactionType(PhabricatorProjectTransaction::TYPE_NAME)
+        ->setIsRequired(true)
+        ->setDescription(pht('Project name.'))
+        ->setConduitDescription(pht('Rename the project'))
+        ->setConduitTypeDescription(pht('New project name.'))
+        ->setValue($object->getName()),
+      id(new PhabricatorIconSetEditField())
+        ->setKey('icon')
+        ->setLabel(pht('Icon'))
+        ->setTransactionType(PhabricatorProjectTransaction::TYPE_ICON)
+        ->setIconSet(new PhabricatorProjectIconSet())
+        ->setDescription(pht('Project icon.'))
+        ->setConduitDescription(pht('Change the project icon.'))
+        ->setConduitTypeDescription(pht('New project icon.'))
+        ->setValue($object->getIcon()),
+      id(new PhabricatorSelectEditField())
+        ->setKey('color')
+        ->setLabel(pht('Color'))
+        ->setTransactionType(PhabricatorProjectTransaction::TYPE_COLOR)
+        ->setOptions(PhabricatorProjectIconSet::getColorMap())
+        ->setDescription(pht('Project tag color.'))
+        ->setConduitDescription(pht('Change the project tag color.'))
+        ->setConduitTypeDescription(pht('New project tag color.'))
+        ->setValue($object->getColor()),
+      id(new PhabricatorStringListEditField())
+        ->setKey('slugs')
+        ->setLabel(pht('Additional Hashtags'))
+        ->setTransactionType(PhabricatorProjectTransaction::TYPE_SLUGS)
+        ->setDescription(pht('Additional project slugs.'))
+        ->setConduitDescription(pht('Change project slugs.'))
+        ->setConduitTypeDescription(pht('New list of slugs.'))
+        ->setValue($slugs),
+    );
+  }
+
+}
diff --git a/src/applications/project/storage/PhabricatorProjectTransaction.php b/src/applications/project/storage/PhabricatorProjectTransaction.php
--- a/src/applications/project/storage/PhabricatorProjectTransaction.php
+++ b/src/applications/project/storage/PhabricatorProjectTransaction.php
@@ -99,9 +99,15 @@
   public function getTitle() {
     $old = $this->getOldValue();
     $new = $this->getNewValue();
-    $author_handle = $this->renderHandleLink($this->getAuthorPHID());
+    $author_phid = $this->getAuthorPHID();
+    $author_handle = $this->renderHandleLink($author_phid);
 
     switch ($this->getTransactionType()) {
+      case PhabricatorTransactions::TYPE_CREATE:
+        return pht(
+          '%s created this project.',
+          $this->renderHandleLink($author_phid));
+
       case self::TYPE_NAME:
         if ($old === null) {
           return pht(
diff --git a/src/applications/transactions/editfield/PhabricatorIconSetEditField.php b/src/applications/transactions/editfield/PhabricatorIconSetEditField.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/editfield/PhabricatorIconSetEditField.php
@@ -0,0 +1,30 @@
+<?php
+
+final class PhabricatorIconSetEditField
+  extends PhabricatorEditField {
+
+  private $iconSet;
+
+  public function setIconSet(PhabricatorIconSet $icon_set) {
+    $this->iconSet = $icon_set;
+    return $this;
+  }
+
+  public function getIconSet() {
+    return $this->iconSet;
+  }
+
+  protected function newControl() {
+    return id(new PHUIFormIconSetControl())
+      ->setIconSet($this->getIconSet());
+  }
+
+  protected function newConduitParameterType() {
+    return new ConduitStringParameterType();
+  }
+
+  protected function newHTTPParameterType() {
+    return new AphrontStringHTTPParameterType();
+  }
+
+}
diff --git a/src/applications/transactions/editfield/PhabricatorStringListEditField.php b/src/applications/transactions/editfield/PhabricatorStringListEditField.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/editfield/PhabricatorStringListEditField.php
@@ -0,0 +1,18 @@
+<?php
+
+final class PhabricatorStringListEditField
+  extends PhabricatorEditField {
+
+  protected function newControl() {
+    return new AphrontFormTextControl();
+  }
+
+  protected function newConduitParameterType() {
+    return new ConduitStringListParameterType();
+  }
+
+  protected function newHTTPParameterType() {
+    return new AphrontStringListHTTPParameterType();
+  }
+
+}
diff --git a/src/infrastructure/customfield/standard/PhabricatorStandardCustomField.php b/src/infrastructure/customfield/standard/PhabricatorStandardCustomField.php
--- a/src/infrastructure/customfield/standard/PhabricatorStandardCustomField.php
+++ b/src/infrastructure/customfield/standard/PhabricatorStandardCustomField.php
@@ -17,12 +17,14 @@
   private $default;
   private $isCopyable;
   private $hasStorageValue;
+  private $isBuiltin;
 
   abstract public function getFieldType();
 
   public static function buildStandardFields(
     PhabricatorCustomField $template,
-    array $config) {
+    array $config,
+    $builtin = false) {
 
     $types = id(new PhutilClassMapQuery())
       ->setAncestorClass(__CLASS__)
@@ -48,6 +50,10 @@
         ->setFieldConfig($value)
         ->setApplicationField($template);
 
+      if ($builtin) {
+        $standard->setIsBuiltin(true);
+      }
+
       $field = $template->setProxy($standard);
       $fields[] = $field;
     }
@@ -93,6 +99,15 @@
     return $this;
   }
 
+  public function setIsBuiltin($is_builtin) {
+    $this->isBuiltin = $is_builtin;
+    return $this;
+  }
+
+  public function getIsBuiltin() {
+    return $this->isBuiltin;
+  }
+
   public function setFieldConfig(array $config) {
     foreach ($config as $key => $value) {
       switch ($key) {
@@ -470,7 +485,11 @@
   }
 
   public function getModernFieldKey() {
-    return 'custom.'.$this->getRawStandardFieldKey();
+    if ($this->getIsBuiltin()) {
+      return $this->getRawStandardFieldKey();
+    } else {
+      return 'custom.'.$this->getRawStandardFieldKey();
+    }
   }
 
   public function getConduitDictionaryValue() {