Skip to content

DAG Format

The DAG (Directed Acyclic Graph) is the execution plan that determines the order in which war-rooms are activated. It is stored as DAG.json in the war-rooms directory.

DAG.json Structure

{
"generated_at": "2026-03-27T12:27:48Z",
"total_nodes": 9,
"max_depth": 1,
"nodes": { },
"topological_order": [],
"critical_path": [],
"critical_path_length": 2,
"waves": { }
}

Top-Level Fields

FieldTypeDescription
generated_atstringISO 8601 generation timestamp
total_nodesintTotal number of nodes in the DAG
max_depthintMaximum dependency depth
topological_orderstring[]Valid execution order
critical_pathstring[]Longest dependency chain
critical_path_lengthintLength of the critical path

Node Schema

Each node represents a war-room:

{
"EPIC-001": {
"room_id": "room-001",
"task_ref": "EPIC-001",
"role": "engineer",
"candidate_roles": ["engineer"],
"depends_on": "PLAN-REVIEW",
"dependents": [],
"depth": 1,
"on_critical_path": false
}
}
FieldTypeDescription
room_idstringAssociated war-room directory
task_refstringEpic or task reference
rolestringPrimary assigned role
candidate_rolesstring[]All roles that may work on this node
depends_onstring|nullUpstream dependency (single or null)
dependentsstring[]Downstream nodes that depend on this
depthintDistance from root (0-indexed)
on_critical_pathboolWhether this node is on the critical path

The PLAN-REVIEW Root

Every DAG has a PLAN-REVIEW root node at depth 0:

{
"PLAN-REVIEW": {
"room_id": "room-000",
"task_ref": "PLAN-REVIEW",
"role": "architect",
"candidate_roles": ["architect", "manager"],
"depends_on": null,
"dependents": ["EPIC-001", "EPIC-002", "EPIC-003"],
"depth": 0,
"on_critical_path": true
}
}

PLAN-REVIEW always:

  • Maps to room-000
  • Has depends_on: null (no upstream)
  • Is on the critical path
  • Runs the architect role
  • Must pass before any epic starts

Wave Scheduling

Waves group nodes by depth for parallel execution:

{
"waves": {
"0": ["PLAN-REVIEW"],
"1": ["EPIC-001", "EPIC-002", "EPIC-003", "EPIC-004"],
"2": ["EPIC-005", "EPIC-006"]
}
}

The manager processes waves sequentially:

  1. Wave 0: Execute PLAN-REVIEW
  2. Wave 1: When wave 0 passes, launch all wave-1 rooms in parallel
  3. Wave 2: When all wave-1 dependencies pass, launch wave-2 rooms

Within a wave, all rooms run concurrently up to max_concurrent_rooms.

Kahn’s Algorithm

OSTwin uses Kahn’s algorithm for topological sorting:

  1. Compute in-degree for each node
  2. Enqueue all nodes with in-degree 0 (roots)
  3. While the queue is not empty:
    • Dequeue a node, append to sorted order
    • For each dependent, decrement in-degree
    • If in-degree reaches 0, enqueue
  4. If sorted order length equals total nodes, the graph is a valid DAG
  5. Otherwise, a cycle exists (error)

The algorithm also computes:

  • Depth: Maximum distance from any root
  • Critical path: Longest chain through the DAG
  • Waves: Nodes grouped by depth

Critical Path

The critical path is the longest dependency chain. It determines the minimum wall-clock time for plan execution (assuming unlimited parallelism).

{
"critical_path": ["PLAN-REVIEW", "EPIC-002"],
"critical_path_length": 2
}

Nodes on the critical path are flagged with on_critical_path: true and may receive priority scheduling.

DAG Builders

OSTwin includes two DAG builders:

PowerShell Builder

The primary builder runs inside the manager loop. It:

  1. Parses PLAN.md for epic definitions
  2. Extracts depends_on fields
  3. Runs Kahn’s algorithm
  4. Creates room directories
  5. Writes DAG.json

Located in the manager PowerShell scripts.

Python Builder

A standalone Python builder for testing and validation:

Terminal window
python -m agents.dag_builder PLAN.md --output DAG.json

Both builders produce identical DAG.json output. The Python builder is used in CI tests.

Validation Rules

The DAG builder enforces:

RuleError
No cyclesCircular dependency detected: EPIC-001 → EPIC-002 → EPIC-001
Valid referencesUnknown dependency: EPIC-099
Single rootMultiple roots found (warning, not error)
Connected graphOrphan nodes: EPIC-007 (warning)

Runtime Updates

The DAG is immutable once generated. Runtime state changes (pass, fail) are tracked in individual room status files, not in DAG.json.

The manager checks the DAG to determine which rooms can be activated:

for each room in current_wave:
if all dependencies are "passed":
activate room