(v1) Migrating from Obsidian-Tasks

Not exactly this but I’ve been using a very customized version of this for a while. I use some special SB tags for task statuses and priorities - since I use it in contexts other than task as well. Other than that, I have all the projects under Projects/ directory in the space and all people under People/ directory. So that makes my space-lua something like:

taskmgmt = taskmgmt or {}
taskmgmt.valid_priorities = {"P0", "P1", "P2"}
taskmgmt.valid_statuses = {"TODO", "IN-PROGRESS", "PAUSED", "IN-REVIEW", "DONE", "CANCELED"}

function parseTaskAttributes(task, date)
  local taskattrs = {}
  local sev = ""
  local deadline = task.deadline or os.date("%Y-%m-%d")
  local diff = dateDiff(date, deadline)
  if task.done == true then sev = " ✅"
  elseif diff < -4 then sev = " 🔥"
  elseif diff >= -4 and diff < 0 then sev = " ‼️"
  elseif diff >= 0 and diff < 2 then sev = " 🔴"
  elseif diff >= 2 and diff < 4 then sev = " 🟡"
  else sev = " 🟢"
  end
  taskattrs["severity"] = sev
  local _, pri = table.find(task.tags, function(tag) return  table.includes(taskmgmt.valid_priorities, tag) end)
  taskattrs["priority"] = pri and "#" .. pri or "-"
  local _, st = table.find(task.tags, function(tag) return table.includes(taskmgmt.valid_statuses, tag) end)
  taskattrs["status"] = st and "#" .. st or "-"
  local proj = string.match(task.name, "%[%[Projects/.*%]%]")
  taskattrs["project"] = proj or ""
  local as = ""
  for assignee in string.gmatch(task.name, "%[%[People/.-%]%]") do
    as = as .. assignee .. " "
  end
  taskattrs["assignees"] = as
  local completed = string.match(task.name, "✅(%d+%-%d+%-%d+)")
  taskattrs["completed"] = completed
  local created = string.match(task.name, "➕(%d+%-%d+%-%d+)")
  taskattrs["created"] = created
  local name = string.gsub(task.name, "%[%[.*%]%]", "")
  name = string.gsub(name, "✅(%d+%-%d+%-%d+)", "")
  name = string.gsub(name, "➕(%d+%-%d+%-%d+)", "")
  taskattrs["taskname"] = name
  return taskattrs
end

local mt = { 
  __index = function(self, attr) 
    if attr == "extraAttrs" then 
      return parseTaskAttributes(self, os.date("%Y-%m-%d"))
    end 
  end 
}
index.defineTag { name = "task", metatable = mt }

function markTaskStatus(status)
  local line = editor.getCurrentLine()
  local newline = line.text
  for i, v in ipairs(taskmgmt.valid_statuses) do
    if string.find(newline, v) then
      newline = string.gsub(newline, v, status)
      if string.find(newline, "[ ]") and status == "DONE" then
        newline = string.gsub(newline, "%[ %]", "[x]")
        newline = newline .. " ✅" .. os.date("%Y-%m-%d")
      end
      if string.find(newline, "[x]", 0, true) and status ~= "DONE" then
        newline = string.gsub(newline, "%[x%]", "[ ]")
        newline = string.gsub(newline, "✅(%d+%-%d+%-%d+)", "")
      end
      break
    end
  end
  editor.replaceRange(line.from, line.to, newline)
end

function markTaskPriority(priority)
  local line = editor.getCurrentLine()
  local newline = line.text
  for i, v in ipairs(taskmgmt.valid_priorities) do
    if string.find(newline, v) then
      newline = string.gsub(newline, v, status)
    end
  end
  editor.replaceRange(line.from, line.to, newline)
end

for i, v in ipairs(taskmgmt.valid_statuses) do
  slashcommand.define {
    name = v,
    run = function()
      markTaskStatus(v)
    end
  }
end

for i, v in ipairs(taskmgmt.valid_priorities) do
  slashcommand.define {
    name = v,
    run = function()
      markTaskStatus(v)
    end
  }
end

And with some custom styling for the special tags:

/* TODO tag */
.sb-hashtag[data-tag-name="TODO"] {
  background: #ff8080 !important;
  color: #333333 !important;
  font-weight: bolder;
}

.sb-hashtag[data-tag-name="TODO"]::before {
  content: "📌 ";
}

/* IN-PROGRESS tag */
.sb-hashtag[data-tag-name="IN-PROGRESS"] {
  background: #ffcc77 !important;
  color: #333333 !important;
  font-weight: bolder;
}

.sb-hashtag[data-tag-name="IN-PROGRESS"]::before {
  content: "🚧 ";
}

/* IN-REVIEW tag */
.sb-hashtag[data-tag-name="IN-REVIEW"] {
  background: #bf88bf !important;
  color: #333333 !important;
  font-weight: bolder;
}

.sb-hashtag[data-tag-name="IN-REVIEW"]::before {
  content: "🟪 ";
}

/* PAUSED tag */
.sb-hashtag[data-tag-name="PAUSED"] {
  background: #ffa742 !important;
  color: #333333 !important;
  font-weight: bolder;
}

.sb-hashtag[data-tag-name="PAUSED"]::before {
  content: "🟧 ";
}

/* DONE tag */
.sb-hashtag[data-tag-name="DONE"] {
  background: #b0ffa9 !important;
  color: #333333 !important;
  font-weight: bolder;
}

.sb-hashtag[data-tag-name="DONE"]::before {
  content: "✅ ";
}

/* CANCELED tag */
.sb-hashtag[data-tag-name="CANCELED"] {
  background: #b3d9ff !important;
  color: #333333 !important;
  font-weight: bolder;
}

.sb-hashtag[data-tag-name="CANCELED"]::before {
  content: "⛔ ";
}

/* P0 tag */
.sb-hashtag[data-tag-name="P0"] {
  background: #ffb3b3 !important;
  color: #333333 !important;
  font-weight: bolder;
}

.sb-hashtag[data-tag-name="P0"]::before {
  content: "🔴 ";
}

/* P1 tag */
.sb-hashtag[data-tag-name="P1"] {
  background: #ffdbb3 !important;
  color: #333333 !important;
  font-weight: bolder;
}

.sb-hashtag[data-tag-name="P1"]::before {
  content: "🟠 ";
}

/* P2 */
.sb-hashtag[data-tag-name="P2"] {
  background: #ffe3b3 !important;
  color: #333333 !important;
  font-weight: bolder;
}

.sb-hashtag[data-tag-name="P2"]::before {
  content: "🟡 ";
}

This sort of fits my use cases mostly I can write a task of the form:

* [ ] Test task 1 [[People/Person-1]] [[Projects/Project-blah]] 📅2025-11-14 #TODO #P1 

and get all the relevant fields extracted out. This is not a 100 percent replacement, but thought I’d share it if anyone wants to improve on it.

2 Likes