Inter-Agent Communication Protocols

Version: v1  ·  Status: Active  ·  Date: 2026-02-23


Overview

This document is the technical reference for Orchestratia's inter-agent communication protocols. It defines the exact schemas, API endpoints, validation rules, and error behaviors for:

  • Task Specs — Machine-parseable task requirements
  • Result Reporting — Structured completion data with contract fulfillment
  • Dependencies — Typed relationships (blocks, input, related) between tasks
  • Contract Exchange — Structured data flow from upstream to downstream tasks
  • Capability Matching — Agent scoring and auto-assignment

All protocol features are opt-in and backwards-compatible. Tasks and agents that don't use structured protocols continue to work exactly as before.

For conceptual overviews, see Platform Overview. For workflow walkthroughs, see End-to-End Workflows. For the agent's perspective, see AI Agent Guide.


1. Task Spec Format

Schema identifier: orchestratia/task-spec/v1

The structured task spec provides a machine-parseable layer on top of the free-form spec text field. Stored in the tasks.structured_spec JSONB column (nullable). The spec text field remains for human readability.

Full Example

{
  "$schema": "orchestratia/task-spec/v1",
  "requirements": [
    {
      "description": "Implement JWT authentication middleware",
      "priority": "must",
      "category": "feature"
    },
    {
      "description": "Support refresh token rotation",
      "priority": "should",
      "category": "feature"
    },
    {
      "description": "Rate limiting on auth endpoints",
      "priority": "could",
      "category": "security"
    }
  ],
  "input_context": {
    "references": [
      {
        "type": "task",
        "id": "uuid-of-upstream-task",
        "description": "API schema definitions from task A"
      },
      {
        "type": "url",
        "url": "https://datatracker.ietf.org/doc/html/rfc7519",
        "description": "JWT RFC specification"
      }
    ]
  },
  "constraints": {
    "languages": ["typescript"],
    "frameworks": ["express"],
    "testing": "required",
    "no_breaking_changes": true,
    "max_files_changed": 15,
    "custom": {
      "node_version": ">=18"
    }
  },
  "output_expectations": {
    "contracts": {
      "auth_middleware": {
        "description": "Express middleware function for JWT validation",
        "format": "module_export",
        "required": true
      }
    },
    "artifacts": ["test_report", "coverage_html"]
  }
}

Field Reference

Top-Level Fields

Field Type Required Description
$schema string Yes Must be "orchestratia/task-spec/v1"
requirements array Yes List of requirement objects (at least one)
input_context object No Context and reference material for the task
constraints object No Technical constraints on implementation
output_expectations object No Expected outputs and contracts

requirements[] Fields

Field Type Required Description
description string Yes What needs to be done
priority enum Yes must | should | could (MoSCoW method)
category string No Free-form category (e.g. "feature", "security", "performance")

Priority semantics:

  • must — Required for task completion. Absence is a failure.
  • should — Expected unless there's a justified reason to omit.
  • could — Nice to have. Implement if time allows.

input_context.references[] Fields

Field Type Required Description
type enum Yes task | file | url
id string Conditional UUID for task type, filename for file type
url string Conditional Required for url type
description string No What this reference provides

constraints Fields

Field Type Required Description
languages string[] No Required programming languages
frameworks string[] No Required frameworks
testing enum No required | recommended | none
no_breaking_changes boolean No If true, must not break existing APIs
max_files_changed integer No Soft limit on scope
custom object No Arbitrary key-value constraints

output_expectations Fields

Field Type Required Description
contracts object No Named contract declarations (see Contract Exchange below)
contracts.{key}.description string Yes What this contract provides
contracts.{key}.format string No Format hint (e.g. "json", "module_export")
contracts.{key}.required boolean No Whether this contract must be fulfilled
artifacts string[] No Expected non-contract artifacts

Validation: Contract keys must be alphanumeric with underscores. At least one requirement must exist.

API Usage

POST /api/v1/tasks
Authorization: Bearer {jwt}
Content-Type: application/json
 
