Status: Canonical Version: v0.3 Date: October 2026 Authority for: runtime task graph instances, tasks, task edges, task executions, graph lifecycle, runnability, suspension/resumption, governed replanning, persistence, and graph projection.

Purpose

This specification defines the canonical executable work model for Synedrix OS. A Runtime Task Graph Instance is the versioned, persisted execution plan generated for one Goal Instance.

The graph is not an n8n workflow, not a LangGraph runtime graph, and not an LLM reasoning transcript. It is Synedrix OS runtime state describing what work must be performed, in what dependency structure, under what conditions and governance constraints.

Runtime object hierarchy

flowchart TD
  G[Goal Instance]:::term --> R[Runtime Task Graph Instance]:::agent --> T[Task]:::agent --> X[Execution]:::agent --> O[Outcome]:::term

Definitions:

  • Runtime Task Graph Instance — executable plan for one Goal Instance.
  • Task — one bounded unit of work in that graph.
  • Task Edge — dependency, data, condition, or governance relationship between Tasks.
  • Execution — one attempt to perform a Task.
  • Outcome — immutable terminal record of an agent or workflow execution, governed by the Synedrix OS — Outcome Spec.

Runtime Task Graph Instance

Canonical fields:

tenant_id: string                      # copied from the Goal Instance; immutable
business_instance_id: string | null    # copied from the Goal Instance
task_graph_id: string
goal_id: string
graph_version: integer
planning_mode: recipe | adapted | composed | dynamic
status: proposed | validated | active | suspended | completed | partially_completed | failed | blocked | cancelled
created_by: string
created_at: timestamp
activated_at: timestamp | null
completed_at: timestamp | null
correlation_id: string
graph_hash: string
replan_reason: string | null
Illustrative example, not a production implementation. Review and test before use.

Rules:

  1. Every accepted Goal Instance is associated with one Runtime Task Graph identity.
  2. Graph structure is versioned. Governed replanning creates a new graph_version; it does not silently overwrite prior structure.
  3. Only a validated graph may become active.
  4. Every active graph must have at least one legal path to a Goal terminal state.
  5. Runtime Task Graphs are durable execution records and are never directly replayed for a different Goal Instance.

Task

Canonical fields:

tenant_id: string                      # same as the graph's
business_instance_id: string | null
task_id: string
task_graph_id: string
graph_version: integer
task_type: string
purpose: string
required_capability: string
executor:
  type: agent | workflow | deterministic_function | tool
  id: string
  version: string
input_payload: object
status: pending | runnable | running | waiting_approval | retrying | succeeded | failed | blocked | skipped | cancelled
timeout_ms: integer
side_effect_class: none | low | high | irreversible
policy_required: boolean
approval_mode: none | policy | hitl | conditional
idempotency_required: boolean
created_at: timestamp
started_at: timestamp | null
completed_at: timestamp | null
Illustrative example, not a production implementation. Review and test before use.

A Task expresses executable work. It does not contain an LLM chain of thought or free-form planning transcript.

Task Edge

Canonical edge types:

requires
conditional
data
governance
Illustrative example, not a production implementation. Review and test before use.

Fields:

tenant_id: string                      # same as both tasks'
edge_id: string
task_graph_id: string
graph_version: integer
source_task_id: string
target_task_id: string
edge_type: requires | conditional | data | governance
condition: object | null
Illustrative example, not a production implementation. Review and test before use.

Semantics:

  • requires — target cannot run until source reaches the required terminal condition.
  • conditional — target is activated only if a declared condition evaluates true.
  • data — target consumes declared output from source.
  • governance — source supplies a required policy or approval condition for target.

Safe condition model

Task Graph conditions must be structured and serializable. Arbitrary executable code in graph conditions is prohibited.

Example:

{
  "all": [
    {
      "source": "T3.result.decision",
      "op": "eq",
      "value": "allow"
    },
    {
      "source": "T2.result.budget_available",
      "op": "eq",
      "value": true
    }
  ]
}
Illustrative example, not a production implementation. Review and test before use.

The canonical operator set is implementation-defined for v0.1 but MUST remain deterministic, bounded, auditable, and free of arbitrary code execution.

Execution

An Execution is one attempt to perform a Task.

Canonical fields:

tenant_id: string                      # same as the task's
business_instance_id: string | null
execution_id: string
task_graph_id: string                  # of the task executed
graph_version: integer                 # of the task executed
task_id: string
attempt: integer
executor_type: agent | workflow | deterministic_function | tool
executor_id: string
executor_version: string
status: started | running | waiting | completed | failed | timed_out | cancelled
correlation_id: string
causation_id: string
outcome_id: string | null             # Outcome Envelope id when terminal
invocation_id: string | null          # agent_invocations.id when executor_type = agent
started_at: timestamp
completed_at: timestamp | null
Illustrative example, not a production implementation. Review and test before use.

A Task may have multiple Executions because of retries or governed alternative attempts. Each agent or workflow Execution terminates in exactly one immutable Outcome Envelope.

