piyaz
How it works

Task Graph

Tasks, dependencies, and the directed acyclic graph that connects them.

Task Graph

Every Piyaz project is a directed acyclic graph (DAG) of tasks connected by edges. Tasks are nodes; edges define how work relates and what must happen in what order.

Tasks move through a fixed set of statuses (draft, planned, in_progress, in_review, done, and cancelled). See Task lifecycle for what each state means, the transitions, and the fields that mark a task complete. A cancelled task stays transparent in the graph: it is walked through but never counted, and it is excluded from progress and critical-path calculations.

Edge Types

Two edge types define relationships between tasks:

depends_on (blue, #55b3ff)

A depends_on edge from A to B means A cannot start until B is done. This is a hard ordering constraint. Piyaz uses these edges to compute ready tasks, blocked tasks, and the critical path.

A ──depends_on──▶ B
     (A needs B done first)

Use depends_on when: removing the target task would make the source task impossible to implement. The source needs the target's code, APIs, data, or decisions.

relates_to (violet, #a78bfa)

A relates_to edge from A to B means A and B share context but neither blocks the other. These edges appear in context views and help agents understand related work, but they don't affect scheduling.

A ──relates_to──▶ B
     (A and B share context)

Use relates_to when: the tasks inform each other but can proceed independently. Removing the target would make the source harder but not impossible.

When in doubt: removing the target makes the source impossible? Use depends_on. Just harder? Use relates_to.

Edge Notes

Every edge has a note field explaining why the relationship exists. Edge notes propagate into agent context for downstream tasks, so an agent implementing a dependent task knows not just that a dependency exists but why it matters.

Good edge notes answer: "What does the source task need from the target task?"

Graph Analysis

Piyaz provides 5 analysis types that query the task graph. Each is available programmatically via the piyaz_analyze MCP tool.

Consider this example graph:

  [Define API schema]  (done)

    depends_on


  [Build REST endpoints]  (planned)

    depends_on


  [Add auth middleware]  (draft, has description + criteria)

    depends_on


  [Write integration tests]  (draft, no criteria yet)

  [Update docs]  ──relates_to──▶  [Build REST endpoints]

Here's what each analysis returns for this graph:

Ready

Tasks where all depends_on targets have status done and the task itself is planned. These are the tasks that can be worked on right now.

Example result: Build REST endpoints -- it's planned and its only dependency (Define API schema) is done.

Blocked

Tasks with at least one depends_on target that isn't done. The response includes which specific tasks are blocking and their current statuses.

Example result: Add auth middleware is blocked by Build REST endpoints (planned). Write integration tests is blocked by Add auth middleware (draft).

Plannable

Draft tasks that have a description and at least one acceptance criterion. These tasks have enough specification to write an implementation plan but haven't been planned yet.

Example result: Add auth middleware -- it's draft with a description and acceptance criteria. Write integration tests would not appear because it lacks criteria. See lib/data/traversal.ts for the filtering logic.

Critical Path

The highest-weight path through the project's effective depends_on graph -- the chain that most constrains delivery. It is not simply the longest chain: each task contributes its priority weight on a doubling ladder (urgent = 8, core = 4, normal = 2, backlog = 1), so a single urgent task outweighs a longer run of normal ones. The graph is the effective one, so cancelled tasks are transparent (walked through, never counted), and they never appear on the path. Shortening the critical path is the fastest way to accelerate the project. See lib/data/traversal.ts for the implementation.

Example result: with equal priorities, Define API schemaBuild REST endpointsAdd auth middlewareWrite integration tests. Update docs is not on the path because relates_to edges don't count.

Downstream

All tasks that transitively depend on a given task, following depends_on edges in reverse. The reverse walk treats cancelled tasks as transparent, passing through them and collecting every active task that transitively depends on the target, so the result reflects the effective dependents. Use it for impact analysis: before changing a completed task's output, check what downstream work might be affected. See lib/data/traversal.ts for the implementation.

Example result: Calling downstream on Define API schema returns Build REST endpoints (depth 1), Add auth middleware (depth 2), Write integration tests (depth 3).

Constraints

The graph enforces several invariants (see lib/graph/mutations.ts:createEdge for validation logic):

  • No self-edges -- a task cannot depend on itself.
  • No duplicate edges -- each (source, target, type) triple is unique (enforced by a database unique index).
  • No cross-project edges -- both tasks must belong to the same project.
  • No cycles -- adding a depends_on edge that would create a cycle is rejected. Piyaz walks the dependency chain from the target to check if the source would be reached.
  • Cascade deletion -- deleting a task removes all its edges automatically via database foreign key cascades.

On this page