Index: src/__phutil_library_map__.php
===================================================================
--- src/__phutil_library_map__.php
+++ src/__phutil_library_map__.php
@@ -902,9 +902,14 @@
     'HarbormasterCommandBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterCommandBuildStepImplementation.php',
     'HarbormasterConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterConduitAPIMethod.php',
     'HarbormasterController' => 'applications/harbormaster/controller/HarbormasterController.php',
+    'HarbormasterCustomFieldRepository' => 'applications/harbormaster/customfield/HarbormasterCustomFieldRepository.php',
     'HarbormasterDAO' => 'applications/harbormaster/storage/HarbormasterDAO.php',
     'HarbormasterHTTPRequestBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterHTTPRequestBuildStepImplementation.php',
     'HarbormasterLeaseHostBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterLeaseHostBuildStepImplementation.php',
+    'HarbormasterLeaseWorkingCopyBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterLeaseWorkingCopyBuildStepImplementation.php',
+    'HarbormasterLeaseWorkingCopyFromBuildableBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterLeaseWorkingCopyFromBuildableBuildStepImplementation.php',
+    'HarbormasterLeaseWorkingCopyFromRepositoryBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterLeaseWorkingCopyFromRepositoryBuildStepImplementation.php',
+    'HarbormasterLeaseWorkingCopyFromURLBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterLeaseWorkingCopyFromURLBuildStepImplementation.php',
     'HarbormasterLintMessagesController' => 'applications/harbormaster/controller/HarbormasterLintMessagesController.php',
     'HarbormasterLintPropertyView' => 'applications/harbormaster/view/HarbormasterLintPropertyView.php',
     'HarbormasterManagePlansCapability' => 'applications/harbormaster/capability/HarbormasterManagePlansCapability.php',
@@ -4406,9 +4411,14 @@
     'HarbormasterCommandBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
     'HarbormasterConduitAPIMethod' => 'ConduitAPIMethod',
     'HarbormasterController' => 'PhabricatorController',
+    'HarbormasterCustomFieldRepository' => 'PhabricatorStandardCustomFieldPHIDs',
     'HarbormasterDAO' => 'PhabricatorLiskDAO',
     'HarbormasterHTTPRequestBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
     'HarbormasterLeaseHostBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
+    'HarbormasterLeaseWorkingCopyBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
+    'HarbormasterLeaseWorkingCopyFromBuildableBuildStepImplementation' => 'HarbormasterLeaseWorkingCopyBuildStepImplementation',
+    'HarbormasterLeaseWorkingCopyFromRepositoryBuildStepImplementation' => 'HarbormasterLeaseWorkingCopyBuildStepImplementation',
+    'HarbormasterLeaseWorkingCopyFromURLBuildStepImplementation' => 'HarbormasterLeaseWorkingCopyBuildStepImplementation',
     'HarbormasterLintMessagesController' => 'HarbormasterController',
     'HarbormasterLintPropertyView' => 'AphrontView',
     'HarbormasterManagePlansCapability' => 'PhabricatorPolicyCapability',
