diff --git a/bin/arc b/bin/arc
--- a/bin/arc
+++ b/bin/arc
@@ -1,21 +1,14 @@
-#!/usr/bin/env bash
+#!/usr/bin/env php
+<?php
 
-# NOTE: This file is a wrapper script instead of a symlink so it will work in
-# the Git Bash environment in Windows.
+if (function_exists('pcntl_async_signals')) {
+  pcntl_async_signals(true);
+} else {
+  declare(ticks = 1);
+}
 
-# Do bash magic to resolve the real location of this script through aliases,
-# symlinks, etc.
-SOURCE="${BASH_SOURCE[0]}";
-while [ -h "$SOURCE" ]; do
-  LINK="$(readlink "$SOURCE")";
-  if [ "${LINK:0:1}" == "/" ]; then
-    # absolute symlink
-    SOURCE="$LINK"
-  else
-    # relative symlink
-    SOURCE="$(cd -P "$(dirname "$SOURCE")" && pwd)/$LINK"
-  fi
-done;
-DIR="$(cd -P "$(dirname "$SOURCE")" && pwd)"
+require_once dirname(dirname(__FILE__)).'/scripts/init/init-arcanist.php';
+
+$runtime = new ArcanistRuntime();
+return $runtime->execute($argv);
 
-exec "$DIR/../scripts/arcanist.php" "$@"
diff --git a/bin/arc.bat b/bin/arc.bat
--- a/bin/arc.bat
+++ b/bin/arc.bat
@@ -1,2 +1,2 @@
 @echo off
-php -f "%~dp0..\scripts\arcanist.php" -- %*
+php -f "%~dp0..\bin\arc" -- %*
diff --git a/bin/phage b/bin/phage
old mode 120000
new mode 100755
--- /dev/null
+++ b/bin/phage
@@ -0,0 +1,14 @@
+#!/usr/bin/env php
+<?php
+
+if (function_exists('pcntl_async_signals')) {
+  pcntl_async_signals(true);
+} else {
+  declare(ticks = 1);
+}
+
+require_once dirname(dirname(__FILE__)).'/scripts/init/init-arcanist.php';
+
+$runtime = new ArcanistRuntime();
+return $runtime->execute($argv);
+
diff --git a/scripts/arcanist.php b/scripts/arcanist.php
--- a/scripts/arcanist.php
+++ b/scripts/arcanist.php
@@ -1,197 +1,32 @@
 #!/usr/bin/env php
 <?php
 
-sanity_check_environment();
-
-require_once dirname(__FILE__).'/__init_script__.php';
-
-ini_set('memory_limit', -1);
-
-$original_argv = $argv;
-$base_args = new PhutilArgumentParser($argv);
-$base_args->parseStandardArguments();
-$base_args->parsePartial(
-  array(
-    array(
-      'name'    => 'load-phutil-library',
-      'param'   => 'path',
-      'help'    => pht('Load a libphutil library.'),
-      'repeat'  => true,
-    ),
-    array(
-      'name'    => 'skip-arcconfig',
-    ),
-    array(
-      'name'    => 'arcrc-file',
-      'param'   => 'filename',
-    ),
-    array(
-      'name'    => 'conduit-uri',
-      'param'   => 'uri',
-      'help'    => pht('Connect to Phabricator install specified by __uri__.'),
-    ),
-    array(
-      'name' => 'conduit-token',
-      'param' => 'token',
-      'help' => pht('Use a specific authentication token.'),
-    ),
-    array(
-      'name' => 'anonymous',
-      'help' => pht('Run workflow as a public user, without authenticating.'),
-    ),
-    array(
-      'name'    => 'conduit-version',
-      'param'   => 'version',
-      'help'    => pht(
-        '(Developers) Mock client version in protocol handshake.'),
-    ),
-    array(
-      'name'    => 'conduit-timeout',
-      'param'   => 'timeout',
-      'help'    => pht('Set Conduit timeout (in seconds).'),
-    ),
-    array(
-      'name'   => 'config',
-      'param'  => 'key=value',
-      'repeat' => true,
-      'help'   => pht(
-        'Specify a runtime configuration value. This will take precedence '.
-        'over static values, and only affect the current arcanist invocation.'),
-    ),
-));
+if (function_exists('pcntl_async_signals')) {
+  pcntl_async_signals(true);
+} else {
+  declare(ticks = 1);
+}
+
+require_once dirname(dirname(__FILE__)).'/scripts/init/init-arcanist.php';
+
+$runtime = new ArcanistRuntime();
+return $runtime->execute($argv);
+
 
 $config_trace_mode = $base_args->getArg('trace');
 
 $force_conduit = $base_args->getArg('conduit-uri');
 $force_token = $base_args->getArg('conduit-token');
