diff --git a/scripts/deploy/git.js b/scripts/deploy/git.js
index 2a1b6ea0a6e6fbc3cd1e605f51f1f48fa5585d21..bb5a5978f9310e5682e8d883872624ec47945b49 100644
--- a/scripts/deploy/git.js
+++ b/scripts/deploy/git.js
@@ -80,7 +80,7 @@ exports.push = function(dir, host, pr, cb) {
 };
 
 exports.pull = function(dir, remote, branch, pr, cb) {
-  var p = spawn('git', [ 'pull', "-f", remote, branch ], { cwd: dir });
+  var p = spawn('git', [ 'pull', "-f", remote, branch + ":" + branch ], { cwd: dir });
 
   p.stdout.on('data', function(c) { splitAndEmit(c, pr); });
   p.stderr.on('data', function(c) { splitAndEmit(c, pr); });
diff --git a/scripts/deploy/vm.js b/scripts/deploy/vm.js
index ae94b2a11691e3daaab585be16b0429a4f9dbee3..6c6e88bf6964b71525ae44ae23e7bd17051e944f 100644
--- a/scripts/deploy/vm.js
+++ b/scripts/deploy/vm.js
@@ -15,8 +15,12 @@ function extractInstanceDeets(horribleBlob) {
   var name = jsel.match('.tagSet :has(.key:val("Name")) > .value', horribleBlob);
   if (name.length) {
     instance.fullName = name[0];
-    instance.name = name[0].replace('browserid deployment (', '')
-                           .replace(/\)$/, '');
+    // if this is a 'browserid deployment', we'll only display the hostname chosen by the
+    // user
+    var m = /^browserid deployment \((.*)\)$/.exec(instance.fullName);
+    instance.name = m ? m[1] : instance.fullName;
+  } else {
+    instance.name = instance.instanceId;
   }
   return instance;
 }
diff --git a/scripts/deploy_server.js b/scripts/deploy_server.js
index fc0e90bf391b5dd86c6a5ca35836f3aba8e90533..1b0935bb5937607db026e9c9042505456c8114f8 100755
--- a/scripts/deploy_server.js
+++ b/scripts/deploy_server.js
@@ -6,18 +6,21 @@ path = require('path'),
 util = require('util'),
 events = require('events'),
 git = require('./deploy/git.js'),
