Share this post :

Plan like a Pro with Automatic Scheduling in Taskjuggler

The Need for Automatic Project Scheduling?

Every one of us has done some project planning in a way or another. Some people would have used fancy GANTT editing tools for that; others would just go ahead and dump their brains onto a backlog. But very few are those who follow an automatic approach to “schedule” their projects.

More often than not, people would go manually about making decisions about the gameplay to adopt facing their daunting projects. They try to envision the best possible plan while mentally trying to sort what we call “precedence constraints,” i.e., one can’t work on Task A before Task B and C have been achieved. They do so all while finding feasible and commercially viable resource allocation schemes. Also, they need to contort to time-bound constraints, like deadlines and seasonal phenomena.

All that makes a perfect case for an automatic scheduling tool, and Taskjuggler might be the most powerful – if not the only – mature alternative you have at hand. But this is not a shiny Kanban-y drag-and-drop thingy: this is a full-fledged enterprise-grade automatic project planning and estimating solution, so much that it takes some learning curve to get fluent in it, but believe me, the effort is worth it.

Taskjuggler: Thinking in Work Breakdown Structure

Without drowning too deep in detail, Taskjuggler lets you focus on your project structure.
Rather than giving you GANTT drawing tools and letting you figure the plan out yourself, Tasjkjuggler asks that you give it your Work Breakdown Structure, and it does the scheduling for you. Simply put, A Work Breakdown Structure is a graph depicting the tasks you need to achieve, along with the relationships between them and the resources necessary to make them happen.

Taskjuggler is also able to follow on the realization of the project and will adjust the plan according to the actual project roll-out. Besides, it offers you the possibility to simulate multiple scenarios.

Taskjuggler is also finance aware, and sports an accounting module that can track the costs inferred by the allocated resources against revenues that you’d record as you’re working on your project. I have used this accounting module so many times as my secret weapon to come up with detailed financial quotes and win the commercial race!

Taskjuggler in action

First of all, you’ll need to install Taskjuggler following the instructions on its website.

Taskjuggler comes as a line command, tj3, that compiles your project descriptions into the project reports you specify. Let’s run through a simple example.

Suppose you want to specify a Software Development project. We first need the data engineer to design the database, then have the web designers design the application, then have the Devops deploy it.

Let’s begin by creating a file for our project. We’ll name it project.tjp.

