diff --git a/.github_changelog_generator b/.github_changelog_generator
index f9d85e795..13de87762 100644
--- a/.github_changelog_generator
+++ b/.github_changelog_generator
@@ -1,5 +1,3 @@
 project=blt
 unreleased-only=true
-future-release=8.6.10
 pr-label=**Misc merged pull requests**
-output=temp-changelog.md
diff --git a/.gitignore b/.gitignore
index b2445d8c2..eae3f46b9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -61,8 +61,27 @@ local.properties
 auto-save-list
 tramp
 .\#*
-temp*
 
+template/docroot/.csslintrc
+template/docroot/.editorconfig
+template/docroot/.eslintignore
+template/docroot/.eslintrc
+template/docroot/.eslintrc.json
+template/docroot/.gitattributes
+template/docroot/.htaccess
+template/docroot/index.php
+template/docroot/robots.txt
+template/docroot/sites/default/default.settings.php
+template/docroot/sites/default/services.yml
+template/docroot/sites/default/settings.php
+template/docroot/sites/default/default.services.yml
+template/docroot/sites/development.services.yml
+template/docroot/sites/example.settings.local.php
+template/docroot/sites/example.sites.php
+template/docroot/update.php
+template/docroot/web.config
+
+# PHPStorm
 .idea
 
 #XHProf
@@ -89,3 +108,5 @@ nbproject/*
 # generates, so they must be specified here rather than in template/.gitignore.
 template/.idea/.name
 template/composer.lock
+
+CHANGELOG.partial
diff --git a/RELEASE.md b/RELEASE.md
index ab4336e66..cc57e5ddf 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -1,8 +1,14 @@
 This document outlines the process for creating a new BLT release.
 
-# Testing
+To perform a release:
 
-## Prerequisites
+1. [Run tests](#testing) locally..
+1. [Generate and commit updated CHANGELOG.md](#generate-changelogmd).
+1. [Create a release](#create-a-release)
+
+## Testing
+
+### Prerequisites
 
 In order to use these testing instructions:
 
@@ -11,67 +17,10 @@ In order to use these testing instructions:
 * MySQL must use `mysql://drupal:drupal@localhost/drupal:3306`. If this is not the case, modify the instructions below for your credentials.
 * In order to test Drupal VM, you must install VirtualBox and Vagrant. See [Drupal VM](https://github.com/geerlingguy/drupal-vm#quick-start-guide) for more information.
 
-## Procedure
-
-1. Test "Create a new project without acquia/blt-project "from scratch", uses Drupal VM".
-1. Test "Update existing project Pipelines project".
-
-## Create a new project via acquia/blt-project, uses local LAMP stack
-
-This test verifies that a new project can be created using `acquia/blt-project` via composer. This also tests the `blt update` process.
-
-    export COMPOSER_PROCESS_TIMEOUT=2000
-    rm -rf blted8
-    composer create-project acquia/blt-project:8.x-dev blted8 --no-interaction
-    cd blted8
-    # Overwrite MySQL creds for your local machine, if necessary.
-    # echo '$databases["default"]["default"]["username"] = "drupal";' >> docroot/sites/default/settings/local.settings.php
-    # echo '$databases["default"]["default"]["password"] = "drupal";' >> docroot/sites/default/settings/local.settings.php
-    blt local:setup
-    cd docroot
-    drush uli
-    read -p "Press any key to continue"
-
-    # This updates to the latest dev version.
-    composer require acquia/blt:8.x-dev
-    dr uli
-    read -p "Press any key to continue"
-    cd ../
-
-## Create a new project without acquia/blt-project "from scratch", uses Drupal VM
-
-This test verifies that a new project can be created from scratch using blt, without blt-project. It also tests Drupal VM integration.
-
-    rm -rf blted8
-    mkdir blted8
-    cd blted8
-    git init
-    composer init --stability=dev --no-interaction
-    composer config prefer-stable true
-    composer require acquia/blt:8.x-dev
-    composer update
-    blt vm
-    blt local:setup
-    drush @blted8.local uli
-    drush @blted8.local ssh blt tests:behat
-    read -p "Press any key to continue"
-    vagrant destroy
-    cd ../
-
-
-## Update existing project Pipelines project
-
-    composer require acquia/blt:8.x-dev --no-update
-    composer update
-    git add -A
-    git commit -m 'Updating acquia/blt to latest dev version.'
-    git push origin
-    pipelines start
-    pipelines log
-    # Replace with remote alias
-    drush @alias ssh blt setup:drupal:install
-    
+### Execute tests
 
+    ./scripts/blt/test-blt.sh [tag]
+ 
 ## Generate CHANGELOG.md
 
 ### Prerequisites
@@ -81,9 +30,14 @@ This test verifies that a new project can be created from scratch using blt, wit
 * Procure a [github api token](https://github.com/skywinder/github-changelog-generator#github-token).
 * Determine the version of your future release.
 
+### Execute command
+
 Then, generate your release notes via:
 
-    github_changelog_generator --token [token] --future-release=[version]
+    ./bin/blt-robo blt:release-notes [tag] [token]
 
 This will update CHANGELOG.md. The information for the new release should be copied and pasted into the GitHub release draft.
 
+## Create a release
+
+    ./bin/blt-robo blt:release [tag] [token]
diff --git a/bin/blt-robo b/bin/blt-robo
new file mode 100755
index 000000000..e8bcfb2a6
--- /dev/null
+++ b/bin/blt-robo
@@ -0,0 +1,28 @@
+#!/usr/bin/env php
+<?php
+
+/**
+ * If we're running from phar load the phar autoload file.
+ */
+$pharPath = \Phar::running(true);
+$consoleRoot = __DIR__ . '/../';
+if ($pharPath) {
+    require_once "$pharPath/vendor/autoload.php";
+} else {
+    if (file_exists($consoleRoot.'/vendor/autoload.php')) {
+        require_once $consoleRoot.'/vendor/autoload.php';
+    } elseif (file_exists(__DIR__.'/../../autoload.php')) {
+        require_once __DIR__ . '/../../autoload.php';
+    }
+}
+
+$commandClasses = [
+  \Acquia\Blt\Robo\Command\BltInternal::class,
+];
+$statusCode = \Robo\Robo::run(
+  $_SERVER['argv'],
+  $commandClasses,
+  'BLT',
+  '0.0.0-alpha0'
+);
+exit($statusCode);
diff --git a/composer.json b/composer.json
index 24993ad13..f95a48ef4 100644
--- a/composer.json
+++ b/composer.json
@@ -51,5 +51,9 @@
         "hirak/prestissimo": "^0.3"
     },
     "minimum-stability": "dev",
