# How dependency scheduling works

A dependency makes one item wait for another. When a date changes, Teamhood moves the waiting items later by the fewest working days that keep every dependency true. A date change never moves an item earlier, and scheduling never moves the item you just placed.

## What a dependency asks of the dates

Working days are Monday to Friday for the whole organization, and holidays still count as working days. Every day count in scheduling is in working days: lag, the days an item moves, and the free days before a limit.

A dependency joins a predecessor, the item that goes first, to a successor, the item that waits. The dependency sets the earliest date the successor may have. Scheduling always reads and writes the **Start** and **Finish** fields. A Gantt that maps other date fields draws its bars from those fields, and a drag there changes only them.

| Type | Date it limits | Earliest allowed date |
|---|---|---|
| **Finish to Start** | the successor's start | the next working day after the predecessor's finish |
| **Start to Start** | the successor's start | the predecessor's start |
| **Finish to Finish** | the successor's finish | the predecessor's finish |
| **Start to Finish** | the successor's finish | the predecessor's start |

**Finish to Start** is the default. Lag adds whole working days to the earliest allowed date, and weekends are skipped. A negative lag is a lead, and it moves the earliest allowed date earlier by that many working days.

## What starts a reschedule

- **Start** or **Finish** changes, from any screen, for one item or for many at once.
- A dependency is added. The successor moves only if it now sits too early, and only by the missing days.
- The type or lag of a dependency changes. The successor is fitted exactly to the new rule, so it can move earlier or later. It never passes a limit set by another predecessor, its own or one of its ancestors'.

Three changes never reschedule:

- removing a dependency;
- dates written by the public API, an import or a webhook;
- moving an item to a different parent.

## How far a change travels

A push travels down the whole chain, from successor to successor. An item with several predecessors moves by the largest number of missing working days.

A successor with enough free days before its limit absorbs the push, and the chain stops there. Every moved item keeps its length in working days. An item moved across a weekend covers more calendar days, because the weekend days are not counted.

Dependencies push and never pull. A successor placed later than its dependency requires stays where it is, and moving a predecessor earlier moves nothing.

To close a gap, change the lag, or use **Re-apply link** in the dependency editor. It names the date it moves the successor to, and it is hidden when nothing would move.

## The gap you draw becomes the lag

When you place one item by hand, every dependency of that item takes the gap now drawn as its lag. Placing means a Gantt drag or resize, or a date edited in the item details or in a date cell.

- Drag a predecessor earlier, and its successor stays. The lag grows by the working days you left empty.
- Drag a successor in front of its predecessor, and the dependency takes a lead.
- A successor that scheduling pushed keeps its lag, because it sits exactly on its limit.

After the lag grows, the successor has no free days left, so the next later move of the predecessor pushes it at once. A change to many items at once does not rewrite any lag.

## A new dependency keeps the drawn gap

A dependency you draw between two items on the Gantt starts with the gap between them as its lag. If the successor sits too early for the new dependency, the dependency starts with lag 0 and scheduling pushes the successor.

## What is never moved automatically

- The item you placed. Its dates are your input.
- A predecessor, for its own links. Scheduling moves successors only. A predecessor still moves when a parent above it moves as a block.
- An item with no dates anywhere below it. It neither limits nor moves, except in the case described under When empty dates are filled in. A parent with no dates of its own is scheduled on its children's span.

## When empty dates are filled in

Scheduling fills in dates for one kind of item: a successor with a **Duration (d)** and no dates anywhere below it. When a change reaches such a successor and one of its predecessors has dates, scheduling places it where its dependencies require. Its finish follows from the **Duration (d)**, and its own successors are pushed like any other.

## Parents move as one block

A parent is scheduled on its whole span, its own dates and the dates of every item below it. When a parent must move as a successor, every dated item under it moves by the same number of working days, and the spacing between them is kept. Changing a **Start** the parent already had moves every dated item under it the same way.

After you add or change a dependency, a message such as **Rescheduled 4 items** offers **Undo**. The count includes every dated item inside a moved parent.

## What is refused

A new dependency is refused when it would:

- link an item to itself;
- link an item to anything above or below it in the hierarchy;
- repeat a dependency the two items already have;
- close a loop.

The refusal appears while you pick or drag, and again when the change is saved. On save, a loop is named in full, for example "Would create a loop: Build → Test → Deploy → Build".

## What red means

A broken dependency is one whose successor sits earlier than the dependency allows. The dependency editor states how many working days too early. The two views draw a broken dependency differently:

- On the Gantt, a broken dependency is a dashed red arrow.
- On the mind map, a broken dependency is a red arrow. A dashed arrow there means a dependency of any type other than **Finish to Start**, so a broken dependency of such a type is red and dashed.

Scheduling never leaves the successors it moves too early. A broken dependency comes from a change that left the dependency behind. Examples are an import, a public API or webhook write, or a move to a new parent. A change to many items at once can also put one before its predecessor.

While the critical path is on, a solid red arrow on the Gantt is not broken. It is a dependency that drives the critical path. A broken dependency stays dashed.

