Skip to content

The system.json Specification

If agent.json defines a single worker, system.json is the factory floor. It orchestrates multiple agents working together in sequence, parallel, or via conditional logic.

The Docker Compose Analogy

Think of agent.json like a Dockerfile, and system.json like docker-compose.yml. Systems are just wiring; the logic lives in the agents.

Referencing Agents

Systems must reference agents that already exist. You can reference them by their deployed ID or by their source file path if deploying a monorepo.

json
// By ID (already deployed)
{ "agent": "id:researcher-agent-v2" }

// By Source Path
{ "agent": "path:./agents/researcher.json" }

Complete System Example

json
{
  "name": "content-pipeline",
  "description": "Researches a topic and writes a blog post.",
  "version": "1.0",
  "config": {
    "max_concurrency": 5,
    "on_failure": "stop"
  },
  "agents": {
    "researcher": { "agent": "path:./agents/researcher.json" },
    "writer": { "agent": "path:./agents/writer.json" }
  },
  "flow": {
    "type": "sequence",
    "steps": [
      {
        "id": "step_research",
        "agent": "researcher",
        "input_template": "Research the following topic: \{\{ system.input }}"
      },
      {
        "id": "step_write",
        "agent": "writer",
        "input_template": "Write a 500-word blog post based on these notes: \{\{ step_research.output }}"
      }
    ]
  }
}

The flow Section

This is the most complex part of a system. It defines the topology of the execution graph.

Sequential Flows

Execute agents one after another, passing the output of step N as the input to step N+1.

Parallel Flows

Execute multiple agents simultaneously. Perfect for divergent tasks like researching multiple sub-topics at once.

json
"flow": {
  "type": "parallel",
  "entry": ["agent_a", "agent_b", "agent_c"],
  "merge_strategy": "concat" // merge strategies: 'concat', 'summarise', 'vote'
}

Conditional Routing

Route execution paths dynamically based on an agent's output. Note: A default route is mandatory.

json
"flow": {
  "type": "router",
  "agent": "classifier_agent",
  "conditions": [
    {
      "if_output_contains": "technical",
      "route_to": "senior_engineer_agent"
    },
    {
      "if_output_contains": "billing",
      "route_to": "billing_support_agent"
    }
  ],
  "default_route": "general_support_agent"
}

Data Mapping

The input_template field uses standard Handlebars mustache syntax. You can reference data from:

  • \{\{ system.input }} - The string passed when calling the system API endpoint.
  • \{\{ step_id.output }} - The final string output from a specific previous step.
  • \{\{ env.VARIABLE_NAME }} - An environment variable.

Validation Rules

When you run savine deploy, the platform runs a topological sort to validate your graph. It checks for:

  • Cyclic dependencies: DAGs strictly enforced, loops return ValidationError.
  • Dangling references: Referencing an agent not declared in the "agents" object.
  • Missing default routes: Every router must have a fallback path.

Example Systems

We maintain a library of common architectures:

  • Research Pipeline (Sequence)
  • Triage and Route (Router)
  • Multi-perspective Analysis (Parallel with Vote merge)
  • Human-in-the-loop Approval (Suspends execution pending API callback)