-$force_conduit_version = $base_args->getArg('conduit-version');
-$conduit_timeout = $base_args->getArg('conduit-timeout');
-$skip_arcconfig = $base_args->getArg('skip-arcconfig');
-$custom_arcrc = $base_args->getArg('arcrc-file');
 $is_anonymous = $base_args->getArg('anonymous');
 $load = $base_args->getArg('load-phutil-library');
 $help = $base_args->getArg('help');
 $args = array_values($base_args->getUnconsumedArgumentVector());
 
-$working_directory = getcwd();
 $console = PhutilConsole::getConsole();
 $config = null;
 $workflow = null;
 
 try {
-  if ($config_trace_mode) {
-    echo tsprintf(
-      "**<bg:magenta> %s </bg>** %s\n",
-      pht('ARGV'),
-      csprintf('%Ls', $original_argv));
-
-    $libraries = array(
-      'phutil',
-      'arcanist',
-    );
-
-    foreach ($libraries as $library_name) {
-      echo tsprintf(
-        "**<bg:magenta> %s </bg>** %s\n",
-        pht('LOAD'),
-        pht(
-          'Loaded "%s" from "%s".',
-          $library_name,
-          phutil_get_library_root($library_name)));
-    }
-  }
-
-  if (!$args) {
-    if ($help) {
-      $args = array('help');
-    } else {
-      throw new ArcanistUsageException(
-        pht('No command provided. Try `%s`.', 'arc help'));
-    }
-  } else if ($help) {
-    array_unshift($args, 'help');
-  }
-
-  $configuration_manager = new ArcanistConfigurationManager();
-  if ($custom_arcrc) {
-    $configuration_manager->setUserConfigurationFileLocation($custom_arcrc);
-  }
-
-  $global_config = $configuration_manager->readUserArcConfig();
-  $system_config = $configuration_manager->readSystemArcConfig();
-  $runtime_config = $configuration_manager->applyRuntimeArcConfig($base_args);
-
-  if ($skip_arcconfig) {
-    $working_copy = ArcanistWorkingCopyIdentity::newDummyWorkingCopy();
-  } else {
-    $working_copy =
-      ArcanistWorkingCopyIdentity::newFromPath($working_directory);
-  }
-  $configuration_manager->setWorkingCopyIdentity($working_copy);
-
-  // Load additional libraries, which can provide new classes like configuration
-  // overrides, linters and lint engines, unit test engines, etc.
-
-  // If the user specified "--load-phutil-library" one or more times from
-  // the command line, we load those libraries **instead** of whatever else
-  // is configured. This is basically a debugging feature to let you force
-  // specific libraries to load regardless of the state of the world.
-  if ($load) {
-    $console->writeLog(
-      "%s\n",
-      pht(
-        'Using `%s` flag, configuration will be ignored and configured '.
-        'libraries will not be loaded.',
-        '--load-phutil-library'));
-    // Load the flag libraries. These must load, since the user specified them
-    // explicitly.
-    arcanist_load_libraries(
-      $load,
-      $must_load = true,
-      $lib_source = pht('a "%s" flag', '--load-phutil-library'),
-      $working_copy);
-  } else {
-    // Load libraries in system 'load' config. In contrast to global config, we
-    // fail hard here because this file is edited manually, so if 'arc' breaks
-    // that doesn't make it any more difficult to correct.
-    arcanist_load_libraries(
-      idx($system_config, 'load', array()),
-      $must_load = true,
-      $lib_source = pht('the "%s" setting in system config', 'load'),
-      $working_copy);
-
-    // Load libraries in global 'load' config, as per "arc set-config load". We
-    // need to fail softly if these break because errors would prevent the user
-    // from running "arc set-config" to correct them.
-    arcanist_load_libraries(
-      idx($global_config, 'load', array()),
-      $must_load = false,
-      $lib_source = pht('the "%s" setting in global config', 'load'),
-      $working_copy);
-
-    // Load libraries in ".arcconfig". Libraries here must load.
-    arcanist_load_libraries(
-      $working_copy->getProjectConfig('load'),
-      $must_load = true,
-      $lib_source = pht('the "%s" setting in "%s"', 'load', '.arcconfig'),
-      $working_copy);
-
-    // Load libraries in ".arcconfig". Libraries here must load.
-    arcanist_load_libraries(
-      idx($runtime_config, 'load', array()),
-      $must_load = true,
-      $lib_source = pht('the %s argument', '--config "load=[...]"'),
-      $working_copy);
-  }
-
-  $user_config = $configuration_manager->readUserConfigurationFile();
-
-  $config_class = $working_copy->getProjectConfig('arcanist_configuration');
-  if ($config_class) {
-    $config = new $config_class();
-  } else {
-    $config = new ArcanistConfiguration();
-  }
 
   $command = strtolower($args[0]);
   $args = array_slice($args, 1);
@@ -211,13 +46,6 @@
   // their behaviors.
   putenv('ARCANIST='.$command);
 
-  if ($force_conduit_version) {
-    $workflow->forceConduitVersion($force_conduit_version);
-  }
-  if ($conduit_timeout) {
-    $workflow->setConduitTimeout($conduit_timeout);
-  }
-
   $need_working_copy = $workflow->requiresWorkingCopy();
 
   $supported_vcs_types = $workflow->getSupportedRevisionControlSystems();
@@ -353,10 +181,6 @@
     ->setBasicAuthUser($basic_user)
     ->setBasicAuthPass($basic_pass);
 
-  if ($conduit_timeout) {
-    $engine->setConduitTimeout($conduit_timeout);
-  }
-
   $workflow->setConduitEngine($engine);
 
   if ($need_auth) {
@@ -470,230 +294,6 @@
 }
 
 
-/**
- * Perform some sanity checks against the possible diversity of PHP builds in
- * the wild, like very old versions and builds that were compiled with flags
- * that exclude core functionality.
- */
-function sanity_check_environment() {
-  // NOTE: We don't have phutil_is_windows() yet here.
-  $is_windows = (DIRECTORY_SEPARATOR != '/');
-
-  // We use stream_socket_pair() which is not available on Windows earlier.
-  $min_version = ($is_windows ? '5.3.0' : '5.2.3');
-  $cur_version = phpversion();
-  if (version_compare($cur_version, $min_version, '<')) {
-    die_with_bad_php(
-      "You are running PHP version '{$cur_version}', which is older than ".
-      "the minimum version, '{$min_version}'. Update to at least ".
-      "'{$min_version}'.");
-  }
-
-  if ($is_windows) {
-    $need_functions = array(
-      'curl_init'     => array('builtin-dll', 'php_curl.dll'),
-    );
-  } else {
-    $need_functions = array(
-      'curl_init'     => array(
-        'text',
-        "You need to install the cURL PHP extension, maybe with ".
-        "'apt-get install php5-curl' or 'yum install php53-curl' or ".
-        "something similar.",
-      ),
-      'json_decode'   => array('flag', '--without-json'),
-    );
-  }
-
-  $problems = array();
-
-  $config = null;
-  $show_config = false;
-  foreach ($need_functions as $fname => $resolution) {
-    if (function_exists($fname)) {
-      continue;
-    }
-
-    static $info;
-    if ($info === null) {
-      ob_start();
-      phpinfo(INFO_GENERAL);
-      $info = ob_get_clean();
-      $matches = null;
-      if (preg_match('/^Configure Command =>\s*(.*?)$/m', $info, $matches)) {
-        $config = $matches[1];
-      }
-    }
-
-    $generic = true;
-    list($what, $which) = $resolution;
-
-    if ($what == 'flag' && strpos($config, $which) !== false) {
-      $show_config = true;
-      $generic = false;
-      $problems[] =
-        "This build of PHP was compiled with the configure flag '{$which}', ".
-        "which means it does not have the function '{$fname}()'. This ".
-        "function is required for arc to run. Rebuild PHP without this flag. ".
-        "You may also be able to build or install the relevant extension ".
-        "separately.";
-    }
-
-    if ($what == 'builtin-dll') {
-      $generic = false;
-      $problems[] =
-        "Your install of PHP does not have the '{$which}' extension enabled. ".
-        "Edit your php.ini file and uncomment the line which reads ".
-        "'extension={$which}'.";
-    }
-
-    if ($what == 'text') {
-      $generic = false;
-      $problems[] = $which;
-    }
-
-    if ($generic) {
-      $problems[] =
-        "This build of PHP is missing the required function '{$fname}()'. ".
-        "Rebuild PHP or install the extension which provides '{$fname}()'.";
-    }
-  }
-
-  if ($problems) {
-    if ($show_config) {
-      $problems[] = "PHP was built with this configure command:\n\n{$config}";
-    }
-    die_with_bad_php(implode("\n\n", $problems));
-  }
-}
-
-function die_with_bad_php($message) {
-  // NOTE: We're bailing because PHP is broken. We can't call any library
-  // functions because they won't be loaded yet.
-
-  echo "\n";
-  echo 'PHP CONFIGURATION ERRORS';
-  echo "\n\n";
-  echo $message;
-  echo "\n\n";
-  exit(1);
-}
-
-function arcanist_load_libraries(
-  $load,
-  $must_load,
-  $lib_source,
-  ArcanistWorkingCopyIdentity $working_copy) {
-
-  if (!$load) {
-    return;
-  }
 
-  if (!is_array($load)) {
-    $error = pht(
-      'Libraries specified by %s are invalid; expected a list. '.
-      'Check your configuration.',
-      $lib_source);
-    $console = PhutilConsole::getConsole();
-    $console->writeErr("%s: %s\n", pht('WARNING'), $error);
-    return;
-  }
-
-  foreach ($load as $location) {
-
-    // Try to resolve the library location. We look in several places, in
-    // order:
-    //
-    //  1. Inside the working copy. This is for phutil libraries within the
-    //     project. For instance "library/src" will resolve to
-    //     "./library/src" if it exists.
-    //  2. In the same directory as the working copy. This allows you to
-    //     check out a library alongside a working copy and reference it.
-    //     If we haven't resolved yet, "library/src" will try to resolve to
-    //     "../library/src" if it exists.
-    //  3. Using normal libphutil resolution rules. Generally, this means
-    //     that it checks for libraries next to libphutil, then libraries
-    //     in the PHP include_path.
-    //
-    // Note that absolute paths will just resolve absolutely through rule (1).
-
-    $resolved = false;
-
-    // Check inside the working copy. This also checks absolute paths, since
-    // they'll resolve absolute and just ignore the project root.
-    $resolved_location = Filesystem::resolvePath(
-      $location,
-      $working_copy->getProjectRoot());
-    if (Filesystem::pathExists($resolved_location)) {
-      $location = $resolved_location;
-      $resolved = true;
-    }
 
-    // If we didn't find anything, check alongside the working copy.
-    if (!$resolved) {
-      $resolved_location = Filesystem::resolvePath(
-        $location,
-        dirname($working_copy->getProjectRoot()));
-      if (Filesystem::pathExists($resolved_location)) {
-        $location = $resolved_location;
-        $resolved = true;
-      }
-    }
 
-    $console = PhutilConsole::getConsole();
-    $console->writeLog(
-      "%s\n",
-      pht("Loading phutil library from '%s'...", $location));
-
-    $error = null;
-    try {
-      phutil_load_library($location);
-    } catch (PhutilBootloaderException $ex) {
-      $error = pht(
-        "Failed to load phutil library at location '%s'. This library ".
-        "is specified by %s. Check that the setting is correct and the ".
-        "library is located in the right place.",
-        $location,
-        $lib_source);
-      if ($must_load) {
-        throw new ArcanistUsageException($error);
-      } else {
-        fwrite(STDERR, phutil_console_wrap(
-          phutil_console_format("%s: %s\n",
-                                pht('WARNING'),
-                                $error)));
-      }
-    } catch (PhutilLibraryConflictException $ex) {
-      if ($ex->getLibrary() != 'arcanist') {
-        throw $ex;
-      }
-
-      // NOTE: If you are running `arc` against itself, we ignore the library
-      // conflict created by loading the local `arc` library (in the current
-      // working directory) and continue without loading it.
-
-      // This means we only execute code in the `arcanist/` directory which is
-      // associated with the binary you are running, whereas we would normally
-      // execute local code.
-
-      // This can make `arc` development slightly confusing if your setup is
-      // especially bizarre, but it allows `arc` to be used in automation
-      // workflows more easily. For some context, see PHI13.
-
-      $executing_directory = dirname(dirname(__FILE__));
-      $working_directory = dirname($location);
-
-      fwrite(
-        STDERR,
-        tsprintf(
-          "**<bg:yellow> %s </bg>** %s\n",
-          pht('VERY META'),
-          pht(
-            'You are running one copy of Arcanist (at path "%s") against '.
-            'another copy of Arcanist (at path "%s"). Code in the current '.
-            'working directory will not be loaded or executed.',
-            $executing_directory,
-            $working_directory)));
-    }
-  }
-}
diff --git a/scripts/init/init-arcanist.php b/scripts/init/init-arcanist.php
new file mode 100644
--- /dev/null
+++ b/scripts/init/init-arcanist.php
@@ -0,0 +1,578 @@
+<?php
+
+final class ArcanistRuntime {
+
+  public function execute(array $argv) {
+    $err = $this->checkEnvironment();
+    if ($err) {
+      return $err;
+    }
+
+    $err = $this->includeCoreLibraries();
+    if ($err) {
+      return $err;
+    }
+
+    PhutilTranslator::getInstance()
+      ->setLocale(PhutilLocale::loadLocale('en_US'))
+      ->setTranslations(PhutilTranslation::getTranslationMapForLocale('en_US'));
+
+    ini_set('memory_limit', -1);
+
+    try {
+      return $this->executeCore($argv);
+    } catch (PhutilArgumentUsageException $ex) {
+      fwrite(
+        STDERR,
+        tsprintf(
+          "**%s:** %s\n",
+          pht('Usage Exception'),
+          $ex->getMessage()));
+      return 77;
+    }
+  }
+
+  private function executeCore(array $argv) {
+    $config_args = array(
+      array(
+        'name' => 'load-phutil-library',
+        'param' => 'path',
+        'help' => pht('Load a libphutil library.'),
+        'repeat' => true,
+      ),
+      array(
+        'name' => 'config',
+        'param' => 'key=value',
+        'repeat' => true,
+        'help' => pht('Specify a runtime configuration value.'),
+      ),
+    );
+
+    $args = id(new PhutilArgumentParser($argv))
+      ->parseStandardArguments();
+
+    $is_trace = $args->getArg('trace');
+    if ($is_trace) {
+      $this->logTrace(pht('ARGV'), csprintf('%Ls', $argv));
+    }
+
+    $args->parsePartial($config_args, true);
+
+    $config = $this->loadConfiguration($args);
+
+    $this->loadLibraries($args, $config);
+
+    $toolset = $this->newToolset($argv);
+
+    $args->parsePartial($toolset->getToolsetArguments());
+
+    $workflows = $this->newWorkflows($toolset);
+
+    $phutil_workflows = array();
+    foreach ($workflows as $key => $workflow) {
+      $phutil_workflows[$key] = $workflow->newPhutilWorkflow();
+    }
+
+    $unconsumed_argv = $args->getUnconsumedArgumentVector();
+
+    $result = $this->resolveAliases($workflows, $unconsumed_argv, $config);
+    if (is_int($result)) {
+      return $result;
+    }
+
+    $args->setUnconsumedArgumentVector($result);
+
+    return $args->parseWorkflows($phutil_workflows);
+  }
+
+
+  /**
+   * Perform some sanity checks against the possible diversity of PHP builds in
+   * the wild, like very old versions and builds that were compiled with flags
+   * that exclude core functionality.
+   */
+  private function checkEnvironment() {
+    // NOTE: We don't have phutil_is_windows() yet here.
+    $is_windows = (DIRECTORY_SEPARATOR != '/');
+
+    // We use stream_socket_pair() which is not available on Windows earlier.
+    $min_version = ($is_windows ? '5.3.0' : '5.2.3');
+    $cur_version = phpversion();
+    if (version_compare($cur_version, $min_version, '<')) {
+      $message = sprintf(
+        'You are running a version of PHP ("%s"), which is older than the '.
+        'minimum supported version ("%s"). Update PHP to continue.',
+        $cur_version,
+        $min_version);
+      return $this->fatalError($message);
+    }
+
+    if ($is_windows) {
+      $need_functions = array(
+        'curl_init'     => array('builtin-dll', 'php_curl.dll'),
+      );
+    } else {
+      $need_functions = array(
+        'curl_init'     => array(
+          'text',
+          "You need to install the cURL PHP extension, maybe with ".
+          "'apt-get install php5-curl' or 'yum install php53-curl' or ".
+          "something similar.",
+        ),
+        'json_decode'   => array('flag', '--without-json'),
+      );
+    }
+
+    $problems = array();
+
+    $config = null;
+    $show_config = false;
+    foreach ($need_functions as $fname => $resolution) {
+      if (function_exists($fname)) {
+        continue;
+      }
+
+      static $info;
+      if ($info === null) {
+        ob_start();
+        phpinfo(INFO_GENERAL);
+        $info = ob_get_clean();
+        $matches = null;
+        if (preg_match('/^Configure Command =>\s*(.*?)$/m', $info, $matches)) {
+          $config = $matches[1];
+        }
+      }
+
+      list($what, $which) = $resolution;
+
+      if ($what == 'flag' && strpos($config, $which) !== false) {
+        $show_config = true;
+        $problems[] = sprintf(
+          'The build of PHP you are running was compiled with the configure '.
+          'flag "%s", which means it does not support the function "%s()". '.
+          'This function is required for Arcanist to run. Install a standard '.
+          'build of PHP or rebuild it without this flag. You may also be '.
+          'able to build or install the relevant extension separately.',
+          $which,
+          $fname);
+        continue;
+      }
+
+      if ($what == 'builtin-dll') {
+        $problems[] = sprintf(
+          'The build of PHP you are running does not have the "%s" extension '.
+          'enabled. Edit your php.ini file and uncomment the line which '.
+          'reads "extension=%s".',
+          $which,
+          $which);
+        continue;
+      }
+
+      if ($what == 'text') {
+        $problems[] = $which;
+        continue;
+      }
+
+      $problems[] = sprintf(
+        'The build of PHP you are running is missing the required function '.
+        '"%s()". Rebuild PHP or install the extension which provides "%s()".',
+        $fname,
+        $fname);
+    }
+
+    if ($problems) {
+      if ($show_config) {
+        $problems[] = "PHP was built with this configure command:\n\n{$config}";
+      }
+      $problems = implode("\n\n", $problems);
+      return $this->fatalError($problems);
+    }
+
+    return 0;
+  }
+
+  private function fatalError($message) {
+    echo "CONFIGURATION ERROR\n\n";
+    echo $message;
+    echo "\n\n";
+    return 1;
+  }
+
+  private function includeCoreLibraries() {
+    // Adjust 'include_path' to add locations where we'll search for libphutil.
+    // We look in these places:
+    //
+    //  - Next to 'arcanist/'.
+    //  - Anywhere in the normal PHP 'include_path'.
+    //  - Inside 'arcanist/externals/includes/'.
+    //
+    // When looking in these places, we expect to find a 'libphutil/' directory.
+
+    // The 'arcanist/' directory.
+    $arcanist_dir = dirname(dirname(dirname(__FILE__)));
+
+    // The parent directory of 'arcanist/'.
+    $parent_dir = dirname($arcanist_dir);
+
+    // The 'arcanist/externals/includes/' directory.
+    $include_dir = implode(
+      DIRECTORY_SEPARATOR,
+      array(
+        $arcanist_dir,
+        'externals',
+        'includes',
+      ));
+
+    $php_include_path = ini_get('include_path');
+    $php_include_path = implode(
+      PATH_SEPARATOR,
+      array(
+        $parent_dir,
+        $php_include_path,
+        $include_dir,
+      ));
+
+    ini_set('include_path', $php_include_path);
+
+    // Load libphutil.
+    @include_once 'libphutil/scripts/__init_script__.php';
+
+    if (!@constant('__LIBPHUTIL__')) {
+      return $this->fatalError(
+        'Unable to load libphutil. Put "libphutil/" next to "arcanist/"; '.
+        'or update your PHP "include_path" to include the parent directory '.
+        'of "libphutil/"; or symlink "libphutil" into '.
+        '"arcanist/externals/includes/".');
+    }
+
+    // Load Arcanist.
+    phutil_load_library($arcanist_dir.'/src/');
+
+    return 0;
+  }
+
+  private function loadConfiguration(PhutilArgumentParser $args) {
+    $configuration_manager = new ArcanistConfigurationManager();
+
+    $cwd = getcwd();
+    $working_copy = ArcanistWorkingCopyIdentity::newFromPath($cwd);
+    $configuration_manager->setWorkingCopyIdentity($working_copy);
+
+    $configuration_manager->applyRuntimeArcConfig($args);
+
+    return $configuration_manager;
+  }
+
+  private function loadLibraries(
+    PhutilArgumentParser $args,
+    ArcanistConfigurationManager $config) {
+
+    $is_trace = $args->getArg('trace');
+
+    if ($is_trace) {
+      $libraries = array(
+        'phutil',
+        'arcanist',
+      );
+
+      foreach ($libraries as $library_name) {
+        $this->logTrace(
+          pht('LOAD'),
+          pht(
+            'Loaded "%s" from "%s".',
+            $library_name,
+            phutil_get_library_root($library_name)));
+      }
+    }
+
+    $load = array();
+    $working_copy = $config->getWorkingCopyIdentity();
+
+    $cli_libraries = $args->getArg('load-phutil-library');
+    if ($cli_libraries) {
+      $load[] = array(
+        '--load-phutil-library',
+        $cli_libraries,
+      );
+    } else {
+      $system_config = $config->readSystemArcConfig();
+      $load[] = array(
+        $config->getSystemArcConfigLocation(),
+        idx($system_config, 'load', array()),
+      );
+
+      $global_config = $config->readUserArcConfig();
+      $load[] = array(
+        $config->getUserConfigurationFileLocation(),
+        idx($global_config, 'load', array()),
+      );
+
+      $load[] = array(
+        '.arcconfig',
+        $working_copy->getProjectConfig('load'),
+      );
+
+      $load[] = array(
+        // TODO: We could explain exactly where this is coming from more
+        // clearly.
+        './.../arc/config',
+        $working_copy->getLocalConfig('load'),
+      );
+
+      $load[] = array(
+        '--config load=...',
+        $config->getRuntimeConfig('load', array()),
+      );
+    }
+
+    foreach ($load as $spec) {
+      list($source, $libraries) = $spec;
+      if ($is_trace) {
+        $this->logTrace(
+          pht('LOAD'),
+          pht(
+            'Loading libraries from "%s"...',
+            $source));
+      }
+
+      if (!$libraries) {
+        if ($is_trace) {
+          $this->logTrace(pht('NONE'), pht('Nothing to load.'));
+        }
+        continue;
+      }
+
+      if (!is_array($libraries)) {
+        throw new PhutilArgumentUsageException(
+          pht(
+            'Libraries specified by "%s" are not formatted correctly. '.
+            'Expected a list of paths. Check your configuration.',
+            $source));
+      }
+
+      foreach ($libraries as $library) {
+        $this->loadLibrary($source, $library, $working_copy, $is_trace);
+      }
+    }
+  }
+
+  private function loadLibrary(
+    $source,
+    $location,
+    ArcanistWorkingCopyIdentity $working_copy,
+    $is_trace) {
+
+    // Try to resolve the library location. We look in several places, in
+    // order:
+    //
+    //  1. Inside the working copy. This is for phutil libraries within the
+    //     project. For instance "library/src" will resolve to
+    //     "./library/src" if it exists.
+    //  2. In the same directory as the working copy. This allows you to
+    //     check out a library alongside a working copy and reference it.
+    //     If we haven't resolved yet, "library/src" will try to resolve to
+    //     "../library/src" if it exists.
+    //  3. Using normal libphutil resolution rules. Generally, this means
+    //     that it checks for libraries next to libphutil, then libraries
+    //     in the PHP include_path.
+    //
+    // Note that absolute paths will just resolve absolutely through rule (1).
+
+    $resolved = false;
+
+    // Check inside the working copy. This also checks absolute paths, since
+    // they'll resolve absolute and just ignore the project root.
+    $resolved_location = Filesystem::resolvePath(
+      $location,
+      $working_copy->getProjectRoot());
+    if (Filesystem::pathExists($resolved_location)) {
+      $location = $resolved_location;
+      $resolved = true;
+    }
+
+    // If we didn't find anything, check alongside the working copy.
+    if (!$resolved) {
+      $resolved_location = Filesystem::resolvePath(
+        $location,
+        dirname($working_copy->getProjectRoot()));
+      if (Filesystem::pathExists($resolved_location)) {
+        $location = $resolved_location;
+        $resolved = true;
+      }
+    }
+
+    if ($is_trace) {
+      $this->logTrace(
+        pht('LOAD'),
+        pht('Loading phutil library from "%s"...', $location));
+    }
+
+    $error = null;
+    try {
+      phutil_load_library($location);
+    } catch (PhutilBootloaderException $ex) {
+      fwrite(
+        STDERR,
+        "%s",
+        tsprintf(
+          "**<bg:red> %s </bg>** %s\n",
+          pht(
+            'Failed to load phutil library at location "%s". This library '.
+            'is specified by "%s". Check that the setting is correct and '.
+            'the library is located in the right place.',
+            $location,
+            $source)));
+
+      $prompt = pht('Continue without loading library?');
+      if (!phutil_console_confirm($prompt)) {
+        throw $ex;
+      }
+    } catch (PhutilLibraryConflictException $ex) {
+      if ($ex->getLibrary() != 'arcanist') {
+        throw $ex;
+      }
+
+      // NOTE: If you are running `arc` against itself, we ignore the library
+      // conflict created by loading the local `arc` library (in the current
+      // working directory) and continue without loading it.
+
+      // This means we only execute code in the `arcanist/` directory which is
+      // associated with the binary you are running, whereas we would normally
+      // execute local code.
+
+      // This can make `arc` development slightly confusing if your setup is
+      // especially bizarre, but it allows `arc` to be used in automation
+      // workflows more easily. For some context, see PHI13.
+
+      $executing_directory = dirname(dirname(__FILE__));
+      $working_directory = dirname($location);
+
+      fwrite(
+        STDERR,
+        tsprintf(
+          "**<bg:yellow> %s </bg>** %s\n",
+          pht('VERY META'),
+          pht(
+            'You are running one copy of Arcanist (at path "%s") against '.
+            'another copy of Arcanist (at path "%s"). Code in the current '.
+            'working directory will not be loaded or executed.',
+            $executing_directory,
+            $working_directory)));
+    }
+  }
+
+  private function newToolset(array $argv) {
+    $binary = basename($argv[0]);
+
+    $toolsets = ArcanistToolset::newToolsetMap();
+    if (!isset($toolsets[$binary])) {
+      throw new PhutilArgumentUsageException(
+        pht(
+          'Arcanist toolset "%s" is unknown. The Arcanist binary should '.
+          'be executed so that "argv[0]" identifies a supported toolset. '.
+          'Rename the binary or install the library that provides the '.
+          'desired toolset. Current available toolsets: %s.',
+          $binary,
+          implode(', ', array_keys($toolsets))));
+    }
+
+    return $toolsets[$binary];
+  }
+
+  private function newWorkflows(ArcanistToolset $toolset) {
+    $workflows = id(new PhutilClassMapQuery())
+      ->setAncestorClass('ArcanistWorkflow')
+      ->execute();
+
+    foreach ($workflows as $key => $workflow) {
+      if (!$workflow->supportsToolset($toolset)) {
+        unset($workflows[$key]);
+      }
+    }
+
+    $map = array();
+    foreach ($workflows as $workflow) {
+      $key = $workflow->getWorkflowName();
+      if (isset($map[$key])) {
+        throw new Exception(
+          pht(
+            'Two workflows ("%s" and "%s") both have the same name ("%s") '.
+            'and both support the current toolset ("%s", "%s"). Each '.
+            'workflow in a given toolset must have a unique name.',
+            get_class($workflow),
+            get_class($map[$key]),
+            get_class($toolset),
+            $toolset->getToolsetKey()));
+      }
+      $map[$key] = id(clone $workflow)
+        ->setToolset($toolset);
+    }
+
+    return $map;
+  }
+
+  private function resolveAliases(
+    array $workflows,
+    array $argv,
+    ArcanistConfigurationManager $config) {
+
+    $command = head($argv);
+
+    // If this is a match for a recognized workflow, just return the arguments
+    // unmodified. You aren't allowed to alias over real workflows.
+    if (isset($workflows[$command])) {
+      return $argv;
+    }
+
+    $aliases = ArcanistAliasWorkflow::getAliases($config);
+    list($new_command, $new_args) = ArcanistAliasWorkflow::resolveAliases(
+      $command,
+      $this,
+      array_slice($argv, 1),
+      $config);
+
+    // You can't alias something to itself, so if the new command isn't new,
+    // we're all done resolving aliases.
+    if ($new_command === $command) {
+      return $argv;
+    }
+
+    $full_alias = idx($aliases, $command, array());
+    $full_alias = implode(' ', $full_alias);
+
+    // Run shell command aliases.
+    if (ArcanistAliasWorkflow::isShellCommandAlias($new_command)) {
+      fwrite(
+        STDERR,
+        tsprintf(
+          '**<bg:green> %s </bg>** arc %s -> $ %s',
+          pht('ALIAS'),
+          $command,
+          $shell_cmd));
+
+      $shell_cmd = substr($full_alias, 1);
+
+      return phutil_passthru('%C %Ls', $shell_cmd, $args);
+    }
+
+    fwrite(
+      STDERR,
+      tsprintf(
+        '**<bg:green> %s </bg>** arc %s -> arc %s',
+        pht('ALIAS'),
+        $command,
+        $new_command));
+
+    $new_argv = array_merge(array($new_command), $new_args);
+
+    return $this->resolveAliases($workflows, $new_argv, $config);
+  }
+
+  private function logTrace($label, $message) {
+    echo tsprintf(
+      "**<bg:magenta> %s </bg>** %s\n",
+      $label,
+      $message);
+  }
+
+}
diff --git a/scripts/phage.php b/scripts/phage.php
deleted file mode 100755
--- a/scripts/phage.php
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/usr/bin/env php
-<?php
-
-require_once dirname(__FILE__).'/__init_script__.php';
-ini_set('memory_limit', -1);
-
-$args = new PhutilArgumentParser($argv);
-$args->parseStandardArguments();
-
-$args->parsePartial(array());
-
-
-// TODO: This is pretty minimal and should be shared with "arc".
-$working_directory = getcwd();
-$working_copy = ArcanistWorkingCopyIdentity::newFromPath($working_directory);
-$config = id(new ArcanistConfigurationManager())
-  ->setWorkingCopyIdentity($working_copy);
-
-foreach ($config->getProjectConfig('load') as $load) {
-  $load = Filesystem::resolvePath($working_copy->getProjectRoot().'/'.$load);
-  phutil_load_library($load);
-}
-
-
-$workflows = id(new PhutilClassMapQuery())
-  ->setAncestorClass('PhageWorkflow')
-  ->execute();
-$workflows[] = new PhutilHelpArgumentWorkflow();
-$args->parseWorkflows($workflows);