-    "prefer-stable": true
+    "prefer-stable": true,
+    "require-dev": {
+        "consolidation/Robo": "^1.0",
+        "guzzlehttp/guzzle": "^6.2"
+    }
 }
diff --git a/composer.lock b/composer.lock
index e59f23f43..086d9fb17 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
         "This file is @generated automatically"
     ],
-    "content-hash": "2134cd5cc4e949518b3f30dad456afc2",
+    "content-hash": "333c417335586053fe47c4ecaba79f81",
     "packages": [
         {
             "name": "alchemy/zippy",
@@ -4312,7 +4312,324 @@
             "time": "2016-11-23T20:04:58+00:00"
         }
     ],
-    "packages-dev": [],
+    "packages-dev": [
+        {
+            "name": "consolidation/annotated-command",
+            "version": "2.2.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/consolidation/annotated-command.git",
+                "reference": "1f1d92807f72901e049e9df048b412c3bc3652c9"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/consolidation/annotated-command/zipball/1f1d92807f72901e049e9df048b412c3bc3652c9",
+                "reference": "1f1d92807f72901e049e9df048b412c3bc3652c9",
+                "shasum": ""
+            },
+            "require": {
+                "consolidation/output-formatters": "^3.1.5",
+                "php": ">=5.4.0",
+                "phpdocumentor/reflection-docblock": "^2.0|^3.0.2",
+                "psr/log": "~1",
+                "symfony/console": "^2.8|~3",
+                "symfony/event-dispatcher": "^2.5|~3",
+                "symfony/finder": "^2.5|~3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "4.*",
+                "satooshi/php-coveralls": "^1.0",
+                "squizlabs/php_codesniffer": "^2.7"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Consolidation\\AnnotatedCommand\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Greg Anderson",
+                    "email": "greg.1.anderson@greenknowe.org"
+                }
+            ],
+            "description": "Initialize Symfony Console commands from annotated command class methods.",
+            "time": "2016-12-16T01:23:33+00:00"
+        },
+        {
+            "name": "consolidation/log",
+            "version": "1.0.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/consolidation/log.git",
+                "reference": "74ba81b4edc585616747cc5c5309ce56fec41254"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/consolidation/log/zipball/74ba81b4edc585616747cc5c5309ce56fec41254",
+                "reference": "74ba81b4edc585616747cc5c5309ce56fec41254",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.0",
+                "psr/log": "~1.0",
+                "symfony/console": "~2.5|~3.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "4.*",
+                "squizlabs/php_codesniffer": "2.*"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Consolidation\\Log\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Greg Anderson",
+                    "email": "greg.1.anderson@greenknowe.org"
+                }
+            ],
+            "description": "Improved Psr-3 / Psr\\Log logger based on Symfony Console components.",
+            "time": "2016-03-23T23:46:42+00:00"
+        },
+        {
+            "name": "consolidation/output-formatters",
+            "version": "3.1.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/consolidation/output-formatters.git",
+                "reference": "c8ea5734985cea4acd6343a2465a2f71cf011c82"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/consolidation/output-formatters/zipball/c8ea5734985cea4acd6343a2465a2f71cf011c82",
+                "reference": "c8ea5734985cea4acd6343a2465a2f71cf011c82",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.4.0",
+                "symfony/console": "~2.5|~3.0",
+                "symfony/finder": "~2.5|~3.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "4.*",
+                "satooshi/php-coveralls": "^1.0",
+                "squizlabs/php_codesniffer": "2.*",
+                "victorjonsson/markdowndocs": "^1.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Consolidation\\OutputFormatters\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Greg Anderson",
+                    "email": "greg.1.anderson@greenknowe.org"
+                }
+            ],
+            "description": "Format text by applying transformations provided by plug-in formatters.",
+            "time": "2017-01-08T20:32:20+00:00"
+        },
+        {
+            "name": "consolidation/robo",
+            "version": "1.0.5",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/consolidation/Robo.git",
+                "reference": "d06450370e8e303ebd1495dfc956f4c6c1b9dd01"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/consolidation/Robo/zipball/d06450370e8e303ebd1495dfc956f4c6c1b9dd01",
+                "reference": "d06450370e8e303ebd1495dfc956f4c6c1b9dd01",
+                "shasum": ""
+            },
+            "require": {
+                "consolidation/annotated-command": "^2.2",
+                "consolidation/log": "~1",
+                "consolidation/output-formatters": "^3.1.5",
+                "league/container": "^2.2",
+                "php": ">=5.5.0",
+                "symfony/console": "~2.8|~3.0",
+                "symfony/event-dispatcher": "~2.5|~3.0",
+                "symfony/filesystem": "~2.5|~3.0",
+                "symfony/finder": "~2.5|~3.0",
+                "symfony/process": "~2.5|~3.0"
+            },
+            "replace": {
+                "codegyre/robo": "< 1.0"
+            },
+            "require-dev": {
+                "codeception/aspect-mock": "~1",
+                "codeception/base": "^2.2.6",
+                "codeception/verify": "^0.3.2",
+                "henrikbjorn/lurker": "~1",
+                "natxet/cssmin": "~3",
+                "patchwork/jsqueeze": "~2",
+                "pear/archive_tar": "^1.4.2",
+                "phpunit/php-code-coverage": "~2|~4",
+                "satooshi/php-coveralls": "~1",
+                "squizlabs/php_codesniffer": "~2"
+            },
+            "suggest": {
+                "henrikbjorn/lurker": "For monitoring filesystem changes in taskWatch",
+                "natxet/CssMin": "For minifying JS files in taskMinify",
+                "patchwork/jsqueeze": "For minifying JS files in taskMinify",
+                "pear/archive_tar": "Allows tar archives to be created and extracted in taskPack and taskExtract, respectively."
+            },
+            "bin": [
+                "robo"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "scripts/composer/ScriptHandler.php"
+                ],
+                "psr-4": {
+                    "Robo\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Davert",
+                    "email": "davert.php@resend.cc"
+                }
+            ],
+            "description": "Modern task runner",
+            "time": "2016-11-24T02:07:48+00:00"
+        },
+        {
+            "name": "container-interop/container-interop",
+            "version": "1.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/container-interop/container-interop.git",
+                "reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/container-interop/container-interop/zipball/fc08354828f8fd3245f77a66b9e23a6bca48297e",
+                "reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e",
+                "shasum": ""
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Interop\\Container\\": "src/Interop/Container/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "Promoting the interoperability of container objects (DIC, SL, etc.)",
+            "time": "2014-12-30T15:22:37+00:00"
+        },
+        {
+            "name": "league/container",
+            "version": "2.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/thephpleague/container.git",
+                "reference": "c0e7d947b690891f700dc4967ead7bdb3d6708c1"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/thephpleague/container/zipball/c0e7d947b690891f700dc4967ead7bdb3d6708c1",
+                "reference": "c0e7d947b690891f700dc4967ead7bdb3d6708c1",
+                "shasum": ""
+            },
+            "require": {
+                "container-interop/container-interop": "^1.1",
+                "php": ">=5.4.0"
+            },
+            "provide": {
+                "container-interop/container-interop-implementation": "^1.1"
+            },
+            "replace": {
+                "orno/di": "~2.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "4.*"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.x-dev",
+                    "dev-1.x": "1.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "League\\Container\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Phil Bennett",
+                    "email": "philipobenito@gmail.com",
+                    "homepage": "http://www.philipobenito.com",
+                    "role": "Developer"
+                }
+            ],
+            "description": "A fast and intuitive dependency injection container.",
+            "homepage": "https://github.com/thephpleague/container",
+            "keywords": [
+                "container",
+                "dependency",
+                "di",
+                "injection",
+                "league",
+                "provider",
+                "service"
+            ],
+            "time": "2016-03-17T11:07:59+00:00"
+        }
+    ],
     "aliases": [],
     "minimum-stability": "dev",
     "stability-flags": {
diff --git a/scripts/blt/test-blt.sh b/scripts/blt/test-blt.sh
new file mode 100755
index 000000000..a3f226c7b
--- /dev/null
+++ b/scripts/blt/test-blt.sh
@@ -0,0 +1,44 @@
+#!/usr/bin/env bash
+
+# Usage ./scripts/blt/release-blt 8.6.11
+
+tag="$1"
+branch=$tag-build
+
+SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
+clear
+echo "Make sure that your local LAMP stack is running!"
+echo "This will destroy the $(cd $SCRIPT_DIR/../../../blted8 && pwd) directory."
+read -p "Press any key to continue."
+set -x
+cd $SCRIPT_DIR/../../../
+export COMPOSER_PROCESS_TIMEOUT=2000
+# @todo prompt to delete if exists
+rm -rf blted8
+composer create-project acquia/blt-project:8.x-dev blted8 --no-interaction
+cd blted8
+# Overwrite MySQL creds for your local machine, if necessary.
+# echo '$databases["default"]["default"]["username"] = "drupal";' >> docroot/sites/default/settings/local.settings.php
+# echo '$databases["default"]["default"]["password"] = "drupal";' >> docroot/sites/default/settings/local.settings.php
+./vendor/bin/blt local:setup
+cd docroot
+cd ..
+./vendor/bin/blt validate
+./vendor/bin/blt tests
+read -p "Press any key to continue. This will create a VM and re-run tests there."
+./vendor/bin/blt vm
+./vendor/bin/blt local:setup
+drush @blted8.local ssh blt tests:behat
+read -p "Press any key to continue. This will destroy the VM and attempt to perform a Pipelines build."
+vagrant destroy
+
+./vendor/bin/yaml-cli update:value blt/project.yml git.remotes.0 bolt8pipeline@svn-2420.devcloud.hosting.acquia.com:bolt8pipeline.git
+./vendor/bin/blt ci:pipelines:init
+git co -b ${branch}
+git add -A
+git commit -m "BLT-000: Creating test branch for BLT release ${tag}"
+git remote add origin bolt8pipeline@svn-2420.devcloud.hosting.acquia.com:bolt8pipeline.git
+git push origin ${branch}
+pipelines start
+
+# @todo have pipelines deploy and install on ODE.
diff --git a/scripts/release-notes/README.md b/scripts/release-notes/README.md
deleted file mode 100644
index f13dccff3..000000000
--- a/scripts/release-notes/README.md
+++ /dev/null
@@ -1,28 +0,0 @@
-# Generate Release Notes Script
-
-## Overview
-Use a script compiles PR comments for a project into a Markdown file that can
-be copy and pasted into GitHub release notes.
-
-## Usage
-
-### Required Inputs
-* **username:** your GitHub username
-* **password:** your GitHub password. Note that if you use two factor 
-  authentication you will need to use an [Access Token](https://help.github.com/articles/creating-an-access-token-for-command-line-use/) 
-  in lieu of a password.
-* **repository:** the name of the GitHub repository (e.g. `https://github.com/acquia-pso/my-repo`)
-
-### Simple usage
-
-    php generate-release-notes.php github username:password org:repo-name:branch > release-notes.md
-
-### Specify a start date
-
-    php generate-release-notes.php github username:password org:repo-name:branch 1/30/2014 > release-notes.md
-
-### Specify a start date and number of PRs
-
-    php generate-release-notes.php github username:password org:repo-name:branch 1/30/2014 50 > release-notes.md
-
-    # Example: Commit Message
diff --git a/scripts/release-notes/generate-release-notes.md b/scripts/release-notes/generate-release-notes.md
deleted file mode 100644
index 87c1b9e20..000000000
--- a/scripts/release-notes/generate-release-notes.md
+++ /dev/null
@@ -1,32 +0,0 @@
-# Generate Release Notes Script
-
-## Overview
-This script compiles PR comments for a project into a Markdown file that can be copy and pasted into Github release notes or a Confluence Page.
-
-## Usage
-
-### Github
-
-#### Simple Usage
-`php generate-release-notes.php github [github username]:[github password] [github project]:[github repository]:[branch] > release-notes.md`  
-`php generate-release-notes.php github dan:password acquia-pso:client-repo:master > release-notes.md`
-
-### Specify a start date
-`php generate-release-notes.php github dan:password acquia-pso:client-repo:master 12/31/2014 > release-notes.md`
-
-### Specify a start date and number of PRs
-`php generate-release-notes.php github dan:password acquia-pso:client-repo:master 12/31/2014 15 > release-notes.md`
-
-### Stash and Confluence
-Since stash is hosted by a client or service, you must pass in the base path, for example `stash.client.com`. You should not include `https://`.
-
-#### Simple Usage
-`php generate-release-notes.php stash:[base path] [stash username]:[stash password] [stash project]:[stash repository]:[branch] > release-notes.md`  
-`php generate-release-notes.php stash:stash.client.com dan:password client-project:client-repo:master > release-notes.md`
-
-### Specify a start date
-`php generate-release-notes.php stash:stash.client.com dan:password client-project:client-repo:master 12/31/2014 > release-notes.md`
-
-### Specify a start date and number of PRs
-`php generate-release-notes.php stash:stash.client.com dan:password client-project:client-repo:master 12/31/2014 15 > release-notes.md`
-
diff --git a/scripts/release-notes/generate-release-notes.php b/scripts/release-notes/generate-release-notes.php
deleted file mode 100644
index a80540caa..000000000
--- a/scripts/release-notes/generate-release-notes.php
+++ /dev/null
@@ -1,166 +0,0 @@
-<?php
-if ($argc < 3) {
-  print 'You must pass in arguments for the following variables:' . PHP_EOL
-  . 'service(git or stash), username:password, project:repository:branch, [month/day/year], [limit]' . PHP_EOL . PHP_EOL
-  . 'example: php generate-release-notes.php github dan:password acquia-pso:test-repo:master > example-release-notes.md' . PHP_EOL
-  . 'example: php generate-release-notes.php github dan:password acquia-pso:test-repo:master 4/10/2014 > example-release-notes.md' . PHP_EOL
-  . 'example: php generate-release-notes.php stash:stash.client.com dan:password client-project:test-repo:master 4/10/2014 100 > example-release-notes.md' . PHP_EOL . PHP_EOL
-  . 'note: by default, PRs are gathered from 30 days previous and up to 100 PRs' . PHP_EOL;
-  exit;
-}
-
-// Parse Service
-$service_array = explode(':', $argv[1]);
-
-$service = array(
-  'type' => $service_array[0],
-);
-
-if (count($service_array) > 1) {
-  $service['base_path'] = $service_array[1];
-}
-
-unset($service_array);
-
-// Set Username / Password
-$user_array = explode(':', $argv[2]);
-
-$user = array(
-  'name' => $user_array[0],
-  'password' => $user_array[1],
-);
-
-unset($user_array);
-
-// Split Project / Repo / Branch into variables.
-$repo_array = explode(':', $argv[3]);
-
-$repository = array(
-  'project' => $repo_array[0],
-  'repository' => $repo_array[1],
-  'branch' => $repo_array[2],
-);
-
-unset($repo_array);
-
-// Parse date.
-$since = ($argc < 5) ? strtotime('30 days ago') : strtotime($argv[4]);
-
-// Default to pulling 100 PRs.
-$limit = ($argc < 6) ? 100 : $argv[5];
-
-// Print the header.
-print '# Release notes for ' . date("F j, Y") . PHP_EOL . PHP_EOL;
-
-// Proceed based on service.
-switch ($service['type']) {
-  case 'github':
-    process_github();
-    break;
-
-  case 'stash':
-    process_stash();
-    break;
-}
-
-function process_github() {
-  global $repository, $since, $limit;
-
-  // Create a date like 2014-12-23T00:00:00Z.
-  $since_github = date('Y-m-d', $since) . 'T00:00:00Z';
-
-  // We can only get 100 results at a time, so we need to split the calls into chunks of 100.
-  $calls = ceil($limit / 100);
-
-  $url = 'https://api.github.com/repos/' . $repository['project'] . '/' . $repository['repository'] . '/pulls?state=closed&since=' . $since_github . '&per_page=' . $limit . '&base=' . $repository['branch'];
-
-  for ($page = 1; $page <= $calls; $page++) {
-
-    $prs = fetch_pr($url . '&page=' . $page);
-
-    // Print each Pull Request.
-    foreach ($prs as $pr) {
-      // We don't want to print PRs that are not merged.
-      if (is_null($pr['merged_at'])) {
-        continue;
-      }
-
-      // Check our date is within the time period.
-      $closed_date = strtotime($pr['closed_at']);
-
-      if ($closed_date < $since) {
-        continue;
-      }
-
-      print_pr_compact($pr['title'], $pr['body'], $closed_date, $pr['html_url']);
-    }
-  }
-}
-
-function process_stash() {
-  global $service, $repository, $since, $limit;
-
-  $url = 'https://' . $service['base_path'] . '/rest/api/1.0/projects/' . $repository['project'] . '/repos/' . $repository['repository'] . '/pull-requests?state=merged' . '&limit=' . $limit . '&at=refs/heads/' . $repository['branch'];
-
-  $json = fetch_pr($url);
-
-  // Print each Pull Request.
-  foreach ($json['values'] as $pr) {
-    // Check our date is within the time period.
-    // Stash uses epoch time with milliseconds.
-    $closed_date = date($pr['updatedDate'] / 1000);
-
-    if ($closed_date < $since) {
-      continue;
-    }
-
-    $link = 'https://' . $service['base_path'] . $pr['link']['url'];
-
-    print_pr($pr['title'], $pr['description'], $closed_date, $link);
-  }
-}
-
-function fetch_pr($url) {
-  global $user;
-  // Download the json file.
-  $ch = curl_init();
-
-  curl_setopt($ch, CURLOPT_HEADER, 0);
-  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
-  curl_setopt($ch, CURLOPT_USERPWD, $user['name'] . ':' . $user['password']);
-  curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
-  curl_setopt($ch, CURLOPT_USERAGENT, 'Acquia-PS');
-  curl_setopt($ch, CURLOPT_URL, $url);
-
-  $json_raw = curl_exec($ch);
-  $chinfo = curl_getinfo($ch);
-
-  // We bail if we don't get a successful connection.
-  if ($chinfo['http_code'] !== 200) {
-    print 'HTTP Error: ' . $chinfo['http_code'] . PHP_EOL;
-    print 'URL: ' . $url . PHP_EOL;
-    print $json_raw . PHP_EOL;
-    exit;
-  }
-
-  curl_close($ch);
-
-  // Decode the JSON.
-  return json_decode($json_raw, TRUE);
-}
-
-function print_pr($title, $description, $date, $link) {
-  // Print the PR Title.
-  print '## ' . $title . PHP_EOL;
-  // Print the PR Time and URL.
-  print date("F j, Y", $date) . ' ([' . $link . ']' . '(' . $link . '))' . PHP_EOL . PHP_EOL;
-  // Print the PR Body.
-  print $description . PHP_EOL . PHP_EOL;
-}
-
-function print_pr_compact($title, $description, $date, $link) {
-  $date_formatted =  date("F j, Y", $date);
-  print "* $date_formatted: [$title]($link) \n";
-}
-
-?>
diff --git a/scripts/release-notes/pull-request.example.md b/scripts/release-notes/pull-request.example.md
deleted file mode 100644
index 2f85ccf3b..000000000
--- a/scripts/release-notes/pull-request.example.md
+++ /dev/null
@@ -1,23 +0,0 @@
-## [Jira Issue Number]: [Pull request title]
-
-### Changes
-- [Description for non-devlepers.]
-- [Another thing in the PR]
-
-### Technical Details
-- [More technical description if needed.]
-
-### Affected Pages
-- [Globally]
-- [example url]
-- [/product-finder/123]
-
-### Key Affected Code
-- [example.php]
-- [example.scss]
-
-### References
-- [drupal.org/node/123456]
-
-### Notices
-- [If there is an important change developers should be aware of such as a change in architecture, the need for database updates, etc, put that information here.]
diff --git a/scripts/release-notes/release.example.md b/scripts/release-notes/release.example.md
deleted file mode 100644
index 83d609036..000000000
--- a/scripts/release-notes/release.example.md
+++ /dev/null
@@ -1,13 +0,0 @@
-## Main Additions
-- Addition 1
-- Addition 2
-
-## Important Notices
-- Notice 1
-- Notice 2
-
-- - -
-# Pull Requests in Detail
-- - -
-
-_This is where you copy and paste the output from generate-release-notes.php_
diff --git a/src/Robo/Command/BltInternal.php b/src/Robo/Command/BltInternal.php
new file mode 100644
index 000000000..a880e3b00
--- /dev/null
+++ b/src/Robo/Command/BltInternal.php
@@ -0,0 +1,217 @@
+<?php
+
+namespace Acquia\Blt\Robo\Command;
+
+use Robo\Tasks;
+use GuzzleHttp\Client;
+
+/**
+ * This is project's console commands configuration for Robo task runner.
+ *
+ * @see http://robo.li/
+ */
+class BltInternal extends Tasks
+{
+
+  /**
+   * Generates release notes and cuts a new tag on GitHub.
+   *
+   * @command blt:release
+   *
+   * @param string $tag The tag name. E.g, 8.6.10
+   * @param string $github_token A github access token
+   *
+   * @return int
+   *   The CLI status code.
+   */
+  public function bltRelease($tag, $github_token)
+  {
+
+    $requirements_met = $this->checkCommandsExist([
+      'git',
+      'github_changelog_generator',
+    ]);
+    if (!$requirements_met) {
+      return 1;
+    }
+
+    $this->yell("This will destroy any uncommitted work on the current branch. It will also hard reset 8.x and 8.x-release to match the upstream history.");
+    $continue = $this->confirm("Continue?");
+
+    if (!$continue) {
+      return 0;
+    }
+      // Clean up all staged and unstaged files on current branch.
+      $this->_exec('git clean -fd .');
+      $this->_exec('git remote update');
+      $this->_exec('git reset --hard');
+
+      // Reset local 8.x to match upstream history of 8.x.
+      $this->_exec('git checkout 8.x');
+      $this->_exec('git reset --hard origin/8.x');
+
+      // Reset local 8.x-release to match upstream history of 8.x-release.
+      $this->_exec('git checkout 8.x-release');
+      $this->_exec('git reset --hard origin/8.x-release');
+
+      // Merge 8.x into 8.x-release and push.
+      $this->_exec('git merge 8.x');
+      $this->_exec('git push origin 8.x-release');
+
+      $partial_release_notes = $this->generateReleaseNotes($tag, $github_token);
+      $trimmed_release_notes = $this->trimStartingLines($partial_release_notes, 3);
+
+      $request_payload = [
+        'tag_name' => $tag,
+        'name' => $tag,
+        'target_commitish' => '8.x-release',
+        'body' => $trimmed_release_notes,
+        'draft' => true,
+        'prerelease' => true,
+      ];
+
+    $client = new Client([
+      // Base URI is used with relative requests
+      'base_uri' => 'https://api.github.com/repos/acquia/blt/',
+      'query' => [
+        'access_token' => $github_token,
+      ],
+    ]);
+    $response = $client->request('POST', 'releases', [
+      'json' => $request_payload,
+    ]);
+    if ($response->getStatusCode() != 201) {
+      $this->yell("Something went wrong when attempting to create release $tag.");
+      $this->say($response->getBody());
+    }
+
+    $response_body = json_decode($response->getBody(), TRUE);
+    $this->say("Release $tag has been created on GitHub: \n");
+    $this->_exec("open {$response_body['html_url']}");
+  }
+
+  /**
+   * Update CHANGELOG.md with notes for new release.
+   *
+   * @param string $tag The tag name. E.g, 8.6.10
+   * @param string $github_token A github access token
+   *
+   * @return int
+   *   The CLI status code.
+   */
+  public function bltReleaseNotes($tag, $github_token) {
+
+    $requirements_met = $this->checkCommandsExist([
+      'github_changelog_generator',
+    ]);
+    if (!$requirements_met) {
+      return 1;
+    }
+
+    $this->yell("You should execute this command on a clean, updated checkout of 8.x.");
+    $continue = $this->confirm("Continue?");
+
+    if (!$continue) {
+      return 0;
+    }
+
+    if (!$trimmed_partial_changelog = $this->generateReleaseNotes($tag, $github_token)) {
+      $this->yell("Failed to generate release notes");
+      return 1;
+    }
+
+    // Remove first 4 lines from full changelog.
+    $full_changelog_filename = 'CHANGELOG.md';
+    $full_changelog = file_get_contents($full_changelog_filename);
+    $trimmed_full_changelog = $this->trimStartingLines($full_changelog, 1);
+
+    $new_full_changelog = $trimmed_partial_changelog . $trimmed_full_changelog;
+    file_put_contents($full_changelog_filename, $new_full_changelog);
+
+    $this->say("$full_changelog_filename has been updated. Please commit and PUSH the changes.");
+
+    return 0;
+  }
+
+  /**
+   * Generate notes for new release.
+   *
+   * @param $tag
+   * @param $github_token
+   *
+   * @return int|string
+   *   FALSE on failure, otherwise the release notes.
+   */
+  protected function generateReleaseNotes($tag, $github_token) {
+    // Generate release notes.
+    $partial_changelog_filename = 'CHANGELOG.partial';
+    if (!$this->taskExec("github_changelog_generator --token=$github_token --future-release=$tag --output=$partial_changelog_filename")->run()->wasSuccessful()) {
+      $this->yell("Unable to generate CHANGELOG using github_changelog_generator.");
+      return 1;
+    }
+
+    // Remove last 3 lines from new, partial changelog.
+    $partial_changelog_contents = file_get_contents($partial_changelog_filename);
+    $trimmed_partial_changelog = $this->trimEndingLines($partial_changelog_contents, 3);
+    unlink($partial_changelog_filename);
+
+    return $trimmed_partial_changelog;
+  }
+
+  /**
+   * Trims the last $num_lines lines from end of a text string.
+   *
+   * @param string $text A string of text.
+   * @param int $num_lines The number of lines to trim from the end of the text.
+   *
+   * @return string
+   *   The trimmed text.
+   */
+  protected function trimEndingLines($text, $num_lines) {
+    return implode("\n", array_slice(explode("\n", $text), 0, sizeof($text) - $num_lines));
+  }
+
+  /**
+   * Trims the last $num_lines lines from beginning of a text string.
+   *
+   * @param string $text A string of text.
+   * @param int $num_lines The number of lines to trim from beginning of text.
+   *
+   * @return string
+   *   The trimmed text.
+   */
+  protected function trimStartingLines($text, $num_lines) {
+    return implode("\n", array_slice(explode("\n", $text), $num_lines));
+  }
+
+    /**
+     * Check if an array of commands exists on the system.
+     *
+     * @param $commands array An array of command binaries.
+     *
+     * @return bool
+     *   TRUE if all commands exist, otherwise FALSE.
+     */
+    protected function checkCommandsExist($commands) {
+      foreach ($commands as $command) {
+        if (!$this->commandExists($command)) {
+          $this->yell("Unable to find '$command' command!");
+          return FALSE;
+        }
+      }
+
+      return TRUE;
+    }
+
+    /**
+     * Checks if a given command exists on the system.
+     *
+     * @param $command string the command binary only. E.g., "drush" or "php".
+     *
+     * @return bool
+     *   TRUE if the command exists, otherwise FALSE.
+     */
+    protected function commandExists($command) {
+      return $this->taskExec("command -v $command >/dev/null 2>&1")->run()->wasSuccessful();
+    }
+}