Moving Archived Tasks to a Weekly File

I like to keep a log of what I’ve completed in Taskpaper, so I can review it later. The script below will take all the items in the Archived project of the open document and move them to a weekly archive, under a project it manages called “Achieved”.

The only rule here is that you need to have a TaskPaper document that:

  • has a name of the format “Week of 2021-03-07” (it looks for the Sunday of the current week)
  • is currently open in TaskPaper

So you’ll need to create and open one of these each Sunday. I usually leave it open in a tab in TaskPaper (you’ll get an error message if the document doesn’t exist, so no need to worry about silent failures).

But once that’s set up, you can just run this script to move everything in the archive of the active document to the weekly archive file. You’ll end up with something like this (it will automatically create the Achieved project and the day entry under Achieved if they don’t already exist).


Here’s the script:

function formatYMDDate(date) {
  const monthString = String(date.getMonth() + 1).padStart(2, '0');
  const dayString = String(date.getDate()).padStart(2, '0');

  return `${date.getFullYear()}-${monthString}-${dayString}`;

function generateWeeklyDocName() {
  const now = new Date();
  const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
  const lastSunday = new Date(today.setDate(today.getDate()-today.getDay()));

  return "Week of " + formatYMDDate(lastSunday);

function extractArchivedTasks(editor, options) {
  'use strict';

  const outline = editor.outline;
  const matches = outline.evaluateItemPath("project Archive:");
  const archiveProject = matches[0];

  if( matches.length == 0 || archiveProject.children.length == 0 ) {
    return null;

  const savedChildren = => child.bodyString.replace(/\s*\@done/, ""));

  outline.groupUndoAndChanges(function() {

  return savedChildren;

function saveArchivedTasks(editor, options) {
  'use strict';

  const archivedTaskNames = options.archivedTaskNames;
  const outline = editor.outline;

  outline.groupUndoAndChanges(function() {
    let achievedProjectMatches = outline.evaluateItemPath("project Achieved:")
    if( achievedProjectMatches.length == 0 ) {
      // create "Achieved" project if it doesn't exist


    let matches = outline.evaluateItemPath("project Achieved:/" + options.todayString);

    if( matches.length == 0 ) {
      // create today's entry if it doesn't exist

      let achieved = outline.evaluateItemPath("project Achieved:")[0];
      achieved.appendChildren(outline.createItem(options.todayString + ":"));
      matches = outline.evaluateItemPath("project Achieved:/" + options.todayString);

    const dailyLog = matches[0];
    dailyLog.appendChildren( => outline.createItem(name)));

  return true;

const docs = Application("TaskPaper").documents;
const weeklyDoc = docs.whose({ name: generateWeeklyDocName() })[0];
const activeDoc = docs[0];

const archivedTaskNames = activeDoc.evaluate({
  script: extractArchivedTasks.toString()

if( archivedTaskNames != null ) {
  const todayString = formatYMDDate(new Date());

    script: saveArchivedTasks.toString(),
    withOptions: { 
      archivedTaskNames: archivedTaskNames, 
      todayString: todayString
1 Like