docs: function(branch, category, appName) {
  
    // Validate.
    if (!isBranch(branch)) {
      throw new TypeError('Invalid branch: ' + pp(branch));
    }
  
    // Recursively map branch to get the cli look we want.
    var recMap = function(node) {
  
      if (isTask(node)) {
  
        // This is a task so do nothing.
        return [node];
  
      } else if (isBranch(node)) {
  
        // Concat map children with a recMap.
        node.children = _.flatten(_.map(node.children, recMap));
  
        // Sort children.
        node.children.sort(compareBranchOrTask);
  
        // Resolve duplicate named children.
        // Group children by name.
        var nameMap = _.groupBy(node.children, getName);
  
        // Resolve conflicts.
        node.children = _.map(_.values(nameMap), function(children) {
  
          if (children.length === 1) {
  
            // No conflicts so just return head of array.
            return children[0];
  
          } else {
  
            // Resolve conflict by finding a single node with the override flag.
            var overrides = _.filter(children, function(child) {
              return child.__override;
            });
  
            if (overrides.length === 1) {
  
              // Conflict resolved.
              return overrides[0];
  
            } else {
  
              // Conflict can not be resolved, throw an error.
              throw new Error('Conflicting task names can not be resolved: ' +
                pp(children));
  
            }
  
          }
  
        });
  
        if (getName(node) === appName) {
  
          // Replace this node with this nodes children.
          _.each(node.children, function(child) {
            // Mark each child with an override flag so we can resolve conflicts.
            child.__override = true;
          });
          return node.children;
  
        } else {
  
          // Just return.
          return [node];
  
        }
  
      } else {
  
        // This should never happen.
        assert(false);
  
      }
  
    };
  
    // Recursively build list of lines.
    var recAdd = function(node, lines, parentName, depth) {
  
      // Default depth.
      if (_.isUndefined(depth)) {
        depth = 0;
      }
  
      // Default parentName.
      if (_.isUndefined(parentName)) {
        parentName = 'root';
      }
  
      if (isTask(node)) {
  
        // This is a task so add to lines and nothing further.
        lines.push({
          depth: depth,
          name: getName(node),
          parentName: parentName,
          description: node.description
        });
  
      } else if (isBranch(node)) {
  
        lines.push({
          depth: depth,
          name: getName(node),
          parentName: parentName
        });
        node.children.forEach(function(child) {
          recAdd(child, lines, getName(node), depth + 1);
        });
  
      } else {
  
        // This should never happen.
        assert(false);
  
      }
  
    };
  
    // Only do this is branch is not the app branch.
    if (getName(branch) !== appName) {
      branch = recMap(branch)[0];
    }
  
    // Filter by correct category
    var kids = _.filter(branch.children, function(child) {
      // Go one level deeper if we are on a branch and
      // want to find the category of its children
      if (child.category === undefined) {
        if (!_.isEmpty(child.children)) {
          return child.children[0].category === category;
        }
      }
      else {
        return child.category === category;
      }
    });
  
    if (!_.isEmpty(kids)) {
      // Number of spaces sub commands will be indented.
      var tabSpacing = 4;
  
      // Header for menu.
      var header = '\n' + catDesc[category];
  
      // Init list of lines.
      var lines = [];
  
      kids.forEach(function(child) {
        recAdd(child, lines);
      });
  
      lines = _.map(lines, function(line) {
        var depthPrefix = _.repeat(' ', tabSpacing * line.depth + 2);
        var name = depthPrefix + line.name;
        return {
          name: name,
          description: line.description
        };
      });
  
      /*
      var widths = _.map(lines, function(line) {
        return line.name.length;
      });
      */
      var maxWidth = 15;
  
      lines = _.map(lines, function(line) {
        var name = _.padRight(line.name, maxWidth);
        if (line.description) {
          return [
            chalk.green(name),
            chalk.yellow(line.description)
          ].join(_.repeat(' ', tabSpacing));
        } else {
          return chalk.green(name);
        }
      });
  
      lines.unshift(header);
      return lines.join('\n');
    }
  }