Relationships
Task Relationship Types
Section titled “Task Relationship Types”dart-query supports five relationship types for modeling task dependencies. Each has a canonical (industry-standard) field name and a legacy _ids-suffixed alias:
| Type | Canonical Field | Legacy Field | Meaning |
|---|---|---|---|
| Subtasks | subtasks | subtask_ids | Child tasks that compose a parent task |
| Blockers | blocked_by | blocker_ids | Tasks that must complete before this task can proceed |
| Blocking | blocks | blocking_ids | Tasks that this task is blocking |
| Duplicates | duplicates | duplicate_ids | Tasks that duplicate this task |
| Related | related | related_ids | Tasks with a logical connection but no dependency |
Creating Tasks with Relationships
Section titled “Creating Tasks with Relationships”Set relationships at creation time by passing arrays of dart_id values:
create_task({ title: "Deploy OAuth2 to production", dartboard: "Engineering/backend", priority: 4, blocked_by: ["duid_oauth_impl"]})
create_task({ title: "Update user documentation", dartboard: "Documentation", related: ["duid_oauth_impl", "duid_api_docs"], blocks: ["duid_release_v2"]})Updating Relationships
Section titled “Updating Relationships”Use update_task to modify relationships on existing tasks.
Full replacement semantics: providing a relationship array replaces all existing values for that type. Omitting a field leaves it unchanged.
// Set blockers (replaces any existing blockers)update_task({ dart_id: "duid_deploy_task", blocked_by: ["duid_testing", "duid_code_review"]})
// Clear all blockersupdate_task({ dart_id: "duid_deploy_task", blocked_by: []})
// Link related tasks (does not affect blockers or other types)update_task({ dart_id: "duid_feature_a", related: ["duid_feature_b", "duid_feature_c"]})Safe Modification Pattern
Section titled “Safe Modification Pattern”update_task also accepts add_to and remove_from objects that merge into existing relationship arrays instead of replacing them — see Task Management for that shortcut. To add a relationship manually without losing existing ones, read the current state first:
// Step 1: Get current relationshipsconst task = get_task({ dart_id: "duid_deploy_task" })// task.blocker_ids = ["duid_testing"]
// Step 2: Append and updateupdate_task({ dart_id: "duid_deploy_task", blocked_by: [...task.blocker_ids, "duid_code_review"]})// blocker_ids is now ["duid_testing", "duid_code_review"]Linking Existing Tasks Atomically
Section titled “Linking Existing Tasks Atomically”link_tasks writes both sides of a relationship in one call, so the graph never ends up one-sided (a parent set on the child without a matching entry in the parent’s subtasks, for example). Prefer it over hand-editing relationship arrays on two separate update_task calls.
// Anchor task gets a parent; the parent's subtasks array is updated to matchlink_tasks({ type: "parent", from: "duid_oauth_subtask", to: ["duid_oauth_epic"]})
// Anchor task blocks one or more others; each target's blocked_by is updated to matchlink_tasks({ type: "blocks", from: "duid_migration", to: ["duid_deploy_prod", "duid_release_notes"]})type accepts parent, subtasks, blocks, blocked_by, duplicates, or related. For type: "parent", to must contain exactly one dart_id; the other types accept any number of targets. The response includes mirror_applied (which inverse-side tasks were patched) and mirror_warnings (any inverse-side writes that failed).
Viewing Relationships
Section titled “Viewing Relationships”get_task returns relationship IDs by default. Use expand_relationships: true to include titles:
get_task({ dart_id: "duid_task123", expand_relationships: true })// {// blocker_ids: ["duid_design_review"],// blocking_ids: ["duid_deploy_prod"],// expanded_relationships: {// blockers: [{ dart_id: "duid_design_review", title: "Design review meeting" }],// blocking: [{ dart_id: "duid_deploy_prod", title: "Deploy to production" }]// },// relationship_counts: { subtasks: 0, blockers: 1, blocking: 1, duplicates: 0, related: 0 }// }Use include_relationships: false to exclude relationship data entirely and save tokens.
CSV Import with Relationships
Section titled “CSV Import with Relationships”Relationship columns in CSV use comma-separated dart_id values:
title,priority,blocker_ids,related_ids,tags"Deploy to production",critical,"duid_testing,duid_code_review",,deployment"Write unit tests",high,,"duid_feature_impl","testing,quality""Code review",medium,"duid_feature_impl",,reviewWrap values in quotes when they contain commas. Column names are flexible: blockers, blocked_by, and blocker_ids all map to the same field.
Relationship Counts
Section titled “Relationship Counts”Every get_task response includes relationship_counts as a compact summary:
{ "relationship_counts": { "subtasks": 3, "blockers": 1, "blocking": 2, "duplicates": 0, "related": 1, "total": 7 }}This lets agents check for dependencies without loading the full relationship arrays.
See Also
Section titled “See Also”- Task Management — full
create_taskandupdate_taskparameter reference - DartQL Selectors — query tasks by relationship fields
- Batch Operations — bulk-update relationships with DartQL