Skip to main content

mktask

PyPI Python License

A work task prioritizer built on mkio (config-driven microservice backend) and mkui (config-driven Web Components workspace with dockable panes).

Tasks live in a local SQLite database and show up in a live-updating blotter you can sort, filter, and arrange however you like. Each task carries an importance and an urgency (1–5); the blotter derives a score from them so the most pressing work floats to the top.

A task can be split into child tasks, and a child can be split again, to any depth. The blotter nests children under their parent, each level sorted by score. It opens on the top level, every subtree folded behind its caret; click one to unfold a task's children (shift-click for the whole subtree; the header caret does every root, shift-clicked every level, and shift-clicked again folds the lot), and a task split under a folded parent waits behind that caret. Every pane's Columns button (top right of the header) offers every column its table has beyond the ones it opens on — the internal ids, when a task was last updated or completed, a reference's target and file type, and the Parent each task was split from, which is what a flattened tree needs to say what belongs to what. Completing a task completes everything split from it; reopening a child reopens its ancestors; deleting a task deletes its whole subtree — permanently, and it is the one thing here that cannot be undone.

Move re-files a task: pick a new parent, or — Top level — to make it a top-level task again. Everything split from it comes along. The picker offers every open task except the ones under the task being moved, and a move that would land a related task in its own tree is refused, naming the task references to remove first.

A task can be assigned to someone. Assigned To is a dropdown: pick a name, pick — New name — and type one — a name typed there joins the list and is offered from then on — or pick the blank first entry, which means nobody. The dropdown opens on whoever the task is assigned to, so leaving it alone changes nothing, and splitting a task opens on the parent's name, so a child usually needs no picking at all.

The list itself is yours to keep, under Configure › Assignees: add a name before anyone is assigned to it, fix a spelling, or take a name off it when someone leaves. Taking a name off the list changes the list and nothing else — every task already assigned to that name keeps it, and the name still shows in the dropdown of a task that carries it, so editing that task cannot lose it by accident. Renaming works the same way: it changes what the picker offers next time, not what any task says.

Every task gets a Task ID like TKMA00000042: TK, two letters from the username the server runs as (--user), and a sequence number that starts at 00000001, never repeats, and grows past eight digits rather than wrapping (TKMA100000000 follows TKMA99999999).

A task carries references: the things to refer back to while working on it. A reference is a link (a URL, including mailto: and mail-client deep links), a pasted text snippet (an email, a chat exchange), a file (a screenshot, a PDF), or another task with a relation. The References pane's Add Link, Add Text, and Reference Task buttons add one each, and the Detail pane has the same three. Each dialog opens on a Task picker already set to the task selected in the blotter — change it to file the reference on another task, or pick one when nothing is selected — with the label suggested from the URL or the first line of the text; once added, the blotter selects the task it went to, so the new reference is on show whichever task that was. Files are added from the Detail pane instead: select a task and drop, paste, or pick a file there; an image pastes straight from the clipboard, a pasted URL becomes a link, pasted text a snippet. The Detail pane opens with the task itself — its status, importance, urgency, score, due date, who it is assigned to, and notes — and lists every reference of the selected task the moment it is selected, and every reference of the tasks split from it — a section per relation ("Blocks", "Blocked by"), then the snippets, images, files, and links, each section counted, and a reference a child owns tagged with its Task ID. Images show as a grid of thumbnails; clicking one opens it full size under the grid, and clicking a snippet or a link opens it where it stands. The subtree comes from the tasks themselves, not from what the blotter is showing, so a completed child's references stay with its ancestor.