Index: src/applications/harbormaster/customfield/HarbormasterCustomFieldRepository.php
===================================================================
--- /dev/null
+++ src/applications/harbormaster/customfield/HarbormasterCustomFieldRepository.php
@@ -0,0 +1,43 @@
+<?php
+
+final class HarbormasterCustomFieldRepository
+  extends PhabricatorStandardCustomFieldPHIDs {
+
+  public function getFieldType() {
+    return 'repository';
+  }
+
+  public function renderEditControl(array $handles) {
+    $value = $this->getFieldValue();
+
+    $control = id(new AphrontFormTokenizerControl())
+      ->setUser($this->getViewer())
+      ->setLabel($this->getFieldName())
+      ->setName($this->getFieldKey())
+      ->setDatasource(new DiffusionRepositoryDatasource())
+      ->setCaption($this->getCaption())
+      ->setValue(nonempty($value, array()));
+
+    $limit = $this->getFieldConfigValue('limit');
+    if ($limit) {
+      $control->setLimit($limit);
+    }
+
+    return $control;
+  }
+
+  public function appendToApplicationSearchForm(
+    PhabricatorApplicationSearchEngine $engine,
+    AphrontFormView $form,
+    $value) {
+
+    $control = id(new AphrontFormTokenizerControl())
+      ->setLabel($this->getFieldName())
+      ->setName($this->getFieldKey())
+      ->setDatasource(new DiffusionRepositoryDatasource())
+      ->setValue(nonempty($value, array()));
+
+    $form->appendControl($control);
+  }
+
+}
Index: src/applications/harbormaster/step/HarbormasterLeaseWorkingCopyBuildStepImplementation.php
===================================================================
--- /dev/null
+++ src/applications/harbormaster/step/HarbormasterLeaseWorkingCopyBuildStepImplementation.php
@@ -0,0 +1,83 @@
+<?php
+
+abstract class HarbormasterLeaseWorkingCopyBuildStepImplementation
+  extends HarbormasterBuildStepImplementation {
+
+  abstract protected function getLeaseAttributes(
+    HarbormasterBuild $build,
+    HarbormasterBuildTarget $build_target,
+    array $settings);
+
+  public function execute(
+    HarbormasterBuild $build,
+    HarbormasterBuildTarget $build_target) {
+
+    $settings = $this->getSettings();
+
+    $custom_attributes = DrydockCustomAttributes::parse(
+      $settings['attributes']);
+
+    // Create the lease.
+    $lease = id(new DrydockLease())
+      ->setResourceType('working-copy')
+      ->setAttributes(
+        array(
+          'platform' => $settings['platform'],
+          'buildablePHID' => $build->getBuildablePHID(),
+        ) + $this->getLeaseAttributes($build, $build_target, $settings)
+        + $custom_attributes)
+      ->queueForActivation();
+
+    // Create the associated artifact.
+    $artifact = $build->createArtifact(
+      $build_target,
+      $settings['name'],
+      HarbormasterBuildArtifact::TYPE_HOST);
+    $artifact->setArtifactData(array(
+      'drydock-lease' => $lease->getID(),
+    ));
+    $artifact->save();
+
+    // Wait until the lease is fulfilled.
+    // TODO: This will throw an exception if the lease can't be fulfilled;
+    // we should treat that as build failure not build error.
+    $lease->waitUntilActive();
+  }
+
+  public function getArtifactOutputs() {
+    return array(
+      array(
+        'name' => pht('Leased Working Copy'),
+        'key' => $this->getSetting('name'),
+        'type' => HarbormasterBuildArtifact::TYPE_HOST,
+      ),
+    );
+  }
+
+  abstract protected function getLeaseFieldSpecifications();
+
+  public function getFieldSpecifications() {
+    return array(
+      'name' => array(
+        'name' => pht('Artifact Name'),
+        'type' => 'text',
+        'required' => true,
+      ),
+      'platform' => array(
+        'name' => pht('Host Platform'),
+        'type' => 'text',
+        'required' => true,
+      ),
+    ) + $this->getLeaseFieldSpecifications() + array(
+      'attributes' => array(
+        'name' => pht('Required Attributes'),
+        'type' => 'textarea',
+        'caption' => pht(
+          'A newline separated list of required working copy attributes.  '.
+          'Each attribute should be specified in a key=value format.'),
+        'monospace' => true,
+      ),
+    );
+  }
+
+}
Index: src/applications/harbormaster/step/HarbormasterLeaseWorkingCopyFromBuildableBuildStepImplementation.php
===================================================================
--- /dev/null
+++ src/applications/harbormaster/step/HarbormasterLeaseWorkingCopyFromBuildableBuildStepImplementation.php
@@ -0,0 +1,30 @@
+<?php
+
+final class HarbormasterLeaseWorkingCopyFromBuildableBuildStepImplementation
+  extends HarbormasterLeaseWorkingCopyBuildStepImplementation {
+
+  public function getName() {
+    return pht('Lease Working Copy from Buildable');
+  }
+
+  public function getGenericDescription() {
+    return pht(
+      'Obtain a lease on a Drydock working copy of the '.
+      'current buildable for performing builds.');
+  }
+
+  protected function getLeaseAttributes(
+    HarbormasterBuild $build,
+    HarbormasterBuildTarget $build_target,
+    array $settings) {
+
+    return array(
+      'buildablePHID' => $build->getBuildablePHID(),
+    );
+  }
+
+  protected function getLeaseFieldSpecifications() {
+    return array();
+  }
+
+}
Index: src/applications/harbormaster/step/HarbormasterLeaseWorkingCopyFromRepositoryBuildStepImplementation.php
===================================================================
--- /dev/null
+++ src/applications/harbormaster/step/HarbormasterLeaseWorkingCopyFromRepositoryBuildStepImplementation.php
@@ -0,0 +1,44 @@
+<?php
+
+final class HarbormasterLeaseWorkingCopyFromRepositoryBuildStepImplementation
+  extends HarbormasterLeaseWorkingCopyBuildStepImplementation {
+
+  public function getName() {
+    return pht('Lease Working Copy from Repository');
+  }
+
+  public function getGenericDescription() {
+    return pht(
+      'Obtain a lease on a Drydock working copy of a '.
+      'repository hosted on Phabricator.');
+  }
+
+  protected function getLeaseAttributes(
+    HarbormasterBuild $build,
+    HarbormasterBuildTarget $build_target,
+    array $settings) {
+
+    return array(
+      'repositoryPHID' =>
+        head(phutil_json_decode(idx($settings, 'repositoryPHID'))),
+      'ref' => idx($settings, 'ref'),
+    );
+  }
+
+  protected function getLeaseFieldSpecifications() {
+    return array(
+      'repositoryPHID' => array(
+        'name' => pht('Repository'),
+        'type' => 'repository',
+        'required' => true,
+      ),
+      'ref' => array(
+        'name' => pht('Reference to Checkout'),
+        'type' => 'text',
+        'required' => true,
+        'caption' => pht('e.g. master'),
+      ),
+    );
+  }
+
+}
Index: src/applications/harbormaster/step/HarbormasterLeaseWorkingCopyFromURLBuildStepImplementation.php
===================================================================
--- /dev/null
+++ src/applications/harbormaster/step/HarbormasterLeaseWorkingCopyFromURLBuildStepImplementation.php
@@ -0,0 +1,43 @@
+<?php
+
+final class HarbormasterLeaseWorkingCopyFromURLBuildStepImplementation
+  extends HarbormasterLeaseWorkingCopyBuildStepImplementation {
+
+  public function getName() {
+    return pht('Lease Working Copy from URL');
+  }
+
+  public function getGenericDescription() {
+    return pht(
+      'Obtain a lease on a Drydock working copy of a '.
+      'repository at a given URL.');
+  }
+
+  protected function getLeaseAttributes(
+    HarbormasterBuild $build,
+    HarbormasterBuildTarget $build_target,
+    array $settings) {
+
+    return array(
+      'url' => idx($settings, 'url'),
+      'ref' => idx($settings, 'ref'),
+    );
+  }
+
+  protected function getLeaseFieldSpecifications() {
+    return array(
+      'url' => array(
+        'name' => pht('Repository URL'),
+        'type' => 'text',
+        'required' => true,
+      ),
+      'ref' => array(
+        'name' => pht('Reference to Checkout'),
+        'type' => 'text',
+        'required' => true,
+        'caption' => pht('e.g. master'),
+      ),
+    );
+  }
+
+}