Red on a bar is a different signal. It marks the part of a child's bar that runs past its parent's finish. While a baseline is selected, a red bar marks a finish that slipped against the baseline. While the critical path is on, a red line along the bottom edge of a bar marks a critical item, and a red bracket marks a critical parent.

## The mind map draws the same dependencies

Every arrow on the mind map is the same dependency the Gantt draws, stored once. A dependency drawn on the mind map is **Finish to Start** with no lag, and it reschedules like any other.

## Float and the critical path

A plan is a top-level item and every item below it. Top-level means the item has no parent at all. A view that shows only part of a plan, such as the contents of one item, still measures float against the whole plan. The plan finishes on the latest finish inside it.

Total float is how many working days an item can finish later before a plan finishes later. That plan is the item's own plan, or a plan that waits on it through a dependency. An item with no float left is critical, and the critical items together are the critical path.

- Float is counted in working days, so holidays count as working days here too.
- Float is measured on the **Start** and **Finish** fields, at the dates every item would have with all dependencies met. When no dependency is broken, those are the dates the items have now.
- A Gantt that maps other date fields still takes float and the critical path from **Start** and **Finish**. Its bars can then disagree with its critical marks.
- A parent is critical when its own dates, or any item below it, are critical.
- A completed item is never critical: finished work cannot delay the plan any more. Its float is still shown, and it still holds back the items that wait on it. A parent whose only critical items are completed is not critical either.
- A dependency between two top-level items carries float across them, so a late item in one plan can make another plan finish later.
- Float cannot be worked out for an item without both a start and a finish date, unless an item below it has both. Nor can it for an item in a loop of dependencies, an item with such a loop below it, or an item that waits on one. The **Total float** cell of such an item shows a dash.
- Float is worked out in your browser whenever a **Start** or **Finish** date, a dependency, completion or an item's parent changes. Nothing is stored, and turning the critical path on or off changes nothing for anyone else.

## How the Gantt draws the critical path

Until float has been worked out for every item in the view, which can take a moment after the critical path is turned on or the view changes, nothing fades and no bar or arrow turns red. The key at the bottom appears straight away.

- Bars, brackets, dotted rails, baseline ghosts and arrows that are not critical are drawn faded. On a grouped view, a group's bracket is never critical, so it fades too.
- The buttons at the left and right edges of the timeline, which scroll to a bar out of view, do not fade.
- A faded bar still moves, resizes and opens as usual. Point at a faded bar and it returns to its normal strength. Faded brackets, dotted rails and baseline ghosts stay faded.
- A critical item gets a red line along the bottom edge of its bar. A critical parent's bracket turns red.
- A dependency between two critical items, with no gap between them, is drawn as a solid red arrow. It drives the critical path.
- A broken dependency stays a dashed red arrow. A broken dependency that drives the critical path stays at full strength. Every other dashed arrow fades.
- The key **Critical path — open items with no float** sits at the bottom of the timeline, centred. The key replaces the bracket that spans the whole view. That bracket comes back when the critical path is turned off.

## What the Total float column shows

- A negative number means the plan already finishes later. Its hint starts with **Over by**.
- A dash means float cannot be worked out. The cell also shows a dash briefly while the column first loads.
- Sorted ascending, the least float comes first. Sorted descending, the most float comes first. Rows with a dash sort last in both directions.
- **Export to CSV** writes the plain number, and an empty cell where the screen shows a dash.

## Worked example

Three items, each joined by **Finish to Start**. The dates are in March 2026.

| Item | Dates | Waits for |
|---|---|---|
| Design | Monday 2 to Friday 6 March | nothing |
| Build | Monday 9 to Friday 13 March | Design, lag 0 |
| Test | Wednesday 18 to Thursday 19 March | Build, lag +2 |

Build starts on Monday 9 March, because the weekend after Design finishes is skipped.

1. Drag Design 3 working days later, to Thursday 5 to Wednesday 11 March. Design keeps its 5 working days across the weekend.
   - Build must now start on Thursday 12 March, so it moves to Thursday 12 to Wednesday 18 March.
   - Test must start on Monday 23 March, so it moves to Monday 23 to Tuesday 24 March.
   - No lag changes.
2. Drag Design 2 working days earlier, to Tuesday 3 to Monday 9 March. Build and Test stay. The dependency from Design to Build now shows lag +2, the 2 working days you left empty.
3. Set that lag back to 0 in the dependency editor. Build is fitted to the new rule and moves earlier, to Tuesday 10 to Monday 16 March. Test stays, because a fit reaches only the successor of the dependency you edited.

## Behaviours that surprise people

- No item is pinned. A completed item with dates moves like any other, and no setting holds dates in place.
- A single undo step reverts the dates you changed, every item that scheduling moved, and any lag your placement rewrote.
- A dependency held by a parent is not given a new lag when you place one of its children, so it can stay red.
- A dependency whose successor you may not edit is never given a new lag. Your drag still lands, and that dependency can stay red.

## Next

- [Gantt view](../../views/gantt-view/)
- [Mind map view](../../views/mind-map-view/)