Snippets and notes are written formatted. Add Text, New, Split and the Edit dialogs write in an editor that shows the formatting as you type: select a few letters (even in the middle of a word) and press ⌘/Ctrl+B or I; start a line with 1. or - for a list, # for a heading, > for a quote. The toolbar under the text does the same and shows what the cursor is in; ⌘/Ctrl+K adds a link. Enter is a new line and ⌘/Ctrl+Enter saves. What is stored is still plain text (Markdown), so a database stays readable by any tool. A snippet's label, left blank, is its first line without the formatting. A snippet or note written as plain text before 0.21.0 opens in Edit exactly as written, with a Format picker: Formatted moves it into the editor character for character, and from then on it stays formatted. A snippet pasted or dropped in the Detail pane keeps the formatting of what was copied — bold, lists and links from a web page, a document or an email — and is plain text when what was copied had none, so code copied from an editor keeps every space. Anything that looks like HTML is shown as the characters typed, never as markup, and a link only opens a web or mail address.

Snippets are open from the start in the Detail pane, so selecting a task shows its notes and every snippet, formatted, with nothing more to click. Click a snippet to fold it; Fold all on the Snippets heading folds every one, and the browser remembers which you prefer.

The Text pane (under Detail; Tasks › Text reopens it) shows the text of the last thing you picked, full height, and nothing else: a task's notes, or a snippet picked in the References or Detail pane (an image shows as itself). Click the text to edit it right there: as in an Edit dialog, the formatting tools, with Cancel and Save at the right, appear in one row below the text, so the text never moves or hides. The edit stays open until you press Save (⌘/Ctrl+Enter) or Cancel (Esc), even if you pick something else meanwhile. A plain note is saved formatted, and one save is one step for Undo.

The Detail pane edits what it shows. It has its own toolbar — Add Link, Add Text, and Reference Task are the References pane's add buttons — and one cursor: click the task block or click a reference. Edit opens the dialog that matches — the same Edit dialog the blotter opens for a task, the same one the References pane opens for a reference — and Delete removes a reference (a task is deleted from the blotter, where the row being deleted is the row that was picked). An edit shows up here the moment the server announces it.

The References pane follows the selected tasks (mkui table linking; clear the selection to see every reference), each reference beside its task's Task ID and title (the title is joined in live: renaming the task updates the column), with links and files clickable and a text snippet's body in the Text column; selecting one there opens and marks the same line in the Detail pane, and a reference the Detail pane does not list leaves it alone. A task reference shows on both tasks, worded from each side, and Go to selects the related task in the blotter, so the Detail and References panes follow it (a related task the current filter hides is revealed first). The two chevrons that lead the Detail toolbar are Back and Forward: Back returns to the task, and the reference line, the last Go to left from, and Forward undoes a Back. Only Go to adds to that trail (a click in the blotter is not a jump), a new Go to after a Back drops what Forward had, a task deleted since is passed over, and one the filter hides is revealed, as Go to reveals it. The trail holds the last 50 places and does not outlive the page. Only tasks from different trees can reference each other; tasks that share a root are already related by splitting.

Relations are yours to define under Configure › Relations: each is a pair of wordings, one from this task to that one ("blocks") and one back ("blocked by"), or a single wording that reads the same both ways ("relates to"). A new database starts with those two. Renaming a relation rewrites every task reference that uses it; a relation in use cannot be deleted. Uploaded files live beside the database in <db>.files/, named by content hash; deleting the last reference to a file, or its task, removes the file.

Each task also shows its Last Event — the most recent thing to have happened to it, in words: Created, Split into Wire the pane, Attached a file: shot.png, Related: blocks TKMA00000002, Moved under TKMA00000007.

Every change is kept. Tasks and references carry a version number, shown as a column, and every version of every row is recorded. Adding, editing or removing a reference makes a version of the task that owns it — both sides of a task reference — so a task's history covers its references as well as its own fields, and each version says what it was about. History on the Tasks or References pane — or in the Detail pane, for whatever its cursor is on — opens that record: the versions as a table you can sort and search, a Diff of what changed between any two, and Blame for which version last set each field.