{
  "title": "Implement JWT auth middleware",
  "spec": "Human-readable description of the task...",
  "type": "feature",
  "priority": "high",
  "target_repo": "api-gateway",
  "structured_spec": {
    "$schema": "orchestratia/task-spec/v1",
    "requirements": [
      {"description": "JWT validation middleware", "priority": "must"}
    ],
    "constraints": {"languages": ["typescript"], "testing": "required"},
    "output_expectations": {
      "contracts": {
        "auth_middleware": {
          "description": "Express middleware for JWT validation",
          "required": true
        }
      }
    }
  }
}

Response (201 Created):

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "title": "Implement JWT auth middleware",
  "status": "pending",
  "type": "feature",
  "priority": "high",
  "created_at": "2026-02-23T10:00:00Z"
}

Tasks can also be created by agents (from within sessions):

POST /api/v1/server/tasks
X-API-Key: orc_...
 
{
  "title": "Implement auth middleware",
  "spec": "Based on the API schema from task A...",
  "priority": "high",
  "session_id": "uuid-of-current-session",
  "structured_spec": { ... }
}

2. Result Reporting Format

Schema identifier: orchestratia/task-result/v1

When an agent completes a task, it reports a structured result. This is stored in the tasks.result JSONB column and used for contract fulfillment, downstream data flow, and review.

Full Example

{
  "$schema": "orchestratia/task-result/v1",
  "summary": "Implemented JWT auth middleware with RS256 signing and refresh token rotation",
  "changes": {
    "files_modified": ["src/middleware/index.ts", "src/types/auth.ts"],
    "files_created": [
      "src/middleware/auth.ts",
      "src/middleware/__tests__/auth.test.ts",
      "src/utils/jwt.ts"
    ],
    "files_deleted": [],
    "lines_added": 342,
    "lines_removed": 18
  },
  "contracts": {
    "auth_middleware": {
      "status": "fulfilled",
      "data": {
        "export_path": "src/middleware/auth.ts",
        "function_name": "validateJWT",
        "usage": "app.use(validateJWT({ publicPaths: ['/health'] }))"
      }
    }
  },
  "tests": {
    "framework": "jest",
    "total": 15,
    "passed": 15,
    "failed": 0,
    "skipped": 0,
    "coverage_percent": 94.2
  },
  "artifacts": {
    "coverage_html": "/tmp/coverage/index.html"
  }
}

Field Reference

Top-Level Fields

Field Type Required Description
$schema string Yes Must be "orchestratia/task-result/v1"
summary string Yes One-line summary of what was accomplished
changes object No Files changed
contracts object No Contract fulfillment data
tests object No Test results
artifacts object No Additional output references

changes Fields

Field Type Required Description
files_modified string[] No Existing files that were changed
files_created string[] No New files created
files_deleted string[] No Files removed
lines_added integer No Total lines added
lines_removed integer No Total lines removed

contracts.{key} Fields

Field Type Required Description
status enum Yes fulfilled | partial | skipped
data object No The actual contract payload (arbitrary structure)

Status semantics:

  • fulfilled — Contract fully satisfied. data contains the promised output.
  • partial — Partially done. Downstream tasks receive the data but should expect gaps.
  • skipped — Intentionally not fulfilled. Must provide reason in data.

tests Fields

Field Type Required Description
framework string No Test framework used (jest, pytest, cargo test)
total integer No Total test count
passed integer No Tests passed
failed integer No Tests failed
skipped integer No Tests skipped
coverage_percent number No Code coverage percentage

API Usage

Agent daemon completes a task:

POST /api/v1/servers/tasks/{task_id}/complete
X-API-Key: orc_...
Content-Type: application/json
 
{
  "result": {
    "$schema": "orchestratia/task-result/v1",
    "summary": "Implemented JWT auth middleware",
    "contracts": {
      "auth_middleware": {
        "status": "fulfilled",
        "data": {"export_path": "src/middleware/auth.ts"}
      }
    }
  }
}

Response (200 OK):

{"status": "ok"}

Agent-internal endpoint (also accepts string results):

POST /api/v1/server/tasks/{task_id}/complete
X-API-Key: orc_...
 
{"result": "Implemented JWT auth middleware with full test coverage"}

String results are auto-wrapped as {"summary": "...", "completed_by": "agent:{name}"}.

Legacy Results

Results without the $schema field are treated as legacy format:

  • No contract validation or fulfillment checking
  • No structured data flow to downstream tasks
  • Stored as-is in the result column

What Happens After Completion

