       args: ['--test', "--resource-path=#{resourcePath}", "--spec-directory=#{coreSpecsPath}"]
     spawn options, (error, results, code) ->
       packageSpecQueue.concurrency = 2
-      callback(null, not error)
+      callback(null, error)
 
   grunt.registerTask 'run-specs', 'Run the specs', ->
     done = @async()
     startTime = Date.now()
 
     async.parallel [runCoreSpecs, runPackageSpecs], (error, results) ->
-      [coreSpecPassed, packageSpecsPassed] = results
+      [coreSpecFailed, failedPackages] = results
       elapsedTime = Math.round((Date.now() - startTime) / 100) / 10
       grunt.verbose.writeln("Total spec time: #{elapsedTime}s")
-      done(coreSpecPassed and packageSpecsPassed)
+      failures = failedPackages
+      failures.push "atom core" if coreSpecFailed
+
+      grunt.log.error("[Error]".red + " #{failures.join(', ')} spec(s) failed") if failures.length > 0
+
+      done(!coreSpecFailed and failedPackages.length == 0)

      packageSpecQueue.push(packagePath)

    packageSpecQueue.concurrency = 1
    packageSpecQueue.drain = -> callback(null, passed)

  runCoreSpecs = (callback) ->
    contentsDir = grunt.config.get('atom.contentsDir')

  packageSpecQueue = null

  runPackageSpecs = (callback) ->
    failedPackages = []
    rootDir = grunt.config.get('atom.shellAppDir')
    appDir = grunt.config.get('atom.appDir')
    atomPath = path.join(appDir, 'atom.sh')
