{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "multi-agent-handoff",
  "type": "registry:ui",
  "title": "Multi-agent handoff",
  "description": "Moves task ownership, artifacts, and the next responsible agent along one continuous relay.",
  "dependencies": [
    "motion"
  ],
  "categories": [
    "agent"
  ],
  "docs": "https://motion-lexicon.pages.dev/en/components/multi-agent-handoff/",
  "meta": {
    "engines": [
      "motion"
    ],
    "runtimeCost": "light",
    "signature": "Task ownership travels along an agent relay rail"
  },
  "files": [
    {
      "path": "src/registry/components/multi-agent-handoff.tsx",
      "type": "registry:ui",
      "target": "components/motion-lexicon/multi-agent-handoff.tsx",
      "content": "\"use client\";\n\nimport { motion, useReducedMotion } from \"motion/react\";\nimport { useState } from \"react\";\n\nexport type HandoffAgent = {\n  id: string;\n  name: string;\n  role: string;\n  initials: string;\n  tone?: \"blue\" | \"green\" | \"amber\";\n};\nexport type MultiAgentHandoffProps = {\n  agents: readonly HandoffAgent[];\n  task: string;\n  artifact?: string;\n  defaultActive?: number;\n  eyebrow?: string;\n  handoffLabel?: string;\n  ownerLabel?: (name: string) => string;\n  onHandoff?: (agent: HandoffAgent) => void;\n  className?: string;\n};\n\nconst tones = {\n  blue: \"bg-neutral-950 dark:bg-neutral-50 dark:text-neutral-950\",\n  green: \"bg-neutral-700 dark:bg-neutral-300 dark:text-neutral-950\",\n  amber: \"bg-neutral-500 dark:bg-neutral-400 dark:text-neutral-950\",\n} as const;\n\nexport function MultiAgentHandoff({\n  agents,\n  task,\n  artifact,\n  defaultActive = 0,\n  eyebrow = \"Agent relay\",\n  handoffLabel = \"Hand off\",\n  ownerLabel = (name) => `${name} owns the next action`,\n  onHandoff,\n  className = \"\",\n}: MultiAgentHandoffProps) {\n  const [active, setActive] = useState(\n    Math.min(defaultActive, Math.max(0, agents.length - 1)),\n  );\n  const reduced = useReducedMotion();\n  const next = agents.length ? (active + 1) % agents.length : 0;\n  const advance = () => {\n    if (!agents.length) return;\n    setActive(next);\n    onHandoff?.(agents[next]);\n  };\n  return (\n    <section\n      className={`w-full rounded-[10px] border border-neutral-200 bg-white p-4 text-neutral-950 dark:border-white/10 dark:bg-[#1b1b1b] dark:text-neutral-50 ${className}`}\n    >\n      <header className=\"flex items-center gap-2\">\n        <span className=\"text-[11px] font-medium text-neutral-500 dark:text-neutral-400\">\n          {eyebrow}\n        </span>\n        {artifact ? (\n          <code className=\"ml-auto rounded-md bg-neutral-100 px-2 py-1 text-[9px] text-neutral-500 dark:bg-white/5 dark:text-neutral-400\">\n            {artifact}\n          </code>\n        ) : null}\n      </header>\n      <h3 className=\"mt-3 text-[14px] font-semibold tracking-[-.02em]\">\n        {task}\n      </h3>\n      <div\n        className=\"relative mt-5 grid\"\n        style={{\n          gridTemplateColumns: `repeat(${Math.max(agents.length, 1)}, minmax(0, 1fr))`,\n        }}\n      >\n        <span\n          aria-hidden=\"true\"\n          className=\"absolute left-[12%] right-[12%] top-5 h-px bg-neutral-200 dark:bg-white/10\"\n        />\n        {agents.map((agent, index) => (\n          <div\n            key={agent.id}\n            className=\"relative z-10 grid justify-items-center text-center\"\n          >\n            <motion.span\n              className={`grid size-10 place-items-center rounded-full border-4 border-white text-[10px] font-semibold text-white shadow-sm dark:border-[#181818] ${tones[agent.tone ?? \"blue\"]}`}\n              animate={\n                index === active && !reduced\n                  ? {\n                      y: [0, -3, 0],\n                      boxShadow: [\n                        \"0 2px 6px rgba(0,0,0,.12)\",\n                        \"0 4px 10px rgba(0,0,0,.2)\",\n                        \"0 2px 6px rgba(0,0,0,.12)\",\n                      ],\n                    }\n                  : { opacity: index <= active ? 1 : 0.45 }\n              }\n              transition={{\n                duration: 1.6,\n                repeat: index === active ? Infinity : 0,\n              }}\n            >\n              {agent.initials}\n            </motion.span>\n            <strong className=\"mt-2 text-[10px]\">{agent.name}</strong>\n            <span className=\"mt-0.5 text-[8px] text-neutral-400\">\n              {agent.role}\n            </span>\n          </div>\n        ))}\n      </div>\n      <div className=\"mt-5 border-t border-neutral-100 pt-3 dark:border-white/8\">\n        <div className=\"flex items-center gap-2\">\n          <span className=\"size-1.5 rounded-full bg-neutral-950 dark:bg-neutral-50\" />\n          <span className=\"text-[10px] text-neutral-500 dark:text-neutral-400\">\n            {ownerLabel(agents[active]?.name ?? \"Agent\")}\n          </span>\n        </div>\n        <button\n          type=\"button\"\n          disabled={agents.length < 2}\n          onClick={advance}\n          className=\"mt-3 min-h-11 w-full rounded-lg bg-neutral-950 text-[10px] font-semibold text-white outline-none focus-visible:ring-2 focus-visible:ring-blue-600 disabled:opacity-40 dark:bg-neutral-50 dark:text-neutral-950\"\n        >\n          {handoffLabel} → {agents[next]?.name}\n        </button>\n      </div>\n    </section>\n  );\n}\n"
    }
  ]
}