Undo and Redo step a record back and forth along those versions, from the same panes. They step the whole action, not one row: undoing a completion reopens the subtree it completed, undoing a task reference removes both halves, undoing a move puts back the ancestors it reopened. A confirmation says what is about to change. Undoing the creation of a task removes it, and redo brings it back. Editing a task after undoing it discards what was undone, the way typing after an undo does in an editor. There is no keyboard shortcut on purpose — this writes to data everyone on the server shares.

Undo and redo are refused rather than half-applied when they would strand something: a task that has since been split, a parent or a related task that has since been deleted, or a row another change has moved past.

Activity (under the Tasks menu) is the other half: a plain list of what happened to the selected task — created, split from, split to, edited, moved, completed, reopened, references added, edited and deleted, and every undo and redo. It follows the blotter's selection like the References pane, and unlike the version record it is never rewritten.

The Help menu has Keyboard Shortcuts — the keys the tables and dialogs answer to, and the reminder that Undo and Redo have none — and About: the version of the server you are connected to, the versions of mkui and mkio under it, links to the project, its issue tracker and its license, and Copy details, which puts all of it on the clipboard for a bug report.

Quick start

pip install mktask
mktask                    # http://127.0.0.1:8080/

Everything installs via pip; nothing is fetched at runtime.

CLI

mktask [config] [-p PORT] [--host HOST] [-d PATH] [-u USER] [--files DIR] [--version]
  • config — path to a mktask.toml. Defaults to ./mktask.toml if present, otherwise the one bundled with the package.
  • -p, --port — override the listening port (default 8080).
  • --host — override the listening host (default 127.0.0.1). mktask has no login, so 0.0.0.0 shares your tasks with the network.
  • -d, --db — database file (default mktask.db in the current directory); .db is appended when there is no extension. :memory: runs without persistence.
  • -u, --user — the username whose first two alphanumeric characters, uppercased, prefix new Task IDs (mark → TKMA…; a one-character name is padded with X), and which is recorded as the actor in each task's activity. Defaults to the OS login name.
  • --files — directory for uploaded reference files, served at /files. Defaults to <db>.files beside the database (mktask.db.files/), a temporary directory for :memory:.

The server prints the URL to open once it is listening. If the port is already taken it exits immediately with an error instead of starting.

Customizing

Copy the bundled config out and edit it:

python -c "import mktask, pathlib; print(pathlib.Path(mktask.__file__).parent / 'mktask.toml')"

