How to Calculate the Critical Path, and What Andamio Calculates

In any plan with more than a handful of tasks, some tasks can slip by a week without moving the launch, and others can’t slip by a day. The critical path method (CPM) is how you tell them apart. It was published in 1959 by James Kelley and Morgan Walker in “Critical-path planning and scheduling”, and the arithmetic hasn’t changed since.

The critical path is the longest chain of dependent tasks from start to finish. Its length is the shortest time in which the project can be done, and any delay on it delays the end.

This post works through the method by hand, then says plainly which part Andamio calculates and which part you still do yourself.

An example with two tracks

Say you’re launching a mobile app. There are two tracks of work, and both must be done before launch day:

Track A is the critical path. The launch can’t happen before day 32. Track B has 18 days of slack (also called float): it could start late, or run late, by up to 18 days and the launch would still be on day 32. If the API takes 11 days instead of 10, the launch moves to day 33.

If you don’t know which track is critical, it’s easy to spend your attention on the wrong one. Chasing the marketing site, which has 18 days to spare, does nothing for the date. The API has no spare days at all.

Step 1: write down the dependencies

For each task, ask one question: what has to be finished before this can start? Write down only real blockers, not things that would be nice to have first. Too many links turn the plan into a single line and hide work that could happen in parallel.

There are four formal types of dependency:

Any of them can carry a lag, a forced wait (three days for concrete to set), or a lead, an overlap (start editing when half the chapters are written).

Step 2: the forward pass

Go through the tasks from left to right and work out the earliest each one can start (ES) and finish (EF):

EF = ES + duration

A task with several predecessors starts at the latest of their finishes: testing can’t start until both the backend and the frontend are done. For our example, database setup runs from day 0 to 5, the API 5 to 15, the frontend 15 to 25 and the store review 25 to 32. On Track B, copywriting runs 0 to 4, design 4 to 9 and web development 9 to 14. Launch is day 32.

Step 3: the backward pass

Now start from the end date and go right to left, working out the latest each task can finish (LF) and start (LS) without moving the end:

LS = LF − duration

A task with several successors must finish by the earliest of their late starts. On Track B, web development must finish by day 32, so it can start as late as day 27. Design must finish by 27, so its latest start is 22. Copywriting must finish by 22, so it can start as late as day 18.

Step 4: slack

slack = LS − ES

Copywriting’s earliest start is day 0 and its latest is day 18, so it has 18 days of slack, and so do the other two tasks on Track B. Every task on Track A has an earliest start equal to its latest start: zero slack. The tasks with zero slack are the critical path.

What Andamio calculates

Andamio does step 2. Every time the plan changes, calculateSchedule (in src/utils/scheduling.ts) gives each task a length, places it after the latest end among its dependencies, and repeats until no date moves. If you enter the example above, the store review ends on day 32, the marketing site on day 14 and the launch milestone sits on day 32. We checked this by running the function on exactly these tasks.

It doesn’t do steps 3 and 4. There’s no backward pass, so Andamio doesn’t know that Track B has 18 days to spare. It doesn’t compute slack, and it doesn’t highlight a critical path. The tasks with zero slack look the same as the rest.

One thing can look like it: the “Blocked” status. In the Mermaid export it becomes Mermaid’s crit tag, which draws the bar in red. It’s a status you set by hand, not a calculation.

Which dependencies it supports

Only finish-to-start, with an optional offset in days:

There’s no start-to-start, finish-to-finish or start-to-finish. If you need one, the closest approach is to split a task. For “the manual starts when the beta starts”, make the beta’s first day its own short task and hang the manual from that.

Two more details affect the numbers. Durations are calendar days: weekends are shaded in the chart, but they’re counted. And a task’s length includes its buffer and review time (max(effort, timespan) + buffer + ceil(effort × validation complexity)), so a chain in Andamio is usually longer than the same chain drawn with effort alone. That’s intended; the buffer post explains why.

Doing the rest by hand

Andamio gives you the early dates. For slack, you need the late ones:

  1. Take the date of the final milestone (hover over it in the chart to see it).
  2. For each task at the end of a chain, the latest finish is that date.
  3. Work backwards: latest start = latest finish − length (use the length from the bar’s tooltip, which includes buffer and review time).
  4. Where a task feeds several others, take the earliest of their latest starts.
  5. Compare with the start date Andamio shows. The difference is the slack.

If you only need to know which chain is critical, a quicker check works. Make a task one day longer and see whether the final milestone moves. If it does, that task is on the critical path.

What to do with the critical path

Once you know which tasks have no slack:

  1. Protect them. The people on critical tasks are the ones who shouldn’t be pulled into other work. Splitting their time has a cost we look at in the fallacy of multitasking.
  2. Move help towards them. If a critical task falls behind, people from tasks with slack can help, as long as the work can actually be shared.
  3. Spend money where it changes the date. If the launch has to come earlier, paying overtime on Track B changes nothing. Only shortening a task on Track A does.

To size the margin at the end of the critical path, try the project buffer calculator. It adds up a chain of three-point estimates and gives you a buffer for the whole chain.