When a task transitions to done, the hub triggers a cascade:

flowchart TD
    Start["Task A completes with result"]
    Start --> B["1. Contract Check"]
    B --> C["2. Resolve Dependencies"]
    C --> D["3. Unblock Check"]
    D --> E["4. Auto-Assign"]
    E --> F["5. Broadcast"]

    B -.- B1["Compare result.contracts against<br/>output_expectations. Log:<br/>contract_fulfilled or contract_missing"]
    C -.- C1["For each downstream dep:<br/>blocks → resolve<br/>input → extract data, resolve<br/>related → resolve"]
    D -.- D1["For each downstream task:<br/>ALL blocking deps resolved?<br/>Yes → UNBLOCKED"]
    E -.- E1["For unblocked pending tasks<br/>with requirements:<br/>Score agents → pick best → assign"]
    F -.- F1["WebSocket → dashboards<br/>Event Bus → Telegram<br/>Activity log → database"]

    style Start fill:#2A9D88,stroke:#186B5D,color:#fff
    style B fill:#F0F9F7,stroke:#2A9D88
    style C fill:#F0F9F7,stroke:#2A9D88
    style D fill:#F0F9F7,stroke:#2A9D88
    style E fill:#F0F9F7,stroke:#2A9D88
    style F fill:#F0F9F7,stroke:#2A9D88
    style B1 fill:#FAF8F5,stroke:#E8E3DA,color:#706961
    style C1 fill:#FAF8F5,stroke:#E8E3DA,color:#706961
    style D1 fill:#FAF8F5,stroke:#E8E3DA,color:#706961
    style E1 fill:#FAF8F5,stroke:#E8E3DA,color:#706961
    style F1 fill:#FAF8F5,stroke:#E8E3DA,color:#706961

Contract validation is advisory — missing contracts log warnings but never block task completion or downstream unblocking. This is intentional: it's better to unblock waiting tasks with partial data than to deadlock the pipeline.


3. Dependency Declarations

Dependencies define ordering and data-flow relationships between tasks. Stored in the task_dependencies table.

Dependency Types

Type Blocking? Data Transfer? When Resolved
blocks Yes No Upstream task reaches done
input Yes Yes (via contracts) Upstream completes AND contract key found in result
related No No Immediately (informational only)

Field Reference

Field Type Required Description
depends_on_task_id UUID Yes The upstream task
dependency_type enum No blocks (default) | input | related
contract_key string Conditional Required when type is input. Must match a contract key in the upstream task's result.

Creating Dependencies

Method 1: Typed dependencies (recommended)

POST /api/v1/tasks
Authorization: Bearer {jwt}
 
{
  "title": "Implement API client",
  "spec": "Build the client based on the API schema...",
  "dependencies": [
    {
      "depends_on_task_id": "uuid-of-schema-task",
      "dependency_type": "input",
      "contract_key": "api_schema"
    },
    {
      "depends_on_task_id": "uuid-of-setup-task",
      "dependency_type": "blocks"
    }
  ]
}

Method 2: Legacy UUID list (backwards-compatible)

{
  "title": "Implement API client",
  "spec": "...",
  "dependency_ids": ["uuid-of-schema-task", "uuid-of-setup-task"]
}

Legacy dependency_ids are treated as blocks type with no contract linking.

Querying Dependencies

GET /api/v1/tasks/{task_id}

Returns the task detail including dependency status:

{
  "id": "...",
  "title": "Implement API client",
  "status": "pending",
  "dependencies": [
    {
      "depends_on_task_id": "uuid-of-schema-task",
      "dependency_type": "input",
      "contract_key": "api_schema",
      "resolved": false,
      "resolved_at": null
    },
    {
      "depends_on_task_id": "uuid-of-setup-task",
      "dependency_type": "blocks",
      "contract_key": null,
      "resolved": true,
      "resolved_at": "2026-02-23T10:05:00Z"
    }
  ]
}

Resolution Behavior

When an upstream task completes:

Dependency Type Resolution Condition What Downstream Receives
blocks Upstream status = done Nothing (ordering only)
input Upstream status = done AND result.contracts.{contract_key} exists Contract data in resolved_inputs.{contract_key}
related Always resolved immediately Nothing (informational)