mktask.toml declares the SQLite tables, the mkio services, and the static and config routes (keep relations.json, the seed for the relations table, beside a copied config); config/app.toml next to it declares the UI (menus, panes, frames, dialogs), which mkio serves to the browser as /config/app.json. A copied mktask.toml looks for static/ and config/ beside itself, so copy those two directories with it (or point its [static] and [config] routes at where they are). Both are plain TOML — see the mkio and mkui READMEs for the formats. The one piece of code is mktask/services.py, which the tasks service points at: it assigns Task IDs, runs the complete, reopen, and delete cascades, re-parents a task on a move (refusing a cycle or a move that would swallow a task reference), and manages references and relations (task references are written as a mirrored pair, labels follow the related task's title, a renamed relation rewrites its task references, orphaned files are removed). static/refs.js is the one custom widget and the whole Detail body: the toolbar, the task block, the drop box, the reference list of the selected task and its descendants (its own live queries), Go to, and the Back / Forward trail it leaves. Its Edit and Delete open the dialogs the Tasks and References panes already declare, borrowed from app.toml by pane and button name rather than copied.

Upgrading

Until 1.0, a release may change the database schema without migrating an older database. 0.2.0 did (Task IDs, splitting, and complete replacing done): delete a 0.1.0 mktask.db before starting a newer version. 0.3.0 only adds the task_refs table, which auto_migrate creates in an existing database, so a 0.2.0 database carries over as is. 0.3.1 changes no schema. 0.4.0 adds the relations table (created and seeded on first start) and stores a task reference's relation as its wording ("blocked by") rather than a key (blocked_by): task references made before 0.4.0 must be removed and re-added. 0.5.0 changes no schema — the Detail pane's new reference list reads the tables 0.4.0 already had, and neither does 0.6.0: moving a task rewrites one existing column. 0.7.0 changes no schema either: the Detail pane's toolbar sends the ops that were already there. 0.8.0 adds a last_event column, the task_events table, and a recorded history of tasks and task_refs — all of which an existing database picks up on first start: auto_migrate adds the column and the tables, and every row already there is recorded as its own version 1 so it can be stepped back to. Nothing has to be deleted. 0.9.0 adds an assigned_to column and the assignees table behind the Assigned To dropdown, both of which auto_migrate adds to an existing database on first start; every task starts unassigned and the list starts empty. 0.10.0 changes no schema: the reference add dialogs read a new lookup service over the tables that were already there. 0.11.0 changes no schema either: the References pane's Task Title is joined in by the task_refs query, which mkio 0.8.0 keeps live, so nothing new is stored. 0.12.0 changes no schema: it only takes the Show Open Only / Show All / Expand All / Collapse All entries off the Tasks menu. 0.13.0 changes no schema: the statusbar now shows the server's version beside the name, read from the same reply that checks the server is mktask. It is also the first release to require mkio and mkui 1.x (pip install --upgrade mktask brings them in); a 0.12.0 database carries over as is. 0.13.1 changes no schema: it is the Windows release, and raises the mkio floor to 1.0.1. 0.13.2 changes no schema: it raises the floor to mkio 1.1.0, whose server runs on asyncio's selector loop on Windows, so the connections a browser opens ahead of a page load and drops no longer print a ConnectionResetError traceback each. 0.13.3 raises it to mkio 1.1.1, whose Windows loop lets Ctrl+C stop the server at once instead of waiting for the next timer or packet. 0.13.4 changes no schema: it requires mkui 1.2.1, whose table redraws the expand caret of a task that gains its first child, or loses its last, by a Move; before, the caret stayed as it was until the row was redrawn. 0.14.0 changes no schema: the References pane gains a Text column showing a text reference's body, which the task_refs query already returned. 0.14.1 changes no schema: mktask --help says what the command starts, states every default, and ends with examples. 0.15.0 changes no schema: it adds the Help menu (Keyboard Shortcuts and About) and requires mkui 1.9.0, whose About box lets an app pick which of its built-in lines to show. 0.15.1 changes no schema: it expects expression language 2 from the server, which mkio 1.5.0 introduced, and raises the mkio floor to match; against mkio 1.5.0 or later, 0.15.0 showed "Server mismatch" on the statusbar. 0.16.0 changes no schema: the blotter opens on the top level, every subtree folded behind its caret, and it requires mkui 1.13.0, whose header caret folds every level on a second shift-click (the Keyboard Shortcuts box says so). It also raises the mkio floor to 1.6.0, the first mkio to send Cache-Control: no-cache on the files it serves: before it a browser could keep running an old mkui table for days after an upgrade, which is how a caret bug mkui fixed in 1.2.1 went on being seen. 0.17.0 changes no schema, only words: Add URL is now Add Link, and the old Add Link is Reference Task. A link is a URL reference; one task referring to another is a task reference to a related task. The stored kinds are still url and task, so a database carries over as is — though Last Events and Activity lines recorded before the upgrade keep the old wording (Added a URL, Linked: blocks …). 0.18.0 changes no schema and nothing on the server: Back and Forward on the Detail toolbar are the page's own memory of where Go to left from. 0.19.0 changes no schema and nothing you can see: the UI config is now TOML, config/app.toml, where it was static/app.json, so it can carry comments. The browser still receives JSON, at /config/app.json. Only a customized copy needs attention: add

[config]
"/config" = "./config"

to a copied mktask.toml, and put the UI config in a config/ directory beside it. An app.json you edited can move there as it is — it is served unchanged when no app.toml sits next to it.

0.20.0 changes no schema: every pane's Columns picker now offers every column its table has (Parent, Updated, Completed, a reference's Target and Type, the internal ids), each off until you tick it, and a task's History diffs its Assigned To. A saved layout keeps the columns it saved. 0.21.0 adds two columns, tasks.notes_format and task_refs.format, which an existing database gains on first start (everything already there is plain text), and requires mkui 1.35.0, whose dialogs take a field type an application registers — the editor. Snippets and notes are written formatted, and the new Text pane (under Detail) shows the picked task's notes or snippet, editable in place. A layout saved before 0.21.0 opens without it: Tasks › Text adds it. 0.22.0 changes no schema: a snippet pasted or dropped in the Detail pane keeps the formatting of what was copied (bold, lists, links), and stays plain when what was copied had none.

