{
  "schemaVersion": 2,
  "name": "shared-handoff",
  "description": "A role-tagged shared-message channel across independent Pi agent invocations.",
  "entry": "analyst",
  "nodes": {
    "analyst": {
      "type": "agent",
      "description": "Analyze the task and establish facts for the writer.",
      "prompt": "Analyze this task and identify the decisive facts, constraints, and unanswered questions:\n\n{{input.task}}",
      "readOnly": true,
      "tools": [
        "read",
        "grep",
        "find",
        "ls"
      ],
      "output": "analysis",
      "context": {
        "mode": "shared",
        "messagesPath": "conversation.messages",
        "maxMessages": 20,
        "maxPromptBytes": 65536,
        "maxStoredMessages": 12
      },
      "limits": {
        "timeoutMs": 300000,
        "maxTurns": 10,
        "maxTokens": 60000,
        "maxCostUsd": 0.6
      }
    },
    "writer": {
      "type": "agent",
      "description": "Continue from the explicit shared conversation and produce the answer.",
      "prompt": "Using the prior shared conversation, produce a concise, actionable answer for:\n\n{{input.task}}\n\nPrior independent review, when present:\n{{review}}",
      "readOnly": true,
      "tools": [],
      "output": "answer",
      "context": {
        "mode": "shared",
        "messagesPath": "conversation.messages",
        "maxMessages": 20,
        "maxPromptBytes": 65536,
        "maxStoredMessages": 12
      },
      "limits": {
        "timeoutMs": 240000,
        "maxTurns": 8,
        "maxTokens": 50000,
        "maxCostUsd": 0.5
      }
    },
    "reviewer": {
      "type": "agent",
      "purpose": "reviewer",
      "description": "Review without inheriting the writer's private or shared conversational framing.",
      "prompt": "Independently review this answer for correctness, completeness, and unsupported claims.\n\nTask:\n{{input.task}}\n\nAnswer:\n{{answer}}\n\nReturn JSON with exactly: {\"approved\": boolean, \"issues\": string[]}.",
      "readOnly": true,
      "tools": [
        "read",
        "grep",
        "find",
        "ls"
      ],
      "output": "review",
      "response": {
        "format": "json",
        "maxBytes": 32768
      },
      "retry": {
        "maxAttempts": 3,
        "backoffMs": 500,
        "backoffMultiplier": 2
      },
      "idempotent": true,
      "onError": {
        "strategy": "route",
        "to": "__end__",
        "output": "errors.reviewer"
      },
      "context": {
        "mode": "isolated"
      },
      "limits": {
        "timeoutMs": 240000,
        "maxTurns": 8,
        "maxTokens": 50000,
        "maxCostUsd": 0.5
      }
    }
  },
  "edges": [
    {
      "from": "analyst",
      "to": "writer"
    },
    {
      "from": "writer",
      "to": "reviewer"
    }
  ],
  "routes": [
    {
      "from": "reviewer",
      "cases": [
        {
          "when": {
            "path": "review.approved",
            "op": "eq",
            "value": true
          },
          "to": "__end__"
        }
      ],
      "default": "writer"
    }
  ],
  "limits": {
    "maxSteps": 7,
    "maxNodeRuns": 9,
    "maxConcurrency": 1,
    "maxCostUsd": 3,
    "maxTokens": 300000,
    "timeoutMs": 1200000,
    "maxStateBytes": 1048576
  },
  "result": {
    "paths": [
      "answer",
      "review",
      "errors.reviewer"
    ],
    "includeState": false,
    "maxBytes": 65536
  },
  "policy": {
    "allowNonInteractive": true,
    "allowNonInteractiveMutations": false,
    "confirmProjectGraph": true,
    "confirmMutatingNodes": true
  }
}
