Plain-text, version-controlled task management for developers. Your tasks live in a simple text file, not some web app.
This project is >> under construction << - more features to come. (c.f. README.vision.md)
tasks.md:
- [ ] a task - this is the task-title
Some more info on this task - this is the task-body
Both inside and outside of tasks, you can just use normal markdown syntax
- [ ] a subtask @markus
more details for this subtask go here.
- [x] this subtask is doneTasks follow a specific syntax. You will receive immediate feedback and quick fix options in your text editor via the language server. Use the CLI tool to add strict checks as pre-commit hooks or in your pipeline – your task list is always consistent. Everything is designed with a "command line first" approach: text files and CLI tools are the primary interface. A graphical client provides a convenient "board view" for your team meetings and some limited editing options.
Simple animated board
Formatting rules enforced via language server with quick fixes!
See INSTALL.md
Tasks must follow the Markdown standard, and subtasks must be correctly indented. A task that is "done" is marked with a lowercase x.
Correct:
- [ ] a task
- [ ] a subtask
- [x] this subtask is done
- [ ] another taskIncorrect:
- [ ] a task
- [ ] a subtask
- [ ] is this a subtask or a task? Nobody knows.Other content is ignored. You can therefore freely complement your task lists with other notes. A newline separates tasks from other tasks or content.
- [x] a task
- [x] a subtask
# A Markdown Heading
And some further notes
- [ ] more tasksmdagile uses the following symbols for syntax: # @ \ '
Escape a #/@ so it's treated as plain text (not a marker) with either:
- a backslash immediately before it (
\#,\@), or - a pair of single ticks fully wrapping the term (
'#not_a_property','@not_an_assignment'— both the opening and closing tick must be present, immediately around the term).
Double quotes (") have no escaping effect — "#foo" and "@bob" are still real markers. Double quotes are reserved for a separate, unrelated convention: marking a subtask as required by a property (see "Subtasks" below).
- [ ] a task with a hashtag \#not_a_property
- [ ] a task with a mail address: markus\@company.org
- [ ] a task mentioning '#not_a_property' or '@not_an_assignment' in prosePrioritization is fully reflected by the order of tasks in your tasks file(s). The most important task is at the top, the least important at the bottom.
No Swim Lanes
Some task management tools define "swim-lanes", where each swim-lane constitutes an independent priority list. mdagile does not have a swim-lanes feature, but you can:
- strictly assign tasks to teams with assignment markers (
@...). - loosely assign tasks to teams with property markers (
#...).
There are no swim-lanes, because this does not work well with milestones—you still have to ultimately decide for each individual task whether it is part of a milestone or not.
If you have multiple truly independent teams, each doing their own prioritization, you can use multiple subdirectories (and multiple mdagile.toml and tasks.md files). Note that these teams will not work towards the same milestones (see "Milestones").
No "High Priority" Markers
There are also no priority categories for tasks ( !prio:high ). There is only a global absolute priority ordering. Ultimately, if I see two tasks in front of me, even if both are "high prio", I still have to pick one of them to do first. There is no way around an absolute priority order. Priority "categories" are misleading. Caveats ;)
agileOpens the highest-priority incomplete task in your $VISUAL or $EDITOR. Jumps to the correct line for vim, nvim, nano, emacs, and VS Code.
agile task list # All active tasks (default)
agile task list --all # All tasks including done and cancelled
agile task list -n 5 # First 5 active tasks
agile task list --last 3 # Last 3 active tasks
agile task list 2:4 # Tasks 2 through 4 (1-based, inclusive), with subtasksagile file # Show all task files in priority order (alias: agile files)agile task next # Print the next incomplete task (same as `agile` with no editor)
agile task show 2.1 # Alias for `task next`; print one specific (sub)task by addressagile checkParses all *.agile.md files and reports validation issues. See doc/checks.md for the full list of checks.
A minimal LSP server that offers real-time diagnostics as you edit, and offers quickfix code actions for fixable issues. Runs the same checks as agile check — see doc/checks.md.
Use the installed shortcuts - just search "mdagile Board". This opens a browser view to your tasks - Don't be confused: Your browser is connecting to a program running fully locally on your machine. We simply use the browser as a powerful "UI framework" so to say.
Alternatively, launch via terminal command agilegui then connect to the shown ip in a browser (in browser search bar type e.g. http://127.0.0.1:8080/).
After launch, indicate the directory where your task files live (Menu > Switch Project).
A task that is "done" is marked with a lowercase x; - marks a task as cancelled. Subtasks must be indented two spaces per level, directly under their parent (no blank line in between) — a blank line always starts a new top-level task:
- [ ] a task
- [ ] a subtask
- [x] this subtask is done
- [-] this subtask is cancelled
- [ ] another top-level taskOther content (headings, prose, etc.) is ignored, so you can freely mix notes into the same file. See doc/checks.md for the full list of formatting/marker rules agile check enforces.
Task files must be named <something>.agile.md and can live anywhere under the project root; every match is picked up automatically (agile file shows them in priority order). Files are ordered alphabetically by path relative to the project root (directories first, then filename) — this determines cross-file task priority, so e.g. tasks in tasks/50_current/001.agile.md outrank tasks in tasks/60_backlog/001.agile.md.
Other markdown files (e.g. your README.mds) are ignored, even if they contain syntactically valid tasks.
By default, all subtasks are mandatory. A parent task may only be marked complete when all subtasks are done.
- [ ] a task
- [ ] some mandatory subtaskOptional subtasks are not required for completion of the parent task. They are prefixed with the special marker #OPT (all caps) after the checkbox:
- [ ] a task
- [ ] #OPT some optional subtaskYou specify available properties globally for your project in the mdagile.toml (or .mdagile.toml) file. Property names cannot contain spaces, but you can use - and _. Properties can then be added to tasks with #<property_name>.
E.g. to declare a property #feature:
mdagile.toml:
[Properties.feature]To use the property, place it anywhere in the task:
tasks.md:
- [ ] #feature: add item to basketYou are not allowed to use a property that is not defined in the mdagile.toml. This is to keep things orderly—no proliferation of random meaningless hashtags, and no duplication (#Feature #feature #feat). The tool will issue an error if you use undefined properties. Otherwise, an "empty" property doesn't do much. It just marks a task as part of some group—but you can do much more with them ...!
Properties are the essential building blocks of your team's task management strategy - you can keep things simple or get really sophisticated - it is up to you!
You can define mandatory subtasks via properties.
[Properties.feature]
subtasks = ["PO review", "dev implementation", "dev documentation", "test"]Properties are added to tasks with a # followed by the property name. This makes the existence of the respective subtasks mandatory:
- [ ] #feature: add item to basket
- [ ] "PO review"
- [ ] "dev implementation"
- [ ] "dev documentation"
- [ ] "test"
- [ ] another custom task that is not part of the '#feature' propertyIf you have added a property, but not the required subtasks, the language server will give you a hint - use the autofix feature of your text editor to quickly complement the missing subtasks.
Subtasks that are required by a property are quoted "".
Properties can also be added to subtasks! Note how '#feature' is quoted in the example above - the ticks prevent the tag from being interpreted as a property of the subtask. Otherwise you get the following:
- [ ] #feature: add item to basket
- [ ] "PO review"
- [ ] "dev implementation"
- [ ] "dev documentation"
- [ ] "test"
- [ ] #feature view number of items in basket
- [ ] "PO review"
- [ ] "dev implementation"
- [ ] "dev documentation"
- [ ] "test"You can mark a task as cancelled with a -
- [-] this task is cancelledSometimes your team may plan something and later decide, that it's not necessary after all. Marking tasks as cancelled makes things transparent ("This was part of the original plan, but discarded").
By default you can not cancel subtasks that are required by properties, but this can be adjusted in the configuration.
[Properties.feature]
subtasks = ["PO review", "dev implementation", "dev documentation", "test"]
subtasks_allow_cancel = [true, true, true, false]
# testing can not be cancelledWhy make subtasks "mandatory" by default, but also allow to cancel them? Properties allow you to define general default workflows. But sometimes a step just doesn't make sense in a specific case. You would then be tempted to just mark the task "done", even though that is a lie. You may add a note, but such notes are non standard and easily misinterpreted. Cancelling a subtask provides an idiomatic way to communicate that a step was skipped. It is honest, transparent and conventional.
Tasks can have multiple properties. The placement of the property in the task is not relevant. The order of the subtasks is not relevant.
[Properties.UI]
subtasks = ["UI / UX concept", "UI review"]- [ ] We want to develop a #feature (add item to basket) that will have a very nice #UI!
- [ ] "UI / UX concept"
- [ ] "PO review"
- [ ] "dev implementation"
- [ ] "dev documentation"
- [ ] "test"
- [ ] "UI review"Properties can be nested. This allows you to define subtasks that are shared across multiple properties in a single place. In the example below, the #review property is shared between #feature and #UI:
[Properties.review]
subtasks = ["independent review by a second person"]
[Properties.feature]
subtasks = ["dev implementation", "dev documentation", "test", "developer #review"]
[Properties.UI]
subtasks = ["UI / UX concept", "UI / UX #review"]A valid task then looks like this:
- [ ] We want to develop a #feature (add item to basket) that will have a very nice #UI!
- [ ] "dev implementation"
- [ ] custom task (not from property)
don't forget that you can still add those anywhere in the structure.
- [ ] "dev documentation"
- [ ] "test"
- [ ] "developer #review"
- [ ] "independent review by a second person"
- [ ] "UI / UX concept"
- [ ] "UI / UX #review"
- [ ] "independent review by a second person"You can define an order in which tasks have to be done:
- [ ] make app more responsive
- [ ] 1. add performance UI test
- [ ] 2. refactor signals
- [ ] 4. document learnings
- [ ] 3. run UI tests
- [ ] 2 or more test users agree that performance is sufficient
- [ ] discuss further stepsOrdering numbers have to follow the checkbox after a single space character, must be followed by a . and must be separated from the next word by at least one space. The subtasks do not have to be arranged in order (note how 3 and 4 are mixed up).
If there is no . after the number, it is not interpreted in any way. There can not be two tasks with the same rank.
When an order is defined, the following rules apply:
- Unordered tasks ("discuss further steps", "2 or more test users ..") can be marked complete at any point.
- Ordered tasks can be marked complete only when all previous tasks are complete.
Meaning the following is not allowed:
- [ ] make app more responsive
- [ ] 1. add performance UI test
- [x] 2. refactor signals
- [ ] 4. document learnings
- [ ] 3. run UI tests
- [ ] 2 or more test users agree that performance is sufficient
- [ ] discuss further stepsSubtasks required by #properties can also be ordered:
[Properties.feature]
subtasks = ["1. dev implementation", "2. dev documentation", "3. test", "4. developer #review"]You can assign tasks to specific people or groups with the assignment marker: @someone
- [ ] implement feature X @markus
- [ ] Review the feature @QA
The implementation can only be marked complete by Markus. The review may be checked by any QA person. mdagile identifies the current user via info available in git config, and checks this ID against the assigned users and groups. You can alternatively identify yourself explicitly via command line argument --as <user>. Use this in pipelines, where the user's .gitconfig is not available.
Assignments on parent tasks do not affect child tasks (but child tasks can be assigned as well).
This feature requires that groups and users are first identified in the configuration.
Consider this feature only "automation", not "access control". This is not secure in any way -- The mechanism can easily be sidestepped! Your git history however will reveal any inconsistencies c.f. MANIFESTO.md "Trust through Transparency".
[Users.markus]
git_names = ["Markus Myman"]
git_emails = ["markusmyman@company.org"]
[Users.svenja]
git_names = ["Svenja Super"]
git_emails = ["svenjasuper@company.org"]
[Groups.DEV]
members = ["markus"]
[Groups.SENIORDEV]
members = ["markus"]
[Groups.QA]
members = ["svenja"]
[Groups.TEAM]
members = [
"markus",
"svenja",
]You can tag multiple people or groups on the same task. In this case any person or any member from any group can mark the task as complete.
- [ ] implement feature X @markus or @josh
If you want an AND connection instead, create subtasks for each person!
Mdagile supports agile planning and time estimation via milestones:
A milestone is simply a marker between tasks, identified by the special tag #MILESTONE . When all tasks above (before) the milestone are complete, the milestone is reached.
- [x] implement all MVP features
- [x] perform first release
#MILESTONE: Release of MVP :)
- [ ] gather first user feedbackPunctuation directly behind the tag is ignored (#MILESTONE is equivalent to #MILESTONE:, #MILESTONE! etc.). A milestone name must be provided, and milestones must be unique across the project.
Once you have defined milestones you can
- get count of remaining tasks (and subtasks) to milestones
- estimate velocity and creep
- calculate ETAs (Estimated Time to Arrival) for each milestone
Milestone-related commands are split by concern: agile milestones (alias milestone) reports the current state of milestones — no time estimation at all — while agile when reports estimation (ETA and velocity).
$ agile milestones
1 0.8 alpha 12 / 20 60%
2 Release of MVP :) 3 / 21 14%
3 Release of v2.0 0 / 34 0%
4 Product generation 2 0 / 50 0%agile milestones lists future milestones only — those that appear after the first incomplete task in the backlog — in backlog order, numbered by rank (1..N) starting from the next milestone to be reached. This is also the primary way to look up a milestone's rank for --next <rank> (here and in agile when). Rank, name, done-count, and percentage columns are padded to line up across all rows; names longer than 40 characters are shortened with a trailing … so they can't throw off that alignment. Percentages are always rounded down (floored) to the nearest whole percent, so 100% is only ever shown once every task in scope is actually complete. Weight values are rounded to at most one decimal place (trailing zero trimmed).
The flag --count shows data based on top-level task counts instead of task weight (the default).
You can inspect one milestone's current state in more detail by providing its rank (as provided by agile milestones), e.g.
$ agile milestones --next 2
milestone: Release of MVP :)
tasks since last milestone: 21
tasks to do: 18
tasks done: 3
tasks percentage done: 14%
weight to do: 23.3
weight done: 6
weight percentage done: 14%with the agile when command:
$ agile when
7 days 0.8 alpha
3 weeks Release of MVP :)
4 months Release of v2.0
2 years Product generation 2Alone, agile when calculates the ETA for all future milestones and lists them in order as they appear in your backlog (which by design is the same as ordering by ETA). The time unit is weeks for ETAs below 8 weeks, years from 3 years and higher, months otherwise.
You can inspect one milestone's ETA in more detail by providing its rank (as provided by agile milestones), e.g.
$ agile when --next 2
milestone: Release of MVP :)
ETA: 3 weeks
ETA date: 2026-05-04
tasks since last milestone: 21
tasks to do: 18
tasks done: 3
tasks percentage done: 15%
weight to do: 23.3
weight done: 6
weight percentage done: 15%Estimation is based on a recency weighted linear fit for both the "total" and "done" tasks (using task weights). ETA is simply the point where the extrapolated trend lines intersect. You can get a visualization with the --plot flag. There are options for ascii art terminal output and html.
(In your terminal this output will come with color ;))
$ agile when --plot
Milestone: Demo milestone
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠤⠒⠁
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⣀⠤⠒⠉⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⣀⠤⠒⠉⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⡧⠒⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠂
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠤⠒⠉⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⢀⠤⠒⠁⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠤⠒⠉⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⣀⠔⠊⠁⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⢤⣒⣉⣀⣀⣀⣀⣀⣀⣀⣀⣀⡇⠀⠀⡠⠔⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠤⠒⢉⠔⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡧⠒⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠔⠊⠁⠀⢀⠔⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠤⠊⠁⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠈⠑⢄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠔⠊⠁⠀⠀⠀⡠⠔⠁⠀⠀⠀⠀⠀⠀⠀⠀⡠⠔⠊⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠈⠢⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠔⠊⠁⠀⠀⠀⠀⠀⡠⠊⠀⠀⠀⠀⠀⠀⠀⢀⡠⠔⠉⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠑⠢⡀⠀⠀⢀⡠⠔⠊⠁⠀⠀⠀⠀⠀⠀⠀⡠⠊⠀⠀⠀⠀⠀⠀⢀⠤⠒⠁⠀⢀⣀⣀⡠⠤⠤⠔⠒⠒⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⢀⡨⠕⢎⣁⣀⣀⡠⠤⠤⠤⠔⠒⠒⠒⠉⠀⠀⠀⠀⠀⣀⠔⠊⢁⠤⠊⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⢀⡠⠔⠊⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⠔⠉⣀⠔⠊⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⣀⡠⠔⠊⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠒⢉⡠⠔⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠤⢊⣁⠤⠒⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⡠⠴⠞⠒⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠔⢒⡪⠝⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⢀⡠⠔⠊⢁⠤⠒⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⢀⡠⠔⠊⠁⣀⠔⠊⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠉⠁⠀⠀⠀⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
2026-06-24 2026-09-05
.... total .... done
.... total trend .... done trend
.... today
Trend lines (x = weeks since 2026-06-24):
total = 8.94 + 1.59/week * x
done = 1.29 + 1.97/week * x
total: 23 tasks (weight 23.00)
done: 18 tasks (weight 18.00)
ETA: 3 months
ETA date: 2026-11-10
If the mathematical intersection point is in the past (or lines are perfectly parallel), the ETA will be "unknown". This happens when your "total" is growing faster than your "done" line, or in other words your scope creep is higher than your velocity. You have runaway scope and should probably put a lid on those feature requests ...
For the purpose of ETA estimation only, the tool assigns different weights to tasks and subtasks. The total weight of a task is the sum of the weights of its subtasks, plus 1 (the task itself). The weight of a subtask is 1/"subtask level". E.g.:
- [ ] A simple task: Weight = **1**
- [ ] A task with two subtasks: Total weight = 1 + .5 + .5 = **2**
- [ ] subtask 1: Weight = 1/2
- [ ] subtask 2: Weight = 1/2
- [ ] Total weight = 1 + .5 + .33 = **1.83**
- [ ] Weight = 1/2
- [ ] Weight = 1/3Whenever the tool needs to "count" tasks, for the purpose of time estimation, task weights are used instead of the raw count. Subtasks that are required by a property are counted in exactly the same way as custom tasks.
See MANIFESTO.md. Term definitions (Marker, Property, Assignment, Special Marker, etc.) are in GLOSSARY.md.