-https = require('https');
+https = require('https'),
+vm = require('./deploy/vm.js'),
+jsel = require('JSONSelect'),
+fs = require('fs'),
+express = require('express');
 
 // a class capable of deploying and emmitting events along the way
 function Deployer() {
   events.EventEmitter.call(this);
 
   // a directory where we'll keep code
-  this._codeDir = '/tmp/fuck'; // temp.mkdirSync();
+  this._codeDir = process.env['CODE_DIR'] || temp.mkdirSync();
   console.log("code dir is:", this._codeDir);
   var self = this;
 
-/*
   git.init(this._codeDir, function(err) {
     if (err) {
       console.log("can't init code dir:", err);
@@ -25,26 +28,19 @@ function Deployer() {
     }
     self.emit('ready');
   });
-*/
-  // a directory where we'll deployment logs
-  this._deployLogDir = temp.mkdirSync();
-  console.log("deployment log dir is:", this._deployLogDir);
-  
-  process.nextTick(function() {
-    self.emit('ready');
-  });
 }
 
 util.inherits(Deployer, events.EventEmitter);
 
 Deployer.prototype._getLatestRunningSHA = function(cb) {
+  var self = this;
+
   // failure is not fatal.  maybe nothing is running?
-  function fail(err) {
+  var fail = function(err) {
     self.emit('info', { msg: "can't get current running sha", reason: err });
     cb(null, null);
   }
 
-  var self = this;
   https.get({ host: 'dev.diresworb.org', path: '/ver.txt' }, function(res) {
     var buf = ""; 
     res.on('data', function (c) { buf += c });
@@ -66,11 +62,31 @@ Deployer.prototype._getLatestRunningSHA = function(cb) {
 
 }
 
-Deployer.prototype._cleanupOldVMs = function() {
-  this.emit('error', "not yet implemented");
+Deployer.prototype._cleanUpOldVMs = function() {
+  var self = this;
+  // what's our sha
+  git.currentSHA(self._codeDir, function(err, latest) {
+    if (err) return self.emit('info', err);
+    vm.list(function(err, r) {
+      if (err) return self.emit('info', err);
+      // only check the vms that have 'dev.diresworb.org' as a name
+      jsel.forEach("object:has(:root > .name:contains(?))", [ "dev.diresworb.org" ], r, function(o) {
+        // don't delete the current one
+        if (o.name.indexOf(latest) == -1) {
+          self.emit('info', 'decommissioning VM: ' + o.name + ' - ' + o.instanceId); 
+          vm.destroy(o.name, function(err, r) {
+            if (err) self.emit('info', 'decomissioning failed: ' + err);
+            else self.emit('info', 'decomissioning succeeded of ' + r);
+          })
+        }
+      });
+    });
+  });
 }
 
 Deployer.prototype._deployNewCode = function(cb) {
+  var self = this;
+
   function splitAndEmit(chunk) {
     if (chunk) chunk = chunk.toString();
     if (typeof chunk === 'string') {
@@ -81,24 +97,35 @@ Deployer.prototype._deployNewCode = function(cb) {
     }
   }
 
-  var p = spawn('scripts/deploy_dev.js', { cwd: self._codeDir });
+  var npmInstall = spawn('npm', [ 'install' ], { cwd: self._codeDir });
+  
+  npmInstall.stdout.on('data', splitAndEmit);
+  npmInstall.stderr.on('data', splitAndEmit);
+
+  npmInstall.on('exit', function(code, signal) {
+    if (code != 0) {
+      self.emit('error', "can't npm install to prepare to run deploy_dev");
+      return;
+    }
+    var p = spawn('scripts/deploy_dev.js', [], { cwd: self._codeDir });
   
-  p.stdout.on('data', splitAndEmit);
-  p.stderr.on('data', splitAndEmit);
+    p.stdout.on('data', splitAndEmit);
+    p.stderr.on('data', splitAndEmit);
 
-  p.on('exit', function(code, signal) {
-    return cb(code = 0);
+    p.on('exit', function(code, signal) {
+      return cb(code != 0);
+    });
   });
 };
 
 Deployer.prototype._pullLatest = function(cb) {
   var self = this;
   git.pull(this._codeDir, 'git@github.com:mozilla/browserid', 'dev', function(l) {
-    self.emit(l);
+    self.emit('progress', l);
   }, function(err) {
-    if (err) return self.emit('error', err);
+    if (err) return cb(err);
     git.currentSHA(self._codeDir, function(err, latest) {
-      if (err) return self.emit('error', err);
+      if (err) return cb(err);
       self.emit('info', 'latest available sha is ' + latest);
       self._getLatestRunningSHA(function(err, running) {
         if (latest != running) {
@@ -108,14 +135,15 @@ Deployer.prototype._pullLatest = function(cb) {
           var startTime = new Date();
 
           self._deployNewCode(function(err, res) {
-            if (err) return self.emit('error', err);
+            if (err) return cb(err);
             // deployment is complete!
             self.emit('deployment_complete', {
               sha: latest,
               time: (startTime - new Date())
             });
             // finally, let's clean up old servers
-            self._cleanUpOldVMS();
+            self._cleanUpOldVMs();
+            cb(null, null);
           });
         } else {
           self.emit('info', 'up to date');
@@ -128,21 +156,83 @@ Deployer.prototype._pullLatest = function(cb) {
 
 // may be invoked any time we suspect updates have occured to re-deploy
 // if needed
-Deployer.prototype.checkForUpdates = function(cb) {
+Deployer.prototype.checkForUpdates = function() {
   var self = this;
+
+  if (this._busy) return;
+
+  this._busy = true;
+  self.emit('info', 'checking for updates');
+
   self._pullLatest(function(err, sha) {
-    if (!err) {
-      console.log(sha);
-    }
+    if (err) self.emit('error', err);
+    self._busy = false;
   });
 }
 
 var deployer = new Deployer();
 
+var currentLogFile = null;
+// a directory where we'll deployment logs
+var deployLogDir = process.env['DEPLOY_LOG_DIR'] || temp.mkdirSync();
+console.log("deployment log dir is:", deployLogDir);
+
 [ 'info', 'ready', 'error', 'deployment_begins', 'deployment_complete', 'progress' ].forEach(function(evName) {
-  deployer.on(evName, function(data) { console.log(evName + ":", data) });
+  deployer.on(evName, function(data) {
+    if (typeof data != 'string') data = JSON.stringify(data, null, 2);
+    var msg = evName + ": " + data;
+    console.log(msg)
+    if (currentLogFile) currentLogFile.write(msg + "\n");
+  });
+});
+
+// now when deployment begins, we log all events
+deployer.on('deployment_begins', function(r) {
+  currentLogFile = fs.createWriteStream(path.join(deployLogDir, r.sha + ".txt"));
+  currentLogFile.write("deployment of " + r.sha + " begins\n");
+});
+
+function closeLogFile() {
+  if (currentLogFile) {
+    currentLogFile.end();
+    currentLogFile = null;
+  }
+}
+
+deployer.on('deployment_complete', function(r) {
+  closeLogFile();
+
+  // always check to see if we should try another deployment after one succeeds to handle rapid fire
+  // commits
+  deployer.checkForUpdates();
+});
+
+deployer.on('error', function(r) {
+  closeLogFile();
+  // on error, try again in 2 minutes
+  setTimeout(function () { 
+    deployer.checkForUpdates();  
+  }, 2 * 60 * 1000);
 });
 
+
+// we check every 30 minutes no mattah what. (checks are cheap)
+setInterval(function () { 
+  deployer.checkForUpdates();  
+}, (1000 * 60 * 30));
+
+// check for updates at startup
 deployer.on('ready', function() {
   deployer.checkForUpdates();
+
+  var app = express.createServer();
+  
+  app.get('/check', function(req, res) {
+    deployer.checkForUpdates();    
+    res.send('ok');
+  });
+  
+  app.use(express.static(deployLogDir));
+
+  app.listen(process.env['PORT'] || 8080);
 });