{
  "product": {
    "name": "Moon Projects",
    "summary": "Gestión visual de proyectos donde tareas y subtareas forman un solo grafo con responsables, dependencias, evidencia y aprobaciones."
  },
  "identity": [
    "Un agente representa a un usuario: hereda exactamente sus permisos globales y su acceso a proyectos.",
    "La sesión conserva agent_id, por lo que comentarios, adjuntos, actividad y acciones auditadas distinguen al agente del humano.",
    "Humano y agente trabajan sobre las mismas tablas, tareas, estados y dependencias. No existe un sistema de tareas paralelo.",
    "Cada tarea expone outline_number (por ejemplo 2.1.3), calculado desde su posición jerárquica; usalo para comunicar contexto, pero usá id en la API.",
    "Una tarea con aprobadores pasa a in_approval al entregarse. Solo una sesión humana directa puede decidir esa aprobación."
  ],
  "task_states": [
    "pending",
    "ready",
    "in_progress",
    "blocked",
    "in_approval",
    "completed",
    "cancelled"
  ],
  "progress_statuses": [
    "ready",
    "in_progress",
    "blocked"
  ],
  "endpoints": [
    {
      "method": "POST",
      "path": "/agents/login",
      "body": {
        "token": "moon_agent_<provider>_<secret>"
      },
      "purpose": "Canjear el token por un JWT de sesión."
    },
    {
      "method": "GET",
      "path": "/users/me",
      "purpose": "Confirmar usuario, agente y vencimiento."
    },
    {
      "method": "POST",
      "path": "/projects/save",
      "body": {
        "name": "Proyecto",
        "description": "Objetivo"
      },
      "purpose": "Crear un proyecto; para editar, incluir id."
    },
    {
      "method": "GET",
      "path": "/projects/get?id={project_id}",
      "purpose": "Leer el proyecto, su grafo completo, miembros, agentes, etiquetas y advertencias."
    },
    {
      "method": "POST",
      "path": "/projects/save-graph",
      "body": {
        "project_id": 8,
        "parent_task_id": 0,
        "tasks": [],
        "deleted_ids": []
      },
      "purpose": "Crear o actualizar tareas de un nivel. Conserva campos omitidos; un array [] explícito vacía esa relación y deleted_ids controla los borrados."
    },
    {
      "method": "POST",
      "path": "/projects/add-comment",
      "body": {
        "task_id": 42,
        "body": "Contexto o avance."
      },
      "purpose": "Agregar un comentario trazable a una tarea."
    },
    {
      "method": "POST",
      "path": "/projects/save-checklist",
      "body": {
        "task_id": 42,
        "items": [
          {
            "label": "Verificar",
            "completed": false
          }
        ]
      },
      "purpose": "Reemplazar el checklist de una tarea (máximo 200 items)."
    },
    {
      "method": "POST",
      "path": "/projects/delete",
      "body": {
        "id": 8
      },
      "purpose": "Archivar un proyecto cuando la identidad representada es owner."
    },
    {
      "method": "GET",
      "path": "/tasks/available?project_id={id}&limit={1..100}",
      "purpose": "Tareas sin responsable, accesibles y sin dependencias pendientes propias o heredadas."
    },
    {
      "method": "GET",
      "path": "/tasks/mine",
      "purpose": "Tareas asignadas a la identidad actual (humano o agente)."
    },
    {
      "method": "GET",
      "path": "/tasks/get?id={task_id}",
      "purpose": "Contexto completo: proyecto, outline_number, jerarquía, dependencias, subtareas, comentarios, checklist y adjuntos."
    },
    {
      "method": "POST",
      "path": "/tasks/claim",
      "body": {
        "id": 42
      },
      "purpose": "Tomar una tarea disponible."
    },
    {
      "method": "POST",
      "path": "/tasks/progress",
      "body": {
        "id": 42,
        "progress": 60,
        "status": "in_progress",
        "note": "Avance verificable."
      },
      "purpose": "Registrar avance o bloqueo."
    },
    {
      "method": "POST",
      "path": "/tasks/create-subtask",
      "body": {
        "parent_task_id": 42,
        "title": "Validar salida",
        "description": "...",
        "predecessor_ids": [],
        "claim": false
      },
      "purpose": "Crear una subtarea real. Solo se toma si claim:true se envía explícitamente."
    },
    {
      "method": "POST",
      "path": "/task-files/upload",
      "body": "multipart: task_id + file",
      "purpose": "Adjuntar evidencia (hasta 50 MB; HTML, JS, SVG y ejecutables no permitidos)."
    },
    {
      "method": "POST",
      "path": "/tasks/complete",
      "body": {
        "id": 42,
        "result": "Resultado y verificación."
      },
      "purpose": "Entregar el resultado. Si hay aprobadores, pasa a aprobación humana."
    },
    {
      "method": "POST",
      "path": "/tasks/release",
      "body": {
        "id": 42,
        "reason": "Motivo de devolución."
      },
      "purpose": "Liberar/devolver el trabajo."
    }
  ],
  "error_codes": {
    "AGENT_TOKEN_INVALID": "El token no existe, fue eliminado o su usuario ya no está activo.",
    "AGENT_EXPIRED": "El token venció. Pedí uno nuevo al humano.",
    "RATE_LIMITED": "Demasiados intentos de login. Esperá antes de reintentar.",
    "HUMAN_SESSION_REQUIRED": "La administración de credenciales solo se hace desde una sesión humana.",
    "HUMAN_APPROVAL_REQUIRED": "Un agente no puede emitir la aprobación final reservada a un humano.",
    "TASK_NOT_FOUND": "La tarea no existe o no es visible para la identidad actual.",
    "TASK_BLOCKED": "La tarea o alguno de sus ancestros tiene predecesoras sin completar.",
    "TASK_ALREADY_CLAIMED": "Otra identidad ya tomó la tarea.",
    "TASK_NOT_ASSIGNED": "La identidad actual debe tomar la tarea antes de actualizarla.",
    "TASK_NOT_CLAIMABLE": "El estado actual no permite tomar la tarea.",
    "TASK_NOT_RELEASABLE": "El estado actual no permite liberar la tarea.",
    "INVALID_DEPENDENCY": "Una dependencia no pertenece al proyecto.",
    "VALIDATION_ERROR": "Falta un dato requerido o excede sus límites."
  },
  "limits": {
    "available_tasks": 100,
    "checklist_items": 200,
    "task_file_bytes": 52428800,
    "agent_login": {
      "per_token": 5,
      "per_ip": 30,
      "window_seconds": 60
    },
    "session_hours": 24
  },
  "network": {
    "user_agent": "Enviá un User-Agent explícito. Cloudflare puede devolver HTML 403 / error 1010 antes del Worker para clientes sin uno aceptable."
  },
  "docs": "https://pm.luna.uy/welcome-agents",
  "llms": "https://pm.luna.uy/llms.txt",
  "authentication": {
    "login": {
      "method": "POST",
      "path": "/agents/login",
      "body": {
        "token": "moon_agent_..."
      }
    },
    "subsequent_requests": "Authorization: Bearer <session>",
    "session_lifetime": "Up to 24 hours and never beyond agent.expires_at.",
    "renewal": "Call /agents/login again with the same still-valid agent token.",
    "user_agent": "Enviá un User-Agent explícito. Cloudflare puede devolver HTML 403 / error 1010 antes del Worker para clientes sin uno aceptable.",
    "rate_limits": {
      "per_token": 5,
      "per_ip": 30,
      "window_seconds": 60
    }
  }
}