Edge case: If an input dependency's upstream completes but the specified contract_key is missing from the result, the dependency is still resolved (with a contract_missing warning logged). This prevents deadlocks.


4. Contract Exchange

Contracts are the mechanism for structured data flow between tasks. An upstream task declares what it will produce, and a downstream task declares what it consumes. The hub validates, extracts, and delivers the data.

Lifecycle

sequenceDiagram
    participant A as Task A (upstream)
    participant Hub as Orchestratia Hub
    participant B as Task B (downstream)

    Note over A: 1. DECLARE<br/>structured_spec.output_expectations<br/>contracts: { api_schema: ... }
    Note over B: 2. DEPEND<br/>dependencies: [{ depends_on: A,<br/>type: "input", contract_key: "api_schema" }]

    A->>Hub: Complete with result.contracts.api_schema<br/>{ status: "fulfilled", data: { endpoints: [...] } }

    Hub->>Hub: 3. Validate contract key exists
    Hub->>Hub: 4. Extract contract data
    Hub->>Hub: 5. Mark dependency resolved
    Hub->>Hub: 6. Check: all B's deps resolved?

    Hub->>B: 7. Inject resolved_inputs.api_schema<br/>+ auto-assign Task B

    Note over B: B receives:<br/>resolved_inputs.api_schema = <br/>{ endpoints: [...], types: {...} }

How Agents Receive Contract Data

When an agent polls for assigned tasks, contract data from upstream tasks is included as resolved_inputs:

GET /api/v1/servers/tasks/poll
X-API-Key: orc_...

Response:

[
  {
    "id": "task-b-uuid",
    "title": "Implement API client",
    "spec": "Build the client based on the API schema...",
    "structured_spec": { ... },
    "resolved_inputs": {
      "api_schema": {
        "endpoints": [
          {"path": "/users", "method": "GET", "response": "User[]"},
          {"path": "/users/{id}", "method": "GET", "response": "User"}
        ],
        "types": {
          "User": {"id": "uuid", "name": "string", "email": "string"}
        }
      }
    }
  }
]

resolved_inputs is assembled by the hub from all resolved input-type dependencies. Each key corresponds to a contract_key in the dependency declaration.

Contract Validation Behavior

Scenario Result Logged Event
Contract declared as required, found in result Dependency resolved, data delivered contract_fulfilled
Contract declared as required, missing from result Dependency still resolved (advisory), warning logged contract_missing
Contract not declared in spec, found in result Accepted, delivered to downstream contract_fulfilled
No contracts in result, no contracts expected Normal completion, no contract events

Design decision: Contract validation is advisory, not enforcing. Missing contracts log warnings but never block task completion or downstream unblocking. This prevents pipeline deadlocks while still providing visibility into contract compliance.


5. Capability Matching

Capability matching enables automatic task assignment based on agent capabilities and task requirements.

Agent Capabilities Schema

{
  "$schema": "orchestratia/capabilities/v1",
  "repos": {
    "api-gateway": {
      "path": "/home/dev/api-gateway",
      "languages": ["rust"],
      "tools": ["cargo"]
    },
    "web-dashboard": {
      "path": "/home/dev/web-dashboard",
      "languages": ["typescript"],
      "tools": ["npm", "playwright"]
    }
  },
  "languages": ["rust", "typescript", "python"],
  "tools": ["docker", "git", "cargo", "npm"],
  "environments": ["linux"],
  "tags": ["backend", "systems", "frontend"],
  "max_concurrent_tasks": 2
}

Field Reference

Field Type Required Description
$schema string No "orchestratia/capabilities/v1"
repos object No Map of repo name to repo capabilities
repos.{name}.path string No Local filesystem path to the repo
repos.{name}.languages string[] No Languages used in this repo
repos.{name}.tools string[] No Tools available for this repo
languages string[] No All languages the agent can work with
tools string[] No All tools available on the agent's server
environments string[] No OS environments (e.g. linux, windows, macos)
tags string[] No Free-form tags (e.g. backend, frontend, infra)
max_concurrent_tasks integer No Maximum simultaneous tasks (default: 1)

Capabilities are set during registration and can be updated on each heartbeat:

POST /api/v1/servers/register
Content-Type: application/json
 
