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.