Runnability

A Task is runnable when all of the following are true:

  1. Task status permits execution.
  2. All mandatory predecessor dependencies are satisfied.
  3. Every applicable conditional edge evaluates true.
  4. Required governance edges are satisfied.
  5. The bound executor is currently available and authorized.
  6. Required inputs are available and contract-valid.
  7. No graph-level suspension or cancellation prevents execution.

Runnability MUST be determined from canonical runtime state and deterministic rules. An LLM must not independently decide that a Task is runnable.

Scheduling and concurrency

The Orchestrator may dispatch all currently runnable Tasks concurrently when graph dependencies permit it.

Parallelism is therefore derived from the graph rather than improvised at execution time.

Suspension and resumption

Long-running waits such as HITL approval must not require one n8n execution to remain open.

Canonical behavior:

flowchart TD
  N0[Task reaches waiting_approval]:::agent --> N1[graph becomes suspended if no other task is runnable]:::agent --> N2[canonical state persists]:::agent --> N3[orchestration execution may terminate cleanly]:::agent --> N4[approval event arrives later]:::agent --> N5[graph state is reloaded]:::agent --> N6[newly runnable Tasks are calculated]:::agent --> N7[execution resumes]:::agent

This makes Task Graph persistence the durable coordination mechanism across workflow executions and process restarts.

Governed replanning

A Goal Instance may require graph revision when significant execution context changes.

Permitted v0.1 replan triggers include:

  • required capability unavailable;
  • policy introduces an additional mandatory step;
  • task outcome explicitly requests escalation or remediation;
  • required information is missing;
  • recoverable failure requires an alternative governed path;
  • human reviewer requests modification.

Replanning rules:

  1. Replanning increments graph_version under the same task_graph_id.
  2. Prior graph versions remain immutable historical records.
  3. Completed Task/Execution/Outcome history must not be deleted or rewritten.
  4. New Tasks and Edges must pass the same graph validation as the original plan.
  5. Replanning must emit audit-visible reason metadata.
  6. v0.1 does not permit unrestricted autonomous graph self-modification.

Graph validation

Before activation, a graph validator MUST check at minimum:

  • unique task identities;
  • valid edge references;
  • no unsupported cycles;
  • executor and capability existence;
  • executor version resolvability;
  • authority compatibility;
  • policy and approval coverage for side effects;
  • safe condition syntax;
  • input availability or declared production path;
  • timeout behavior;
  • retry/idempotency declarations where required;
  • Business Instance scoping;
  • tenant consistency: every task, edge and execution has the graph’s tenant_id, and every bound executor and capability is either shared (platform scope) or belongs to that tenant;
  • at least one legal terminal path.

A graph that fails validation is non-executable.

Persistence authority

Canonical Runtime Task Graph state MUST be stored in Supabase PG17, consistent with the Synedrix OS — Tech Stack.

Relational structures (Postgres schema runtime):

runtime.task_graphs
runtime.tasks
runtime.task_edges
runtime.executions
Illustrative example, not a production implementation. Review and test before use.

These tables are tenant-owned and follow the tenant boundary in the Synedrix OS - Agent DB Schema and the Synedrix OS — Tenancy Spec. Graph and task status columns are mutable; prior graph_version structure rows are immutable historical records (replanning inserts a new version). Execution rows record attempts; in-flight status may update, and terminal rows SHOULD NOT be rewritten except to attach outcome_id / invocation_id once known.

The data model, reduced to its entities and relationships:

erDiagram
    GOAL_INSTANCE ||--o{ TASK_GRAPH : "is planned by"
    TASK_GRAPH ||--|{ TASK : contains
    TASK_GRAPH ||--o{ TASK_EDGE : "orders tasks with"
    TASK ||--o{ TASK_EDGE : "is linked by"
    TASK ||--o{ EXECUTION : "runs as"
    TASK_GRAPH {
        string tenant_id
        string task_graph_id
        int graph_version
        string status
    }
    TASK {
        string task_id
        string status
    }
    TASK_EDGE {
        string edge_id
        string from_task
        string to_task
    }
    EXECUTION {
        string execution_id
        string status
    }

Every runtime.* table MUST have RLS enabled and forced. Tenant-scoped policies MUST deny rows whose tenant_id does not match the request credential’s tenant.

Tenant scoping

A tenant is the isolation boundary above the Business Instance (ADR-OS-008, Synedrix OS — Tenancy Spec). The work graph lives in the pooled control plane, so every record in it must be attributable to one tenant.

  1. A Runtime Task Graph takes its tenant_id and business_instance_id from its Goal Instance when it is created, and neither changes afterward. Every Task, Task Edge and Execution carries the graph’s tenant_id. The Goal Model Spec v0.3 carries tenant_id on a Goal Instance, taken from the credential that submitted the goal, and the graph is created with it. A goal whose submitting credential does not resolve to exactly one tenant, such as a platform-scope credential or a delegated credential spanning several, is rejected, and no graph is created with a null or inferred tenant.
  2. Every runtime.* table has a non-null tenant_id, row-level security that is enabled and forced, and tenant_id as the leading column of every key and index.
  3. References inside the graph use composite same-tenant keys. A Task references its graph by (tenant_id, task_graph_id, graph_version), an Edge references its two Tasks by (tenant_id, task_graph_id, graph_version, task_id), and an Execution references its Task by (tenant_id, task_graph_id, graph_version, task_id), because replanning creates new graph versions and an Execution belongs to the version of the Task it ran. A row can therefore never point at another tenant’s row.
  4. A Task’s executor and capability may be shared platform definitions or the tenant’s own. A reference to another tenant’s agent, workflow or tool is invalid, and graph validation rejects it.
  5. An approval, resumption or cancellation event applies to a graph only when it carries the graph’s tenant_id. An event from another tenant is rejected and never reloads the graph. The Event Taxonomy Standard v1.0 envelope carries tenant_id, stamped by the event layer from the publisher’s authenticated credential, and an event whose tenant_id does not match the graph’s tenant is rejected.
  6. Redis keys for locks, queues and idempotency state are led by tenant_id. The Neo4j projection carries tenant_id on every node and relationship, and it is built and queried per tenant.
  7. Work reaches the data plane over the connection the data plane initiates (Synedrix OS — Tenancy Spec §5). If the control plane is unreachable, the data plane starts no side-effecting Task and pauses one in flight at its next side-effecting step. The graph stays durable and resumes when the connection returns.
  8. input_payload and Execution outputs are tenant content. Where they are stored is the hosting decision still open in the Agent DB Schema; this spec makes them safe to pool but does not decide it.

Redis role

Redis may hold hot scheduling state, locks, queues, idempotency cache, and reconstructible execution coordination data.

Redis is not the authoritative Task Graph store. Loss of Redis must not make an active Goal unrecoverable.

OS coordination-bus key templates (normative; tenant_id always leads). Use {tenant_id} hashtags when multi-key cluster ops require slot affinity. Logical separation: OS bus ≠ n8n queue Redis ≠ LangGraph checkpointer Redis.

{tenant_id}:os:idempotency:{scope}:{key}
{tenant_id}:os:lock:{resource}
{tenant_id}:os:heartbeat:agent:{agent_id}
{tenant_id}:os:heartbeat:execution:{execution_id}
{tenant_id}:os:dedup:event:{event_id}
{tenant_id}:os:ratelimit:{counter_name}:{window}
{tenant_id}:os:working:{tier}:{scope_id}:{key}
{tenant_id}:os:queue:{queue_name}
Illustrative example, not a production implementation. Review and test before use.

See also Redis (normative OS key-template subsection).

Neo4j role

Neo4j stores an asynchronous, rebuildable graph projection for traversal, lineage, analysis, and visualization.

Typical projected relationships include:

(:Goal)-[:HAS_TASK]->(:Task)
(:Task)-[:DEPENDS_ON]->(:Task)
(:Task)-[:EXECUTED_BY]->(:Agent)
(:Task)-[:USES_CAPABILITY]->(:Capability)
(:Execution)-[:PRODUCED]->(:Outcome)
(:Outcome)-[:GOVERNED_BY]->(:PolicyDecision)
Illustrative example, not a production implementation. Review and test before use.

Neo4j MUST NOT be required to determine whether a Task is runnable. The projection must be rebuildable from canonical relational state and immutable execution/audit records.

Relationship to n8n and LangGraph

A Runtime Task Graph is not an n8n workflow.

  • Task Graph: what must be executed for one Goal.
  • n8n workflow: reusable orchestration machinery that dispatches and coordinates Tasks.

A Runtime Task Graph is also not a LangGraph graph.

  • Task Graph: Synedrix-wide work coordination.
  • LangGraph graph: internal stateful/cyclic reasoning within an agent runtime invocation.

Runtime reuse

Completed Runtime Task Graph Instances are retained for recovery history, audit, analytics, evaluation, and planning evidence.

They MUST NOT be directly executed for a new Goal Instance. A new Goal always receives a newly materialized Runtime Task Graph based on current planning knowledge, capabilities, policies, Business Instance configuration, and runtime context.

Invariants

  • One Task Graph identity belongs to one Goal Instance.
  • Only validated graphs execute.
  • A Task has one required capability and one bound executor at a given graph version.
  • A Task may have multiple Executions.
  • Every agent/workflow Execution produces exactly one immutable Outcome.
  • Prior graph versions remain reconstructible after replanning.
  • Postgres is authoritative; Redis is reconstructible hot state; Neo4j is a rebuildable projection.
  • Graph execution may never bypass policy, approval, authority, or Business Instance boundaries.
  • Every Task Graph, Task, Task Edge and Execution belongs to exactly one tenant, and nothing in the graph references a row of another tenant.