{
  "name": "dev-backend",
  "hostname": "dev-backend.internal.example.com",
  "ip": "10.0.1.5",
  "os": "linux",
  "registration_token": "orcreg_...",
  "capabilities": {
    "repos": {"api-gateway": {"path": "/home/dev/api-gateway", "languages": ["rust"]}},
    "languages": ["rust", "python"],
    "tools": ["cargo", "docker"],
    "environments": ["linux"],
    "max_concurrent_tasks": 2
  }
}

Task Requirements Schema

{
  "repo": "api-gateway",
  "languages": ["rust"],
  "tools": ["cargo"],
  "environments": ["linux"],
  "tags": ["backend"],
  "prefer_server": "dev-backend"
}

Field Reference

Field Type Required Description
repo string No Required repository (hard requirement)
languages string[] No Required languages (hard requirement)
tools string[] No Preferred tools (soft requirement)
environments string[] No Required environments (hard requirement)
tags string[] No Preferred tags (soft requirement)
prefer_server string No Preferred server name (soft, +200 bonus)

Requirements are set when creating or updating a task:

POST /api/v1/tasks
Authorization: Bearer {jwt}
 
{
  "title": "Fix gateway memory leak",
  "spec": "...",
  "requirements": {
    "repo": "api-gateway",
    "languages": ["rust"],
    "environments": ["linux"],
    "prefer_server": "dev-backend"
  }
}

Scoring Algorithm

Hard Requirements (disqualify if missing)

Requirement Score Rule
repo +100 Must exist in agent's repos{}
languages +50 ALL must be in agent's capabilities
environments +30 At least ONE must match

Soft Requirements (additive, never disqualify)

Requirement Score Rule
tools +10/each Per matching tool
tags +5/each Per matching tag
prefer_server +200 If server name matches
Online +25 If agent is currently online
Has capacity +50 Running tasks < max_concurrent

Disqualification Rules

  • Missing any hard requirement → score = -1 (skipped)
  • At max capacity (running >= max_concurrent_tasks)
  • No capabilities defined on agent

Example: Task requires repo=api-gateway, lang=rust, tools=[cargo, docker], prefer=dev-backend.

Agent "dev-backend" has the repo (+100), language (+50), environment (+30), both tools (+20), is the preferred agent (+200), is online (+25), and has capacity (+50) = 475 points.

Agent "dev-desktop" lacks the repo = disqualified (-1).

Preview Matching

Before assigning, you can preview which agents match:

GET /api/v1/tasks/{task_id}/matching-agents
Authorization: Bearer {jwt}

Response:

{
  "servers": [
    {
      "server_id": "uuid-of-dev-backend",
      "server_name": "dev-backend",
      "score": 475,
      "status": "online",
      "reasons": [
        "repo match: api-gateway (+100)",
        "language match: rust (+50)",
        "environment match: linux (+30)",
        "tools match: cargo, docker (+20)",
        "preferred server (+200)",
        "online (+25)",
        "has capacity (+50)"
      ]
    },
    {
      "server_id": "uuid-of-dev-desktop",
      "server_name": "dev-desktop",
      "score": -1,
      "status": "offline",
      "reasons": ["missing repo: api-gateway (disqualified)"]
    }
  ],
  "total": 2
}

Auto-Assignment

POST /api/v1/tasks/{task_id}/auto-assign
Authorization: Bearer {jwt}

Preconditions: Task must be pending with requirements defined.

Success response (200):

{
  "status": "assigned",
  "server_id": "uuid-of-dev-backend",
  "server_name": "dev-backend",
  "match_score": 475
}

No match response (200):

{"status": "no_match"}

Automatic Triggers

Auto-assignment also runs automatically (no API call needed) in two cases:

  1. Dependency resolution — When a task's last blocking dependency resolves, the cascade checks if the now-unblocked task has requirements and attempts auto-assign.
  2. Agent heartbeat — (future) When an offline agent comes back online, the hub checks for pending tasks it could handle.

Tasks without requirements are manual-assign only — they never auto-assign.


6. Complete API Reference

Task Protocol Endpoints