We’ll begin by specifying our project name, plus some general information about it, like its start date, and what would be the deadline for it(1 month from the start, hence the +1m”:

project softdev "Software Development"  2020-08-16 +1m {
 timezone "Europe/Paris"
 currency "USD"

Let’s then declare the financial accounts we’ll be using to track the finances of our project:

account cost "cost"
account rev "payments"
balance cost rev

We now declare the resources we need for our tasks:

resource data_engineer "Data Engineer" {
    rate 200

resource web_engineer "Web Engineer" {
    rate 200

resource devops_engineer "Devops Engineer" {
    rate 200

rate will be used to give a financial estimate of our project. We are using the simplest form, but you can organize them into teams, flag them, assign managers…

Let’s now get into the actual business. Next, we’ll describe our Work Breakdown Structure, that is, tasks, constraints, and resources. We’ll organize our tasks into to categories. Work, where we’ll describe our actual tasks to be done, and Milestones, to track important steps and deliveries of our project. For this, we’ll use the possibility to nest Tasks in taskjuggler. First, let’s see the Work part.

task work "Work"{
  task data "Database Design" {
    chargeset cost
    allocate data_engineer
    effort 3d # This task takes 10 days effort

  task web "Web App Design" {
      chargeset cost
      allocate web_engineer
      effort 3d # This task takes 10 days effort
      depends !data  # This task needs task data to be complete

  task deploy "Deployment" {
      chargeset cost
      allocate devops_engineer
      effort 3d # This task takes 10 days effort
      depends !web # This task needs task web to be complete

The chargeset clause is used to add the costs inferred by a resource working on a task to a particular account, which is cost here. We’ll use this account to get a quote for the whole work needed for this project.

The depends construct tells Taskjuggler that a task can’t be worked on BEFORE the referred task has been achieved. This is what we call “Precedence Constraint” in Work Breakdown Speak.

The depends clause uses the exclamation mark ‘!’ to refer to tasks that are one level higher in the hierarchy. For example, deploy depends on !web means that it depends on the task web under a direct parent(one level up), yielding its direct sibling web(their common parent task being work)

Now for the Milestones section:

task milestones "Milestones" {
  task db_milestone "Database Finish" {
      # A milestone has effort 0, it's represented as a little black square
      depends !!

  task web_milestone "Web Finish" {
      # A milestone has effort 0, it's represented as a little black square
      depends !!work.web

  task deploy_milestone "Deploy Finish" {
      # A milestone has effort 0, it's represented as a little black square
      depends !!work.deploy

  task project_end_milestone "Project End" {
    depends !!work.deploy

Note how now depends uses a double exclamation mark. Look at task deploy_milestone for instance. It is meant to track the completion of the deploy task under the work container task. At this level, we are under milestones, so we need one ! to get to the level of the direct parent milestones, then another more to get the grand-parent level, under which we get to the aunt task work and refer deploy by using a familiar dotted syntax, hence the !!work.deploy token.

At this point, our project description is finished, but if you run it through the taskjuggler compiler, you won’t get any output:

tj3 project.tjp
#... Truncated Output
Warning: This project has no reports defined. No output data will be generated.
Warning: None of the reports has a 'formats' attribute. No output data will be generated.

Indeed, you need to specify reports to get the Taskjuggler engine to compile the results under the format you want. And this is presumably the most complicated part. Here we go.

We’ll generate a static website. The entry point to the reports is the Overview report page, with a link to detailed resource allocation by task under the Development subreport, and a link to a resource Utilization under the Resource Graph subreport.

This post won’t dive into the Taskjuggler report syntax, however, you can use the following as a template to start your pro scheduling journey – this is actually the way I followed (without necessarily being fluent in the syntax).

The main report Overview is specified like so:

navigator navbar {
  hidereport @none

macro TaskTip [
  tooltip istask() -8<-
    '''Start: ''' <-query attribute='start'->
    '''End: ''' <-query attribute='end'->

    <-query attribute='resources'->
    '''Precursors: '''

    <-query attribute='precursors'->
    '''Followers: '''

    <-query attribute='followers'->

textreport frame "" {
  header -8<-
    == Toy Software Development Project ==
    <[navigator id="navbar"]>
  footer "----"
  textreport index "Overview" {
    formats html
    center '<[report id="overview"]>'

  textreport development "Development" {
    formats html
    center '<[report id="development"]>'

   textreport "ResourceGraph" {
    formats html
    title "Resource Graph"
    center '<[report id="resourceGraph"]>'

taskreport overview "" {
  header -8<-
    === Project Overview ===

    The project is structured into 3 phases.

    # <-reportlink id='frame.development'->

    === Original Project Plan ===
  columns bsi { title 'WBS' },
          name, start, end, effort, cost,
          revenue, chart { ${TaskTip} }
  # For this report we like to have the abbreviated weekday in front
  # of the date. %a is the tag for this.
  timeformat "%a %Y-%m-%d"
  loadunit days
  hideresource @all
  balance cost rev
  caption 'All effort values are in man days.'

footer -8<-
    === Staffing ===

    All project phases are properly staffed. See [[ResourceGraph]] for
    detailed resource allocations.

The Report for “Development” is as follows:

taskreport development "" {
  headline "Development - Resource Allocation Report"
  columns bsi { title 'WBS' }, name, start, end, effort { title "Work" },
          duration, chart { ${TaskTip} scale day width 500 }
  timeformat "%Y-%m-%d"
  hideresource ~(isleaf() & isleaf_())
  sortresources name.up

and finally, the Report for “Resource Graph” is like so:

resourcereport resourceGraph "" {
  headline "Resource Allocation Graph"
  columns no, name, effort, rate, weekly { ${TaskTip} }
  loadunit shortauto
  # We only like to show leaf tasks for leaf resources.
  hidetask ~(isleaf() & isleaf_())
  sorttasks plan.start.up

Now, save the project definition and compile it:

tj3 project.tjp

after successful scheduling, you’ll see a set of HTML files and other assets that have been created. Head over to Overview.html in your browser:

You see Taskjuggler has computed a schedule for you. Verify that precedence has been respected. Note the cost by task and for the overall project (we have no revenue at this point). Also, see how the Work and Milestones umbrella tasks make our project schedule clearly presented by separating work to be done and the expected deliveries or milestones.

Let’s explore the detailed task description by clicking on the Development link:

You see in this Report how tasks are being worked on by each resource.

Now head over to the Resource Graph report to see how are resources being used overall in this project:

You can notice how this report shows how much is every resource being loaded during the execution of its assigned tasks.


We just scratched the surface of what’s possible with Taskjuggler. It is really a unique scheduling beast; one that can accomplish so much, but which is unfortunately not well served by its looks.
First, the only viable option to interact with it now is the proprietary syntax we’ve covered. This is showing its limits, as very poor tooling exists, and for large projects, with complex task hierarchies and report schemes, one can easily feel lost.
Second, although it’s possible to track the progress of projects, Taskjuggler lacks advanced enterprise collaboration features. I think I’ve read somewhere it has a server or something, but I don’t think it’s of any practical use right now.

All of these problems make this tool only fit for the vim-savvy engineer, unfortunately. But once mastered, this is a very sharp one to run accurate time and money estimates, and to effectively track costs, and I think it can perfectly sit next to other collaborative agile Trellos and Jiras.

This blog was first published in

Share this post :

Sign up for Newsletters