9.1 KiB
status, created, owner
| status | created | owner |
|---|---|---|
| draft | 2026-06-23 | cfl |
Subtask Completion Trigger
Why
Parent agents can delegate work by creating subtasks with create_task_kandev
and parent_id, but today they must poll list_related_tasks_kandev to learn
when all delegated workstreams are done. Polling burns agent turns and pushes
orchestration logic into the parent prompt instead of the workflow system.
What
- A workflow step can define an
on_children_completedevent. - The event fires on a parent task's current workflow step when every direct, active child task has reached terminal completion.
- Terminal task states are
COMPLETED,FAILED, andCANCELLED. - A child also counts as terminal when it is in a final workflow step named
Done,Complete,Completed, orApproved; entering that step persiststasks.state = COMPLETED. - The event is driven by task state changes and workflow-step moves into a
terminal step, including subtasks created through
create_task_kandevwithparent_id. - The event runs the step actions configured on
on_children_completed, such as queueing a parent-agent run or moving the parent to a verification step. - Workflow authors can configure the event from the workflow step editor with the "When Child Tasks Complete" transition selector. The editor explains that the trigger belongs on the parent step, waits for direct active children only, treats terminal task states and terminal workflow-step membership as terminal, and ignores archived or ephemeral child tasks.
- The event fires at most once for the same completed child set. If a child is reopened and later returns to a terminal state, the parent can receive a new event for the new completion cycle.
- The trigger considers direct children only. Grandchildren complete their own parent before any higher-level parent can react.
- Parent tasks with no active or primary session do not auto-create a session for this event; the event is skipped and logged.
- Existing workflows that do not configure
on_children_completedbehave unchanged.
Data model
No new persistent table is required.
tasks
The existing tasks.parent_id relationship defines the direct child set.
Children with archived_at set or is_ephemeral = 1 are ignored by this
feature, matching existing active-child listing semantics.
The existing tasks.state field defines terminal child completion. The terminal
state set for this feature is:
COMPLETED
FAILED
CANCELLED
tasks.workflow_step_id is also considered. A child task is complete when its
current step is the final step in that workflow and the step name is Done,
Complete, Completed, or Approved. This keeps visual board completion and
API state consistent without adding a new persistent terminal-step flag.
Workflow operation idempotency
The existing workflow engine operation-id store records each synthesized
on_children_completed trigger. The operation id is deterministic for the
parent and completed direct-child set, including enough child completion version
data to let a reopen-and-complete cycle fire again.
API surface
No new HTTP route, WebSocket event, MCP tool, or CLI command is introduced.
Workflow step event JSON accepts and returns on_children_completed in the
existing events object:
{
"events": {
"on_children_completed": [
{
"type": "queue_run",
"config": {
"target": "primary",
"task_id": "this",
"reason": "children_completed"
}
}
]
}
}
The workflow settings UI exposes the transition-oriented subset of this event:
{
"events": {
"on_children_completed": [
{
"type": "move_to_step",
"config": {
"step_id": "verification-step-id"
}
}
]
}
}
The event uses the existing workflow-engine trigger payload:
{
"child_summaries": [
{
"task_id": "child-task-id",
"status": "COMPLETED",
"summary": "optional child completion summary",
"pr_links": ["https://github.com/org/repo/pull/123"]
}
]
}
summary and pr_links are best-effort enrichment. A missing summary or PR link
does not block the trigger.
State machine
- A child enters terminal completion when its task state changes from a
non-terminal state to
COMPLETED,FAILED, orCANCELLED, or when it moves into a terminal workflow step. - On that transition or move, the system checks the child's parent.
- If the child has no parent, no parent event is considered.
- If any active direct child of the parent is still non-terminal, no parent event fires.
- If every active direct child is terminal, the parent task receives
on_children_completedat its current workflow step. - If configured actions transition the parent step, the normal workflow
transition lifecycle applies:
on_exit, persisted step change, data patch persistence, thenon_enter. - If a child later moves from terminal to non-terminal, the parent is considered waiting again. A later transition of that child back to terminal can produce a new event.
Permissions
This feature adds no new permission boundary.
- Agents and users can only create child tasks through existing task creation permissions and MCP tool exposure.
- Agents cannot fire
on_children_completeddirectly; they can only cause it by changing task state or moving a child task through existing task completion paths. - Workflow authors control the parent reaction by configuring
on_children_completedactions on the parent step.
Failure modes
- If the child-state event cannot be decoded, the event is dropped and a warning is logged.
- If sibling lookup fails, no parent trigger fires for that event and a warning is logged. A later child state transition can retry the check.
- If terminal step lookup fails, the child is evaluated by task state only.
- If the parent has no active or primary session, no new parent session is created. The skip is logged at debug/info level.
- If the workflow engine rejects or fails a configured action, the error is logged and the child task's terminal state remains unchanged.
- If multiple children finish concurrently, engine operation idempotency prevents duplicate parent actions for the same completed child set.
Persistence guarantees
- Child task state, parent-child relationships, workflow step configuration, and workflow operation ids survive backend restarts.
- A child completion event that was already applied before restart is not re-applied for the same completed child set.
- In-memory event delivery itself is not replayed after restart. A future child state transition or reopen-and-complete cycle can synthesize the trigger again.
Scenarios
-
GIVEN a parent task has two direct children and one child is still
IN_PROGRESS, WHEN the first child changes toCOMPLETED, THEN the parent'son_children_completedevent does not fire. -
GIVEN a parent task has two direct children and the first child is
COMPLETED, WHEN the second child changes fromIN_PROGRESStoCOMPLETED, THEN the parent receives oneon_children_completedtrigger. -
GIVEN a child task still has
state = REVIEW, WHEN it moves into a final workflow step namedDone, THEN the child persistsstate = COMPLETEDand the parent completion check treats that child as terminal. -
GIVEN a parent step configures
on_children_completedwithmove_to_next, WHEN all direct children are terminal, THEN the parent moves to the next workflow step and that step'son_enteractions run normally. -
GIVEN a parent step configures
on_children_completedwithqueue_runfor the primary agent, WHEN all direct children are terminal, THEN a parent run is queued with the children-completed reason and child summary context. -
GIVEN one child finishes as
FAILEDand all other direct children are terminal, WHEN the failed child transitions from non-terminal toFAILED, THEN the parent receiveson_children_completed. -
GIVEN a child is already
COMPLETED, WHEN a duplicate update attempts to set it toCOMPLETEDagain, THEN no duplicate parent trigger fires. -
GIVEN all direct children are terminal and the parent trigger has fired, WHEN one child is reopened to
IN_PROGRESSand later changes back toCOMPLETED, THEN the parent can receive a newon_children_completedtrigger for the new completion cycle. -
GIVEN a child has its own child, WHEN the grandchild completes, THEN only the direct parent of that grandchild is evaluated for
on_children_completed. -
GIVEN a parent has no active or primary session, WHEN all direct children become terminal, THEN no session is created automatically and the skip is logged.
Out of scope
- Adding a second event name such as
on_all_children_completeoron_subtasks_done. - Recursive descendant aggregation.
- Creating parent sessions automatically when no parent session exists.
- Adding a new MCP wait primitive or long-poll API.
- Requiring every child agent to know whether it is the last sibling.