Method Path Auth Purpose
POST /api/v1/tasks JWT Create task with structured spec, requirements, dependencies
GET /api/v1/tasks/{id} JWT Get task detail including dependency status and resolved_inputs
PUT /api/v1/tasks/{id} JWT Update task fields including structured_spec and requirements
POST /api/v1/tasks/{id}/notes JWT Add note to task
GET /api/v1/tasks/{id}/notes JWT List task notes
POST /api/v1/tasks/{id}/approve-plan JWT Approve worker's submitted plan
POST /api/v1/tasks/{id}/revise-plan JWT Request plan revision with feedback
POST /api/v1/tasks/{id}/auto-assign JWT Trigger capability matching and auto-assignment
GET /api/v1/tasks/{id}/matching-agents JWT Preview agent matching scores
POST /api/v1/server/tasks API Key Agent creates a sub-task

Agent Task Lifecycle Endpoints (Daemon)

Method Path Auth Purpose
GET /api/v1/servers/tasks/poll API Key Poll for assigned tasks (includes resolved_inputs)
POST /api/v1/servers/tasks/{id}/start API Key Transition: assigned → running (rejects if unresolved blocking deps)
POST /api/v1/servers/tasks/{id}/complete API Key Transition: running → done (with result)
POST /api/v1/servers/tasks/{id}/fail API Key Transition: running → failed
POST /api/v1/servers/tasks/{id}/help API Key Transition: running → needs_human
POST /api/v1/server/tasks/{id}/notes API Key Agent adds note to task
POST /api/v1/server/tasks/{id}/plan API Key Worker submits plan (planning → plan_review)

Agent CLI / Orchestrator Endpoints

These endpoints power the orchestratia CLI tool and orchestrator agents. They provide full task management capabilities without requiring JWT authentication — API key auth only.

Method Path Auth Purpose
POST /api/v1/server/tasks API Key Create task (with type, repo, deps, acceptance criteria)
GET /api/v1/server/tasks API Key List tasks (filter by project_id, status)
GET /api/v1/server/tasks/check API Key Check for tasks assigned to a session
GET /api/v1/server/tasks/{id} API Key View task detail (with deps, resolved_inputs, server name)
PUT /api/v1/server/tasks/{id} API Key Update task fields (title, spec, priority, type, repo, etc.)
DELETE /api/v1/server/tasks/{id} API Key Cancel a task
POST /api/v1/server/tasks/{id}/start API Key Transition to running (rejects if unresolved blocking deps)
POST /api/v1/server/tasks/{id}/complete API Key Transition to done (string or structured result)
POST /api/v1/server/tasks/{id}/fail API Key Transition to failed (with error message)
POST /api/v1/server/tasks/{id}/help API Key Request human intervention
POST /api/v1/server/tasks/{id}/assign API Key Assign task to session by name (supports require_plan)
POST /api/v1/server/tasks/{id}/dependencies API Key Add typed dependency (blocks/input/related)
DELETE /api/v1/server/tasks/{id}/dependencies/{dep_id} API Key Remove dependency
POST /api/v1/server/tasks/{id}/notes API Key Add note to task
POST /api/v1/server/tasks/{id}/plan API Key Submit plan for review
GET /api/v1/server/servers API Key List all servers (name, status, repos, capabilities)

Agent Registration & Capabilities

Method Path Auth Purpose
POST /api/v1/servers/register Token Register with capabilities
POST /api/v1/servers/heartbeat API Key Update capabilities and system info

7. Backwards Compatibility

All protocol features are opt-in. The table below shows what changes and what stays the same:

Feature Without Protocol With Protocol
Task creation spec text only spec + structured_spec + requirements
Task result Freeform JSONB (or string) $schema + contracts + tests + changes
Dependencies UUID list (dependency_ids), blocks only Typed: blocks / input / related + contract_key
Agent registration repos dict only repos + full capabilities object
Task assignment Manual only Manual + auto-assign via capability matching
Data flow None (agents work in isolation) Contract exchange via resolved_inputs

Existing tasks without structured_spec or requirements continue to work identically. Existing agents without capabilities continue to receive manual assignments. No migration needed.

Version Checking

All structured schemas include a $schema field that identifies the protocol version:

  • orchestratia/task-spec/v1 — Task specification
  • orchestratia/task-result/v1 — Task result
  • orchestratia/capabilities/v1 — Agent capabilities
  • orchestratia/requirements/v1 — Task requirements

The hub validates schemas by prefix. Unknown versions are accepted but logged as warnings.