diff --git a/cake b/cake
new file mode 100644
index 0000000..4b746dc
--- /dev/null
+++ b/cake
@@ -0,0 +1,98 @@
+CAKE.COFFEE
+¶
+cake is a simplified version of Make (Rake, Jake) for CoffeeScript. You define tasks with names and descriptions in a Cakefile, and can call them from the command line, or invoke them from other tasks.
+
+Running cake with no arguments will print out a list of all the tasks in the current directory's Cakefile.
+
+External dependencies.
+
+ 
+fs           = require 'fs'
+path         = require 'path'
+helpers      = require './helpers'
+optparse     = require './optparse'
+CoffeeScript = require './coffee-script'
+
+existsSync   = fs.existsSync or path.existsSync
+¶
+Keep track of the list of defined tasks, the accepted options, and so on.
+
+ 
+tasks     = {}
+options   = {}
+switches  = []
+oparse    = null
+¶
+Mixin the top-level Cake functions for Cakefiles to use directly.
+
+ 
+helpers.extend global,
+¶
+Define a Cake task with a short name, an optional sentence description, and the function to run as the action itself.
+
+ 
+  task: (name, description, action) ->
+    [action, description] = [description, action] unless action
+    tasks[name] = {name, description, action}
+¶
+Define an option that the Cakefile accepts. The parsed options hash, containing all of the command-line options passed, will be made available as the first argument to the action.
+
+ 
+  option: (letter, flag, description) ->
+    switches.push [letter, flag, description]
+¶
+Invoke another task in the current Cakefile.
+
+ 
+  invoke: (name, cb) ->
+    missingTask name unless tasks[name]
+    tasks[name].action options
+¶
+Run cake. Executes all of the tasks you pass, in order. Note that Node's asynchrony may cause tasks to execute in a different order than you'd expect. If no tasks are passed, print the help screen. Keep a reference to the original directory name, when running Cake tasks from subdirectories.
+
+ 
+exports.run = (cb) ->
+  global.__originalDirname = fs.realpathSync '.'
+  process.chdir cakefileDirectory __originalDirname
+  args = process.argv[2..]
+  CoffeeScript.run fs.readFileSync('Cakefile').toString(), filename: 'Cakefile'
+  oparse = new optparse.OptionParser switches
+  return printTasks() unless args.length
+  try
+    options = oparse.parse(args)
+  catch e
+    return fatalError "#{e}"
+  invoke arg for arg in options.arguments
+¶
+Display the list of Cake tasks in a format similar to rake -T
+
+ 
+printTasks = ->
+  relative = path.relative or path.resolve
+  cakefilePath = path.join relative(__originalDirname, process.cwd()), 'Cakefile'
+  console.log "#{cakefilePath} defines the following tasks:\n"
+  for name, task of tasks
+    spaces = 20 - name.length
+    spaces = if spaces > 0 then Array(spaces + 1).join(' ') else ''
+    desc   = if task.description then "# #{task.description}" else ''
+    console.log "cake #{name}#{spaces} #{desc}"
+  console.log oparse.help() if switches.length
+¶
+Print an error and exit when attempting to use an invalid task/option.
+
+ 
+fatalError = (message) ->
+  console.error message + '\n'
+  console.log 'To see a list of all tasks/options, run "cake"'
+  process.exit 1
+
+missingTask = (task) -> fatalError "No such task: #{task}"
+¶
+When cake is invoked, search in the current and all parent directories to find the relevant Cakefile.
+
+ 
+cakefileDirectory = (dir) ->
+  return dir if existsSync path.join dir, 'Cakefile'
+  parent = path.normalize path.join dir, '..'
+  return cakefileDirectory parent unless parent is dir
+  throw new Error "Cakefile not found in #{process.cwd()}"