Development

pip install -e '.[test]'
mktask -d :memory:
python -m pytest

The formatted-text editor is TipTap 3 (MIT), bundled into one file, mktask/static/vendor/tiptap.js, with every bundled package's license beside it. The bundle is committed, so running or installing mktask needs no node or npm; only rebuilding it does:

cd editor && npm install && npm run build

The tests cover the CLI and config loading, Task ID formatting, a real server over HTTP and WebSocket (every task op, splitting and the cascades, moving a task to another parent or the top level, the Task ID sequence across restarts and past eight digits, references and task references with their validation, the same-tree rule, and cascades, user-defined relations (seeding, uniqueness, rename rewriting task references in both directions, a swap flipping them, delete refused in use), file upload, dedupe, and cleanup, live delete announcements, the query filter, saved layouts, the port, host, user, and files flags), the port probe on a fake Windows, what only breaks on Windows (every text read names its encoding, LF pinned), the editor's Markdown under node, when it is installed (typed text comes back as typed, what the editor writes reads back as itself, and nothing typed renders as markup), the Text pane's two saves, and the static integrity of app.toml against mktask.toml and refs.js (every column, dialog field, service, and state path a pane names, the Detail pane's task block and the dialogs its toolbar borrows, and the reference sections against the kinds the server accepts).

Runs on Linux, macOS and Windows with the standard CPython 3.11+ interpreter; Windows needs mkio 1.1.1 or later, which pip install brings in. On Windows, Ctrl+C stops the server the same way as elsewhere. The Task ID prefix comes from the account name's first two ASCII letters or digits, so a name starting with a space or a non-ASCII letter still yields a valid one.

License

Apache License 2.0. See LICENSE.

Metadata

Release files for mktask 0.22.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mktask 0.22.0
File Size Uploaded Provenance
mktask-0.22.0.tar.gz 311.2 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for mktask 0.22.0
File Interpreter ABI Platform
mktask-0.22.0-py3-none-any.whl Python 3 none any Details

Total release size: 532.0 kB

Release files / mktask-0.22.0.tar.gz

Download URL mktask-0.22.0.tar.gz
Size 311.2 kB
Tags Source
SHA-256 checksum
How to use checksums
e2f050cb6d3f4025f46b6f0a76dc472011eb18b587d4c83f52002667faf9d8c5
BLAKE2b-256 checksum
How to use checksums
bbe1c769ed30f6c6de5d6a0b73170b8aeb32ce5183c37d0ff24f4f3a323e970c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.7

Release files / mktask-0.22.0-py3-none-any.whl

Download URL mktask-0.22.0-py3-none-any.whl
Size 220.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2f9465c86d633209c7b82df603de99157393f35b20cc862e167cf9a3e623fb76
BLAKE2b-256 checksum
How to use checksums
a7a42c982bfb88f27d9d6958711c51308bc6883143111e029d9900ea70792310
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.7

Security for mktask 0.22.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.22.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page